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

CreateProcess usage for executable wrapper for Windows?

TL;DR:

CreateProcess(?, ?, ?, ...) 为:


我有以下问题:

所以,我想做的是创建一个非常简单的可执行启动器,它相当于一个批处理文件,例如:

set PATH=...
set WHATEVER=...
...rd-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
);

不是骗子:CreateProcess to execute Windows command

应该相当简单。

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,因为您希望 child 继承标准句柄。

  • dwCreationFlags - none 在你的场景中需要,所以 0.

  • lpEnvironment - NULL传递当前环境。在某些情况下,您可能希望显式构建一个新环境或环境的修改副本,但由于您的进程仅用于启动不必要的 child。

  • lpCurrentDirectory - NULL 继承当前目录。

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

  • lpProcessInformation - 这是一个输出参数,如代码中所示使用。在您的场景中,一个应用程序代表另一个应用程序,您可能希望保留进程句柄并使用它来等待 child 进程退出,然后再退出自己。 (如果您知道如果您在 child 之前退出,您的 parent 不会感到困惑,则没有必要这样做。)

除了确保 bInheritHandles 已设置外,您无需对标准句柄做任何特殊操作。默认情况下 child 与 parent.

保持相同的标准句柄