Retrieving the parent of a process (WinNT) | CodeGuru

Retrieving the parent of a process (WinNT)

Did you ever have to find out parent of a process? Well, if so, you’ll already have found out that there is no documented relation between processes in Win32 (like there is on UN*X). But, fortunately, the emphasis is on ‘documented’, as the NT Native API offers LOTS of undocumented APIs that can be useful […]

Written By
CodeGuru Staff
CodeGuru Staff
May 15, 1999
2 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Did you ever have to find out parent of a process? Well, if so, you’ll already have found out that there is no documented relation between processes in Win32 (like there is on UN*X). But, fortunately, the emphasis is on ‘documented’, as the NT Native API offers LOTS of undocumented APIs that can be useful in a variety of situations. Prototypes and parameter information for about 25 NT API functions can be found in the header files of the NT DDK.
The function that serves the basic purpose of this article is ‘NtQueryInformationProcess()’ and is declared as follows:

NTSYSAPI
NTSTATUS
NTAPI
NtQueryInformationProcess(
    IN HANDLE ProcessHandle,
    IN PROCESSINFOCLASS ProcessInformationClass,
    OUT PVOID ProcessInformation,
    IN ULONG ProcessInformationLength,
    OUT PULONG ReturnLength OPTIONAL
    );

When specifying ‘ProcessBasicInformation’ as the ‘ProcessInformationClass’ parameter and a valid process handle, ‘NtQueryInformationProcess()’ fills in a ‘PROCESS_BASIC_INFORMATION’ structure whose adress has been passed in as the ‘ProcessInformation’ parameter. The structure member ‘InheritedFromUniqueProcessId’ holds the process ID of the process that created process specified in ‘ProcessHandle’.

So, all that has to be done is obtaining a pointer to this function and calling it, supplying the appropriate parameters:

DWORD   GetParentProcessID  (   DWORD   dwPID)
{
    NTSTATUS                        ntStatus;
    DWORD                           dwParentPID =   0xffffffff;
    HANDLE                          hProcess;
    PROCESS_BASIC_INFORMATION       pbi;
    ULONG                           ulRetLen;
    //  create entry point for ‘NtQueryInformationProcess()’
    CREATE_DYNFUNC_5    (   NtQueryInformationProcess,
                            NtQueryInformationProcess,
                            ntdll,
                            NTSTATUS,
                            __stdcall,
                            HANDLE,
                            PROCESSINFOCLASS,
                            PVOID,
                            ULONG,
                            PULONG
                        );
    //  get process handle
    hProcess    =   OpenProcess (   PROCESS_QUERY_INFORMATION,
                                    FALSE,
                                    dwPID
                                );
    //  could fail due to invalid PID or insufficiant privileges
    if  (   !hProcess)
            return  (   0xffffffff);
    //  gather information
    ntStatus    =   NtQueryInformationProcess   (   hProcess,
                                                    ProcessBasicInformation,
                                                    ( void*) &pbi,
                                                    sizeof  (   PROCESS_BASIC_INFORMATION),
                                                    &ulRetLen
                                                );
    //  copy PID on success
    if  (   !ntStatus)
            dwParentPID =   pbi.InheritedFromUniqueProcessId;
    CloseHandle (   hProcess);
    return  (   dwParentPID);
}

The only ‘fancy’ thing in the above code is the ‘CREATE_DYNFUNC_5()’ convenience macro, which just simplifies the method of typedef’ing a function pointer and loading it by serving as a ‘wrapper’ (‘5’ indicates that a pointer to a function taking 5 parameters is created):

#define DYNLOADED_FPTR( ptrname, procname, dllname)
FPTR_##procname ptrname =
( FPTR_##procname ) GetProcAddress ( GetModuleHandle (  _TEXT( #dllname)), #procname);
#define CREATE_DYNFUNC_5( ptrname, procname, dllname, rettype, callconv, a1, a2, a3, a4, a5)
typedef  rettype (callconv *FPTR_##procname) ( a1, a2, a3, a4, a5);
DYNLOADED_FPTR( ptrname, procname, dllname);

which (in our example) expands to

typedef NTSTATUS (__stdcall *FPTR_NtQueryInformationProcess) ( HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
FPTR_NtQueryInformationProcess NtQueryInformationProcess = ( FPTR_NtQueryInformationProcess ) GetProcAddress ( GetModuleHandleA ( “ntdll”), “NtQueryInformationProcess”);

NOTE that this may fail if the DLL isn’t loaded when the above code is executed! (‘ntdll.dll’ is loaded for every process running on NT, so this isn’t checked here)

Download demo executable – 12.6 KB

Download source – 2.03 KB

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.