2009-11-05 21 views
7

Windowsの子プロセスが起動したすべてのプロセスを待つことはできますか?私は子供や孫のプロセスを変更することはできません。Windowsで孫プロセスを待っている

具体的には、ここで私がしたいことがあります。私のプロセスはuninstallA.exeを起動します。 uninistallA.exeプロセスはuninstallB.exeを起動し、直ちに終了し、しばらくの間uninstallB.exeが実行されます。 uninstallB.exeが終了するのを待って、アンインストールが完了したことを知ることができます。

答えて

9

CreateJobObjectでジョブオブジェクトを作成します。 CreateProcessを使用して、中断状態のUninstallA.exeを開始してください。新しいプロセスをAssignProcessToJobObjectでジョブオブジェクトに割り当てます。 UninstallA.exeを実行して、CreateProcessから返されたスレッドのハンドルにResumeThreadを呼び出して実行します。

次に、難しい部分:ジョブオブジェクトの実行が完了するまで待ちます。残念なことに、これは誰でも合理的に望むよりもはるかに複雑です。基本的な考え方は、I/O完了ポートを作成し、そのオブジェクトオブジェクトを作成し、それをI/O完了ポートに関連付け、最後にI/O完了ポートを待つ(状態をGetQueuedCompletionStatusにする)ことです。 Raymond Chenは彼のblogにデモンストレーション(そしてこれについての説明がある)を持っています。

+4

ありがとうございます。シンプルなWaitForSingleObjectのように見えますが、すべてのプロセスが終了したときにはわかりませんが、IO完了ポートを作成してJOB_OBJECT_MSG_ACTIVE_PROCESS_ZEROを待つことができます。 – thudbang

+0

Raymond Chenは彼のブログでそれをカバーしています:[仕事のすべてのプロセスが終了するまでどのように待つのですか?](https://blogs.msdn.microsoft.com/oldnewthing/20130405-00/?p=4743) –

0

named mutexを使用してください。

+0

私はそれを行うことはできません。子プロセスを変更することはできません。 – thudbang

+0

ええ、それは、その後動作しません。 – Cheeso

0

一つの可能​​性は、Cygwinをインストールしてあり、すべての孫を待つ一般的な方法ではありませんが、あなたの特定のケースのために何かをハックすることができるかもしれ

1

を終了するには、孫のために見てpsコマンドを使用することです一緒に。あなたは特定のプロセスインスタンスを探していることを知っています。私はまずuninstallB.exeが開始されたことを知っているので、(WaitForSingleObjectを使用して)uninstallA.exeを終了するのを待ちます。次に、PSAPIのEnumProcessesとGetProcessImageFileNameを使用して、実行中のuninstallB.exeインスタンスを検索します。あなたがそれを見つけられないなら、それは既に終わっていることを知っています、そうでなければあなたはそれを待つことができます。

XPより古いバージョンのWindowsをサポートする必要がある場合は、GetProcessImageFileNameを使用できず、Windows NTではPSAPIをまったく使用できないという複雑な問題があります。 Windows 2000では、GetModuleFileNameExを使用できますが、時には失敗する可能性がある(check docs)といういくつかの警告があります。 NTをサポートする必要がある場合は、Toolhelp32を参照してください。

はいこれは超醜いです。

+1

とにかく、各プロセスの親(生成)IDを提供するだけで、CreateProcess()もプロセスIDを返すため、Toolhelp32の使用を検討することもできます。 uninstallA.exeを起動してそのプロセスIDを取得し、ToolHelp32を使用して同じプロセスIDで開始されたすべてのプロセスを検索できるはずです。 CreateProcess()によって返されたプロセスハンドルを閉じるまで、OSはuninstallAのプロセスIDを再利用できません。 –

1

ここではいくつかの理由で、ジョブオブジェクトを使用できない場合は絶対確実ではないが、役立つことができ、技術があります。アイデアは、匿名パイプを作成し、子プロセスがパイプの書き込み側のハンドルを継承するようにすることです。

典型的には、孫プロセスもパイプの書き込み終了を継承します。特に、cmd.exeによって(例えば、バッチファイルから)起動されたプロセスはハンドルを継承する。子プロセスが終了した後は

、親プロセスはパイプの書き込み側にそのハンドルを閉じ、その後、パイプから読み込もうとします。誰もパイプに書き込んでいないので、読み取り操作は無期限にブロックされます。 (もちろん、孫を待っている間も何かをやりたいのであれば、スレッドや非同期I/Oを使うことができます)。

パイプの書き込み側の最後のハンドルが閉じているときパイプの書き込み終了は自動的に破棄されます。これによりパイプが破壊され、読み取り操作が完了し、ERROR_BROKEN_PIPEエラーが報告されます。

私はこのコード(および同じコードの以前のバージョン)を数年間生産中に使用してきました。

// pwatch.c 
// 
// Written in 2011 by Harry Johnston, University of Waikato, New Zealand. 
// This code has been placed in the public domain. It may be freely 
// used, modified, and distributed. However it is provided with no 
// warranty, either express or implied. 
// 
// Launches a process with an inherited pipe handle, 
// and doesn't exit until (a) the process has exited 
// and (b) all instances of the pipe handle have been closed. 
// 
// This effectively waits for any child processes to exit, 
// PROVIDED the child processes were created with handle 
// inheritance enabled. This is usually but not always 
// true. 
// 
// In particular if you launch a command shell (cmd.exe) 
// any commands launched from that command shell will be 
// waited on. 

#include <windows.h> 

#include <stdio.h> 

void error(const wchar_t * message, DWORD err) { 

    wchar_t msg[512]; 

    swprintf_s(msg, sizeof(msg)/sizeof(*msg), message, err); 

    printf("pwatch: %ws\n", msg); 

    MessageBox(NULL, msg, L"Error in pwatch utility", MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL); 

    ExitProcess(err); 

} 

int main(int argc, char ** argv) { 

    LPWSTR lpCmdLine = GetCommandLine(); 

    wchar_t ch; 

    DWORD dw, returncode; 

    HANDLE piperead, pipewrite; 

    STARTUPINFO si; 

    PROCESS_INFORMATION pi; 

    SECURITY_ATTRIBUTES sa; 

    char buffer[1]; 

    while (ch = *(lpCmdLine++)) { 

    if (ch == '"') while (ch = *(lpCmdLine++)) if (ch == '"') break; 

    if (ch == ' ') break; 

    } 

    while (*lpCmdLine == ' ') lpCmdLine++; 

    sa.nLength = sizeof(sa); 
    sa.bInheritHandle = TRUE; 
    sa.lpSecurityDescriptor = NULL; 

    if (!CreatePipe(&piperead, &pipewrite, &sa, 1)) error(L"Unable to create pipes: %u", GetLastError()); 

    GetStartupInfo(&si); 

    if (!CreateProcess(NULL, lpCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) 
    error(L"Error %u creating process.", GetLastError()); 

    if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED) error(L"Error %u waiting for process.", GetLastError()); 

    if (!GetExitCodeProcess(pi.hProcess, &returncode)) error(L"Error %u getting exit code.", GetLastError()); 

    CloseHandle(pipewrite); 

    if (ReadFile(piperead, buffer, 1, &dw, NULL)) { 

    error(L"Unexpected data received from pipe; bug in application being watched?", ERROR_INVALID_HANDLE); 

    } 

    dw = GetLastError(); 

    if (dw != ERROR_BROKEN_PIPE) error(L"Unexpected error %u reading from pipe.", dw); 

    return returncode; 

} 
関連する問題