Pourquoi ces deux comportements différents avec la fonction WaitForSingleObject dans CPP

J’ai l’exemple de code suivant:

#include  #include  #include  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"); } 

Lorsque j’essaie le code exécutant cmd.exe , le message n’est pas imprimé à l’écran jusqu’à ce que je ferme la fenêtre cmd.exe .

Toutefois, lorsque j’essaie d’utiliser le code exécutant calc.exe , le message est imprimé à l’écran avant la fin du processus de la calculasortingce.

Pourquoi ces deux exécutables présentent-ils des comportements différents?

Je pense avoir raté quelque chose avec ma compréhension de la fonction WaitForSingleObject() .

J’ai essayé votre code sous Windows 10 et SysInternals Process Monitor affiche les éléments suivants:

image

Comme vous pouvez le voir, calc.exe génère un nouveau processus et se termine, satisfaisant ainsi l’attente. C’est pourquoi vous voyez votre sortie immédiatement. Ce deuxième processus est le processus de calculasortingce proprement dit. Dans mon cas, il se situe sur ce chemin:

 C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1612.3341.0_x64__8wekyb3d8bbwe\Calculator.exe 

Comme expliqué dans calc.exe , calc.exe lance un deuxième processus, puis quitte immédiatement. Vous attendez sur un HANDLE pour le processus calc.exe , de sorte que l’attente est satisfaite lorsque calc.exe .

Si vous souhaitez attendre que tous les processus (grand) enfants soient terminés, vous devez envelopper le processus calc.exe dans un object Job .

Appelez CreateJobObject() , passez le HANDLE du processus calc.exe à AssignProcessToJobObject() , puis attendez les notifications de l’object de travail (l’attente du travail lui-même ne fonctionnera pas, voir Comment attendre que tous les processus d’un travail sont sortis? pour une explication pourquoi).

Tous les nouveaux processus calc.exe par calc.exe , lancés, etc., seront automatiquement ajoutés au même travail (à moins qu’ils ne demandent explicitement à ne pas être ajoutés au travail, via l’indicateur CreateProcess() de CreateProcess() , mais ne vous inquiétez pas à ce sujet dans cet exemple). Lorsque le travail vous informe que tous les processus sont terminés, vous pouvez cesser d’attendre d’autres notifications.

Par exemple:

 #include  #include  #include  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(CompletionKey) == Job) && (CompletionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO)) { break; } } CloseHandle(IOPort); CloseHandle(Job); std::cout << "hi! Im done!"; return 0; }