我有以下代码示例:
#include <iostream> #include <windows.h> #include <string> using namespace std; void main() { SHELLEXECUTEINFO ShExecInfo = { 0 }; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = NULL; ShExecInfo.lpFile = "cmd.exe"; ShExecInfo.lpParameters = ""; ShExecInfo.lpDirectory = NULL; ShExecInfo.nShow = SW_SHOW; ShExecInfo.hInstApp = NULL; ShellExecuteEx(&ShExecInfo); WaitForSingleObject(ShExecInfo.hProcess, INFINITE); std::cout << "hi! Im done!"; system("pause"); }
当我尝试运行cmd.exe
的代码时,在我closurescmd.exe
窗口之前,不会将消息打印到屏幕上。
但是,当我尝试运行calc.exe
的代码而不是在计算器进程结束之前将消息打印到屏幕上。
为什么这两个可执行文件performance出不同的行为?
我认为我错过了我对WaitForSingleObject()
函数的理解。
我在Windows 10上试过你的代码, SysInternals Process Monitor显示如下:
正如你所看到的, calc.exe
产生一个新的进程,然后结束,从而满足等待。 这就是为什么你立即看到你的输出。 这第二个过程是实际的计算器过程。 就我而言,它位于这条路上:
C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1612.3341.0_x64__8wekyb3d8bbwe\Calculator.exe
正如marcinj所解释的, calc.exe
正在启动第二个进程,然后立即退出。 您正在等待calc.exe
进程的HANDLE
,以便在calc.exe
退出时等待。
如果要等到所有(大)子进程结束,则需要将calc.exe
进程打包到Job对象中 。
调用CreateJobObject()
,将calc.exe
进程的HANDLE
传递给AssignProcessToJobObject()
,然后等待来自作业对象的通知(简单地等待作业本身将不起作用,请参阅如何等待作业中的所有进程为什么退出?为什么)。
calc.exe
启动并启动的任何新进程都会自动添加到同一个作业中(除非他们通过CreateProcess()
的CREATE_BREAKAWAY_FROM_JOB
标志明确请求不要添加到作业中CreateProcess()
不用担心这个例子)。 当作业通知您所有进程已经结束时,您可以停止等待进一步的通知。
例如:
#include <windows.h> #include <iostream> #include <string> using namespace std; int main() { HANDLE Job = CreateJobObject(NULL, NULL); if (!Job) { std::cout << "CreateJobObject, error " << GetLastError() << "\n"; return 0; } HANDLE IOPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); if (!IOPort) { std::cout << "CreateIoCompletionPort, error " << GetLastError() << "\n"; CloseHandle(Job); return 0; } JOBOBJECT_ASSOCIATE_COMPLETION_PORT Port; Port.CompletionKey = Job; Port.CompletionPort = IOPort; if (!SetInformationJobObject(Job, JobObjectAssociateCompletionPortInformation, &Port, sizeof(Port))) { cout << "SetInformation, error " << GetLastError() << "\n"; CloseHandle(IOPort); CloseHandle(Job); return 0; } STARTUPINFO si = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION pi = {}; WCHAR cmdline[] = L"calc.exe"; if (!CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { cout << "CreateProcess, error " << GetLastError() << "\n"; CloseHandle(IOPort); CloseHandle(Job); return 0; } if (!AssignProcessToJobObject(Job, pi.hProcess)) { cout << "Assign, error " << GetLastError() << "\n"; TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); CloseHandle(IOPort); CloseHandle(Job); return 0; } ResumeThread(pi.hThread); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); DWORD CompletionCode; ULONG_PTR CompletionKey; LPOVERLAPPED Overlapped; while (GetQueuedCompletionStatus(IOPort, &CompletionCode, &CompletionKey, &Overlapped, INFINITE)) { if ((reinterpret_cast<HANDLE>(CompletionKey) == Job) && (CompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)) { break; } } CloseHandle(IOPort); CloseHandle(Job); std::cout << "hi! Im done!"; return 0; }