Winapi 正在windows中等待孙进程

Winapi 正在windows中等待孙进程,winapi,Winapi,是否可以在Windows中等待子进程启动的所有进程?我无法修改子进程或孙子进程 具体来说,以下是我想做的。我的进程启动卸载a.exe。进程uninistallA.exe启动卸载B.exe并立即退出,卸载B.exe运行一段时间。我想等待卸载b.exe退出,以便知道卸载何时完成。请使用 一种可能性是安装Cygwin,然后使用ps命令监视孙子退出没有一种通用的方法等待所有孙子,但对于您的特定情况,您可以一起破解一些东西。您知道您正在寻找一个特定的流程实例。我将首先等待卸载A.exe退出(使用WaitF

是否可以在Windows中等待子进程启动的所有进程?我无法修改子进程或孙子进程


具体来说,以下是我想做的。我的进程启动卸载a.exe。进程uninistallA.exe启动卸载B.exe并立即退出,卸载B.exe运行一段时间。我想等待卸载b.exe退出,以便知道卸载何时完成。

请使用

一种可能性是安装Cygwin,然后使用ps命令监视孙子退出

没有一种通用的方法等待所有孙子,但对于您的特定情况,您可以一起破解一些东西。您知道您正在寻找一个特定的流程实例。我将首先等待卸载A.exe退出(使用WaitForSingleObject),因为此时您知道卸载B.exe已启动。然后使用PSAPI中的EnumProcesses和GetProcessImageFileName查找正在运行的卸载B.exe实例。如果你没有找到它,你知道它已经完成了,否则你可以等待它

另一个复杂问题是,如果您需要支持早于XP的Windows版本,则不能使用GetProcessImageFileName,而对于Windows NT,则根本不能使用PSAPI。对于Windows 2000,您可以使用GetModuleFileNameEx,但它有一些警告,这意味着它有时可能会失败(请检查文档)。如果您必须支持NT,请查阅Toolhelp32


是的,这太难看了。

使用
CreateJobObject
创建作业对象。使用
CreateProcess
以挂起状态启动
UninstallA.exe
。使用
AssignProcessToJobObject
将新流程分配给作业对象。通过调用从
CreateProcess
返回的线程句柄上的
ResumeThread
,开始卸载正在运行的.exe


然后是最难的部分:等待作业对象完成其执行。不幸的是,这比任何人合理期望的要复杂得多。基本思想是创建一个I/O完成端口,然后创建对象对象,将其与I/O完成端口关联,最后等待I/O完成端口(使用
GetQueuedCompletionStatus
获取其状态)。雷蒙德·陈(Raymond Chen)在他的文章中有一个演示(并解释了这是如何产生的)。

这里有一个技巧,虽然不是绝对正确的,但如果出于某种原因你不能使用作业对象,它可能会很有用。其思想是创建一个匿名管道,并让子进程继承管道写入端的句柄

通常,孙进程还将继承管道的写入端。特别是,由
cmd.exe启动的进程(例如,从批处理文件启动)将继承句柄

一旦子进程退出,父进程将关闭其管道写入端的句柄,然后尝试从管道读取。由于没有人向管道写入,读取操作将无限期地阻塞。(当然,如果您想在等待孙子孙女的同时继续做一些事情,可以使用线程或异步I/O。)

当(且仅当)管道写入端的最后一个句柄关闭时,管道的写入端将自动销毁。这将断开管道,读取操作完成并报告错误\u断开\u管道故障

我已经在生产中使用这段代码(以及同一代码的早期版本)很多年了

// 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;

}
//pwatch.c
//
/ 2011由新西兰怀卡托大学的Harry Johnston撰写。
//此代码已置于公共域中。它可能是免费的
//使用、修改和分发。但是,它没有提供
//明示或暗示的担保。
//
//使用继承的管道句柄启动进程,
//并且在(a)进程退出之前不会退出
//和(b)管道手柄的所有实例都已关闭。
//
//这将有效地等待任何子进程退出,
//假设子进程是用句柄创建的
//已启用继承。这通常是,但并不总是
//对。
//
//特别是如果启动命令shell(cmd.exe)
//从该命令shell启动的任何命令都将
//侍候。
#包括
#包括
无效错误(常量wchar\u t*消息,DWORD err){
wchar_t msg[512];
swprintf_s(msg,sizeof(msg)/sizeof(*msg),message,err);
printf(“pwatch:%ws\n”,msg);
MessageBox(NULL,msg,L“pwatch实用程序中的错误”,MB|u OK | MB|u iconclamation | MB|u SYSTEMMODAL);
退出过程(err);
}
int main(int argc,字符**argv){
LPWSTR lpCmdLine=GetCommandLine();
世界卫生组织;
DWORD dw,返回代码;
处理piperead、pipewrite;
STARTUPINFO si;
处理信息;
安全(a);
字符缓冲区[1];
而(ch=*(lpCmdLine++){
if(ch=''“'),而(ch=*(lpCmdLine++)if(ch==''”)中断;
如果(ch='')中断;
}
而(*lpCmdLine='')lpCmdLine++;
sa.nLength=sizeof(sa);
sa.bInheritHandle=TRUE;
sa.lpSecurityDescriptor=NULL;
如果(!CreatePipe(&piperead,&pipewrite,&sa,1))错误(L“无法创建管道:%u”,GetLastError());
GetStartupInfo&si;
if(!CreateProcess(NULL,lpCmdLine,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi))
错误(L“创建进程时出错%u.”,GetLastError());
if(WaitForSingleObject(pi.hProcess,INFINITE)=WAIT_FAILED)错误(L“error%u waiting for process.”,GetLastError());
如果(!GetExitCodeProcess(pi.hProcess,&returncode))错误(L“错误%u获取退出代码”,GetLastError());
闭合手柄(管道写入);
if(ReadFile(piperead、buffer、1和dw、NULL)){
错误(L“从管道接收到意外数据;正在监视的应用程序中存在错误?”,错误\u无效\u句柄);
}
dw=GetLastError();
如果(dw!=错误\u断开\u管道)错误(L“意外错误%u从管道读取”,dw);
返回代码;
}

我想我做不到。我不能修改子进程。无论如何,您可以考虑使用工具帮助32,SIMP。