【问题标题】:How do I know if my app was opened from console or windows in C#我如何知道我的应用程序是从 C# 中的控制台还是窗口打开的
【发布时间】:2018-06-29 11:12:50
【问题描述】:

我有一个既是 gui 又是控制台的应用程序。

控制台:它从windows计划执行以执行一些自动化任务,因此使用参数调用它

GUI:用于输入配置参数,比控制台更好的用户输入方式。

这一切都很好。它主要是一个控制台应用程序,如果在没有参数的情况下打开控制台并显示配置表单,则会隐藏控制台。

问题: 如果我从没有参数的控制台打开它,控制台将被隐藏并显示表单。 我如何检测我打开应用程序的内容或位置,如果它是从 Windows 打开然后隐藏控制台,如果它是从控制台打开然后显示控制台。

【问题讨论】:

  • 也许只是让它默认为控制台模式并需要一个参数来打开 GUI,您可以为此创建一个快捷方式供用户使用。看不到How to check if the program is run from a console?
  • 您可以检查您正在运行的进程并找到您需要的进程并根据需要应用操作。

标签: c# .net winforms console


【解决方案1】:

如果您真的想知道您的应用程序在“哪里”启动,您必须知道您的父进程是什么。为了了解你的父进程,你可以阅读How to get parent process in .NET in managed way的解决方案

然后您可以检查您的父进程名称是否为 explorer(windows) 以将您的应用程序作为 GUI 打开。

示例代码基于How to get parent process in .NET in managed way提供的解决方案

namespace ConsoleApp1
{
    public static class ProcessExtensions
    {
        private static string FindIndexedProcessName(int pid)
        {
            var processName = Process.GetProcessById(pid).ProcessName;
            var processesByName = Process.GetProcessesByName(processName);
            string processIndexdName = null;

            for (var index = 0; index < processesByName.Length; index++)
            {
                processIndexdName = index == 0 ? processName : processName + "#" + index;
                var processId = new PerformanceCounter("Process", "ID Process", processIndexdName);
                if ((int)processId.NextValue() == pid)
                {
                    return processIndexdName;
                }
            }

            return processIndexdName;
        }
        private static Process FindPidFromIndexedProcessName(string indexedProcessName)
        {
            var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName);
            return Process.GetProcessById((int)parentId.NextValue());
        }

        public static Process Parent(this Process process)
        {
            return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id));
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(Process.GetCurrentProcess().Parent().ProcessName);
            Console.ReadKey();
        }
    }
}

此代码将输出:

  • 在 Visual Studio 中调试:devenv
  • 从windows开始:explorer
  • 从cmd开始:cmd
  • 从 powershell 控制台开始:powershell
  • ...

【讨论】:

  • @magiva 是否完全回答了您的问题?如果不能,请告诉我您需要什么或为什么这个答案不完整,我会尽力使它变得更好。如果它确实回答了您的问题,您可以将您的问题标记为已回答吗?
  • 这是一个完美的解决方案,可以很好地完成此任务。现在,我的控制台应用程序将隐藏控制台,如果它从资源管理器中打开,控制台在所有其他类型下保持打开状态,完美。非常感谢
【解决方案2】:

这样做的一种方法是将您的 cli 版本和 gui 版本分离为 2 个可执行文件(例如 7z 使用 7z.exe 命令行工具和 7zG Gui 版本)

你可以在 Visual Studio 中有 3 个项目:

  • MyApp.Console(控制台应用)
  • MyApp.WindowsGui(winform/wpf 应用)
  • MyApp.Logic(所有逻辑)

Console 和 WindowsGui 引用了您的 Logic 项目

这将为您提供更简洁的代码,因为每个“前端”项目将只处理它们的目的(处理 GUI 或控制台内容),并且您的逻辑可以由两个前端调用

【讨论】:

    【解决方案3】:

    我不清楚您要达到的目标。据我了解,无论是否有参数,该应用程序都将作为控制台应用程序启动。为了防止它消失,您可以使用Boolean 来防止窗口在用户输入配置时关闭。例如(DialogResult 的语法可能不是 100%):

    using System;
    using System.Windows.Forms;
    
    // Allows you to access the static objects of Console
    //     without having to repeatedly type Console.Something.
    using static System.Console;
    
    static bool configured = false;
    static bool showForm = false;
    static void Main(string[] args) {
        showForm = args.Length < 1;
        if (showForm) {
            WriteLine("The application needs to be configured.");
            using (ConfigForm config = new ConfigForm()) {
                if (config.ShowDialog() == DialogResult.OK) {
                    showForm = false;
                    configured = true;
                    // Set your configured arguments here.
                }
            }
        }
    
        // Prevents the console from closing.
        while (showForm)
            ReadKey();
    
        // Do your processing in this condition.
        if (!showForm && configured)
            WriteLine("Thanks for playing. Press any key to exit.");
        else // Retry or exit in this one.
            WriteLine("An error occurred. Press any key to exit.");
    
        ReadKey();
    }
    

    如果您的应用程序被设置为控制台应用程序,那么它将默认启动控制台窗口。现在,如果您需要在不同时间显示和隐藏您的控制台,您可以查看this post,其中接受的答案提供了一种利用 Windows API 实现此目的的正确方法,而无需执行一些阴暗的逻辑来按标题查找窗口或身份。

    using System.Runtime.InteropServices;
    
    [DllImport("kernel32.dll")]
    static extern IntPtr GetConsoleWindow();
    
    [DllImport("user32.dll")]
    static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    
    const int SW_HIDE = 0;
    const int SW_SHOW = 5;
    
    var handle = GetConsoleWindow();
    
    // Hide
    ShowWindow(handle, SW_HIDE);
    
    // Show
    ShowWindow(handle, SW_SHOW);
    

    如果这不能解决您的需要,请随时在您的帖子中更详尽,并包含一些代码来为您的问题提供更多定义。我无法评论和提问,所以我给出了一个基本的解决方案。如果您有任何问题,请随时提出。

    【讨论】:

    • 我可以理解这个问题看起来很奇怪,但它是这样工作的。它可以在没有参数的情况下从 cmd 调用,我不希望控制台在那个时候隐藏,或者实际上我想在它关闭时重新显示它,如果我从 Windows 打开那么它只会隐藏控制台,控制台是我需要它在控制台和窗口中工作的副产品。我需要它作为控制台应用程序的原因是我可以使用 Windows 计划中的服务器上的参数调用它。我不确定我是否能以更好的方式帮助解释它。
    【解决方案4】:

    这可能会有所帮助:

    using System;
    using System.Diagnostics;
    
    static class IsRanFromConsole
    {
        private static readonly string[] consoleNames = {
            "cmd", "bash", "ash", "dash", "ksh", "zsh", "csh",
            "tcsh", "ch", "eshell", "fish", "psh", "pwsh", "rc",
            "sash", "scsh", "powershell", "tcc"
        };
    
        private static bool isCache = false;
        private static bool isConsole;
    
        public static bool IsConsole()
        {
            if (!isCache)
            {
                string parentProc = Process.GetCurrentProcess().Parent().ProcessName;
                isConsole = Array.IndexOf(consoleNames, parentProc) > -1;
            }
            return isConsole;
        }
    }
    

    用法:

    Console.WriteLine(IsRanFromConsole.IsConsole());
    

    .Parent()函数需要添加this code

    【讨论】:

      猜你喜欢
      • 2010-10-01
      • 1970-01-01
      • 2015-01-08
      • 1970-01-01
      • 2011-12-04
      • 2011-05-02
      • 1970-01-01
      相关资源
      最近更新 更多