【问题标题】:How can a Win32 process get the pid of its parent?Win32 进程如何获取其父进程的 pid?
【发布时间】:2010-09-16 03:53:23
【问题描述】:

我目前正在将命令行上的 pid 传递给孩子,但有没有办法在 Win32 API 中做到这一点?或者,如果父母已经去世,有人可以减轻我对我传递的 pid 可能在一段时间后属于另一个进程的恐惧吗?

【问题讨论】:

  • 当父进程退出时,Windows XP 不会将父 PID 重新分配为 -1,因此进程树有可能(并且我已经看到这种情况发生)错误。所以你可以在 Process Explorer 显示的树中看到 NOTEPAD.EXE 作为 IEXPLORE.EXE 的父级,这显然是错误的。

标签: winapi process


【解决方案1】:

“或者,有人可以减轻我对我正在传递的 pid 的恐惧吗? 如果父进程在一段时间后可能属于另一个进程 死了吗?”

是的,PID 可以重复使用。与 UNIX 不同,Windows 不维护强大的父子关系树。

【讨论】:

  • 同样在 LINUX 进程 ID 上被重用。仅仅是因为 pid_t 不是无限大的。 MAXPID 是 2^15。我在一天中多次看到这种情况。另一方面,在 Windows 上,通过句柄有很强的父子关系——只要保持句柄打开,就可以继续引用父进程。
【解决方案2】:

更好的方法是调用DuplicateHandle() 来创建进程句柄的可继承副本。然后创建子进程并在命令行上传递句柄值。 Close 父进程中的重复句柄。孩子完成后,还需要Close 其副本。

【讨论】:

  • 此方法的优点是句柄将真正引用您的父级,即使父级在您访问它之前就死了。使用 pid 传递方法,在传递 pid、子访问它、父关闭和 pid 被重用之间可能存在竞争条件(尽管不太可能)......
  • 谢谢彼得... DuplicateHandle 正是我想要的。你是对的,HANDLE 比 PID 好(我只是想 WaitForSingleObject 这样如果父母意外退出,孩子可以终止)。
  • DuplicateHandle 需要的一个参数是目标进程句柄。您写道,首先创建重复句柄,然后创建子进程。它的废话。您必须先创建子进程,然后再创建进程句柄的副本。所以你不能在命令行上传递句柄值。
  • @truthseeker:不...您必须先复制句柄。否则,子进程将无法继承它。您可以在命令行上传递重复句柄,因为子进程中继承的句柄将具有与父进程中相同的数值。想一想:如果您无法在继承它们的进程中访问这些句柄,那么句柄继承将毫无用处!
  • 澄清一下:通常你会要么复制继承句柄。但是,在这种情况下,您所拥有的只是从 GetCurrentProcess() 返回的伪句柄,它不能被继承。所以你必须复制它来生成一个真实的、可继承的句柄。使用继承的原因是,如果您将句柄直接复制到子进程,您将无法简单地告诉子进程句柄值是什么。
【解决方案3】:
ULONG_PTR GetParentProcessId() // By Napalm @ NetCore2K
{
 ULONG_PTR pbi[6];
 ULONG ulSize = 0;
 LONG (WINAPI *NtQueryInformationProcess)(HANDLE ProcessHandle, ULONG ProcessInformationClass,
  PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength); 
 *(FARPROC *)&NtQueryInformationProcess = 
  GetProcAddress(LoadLibraryA("NTDLL.DLL"), "NtQueryInformationProcess");
 if(NtQueryInformationProcess){
  if(NtQueryInformationProcess(GetCurrentProcess(), 0,
    &pbi, sizeof(pbi), &ulSize) >= 0 && ulSize == sizeof(pbi))
     return pbi[5];
 }
 return (ULONG_PTR)-1;
}

【讨论】:

  • 在使用 NtQueryInformationProcess 之前,请注意它是一个不受支持的 API,我从链接中引用:“NtQueryInformationProcess 可能会在未来版本的 Windows 中被更改或不可用。”此外,即使在文档中,父进程 ID 字段也是保留字段。
  • 对,在最后一个 msvc 2017 上不能很好地工作
  • 我发现这种技术大部分有效,但偶尔NtQueryInformationProcess会返回0xC0000024或0xC0000008
【解决方案4】:

以防万一其他人遇到此问题并正在寻找代码示例,我最近必须为我正在处理的 Python 库项目执行此操作。这是我想出的测试/示例代码:

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>

int main(int argc, char *argv[]) 
{
    int pid = -1;
    HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 pe = { 0 };
    pe.dwSize = sizeof(PROCESSENTRY32);

    //assume first arg is the PID to get the PPID for, or use own PID
    if (argc > 1) {
        pid = atoi(argv[1]);
    } else {
        pid = GetCurrentProcessId();
    }

    if( Process32First(h, &pe)) {
        do {
            if (pe.th32ProcessID == pid) {
                printf("PID: %i; PPID: %i\n", pid, pe.th32ParentProcessID);
            }
        } while( Process32Next(h, &pe));
    }

    CloseHandle(h);
}

【讨论】:

  • 你有python版本吗?
  • 这种方法可以提供陈旧的 PID,如其他地方所述,如果您尝试向上遍历父 ID,它甚至可能有循环。
  • +1000000 获取代码示例。不知道最近 stackoverflow 怎么了,但是我已经厌倦了浏览编程网站上的几十个页面而没有看到任何代码。
  • 您可能想要添加检查 INVALID_HANDLE_VALUE。 if ( h == INVALID_HANDLE_VALUE ) { // got an invalid handle
  • @JamesSchmidt,您所说的循环是指进程的父进程也可能是它的子进程/后代?在什么情况下会发生这种情况?
【解决方案5】:

请注意,如果父进程终止,则 PID 很有可能会被另一个进程重用。这是标准的 windows 操作。

因此,可以肯定的是,一旦您收到父母的 id 并确定它确实是您的父母,您应该打开它的句柄并使用它。

【讨论】:

  • 这是使用 OpenProcess() 完成的。请参阅下面 artur02 答案中的链接。
  • 可以通过额外检查开始时间来检测重复使用的 PID。真正的父母会在孩子之前有一个开始时间,一个重复使用的 - 之后。
猜你喜欢
  • 2011-02-01
  • 2014-06-25
  • 2010-09-05
  • 2014-12-11
  • 2016-02-01
  • 2012-05-21
  • 2015-01-05
  • 2014-05-12
  • 1970-01-01
相关资源
最近更新 更多