【问题标题】:How to check if the program is run from a console?如何检查程序是否从控制台运行?
【发布时间】:2012-02-19 00:40:06
【问题描述】:

我正在编写一个将一些诊断信息转储到标准输出的应用程序。

我想让应用程序以这种方式工作:

  • 如果它是从独立的命令提示符运行(通过cmd.exe)或将标准输出重定向/传送到文件,则在完成后立即退出,
  • 否则(如果它从一个窗口运行并且控制台窗口是自动生成的),那么 另外在窗口消失之前等待按键退出(让用户阅读诊断)

我该如何区分? 我怀疑检查父进程可能是一种方法,但我并没有真正进入 WinAPI,因此提出了这个问题。

我在 MinGW GCC 上。

【问题讨论】:

标签: c++ c winapi


【解决方案1】:

典型的测试是:

如果(伊萨蒂(STDOUT_FILENO)){ /* 这是一个终端 */ }

【讨论】:

  • 我认为在 Windows 上它是 _isatty,在 中声明
  • 这是否区分具有自己的控制台窗口的程序和具有从其父进程继承的控制台窗口的程序?
  • 我认为这不是 OP 所追求的,我认为 OP 想要一种方法来确定程序是否在现有终端窗口中运行,或者终端窗口是否只是为过程。
  • 有需要的,windows的方式是:if (_isatty(_fileno(stdout)))
  • 当您使用控制台并将输出重定向到文件时不起作用。
【解决方案2】:

Microsoft 的 I18N 专家 Michael Kaplan 提供了a series of methods on his blog,让您可以在控制台上检查一堆东西,包括控制台是否已被重定向。

它们是用 C# 编写的,但移植到 C 或 C++ 会非常简单,因为这一切都是通过调用 Win32 API 完成的。

【讨论】:

    【解决方案3】:

    您可以使用GetConsoleWindowGetWindowThreadProcessIdGetCurrentProcessId 方法。

    1) 首先您必须使用GetConsoleWindow 函数检索控制台窗口的当前句柄。

    2) 然后你得到控制台窗口句柄的进程所有者。

    3) 最后将返回的 PID 与应用程序的 PID 进行比较。

    检查此示例(VS C++)

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    #if       _WIN32_WINNT < 0x0500
      #undef  _WIN32_WINNT
      #define _WIN32_WINNT   0x0500
    #endif
    #include <windows.h>
    #include "Wincon.h" 
    
    int _tmain(int argc, _TCHAR* argv[])
    {   
        HWND consoleWnd = GetConsoleWindow();
        DWORD dwProcessId;
        GetWindowThreadProcessId(consoleWnd, &dwProcessId);
        if (GetCurrentProcessId()==dwProcessId)
        {
            cout << "I have my own console, press enter to exit" << endl;
            cin.get();
        }
        else
        {
            cout << "This Console is not mine, good bye" << endl;   
        }
    
    
        return 0;
    }
    

    【讨论】:

    • 在我能想到的所有情况下都像魅力一样,在 MinGW 上也是如此。完美,谢谢!
    • 很高兴为您提供帮助,请注意此方法不会检查控制台的重定向。为此,您可以使用 GetStdHandleGetFileInformationByHandle 函数。
    • GetWindowThreadProcessId 不会返回 CSRSS 的 ID,而不是最开始在该窗口中运行的程序吗?
    • 另一种适用于 Windows 和 Linux 的方法是获取环境变量“PROMPT”。如果它没有返回 NULL,那么您是从控制台运行的。然后使用 isatty/_isattty 方法在 William Pursell 的回答中捕获重定向,这比从 GetFileInformationByHandle 检查失败更简单,我认为它仅适用于 Windows。
    • @RobKennedy: GetWindowThreadProcessId() 不会报告csrss.exe(甚至conhost.exe)的进程ID。尽管这是管理控制台 object 及其 I/O 缓冲区的进程,但它并不是创建实际控制台 window 的进程。
    【解决方案4】:

    我在 C# 中需要这个。这是翻译:

    [DllImport("kernel32.dll")]
    static extern IntPtr GetConsoleWindow();
    
    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcessId();
    
    [DllImport("user32.dll")]
    static extern int GetWindowThreadProcessId(IntPtr hWnd, ref IntPtr ProcessId);
    
    static int Main(string[] args)
    {
        IntPtr hConsole = GetConsoleWindow();
        IntPtr hProcessId = IntPtr.Zero;
        GetWindowThreadProcessId(hConsole, ref hProcessId);
    
        if (GetCurrentProcessId().Equals(hProcessId))
        {
            Console.WriteLine("I have my own console, press any key to exit");
            Console.ReadKey();
        }
        else
            Console.WriteLine("This console is not mine, good bye");
    
        return 0;
    }
    

    【讨论】:

      【解决方案5】:

      在尝试了很多不同的 api 和调用之后,我发现只有一种可行的方法:

      bool isConsole = isatty(fileno(stdin));
      

      不能使用标准输出,因为您可以运行控制台应用程序并使用&gt;log.txt 开关将输出重定向到文件。怀疑也可以重定向输入,但在运行控制台应用程序时很少使用它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-02-11
        • 1970-01-01
        • 1970-01-01
        • 2010-10-19
        • 1970-01-01
        相关资源
        最近更新 更多