41

I'm currently passing the pid on the command line to the child, but is there a way to do this in the Win32 API? Alternatively, can someone alleviate my fear that the pid I'm passing might belong to another process after some time if the parent has died?

twk
  • 16,760
  • 23
  • 73
  • 97
  • Windows XP does not reassign the parent PID to be -1 when the parent process exits, so it is possible (and I have seen this happen) for the process tree to be wrong. So you can see NOTEPAD.EXE as the parent of IEXPLORE.EXE in the tree shown by Process Explorer, which is clearly wrong. – Kevin Panko Jun 27 '12 at 21:57

5 Answers5

59

Just in case anyone else runs across this question and is looking for a code sample, I had to do this recently for a Python library project I'm working on. Here's the test/sample code I came up with:

#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);
}
Jay
  • 41,768
  • 14
  • 66
  • 83
  • do you have the python-version by any chance? – Alex Okrushko Aug 29 '12 at 21:16
  • 1
    This approach can provide stale PIDs as mentioned elsewhere, and it can even have cycles if you try to walk up the parent IDs. – jws Sep 11 '14 at 14:01
  • 5
    +1000000 for a code sample. Dunno whats up with stackoverflow lately, but I'm getting tired of browsing dozens of pages on a programming website without seeing any code. –  Feb 28 '15 at 15:26
  • 1
    You might want to add a check for INVALID_HANDLE_VALUE. `if ( h == INVALID_HANDLE_VALUE ) { // got an invalid handle` – hmatt1 Oct 28 '15 at 14:06
  • @JamesSchmidt, By cycles you mean that the parent of a process may also be its child/descendant? Under what conditions could that happen? – GetFree Apr 18 '17 at 12:05
  • A process's parent can exit with the child running, and child will still hold on to the PID of that old parent. Then later the PID can be reassigned, and then child "parent" still refers to this PID that now might even be its own child! – jws Apr 18 '17 at 20:14
22
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;
}
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
Napalm
  • 221
  • 2
  • 2
  • 3
    Before using [NtQueryInformationProcess](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684280.aspx), be aware that it is an unsupported API, and I quote from the link: "NtQueryInformationProcess may be altered or unavailable in future versions of Windows." Furthermore, even in the documentation, the parent process ID field is a reserved field. – Marc Durdin Nov 23 '15 at 23:44
  • Right, does not work pretty well with last msvc 2017 – Stef Feb 06 '19 at 23:30
  • I find that this technique _mostly_ works, but occasionally `NtQueryInformationProcess` returns 0xC0000024 or 0xC0000008 – Oliver Bock Jul 28 '20 at 23:45
22

A better way to do this is to call DuplicateHandle() to create an inheritable duplicate of your process handle. Then create the child process and pass the handle value on the command line. Close the duplicated handle in the parent process. When the child's done, it will need to Close its copy as well.

Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
Peter Ruderman
  • 12,241
  • 1
  • 36
  • 58
  • 8
    This method has the advantage that the handle will really refer to your parent even if the parent dies before you access it. With the pid passing method, there's potentially a race condition (although very unlikely) between passing the pid, the child accessing it, the parent shutting down and the pid being reused... – Len Holgate Jun 11 '09 at 10:23
  • Thanks Peter... DuplicateHandle is just what I was looking for. You're right, the HANDLE is better than PID (I just wanted to WaitForSingleObject so child could terminate if parent quits unexpectedly). – Matt Gallagher Jul 03 '10 at 07:18
  • One argument needed for DuplicateHandle is the target process handle. You wrote that first you create duplicate handle and then create child process. Its nonsense. You must create child process first and then create duplicate of process handle. So you cant pass handle value on command line. – truthseeker Jan 21 '15 at 08:07
  • 1
    @truthseeker: No... you must duplicate the handle first. Otherwise, the child process would have no way to inherit it. You can pass the duplicate handle on the command line because the inherited handle in the child process will have the same numerical value as it does in the parent process. Think about it: handle inheritance would be fairly useless if you could not access those handles in the processes that inherited them! – Peter Ruderman Jan 21 '15 at 13:09
  • 3
    To clarify: ordinarily you would *either* duplicate *or* inherit a handle. In this case, however, all you have is the pseudo handle returned from GetCurrentProcess() which cannot be inherited. So you have to duplicate it to generate a real, inheritable handle. The reason to use inheritance is that if you duplicate the handle directly to the child process you have no easy way of telling the child process what the handle value is. – Harry Johnston Jan 29 '15 at 21:00
  • Why does the parent need to close the handle to its own process? Won't it be automatically closed when the parent process exits? Similarly, I would expect that the child would only need to close the handle it receives if it expects the parent process to outlive it. – Oliver Bock Jul 29 '20 at 00:19
  • @Oliver Block: Strictly speaking, for most applications, closing the handles is not necessary. But it is good hygiene. Keep in mind that handles are a finite resource. If you carelessly leak them, it is possible to run out. – Peter Ruderman Oct 12 '20 at 17:31
13

Notice that if the parent process terminates it is very possible and even likely that the PID will be reused for another process. This is standard windows operation.

So to be sure, once you receive the id of the parent and are sure it is really your parent you should open a handle to it and use that.

shoosh
  • 76,898
  • 55
  • 205
  • 325
3

"Alternatively, can someone alleviate my fear that the pid I'm passing might belong to another process after some time if the parent has died?"

Yes, the PID can be reused. Unlike UNIX, Windows does not maintain a strong parent-child relationship tree.

Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
user15071
  • 3,391
  • 8
  • 31
  • 31
  • 7
    Also on LINUX process IDs are being reused. Simply because pid_t is not of infinite size. MAXPID is 2^15. I see this happening multiple times during a day. On the other side, on Windows there is a strong parent-child relationship via handles -- as long as you keep the handle open, you can keep referring to the parent process. –  Jan 08 '16 at 00:00