代码之家  ›  专栏  ›  技术社区  ›  Ben Voigt

从cygwin shell启动时,写入stdout的位置,没有重定向

  •  14
  • Ben Voigt  · 技术社区  · 14 年前

    我有一个应用程序,我们称之为myapp.exe,它是双模控制台/gui,内置为/subsystem:windows(有一个很小的3kb填充程序myapp.com,它会使cmd.exe等待显示新的提示。)

    如果我从命令提示符启动:

    • myapp ->cmd.exe运行myapp.com,其中运行myapp.exe。stdout最初是一个独立的控制台,通过使用 AttachConsole freopen("CONOUT$", "w", stdout) 我的输出显示在命令框中。好啊
    • myapp.exe ->cmd.exe显示提示太早(已知问题),否则与上一个相同。不是正常使用场景。
    • myapp > log ->stdout是一个文件,通常使用 std::cout 最后出现在文件中。好啊

    如果我从Windows资源管理器启动:

    • myapp.com ->创建控制台,stdout是控制台,输出进入控制台。与对整个程序使用/subsystem:console的结果相同,只是在 myapp.com网站 是控制台中唯一的进程。不是正常使用场景。
    • myapp.exe文件 ->stdout是一个空句柄,我检测到它并挂起 STD:: 到一个图形用户界面。好啊

    如果我从matlab shell启动:

    • system('myapp') system('myapp.com') system('myapp.exe') ->对于所有三种变体,stdout都通过管道传输到matlab。好啊

    如果我从cygwin bash shell启动:

    • ./myapp.com ->就像从cmd.exe启动一样,输出显示在命令框中。好啊
    • ./myapp ->(bash发现 ./myapp.exe ) 这是破箱子 . stdout是一个非空的句柄,但输出不去任何地方。这是从bash运行程序的正常情况,需要修复!
    • ./myapp > log ->就像通过文件重定向从cmd.exe启动一样。好啊
    • ./myapp | cat ->类似于文件重定向,但输出最终出现在控制台窗口上。好啊

    是否有人知道Cygwin在启动/subsystem:windows进程时将什么设置为stdout,以及如何绑定 STD:: 去吗?或者至少告诉我如何找出我要从哪种方式得到回报 GetStdHandle(STD_OUTPUT_HANDLE) ?

    我的程序是用Visual C++ 2010编写的,没有 /clr 如果这在任何方面都很重要。操作系统是Windows7 64位。

    编辑:请求的其他信息。

    cygwin环境变量为空(或不存在)。

    GetFileType() 退货 FILE_TYPE_UNKNOWN . GetLastError() 退货 6 (ERROR_INVALID_HANDLE) . 我打电话之前还是之后都查对了 AttachConsole() .

    但是,如果我只是忽略了无效的句柄, freopen(“conout$”,“w”,stdout) 然后一切都很好。我只是缺少一种区分(总线化)控制台输出和文件重定向的方法,以及 获取文件类型() 前提是。

    编辑:最终代码:

    bool is_console(HANDLE h)
    {
        if (!h) return false;
    
        ::AttachConsole(ATTACH_PARENT_PROCESS);
    
        if (FILE_TYPE_UNKNOWN == ::GetFileType(h) && ERROR_INVALID_HANDLE == GetLastError()) {
            /* workaround cygwin brokenness */
            h = ::CreateFile(_T("CONOUT$"), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
            if (h) {
                ::CloseHandle(h);
                return true;
            }
        }
    
        CONSOLE_FONT_INFO cfi;
        return ::GetCurrentConsoleFont(h, FALSE, &cfi) != 0;
    }
    
    
    bool init( void )
    {
        HANDLE out = ::GetStdHandle(STD_OUTPUT_HANDLE);
    
        if (out) {
            /* stdout exists, might be console, file, or pipe */
            if (is_console(out)) {
    #pragma warning(push)
    #pragma warning(disable: 4996)
                freopen("CONOUT$", "w", stdout);
    #pragma warning(pop)
            }
            //std::stringstream msg;
            //DWORD result = ::GetFileType(out);
            //DWORD lasterror = ::GetLastError();
            //msg << result << std::ends;
            //::MessageBoxA(NULL, msg.str().c_str(), "GetFileType", MB_OK);
            //if (result == FILE_TYPE_UNKNOWN) {
            //  msg.str(std::string());
            //  msg << lasterror << std::ends;
            //  ::MessageBoxA(NULL, msg.str().c_str(), "GetLastError", MB_OK);
            //}
            return true;
        }
        else {
            /* no text-mode stdout, launch GUI (actual code removed) */
        }
    }
    
    1 回复  |  直到 14 年前
        1
  •  3
  •   ak2    14 年前

    这个 GetFileType() 函数允许区分某些类型的句柄,特别是控制台、管道、文件和断开的句柄。