【问题标题】:Making CreateProcess inherit the console of the calling process使 CreateProcess 继承调用进程的控制台
【发布时间】:2008-12-04 12:02:06
【问题描述】:

当我在 Windows 中调用 CreateProcess 时,新进程似乎没有继承调用进程的控制台。我制作了一个运行“ruby xtest”的测试程序,xtest 是一个将“hello”写入标准输出的脚本。我从 Emacs 运行了这个测试程序,但没有得到任何输出。我还尝试了以下调用 GetStdHandle 的代码,但同样没有输出。然后我尝试将 dwCreationFlags 中的 CREATE_NEW_CONSOLE 传递给 CreateProcess,它使用 Ruby 输出创建了一个全新的窗口。最后,我做了一个简单的 fork/exec 测试程序并使用 Cygwin 的 GCC 编译它。该程序有效:Ruby 输出按预期显示在 Emacs 中。我试图破译http://cygwin.com/cgi-bin/cvsweb.cgi/src/winsup/cygwin/spawn.cc?rev=1.268&content-type=text/x-cvsweb-markup&cvsroot=src 中的 Cygwin 源代码,但失败了。那么,如何让新进程继承父进程的控制台,让子进程的输出按预期显示呢?

STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if(!CreateProcess(0, "ruby xtest", 0, 0, 1, 0, 0, 0, &si, &pi)) die("CreateProcess");

【问题讨论】:

  • 我发现最有效的是创建标志的未记录值 0,就像在给出的示例中一样。 VS 2019 和 MSYS2/MinGW 的 gcc 9.1 为 Windows 7(非 UNICODE 模式)编译时按预期工作。因此,如果该示例在大约 11 年前失败,则可能是由于 WIn32 API 在这个未记录的案例中表现不同。

标签: windows console createprocess


【解决方案1】:

我知道,这个帖子有点老了,但是我遇到了同样的问题。

就像 TS 一样,控制台句柄是继承的,并且在 Cygwin 下可以正常工作,但在 Windows 控制台上却不行。相反,既没有显示 stdout 上的输出,也没有报告任何错误。继承的管道句柄仍然可以正常工作。

我花了一些时间来确定(现在很明显的)问题:使用 CREATE_NO_WINDOW 调用了 CreateProcess()。删除此标志,控制台输出就可以了。 (不过,根据 TS 的代码,他们从一开始就没有设置这个标志。)

希望这可能对像我一样偶然发现此线程的人有所帮助。

【讨论】:

  • 谢谢你,它为我节省了很多时间和麻烦!
【解决方案2】:

根据微软文档,lpCommandLine(2.参数):

此函数的 Unicode 版本 CreateProcessW 可以修改此字符串的内容。因此,此参数不能是指向只读内存的指针(例如 const 变量或文字字符串)。如果此参数是一个常量字符串,该函数可能会导致访问冲突。

当我在这里停止使用常量时,它对我有用。我不需要 STARTF_USESTDHANDLES 和 GetStdHandle 东西。

来自控制台 prg 的此代码在同一控制台中运行并输出另一个控制台 exe:

FillChar(SI, SizeOf(SI), 0);
SI.cb:=SizeOf(SI);
FillChar(PI, SizeOf(PI), 0);
if CreateProcess(nil, CmdLineVar, nil, nil, False, 0, nil, nil, SI, PI) then ...

【讨论】:

    【解决方案3】:

    我通过传入hStdInputhStdOutputhStdError 的管道并手动将来自hStdOutputhStdError 管道的数据路由到控制台来完成此操作。

    【讨论】:

      【解决方案4】:

      不确定 debeige 是否解决了这个问题,但我需要同样的东西,但启动另一个线程来监听 stdout 输出,只是把它放在 stdout 上对我来说似乎很疯狂。

      以下内容对我有用,与他最初发布的内容略有不同。一开始我以为不设置si.cb就不行,但是当我在我的评论中,它仍然有效,所以...... YMMV。

         STARTUPINFO siStartInfo;
         ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
         siStartInfo.cb = sizeof(STARTUPINFO); 
         siStartInfo.hStdError = GetStdHandle(STD_OUTPUT_HANDLE); 
         siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 
         siStartInfo.hStdInput = g_hChildStd_IN_Rd;  // my outgoing pipe
         siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
      
      // Create the child process. 
      
         bSuccess = CreateProcess(
            NULL,         
            szCmdline,    
            NULL,         
            NULL,         
            TRUE,         
            0,            
            NULL,         
            NULL,         
            &siStartInfo, 
            &piProcInfo); 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-07-11
        • 2012-09-18
        • 1970-01-01
        • 2012-01-01
        • 2015-03-20
        • 2015-09-15
        • 1970-01-01
        相关资源
        最近更新 更多