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

时间:2016-05-30 14:38:27

标签: windows visual-c++ createprocess

TL; DR

CreateProcess(?, ?, ?, ...)

  • 传递当前流程参数(即"batchfile" %*
  • 正确连接stdin和stdout
  • 创建标志?

我有以下问题:

  • 我需要使用自定义环境和自定义参数启动给定的第三方可执行文件。 (两者都是半固定的)
  • 我无法使用批处理文件,因为调用该模块的(再次,第三方)方面直接调用CreateProcess
  • 我需要传递任何传递的参数

所以,我想要做的是创建一个非常简单的可执行启动程序,它类似于批处理文件,如:

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

而且我当然不想搞砸any bat2exe converter的东西 - 当我还有Visual Studio的时候太难看了。

原则上运行另一个executable via CreateProcess is trivial

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

通过_putenv等建立子进程的环境。也很容易。

然而,对我来说不重要的是传递给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或两者都通过?
  • 如何处理继承和创建标志?
  • 如何正确转发/返回stdin和stdout?

不是骗子:CreateProcess to execute Windows command

1 个答案:

答案 0 :(得分:1)

应该相当简单。

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,则不需要完全限定,甚至不是可执行文件的实际名称,但它确实需要存在。这必须是可写缓冲区,它不能是常量字符串。

如果您的额外参数可以在命令行的 end 处进行,这很容易:

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++;
  • lpProcessAttributeslpThreadAttributes - NULL

  • bInheritHandles - TRUE,因为您希望孩子继承标准句柄。

  • dwCreationFlags - 您的方案中不需要0

  • lpEnvironment - NULL传递当前环境。在某些情况下,您需要显式构建新环境或环境的修改副本,但由于您的流程仅用于启动不必要的子项。

  • lpCurrentDirectory - NULL继承您当前的目录。

  • lpStartupInfo - 使用与当前流程相同的设置调用GetStartupInfo来填充此内容,或者只是将其留空,就像您发布的代码一样。

  • lpProcessInformation - 这是一个输出参数,用于代码中。在您的方案中,一个应用程序代表另一个应用程序,您可能希望保留进程句柄并使用它来等待子进程退出,然后退出自己。 (如果您知道如果您在孩子出生前退出,您的父母不会感到困惑,这是没有必要的。)

除了确保设置bInheritHandles之外,您不需要对标准句柄做任何特殊操作。默认情况下,子项与父项保持相同的标准句柄。