用于Windows的可执行包装的CreateProcess用法?

TL; DR

CreateProcess(?, ?, ?, ...)用于:

  • 传递当前进程参数(即“batchfile” %*
  • 正确连接标准input和标准输出
  • 创build标志?

我有以下问题:

  • 我需要启动一个给定的第三方可执行文件与自定义的环境和自定义参数。 (两个半固定)
  • 我不能使用batch file,因为调用模块的(再次,第三方)方直接调用CreateProcess
  • 我需要传递任何传递的参数

所以,我想要做的是创build一个非常简单的可执行文件启动程序,这将是一个batch file的等价物:

 set PATH=... set WHATEVER=... ...\3rd-pty-tool.exe -switch1 -switch2 %* exit /B %ERRORLEVEL% 

我当然不想把任何bat2exe转换器的东西搞砸了 – 反正当我有Visual Studio的时候太难看了。

原则上 通过CreateProcess运行另一个可执行文件是微不足道

 STARTUPINFO info={sizeof(info)}; PROCESS_INFORMATION processInfo; if (CreateProcess(?, ?, ?, ?, ?, ?, ?, ?, &info, &processInfo)) { WaitForSingleObject(processInfo.hProcess, INFINITE); CloseHandle(processInfo.hProcess); CloseHandle(processInfo.hThread); } 

通过_putenv等设置subprocess的环境。 也很容易。

但对我来说不是微不足道的是传递给CreateProcess

 BOOL WINAPI CreateProcess( _In_opt_ LPCTSTR lpApplicationName, _Inout_opt_ LPTSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCTSTR lpCurrentDirectory, _In_ LPSTARTUPINFO lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation ); 
  • 如何获得当前Win32进程的%*等价物?
  • 只传递lpApplicationName ,只lpCommandLine或两者?
  • 如何处理inheritance和创build标志?
  • 如何正确地转发/返回stdin和stdout?

不是一个愚蠢的: CreateProcess执行Windows命令

应该是合理的直截了当。

 BOOL WINAPI CreateProcess( _In_opt_ LPCTSTR lpApplicationName, _Inout_opt_ LPTSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCTSTR lpCurrentDirectory, _In_ LPSTARTUPINFO lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation ); 

让我们按顺序。

  • lpApplicationName – 如果你有要运行的可执行文件的完整路径,把它放在这里。 这样可以确保获得所需的可执行文件,即使PATH上有另一个具有相同名称的可执行文件。

  • lpCommandLine – 第一个元素是可执行文件的名称。 如果你已经指定了lpApplicationName这个不需要完全限定,甚至是可执行文件的实际名称,但是它确实需要存在。 这必须是一个可写的缓冲区,它不能是一个常量字符串。

如果你的额外参数可以在命令行的末尾进行,这很简单:

 wchar_t buffer[1024]; wcscpy_s(buffer, _countof(buffer), GetCommandLine()); wcscat_s(buffer, _countof(buffer), L" -switch1 -switch2"); 

否则,你需要解析命令行来找到插入参数的正确位置,如下所示:

 while (*lpCmdLine == L' ') lpCmdLine++; while (ch = *lpCmdLine) { if (ch == L'"') for (lpCmdLine++; ch = *lpCmdLine; lpCmdLine++) if (ch == L'"') break; if (ch == L' ') break; lpCmdLine++; } while (*lpCmdLine == L' ') lpCmdLine++; 
  • lpProcessAttributeslpThreadAttributesNULL

  • bInheritHandlesTRUE ,因为您希望孩子继承标准手柄。

  • dwCreationFlags – 在你的场景中不需要,所以0

  • lpEnvironmentNULL以传递当前环境。 在某些情况下,您希望显式构建一个新的环境或修改环境的副本,但是因为您的过程只是为了启动不必要的子项而存在。

  • lpCurrentDirectory – 用于继承当前目录的NULL

  • lpStartupInfo – 调用GetStartupInfo来填充与当前进程相同的设置,或者将其保留为空,就像您发布的代码一样。

  • lpProcessInformation – 这是一个输出参数,如代码中所示使用。 在你的场景中,如果一个应用程序正在为另一个应用程序站立,那么可能需要保留该流程句柄,并在退出之前使用它来等待子流程退出。 (如果您知道如果您在孩子之前退出,您的父母不会感到困惑,则不需要这样做。)

除了确保设置bInheritHandles外,您不需要对标准句柄做任何特殊的操作。 默认是让孩子保持与父母相同的标准手柄。