Windows 的可执行包装器的 CreateProcess 用法?
CreateProcess usage for executable wrapper for Windows?
TL;DR:
CreateProcess(?, ?, ?, ...)
为:
- 传递当前进程参数(即"batchfile"
%*
)
- 正确连接标准输入和标准输出
- 创建标志?
我有以下问题:
- 我需要使用自定义环境和自定义参数启动给定的第 3 方可执行文件。 (均为半固定)
- 我不能使用批处理文件,因为调用模块的(再次,第 3 方)方直接调用
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
);
- 如何获取当前 Win32 进程的
%*
等价物?
- 仅通过
lpApplicationName
、仅通过 lpCommandLine
或两者都通过?
- 处理继承和创建标志怎么办?
- 如何正确转发/return标准输入和标准输出?
不是骗子: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++;
lpProcessAttributes
和 lpThreadAttributes
- NULL
.
bInheritHandles
- TRUE
,因为您希望 child 继承标准句柄。
dwCreationFlags
- none 在你的场景中需要,所以 0
.
lpEnvironment
- NULL
传递当前环境。在某些情况下,您可能希望显式构建一个新环境或环境的修改副本,但由于您的进程仅用于启动不必要的 child。
lpCurrentDirectory
- NULL
继承当前目录。
lpStartupInfo
- 调用 GetStartupInfo
使用与当前进程相同的设置来填充它,或者像您发布的代码一样将其留空。
lpProcessInformation
- 这是一个输出参数,如代码中所示使用。在您的场景中,一个应用程序代表另一个应用程序,您可能希望保留进程句柄并使用它来等待 child 进程退出,然后再退出自己。 (如果您知道如果您在 child 之前退出,您的 parent 不会感到困惑,则没有必要这样做。)
除了确保 bInheritHandles
已设置外,您无需对标准句柄做任何特殊操作。默认情况下 child 与 parent.
保持相同的标准句柄
TL;DR:
CreateProcess(?, ?, ?, ...)
为:
- 传递当前进程参数(即"batchfile"
%*
) - 正确连接标准输入和标准输出
- 创建标志?
我有以下问题:
- 我需要使用自定义环境和自定义参数启动给定的第 3 方可执行文件。 (均为半固定)
- 我不能使用批处理文件,因为调用模块的(再次,第 3 方)方直接调用
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
);
- 如何获取当前 Win32 进程的
%*
等价物? - 仅通过
lpApplicationName
、仅通过lpCommandLine
或两者都通过? - 处理继承和创建标志怎么办?
- 如何正确转发/return标准输入和标准输出?
不是骗子: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++;
lpProcessAttributes
和lpThreadAttributes
-NULL
.bInheritHandles
-TRUE
,因为您希望 child 继承标准句柄。dwCreationFlags
- none 在你的场景中需要,所以0
.lpEnvironment
-NULL
传递当前环境。在某些情况下,您可能希望显式构建一个新环境或环境的修改副本,但由于您的进程仅用于启动不必要的 child。lpCurrentDirectory
-NULL
继承当前目录。lpStartupInfo
- 调用GetStartupInfo
使用与当前进程相同的设置来填充它,或者像您发布的代码一样将其留空。lpProcessInformation
- 这是一个输出参数,如代码中所示使用。在您的场景中,一个应用程序代表另一个应用程序,您可能希望保留进程句柄并使用它来等待 child 进程退出,然后再退出自己。 (如果您知道如果您在 child 之前退出,您的 parent 不会感到困惑,则没有必要这样做。)
除了确保 bInheritHandles
已设置外,您无需对标准句柄做任何特殊操作。默认情况下 child 与 parent.