Click here to Skip to main content
15,896,063 members
Articles / Programming Languages / C++
Article

Getting Process ID from Process Handle

Rate me:
Please Sign up or sign in to vote.
4.40/5 (9 votes)
9 Jan 2008CPOL5 min read 114.6K   1.1K   43   10
Some ways of getting a process identifier if only the process handle is available

Introduction

A process ID is a value uniquely identifying a running process. This means that unlike handles, which can be duplicated, a process ID remains the same during the process life cycle and no other process can have the same ID value during this time. It is common to obtain a process handle by processing an ID using the OpenProcess() call. Here we shall talk about the opposite problem, i.e. having only a handle to a process and how to find the ID of the process represented by that handle. This may arise, in particular, when you inject your code into other applications and you do not know the origination of a handle. If you work under Windows XP SP1 or higher, you can just call the following with a handle you have:

C++
DWORD GetProcessId(HANDLE Process);

For lower versions, there is no simple and uniform solution. Below I shall consider only Windows 2000 and up, as (obsolete) Windows 9X provides no proper tools. Also, driver approaches are not considered here.

Three techniques will be discussed:

  1. Getting the ID by creating remote thread.
  2. Enumerating processes and comparing their attributes.
  3. Using "undocumented" ZwQueryInformationProcess().

1. Getting the ID by Creating a Remote Thread

If we want to find our own process ID, we call GetCurrentProcessId(). Intuitively it would be nice to make a target process to call it in its own context and to return us the result. To implement this, a remote thread creation technique can be used. Here is a prototype of CreateRemoteThread():

C++
HANDLE CreateRemoteThread(
    HANDLE hProcess,        // handle to process to create thread in

    LPSECURITY_ATTRIBUTES lpThreadAttributes,  // pointer to security attributes
    DWORD dwStackSize,      // initial thread stack size, in bytes
    LPTHREAD_START_ROUTINE lpStartAddress, // pointer to thread function

    LPVOID lpParameter,     // argument for new thread
    DWORD dwCreationFlags,  // creation flags

    LPDWORD lpThreadId      // pointer to returned thread identifier

);

By setting lpStartAddress to the address of GetCurrentProcessId(), we cause this function to be executed as a thread routine in the context of a target process. Then it will remain, using the returned thread's handle, to get the thread exit code. One delicate thing is that GetCurrentProcessId() has no input parameters, whereas LPTHREAD_START_ROUTINE assumes one. Indeed, CreateRemoteThread() just passes execution to the code pointed by lpStartAddress not doing all necessary validations. In the majority of cases, it is rather a problem. Here we use it as an advantage: as GetCurrentProcessId() has been executed not using anything from the stack, the thread exits and then its stack is destroyed, causing no problem. Here is a full code of a function doing necessary steps:

C++
DWORD WINAPI GetProcessIDbyProcessHandle(HANDLE hProcess)
{
    // [in]  process handle
    // [out] process ID, or 0xffffffff in case of failure
    
    if (hProcess == NULL)    return 0xffffffff;
    PTHREAD_START_ROUTINE lpStartAddress = (PTHREAD_START_ROUTINE)
        GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "GetCurrentProcessId");
    if (lpStartAddress == NULL) return 0xffffffff;
    // We do not know, whether process handle already has required access rights;

    // thus we have to duplicate it
    HANDLE hProcessAccAdj;
    BOOL bRes = DuplicateHandle(GetCurrentProcess(), 
                                hProcess, GetCurrentProcess(), &hProcessAccAdj, 
                                PROCESS_QUERY_INFORMATION|PROCESS_CREATE_THREAD|
                                PROCESS_VM_OPERATION|PROCESS_VM_WRITE, 
                                FALSE, 0);
    if (!bRes || hProcessAccAdj == NULL)
    {
        UINT unError = GetLastError();
        return 0xffffffff;
    }
    // Create a remote thread; as its starting address 

    // we specify GetCurrentProcessId() address,
    // which is the same for all processes. Note that GetCurrentProcessId() has no input
    // parameters, and we don't care about our thread stack cleanup,
    // as it will be destroyed right after this call

    DWORD dwThreadID;
    HANDLE hRemoteThread = CreateRemoteThread(hProcessAccAdj, NULL, 
        0, lpStartAddress, 0, 0, &dwThreadID);
    CloseHandle(hProcessAccAdj);
    if (hRemoteThread == NULL) return 0xffffffff;
    // Wait until process ID is obtained

    // (replace INFINITE value below to a smaller value to avoid deadlocks);
    // then get the thread exit code, which is a value returned by GetCurrentProcessId()
    // in the context of the remote process
    WaitForSingleObject(hRemoteThread, INFINITE);
    DWORD dwExitCode;
    if (GetExitCodeThread(hRemoteThread, &dwExitCode) == 0)    dwExitCode = 0xffffffff;
    CloseHandle(hRemoteThread);
    return dwExitCode;
}

Unfortunately, this will fail if the security context of a target process does not allow us to open (duplicate) a handle to that process with required access rights. In particular, this will happen with low ID processes such as csrss.exe, winlogon.exe and a few others. Getting debug privilege may or may not solve a problem, as we, by assumption, cannot control the way of getting an initial (available) handle. For instance, in the following sequence of calls...

C++
hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId);
HANDLE hProcessAccessAdjusted;
DuplicateHandle(GetCurrentProcess(), hProcess, GetCurrentProcess(),
                &hProcessAccessAdjusted,
                PROCESS_QUERY_INFORMATION|PROCESS_CREATE_THREAD|
                PROCESS_VM_OPERATION|PROCESS_VM_WRITE,
                FALSE, 0);

...the last call will fail with ERROR_ACCESS_DENIED if dwProcessId represents one of the above processes, whether or not the debug privilege is granted.

2. Is Process Enumeration Helpful?

Using functionality provided by psapi.dll, one can enumerate (identifiers of) processes currently running in the operating system and then get their handles and attempt to work with them. Obviously, it's useless to compare process handles with a given one (think about handle duplication). Instead, we can compare process properties, which can be obtained using process handles. Although none of them uniquely determines a process, GetProcessTimes() can do a pretty good filtering, especially on a single processor machine. The obtained result is valid if no other process has the same creation time. To improve the result, if more than one candidate has the same creation time, we can continue comparison by process name. Below you can see a sketch of a function that does such enumeration. If, by available data, the process can be uniquely identified, its ID is returned. The function fails, returning 0xffffffff, if more than one candidate exists.

C++
#include <Psapi.h>

DWORD WINAPI TryGetProcessIDbyProcessHandle(HANDLE hProcess)
{
    // [in]  process handle
    // [out] process ID, or 0xffffffff in case of failure
    
    if (hProcess == NULL)    return 0xffffffff;
    FILETIME ftSourceCreationTime, ftOtherCreationTime;
    FILETIME ftExitTime;
    FILETIME ftKernelTime;
    FILETIME ftUserTime;
    // Get requested process creation time

    GetProcessTimes(hProcess, &ftSourceCreationTime, 
        &ftExitTime, &ftKernelTime, &ftUserTime);
 
    // Enumerate existing processes and compare creation times
    DWORD cbNeeded;
    DWORD dwProcessesIDs[1024];
    DWORD dwGoodProcessesIDs[1024];
    DWORD dwGoodProcessCount = 0;
    if ( EnumProcesses( dwProcessesIDs, sizeof(dwProcessesIDs), &cbNeeded ) )
    {
        cbNeeded /= sizeof(DWORD);    // bytes to ID cound

        for (UINT i=0; i < cbNeeded; i++)
        {
            HANDLE hOtherProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 
                FALSE, dwProcessesIDs[i]);
            GetProcessTimes(hOtherProcess, &ftOtherCreationTime, &ftExitTime, 
                &ftKernelTime, &ftUserTime);
            CloseHandle(hOtherProcess);
            if (*(__int64*)(&ftSourceCreationTime) == *(__int64*)(&ftOtherCreationTime))
            {
                dwGoodProcessesIDs[dwGoodProcessCount] = dwProcessesIDs[i];
                dwGoodProcessCount ++;
            }
        }
    }
    if (dwGoodProcessCount == 0)    return 0xffffffff;
    if (dwGoodProcessCount == 1)    return dwGoodProcessesIDs[0];

    // Now we can try to compare process names

    DWORD dwRetProcessID = -1;
    USHORT szSourceProcessName[MAX_PATH];
    szSourceProcessName[0] = 0;
    HMODULE hMod[1024];
    if ( EnumProcessModules( hProcess, hMod, sizeof(hMod), &cbNeeded) )
        GetModuleBaseNameW( hProcess, hMod[0], szSourceProcessName, 
        sizeof(szSourceProcessName) );
    if (szSourceProcessName[0] == 0)    return 0xffffffff;        
        // failed to get process name

    UINT i = 0;
    do 
    { 
        szSourceProcessName[i] = towlower(szSourceProcessName[i]);
    } 
    while (szSourceProcessName[++i]);

    USHORT szOtherProcessName[MAX_PATH];
    // work with selected processes only
    for (i=0; i < dwGoodProcessCount; i++)
    {
        HANDLE hOtherProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 
            FALSE, dwGoodProcessesIDs[i]);
        if ( EnumProcessModules( hProcess, hMod, sizeof(hMod), &cbNeeded) )
            GetModuleBaseNameW( hProcess, hMod[0], szOtherProcessName, 
            sizeof(szOtherProcessName) );
        CloseHandle(hOtherProcess);
        if (szOtherProcessName[0] == 0)    return 0xffffffff;  
            // failed to get process name

        UINT j = 0;
        do 
        { 
            szOtherProcessName[j] = towlower(szOtherProcessName[j]);
        } 
        while (szOtherProcessName[++j]);
        if (wcscmp(szSourceProcessName, szOtherProcessName) == 0)
        {
            if (dwRetProcessID == -1)   dwRetProcessID = dwGoodProcessesIDs[i];
            else                        return 0xffffffff;  
            // more than one coincidence

        }
    }
    return dwRetProcessID;
}

Once again, in general, this way cannot guarantee process ID determination in all cases. Use it at your own risk where function failure is not critical.

3. Using "undocumented" ZwQueryInformationProcess()

If you are not afraid of native API calls, one more way to solve this problem is to use ZwQueryInformationProcess(). Indeed, Microsoft provides some information about ZwQueryInformationProcess Function. The word "undocumented" currently means only that Microsoft does not guarantee that the function will be present in future OS releases. As starting from Window XP SP1 there is a documented straightforward solution, and previously released versions obviously cannot be changed, it is not a big problem.

ZwQueryInformationProcess() is exported by Ntdll.dll, but it has no associated import library. Thus, to use it, run-time dynamic linking is required.

Here is this function prototype:

C++
NTSTATUS WINAPI ZwQueryInformationProcess(
  __in       HANDLE ProcessHandle,
  __in       PROCESSINFOCLASS ProcessInformationClass,
  __out      PVOID ProcessInformation,
  __in       ULONG ProcessInformationLength,
  __out_opt  PULONG ReturnLength
);

Here PROCESSINFOCLASS is an enumeration defined in ntddk.h; for our purposes we will set ProcessInformationClass to ProcessBasicInformation value, which is 0. The result will be returned through ProcessInformation parameter, which must point to the following structure:

C++
typedef struct _PROCESS_BASIC_INFORMATION {
    PVOID Reserved1;
    PPEB PebBaseAddress;
    PVOID Reserved2[2];
    ULONG_PTR UniqueProcessId;
    PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;

PebBaseAddress is a pointer to process environment block structure. As we don't need it, we may treat it as PVOID.

Following the same style as above, we can wrap all steps in the following function:

C++
#if !defined NTSTATUS
typedef LONG NTSTATUS;
#endif

#if !defined PROCESSINFOCLASS
typedef LONG PROCESSINFOCLASS;
#endif

#if !defined PPEB
typedef struct _PEB *PPEB;
#endif

#if !defined PROCESS_BASIC_INFORMATION
typedef struct _PROCESS_BASIC_INFORMATION {
    PVOID Reserved1;
    PPEB PebBaseAddress;
    PVOID Reserved2[2];
    ULONG_PTR UniqueProcessId;
    PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
#endif;

typedef NTSTATUS (WINAPI * PFN_ZWQUERYINFORMATIONPROCESS)(HANDLE, PROCESSINFOCLASS,
    PVOID, ULONG, PULONG);


DWORD GetProcessIDbyProcessHandleZw(HANDLE hProcess)
{
    HINSTANCE hNtDll = LoadLibraryW(L"ntdll.dll");
    if (hNtDll == NULL)    return 0xffffffff;
    PFN_ZWQUERYINFORMATIONPROCESS fnProcInfo = PFN_ZWQUERYINFORMATIONPROCESS(
        ::GetProcAddress(hNtDll, "ZwQueryInformationProcess"));
    if (fnProcInfo == NULL)
    {
        CloseHandle(hNtDll);
        return 0xffffffff;
    }
    PROCESS_BASIC_INFORMATION pbi;
    ZeroMemory(&pbi, sizeof(PROCESS_BASIC_INFORMATION));
    if (fnProcInfo(hProcess, 0, &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL) == 0)
    {
        CloseHandle(hNtDll);
        return pbi.UniqueProcessId;
    }
    else
    {
        CloseHandle(hNtDll);
        return 0xffffffff;
    }
}

Sample Project

Real projects where you may need this stuff are too complex for a sample project, but as you're finishing reading this article, then you have probably already seen them. The sample project I've attached is pretty artificial. You specify a process ID (well, how to make it easier to communicate with this program?) and a handle to that process is obtained. Then the program attempts to do the reverse procedure, informing you about the results and functions used. The two above functions are located in the ProcessIdFromHandleConversion.cpp file.

History

  • 7 December, 2007 -- Original version posted
  • 9 January, 2008 -- A solution using ZwQueryInformationProcess() added

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Ukraine Ukraine
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionHow can I get the Thread ID from the Thread Handle in Kernel land? e.g. in NtCreateThreadEx(PHANDLE ThreadHandle, ...) Pin
hassan_sayfi6918-Jul-15 3:26
hassan_sayfi6918-Jul-15 3:26 
QuestionDuplicateHandle parameters problem Pin
jiazhiqiang25-Jun-13 17:31
jiazhiqiang25-Jun-13 17:31 
GeneralPosting this in 2007 : laughable.. Pin
kilt27-Feb-09 1:22
kilt27-Feb-09 1:22 
AnswerAnother simple way... [Getting Process ID from Process Handle] Pin
Ross Brigoli19-Jan-09 20:49
Ross Brigoli19-Jan-09 20:49 
GeneralRe: Another simple way... but solves a completely different problem. Pin
Dmytro Ivanchykhin20-Jan-09 4:09
Dmytro Ivanchykhin20-Jan-09 4:09 
Generalcompile error Pin
gabrielmaldi2-Oct-08 17:21
gabrielmaldi2-Oct-08 17:21 
QuestionVery helpful. What's about 64-bit? Pin
vic_ch200021-Apr-08 18:09
vic_ch200021-Apr-08 18:09 
AnswerBoth approaches are broken, here is one that should not be [modified] Pin
Jakob Bohm27-Dec-07 7:47
Jakob Bohm27-Dec-07 7:47 
As the article says, the injection method needs a lot of permissions for the target process.
The enumeration method is also broken because it is so statistical in nature: No matter how many non-unique process properties you compare, there is always a risk of misidentification.

Fortunately, the internal system call that underlies GetProcessId() has existed at least since NT 4.0,
probably even earlier NT versions (it used to be undocumented, so it is difficult to check without
testing on each prior NT release). The function is "documented" as one of the "settlement APIs" from one of the old lawsuits, and can thus be found in winternl.h from recent platform SDKs.

Beware that I have not had time to test this code on all the platforms that have their own code here, that is left as an exercise for the reader. However the code does compile cleanly with /W4 and (for 32 bits) /Wp64 .

If you compile this with the option -DTESTPROG you get a console Win32/Win64 program which selftests
the code and returns an 'ERRORLEVEL' indicating success or failure. The test is very slow because it does not really enumerate processes, but just tries all numerically valid process ID values.

// Version 2: Updated Dec 27 to fix two sillybugs
// Version 3: Updated Dec 28 to make it compile etc.
// Version 4: Updated Dec 31 to handle magic handle and include test program
// Version 5: Updated Dec 31 to handle differences between Win98 and Win95
// Version 6: Updated Jan  7 to clean up harmless 64 bit portability warnings
#define _WIN32_WINNT 0x0502
#include <windows.h>  // Basic Windows APIs

#if _MSC_VER >= 1200
// These pragmas are missing from winternl.h
#pragma warning(push)
#pragma warning(disable: 4201)
#endif
#define _RUNTIME_FUNCTION _WINTERNL_RUNTIME_FUNCTION
#define  RUNTIME_FUNCTION  WINTERNL_RUNTIME_FUNCTION
#define PRUNTIME_FUNCTION PWINTERNL_RUNTIME_FUNCTION
#include <winternl.h> // Formerly undocumented API
#undef  _RUNTIME_FUNCTION
#undef   RUNTIME_FUNCTION
#undef  PRUNTIME_FUNCTION
#if _MSC_VER >= 1200
#pragma warning(pop)
#endif

#include <stdlib.h>   // _winver
#if _MSC_VER >= 1400
// _winver and _osver are very useful but officially deprecated anyway
#pragma warning(disable: 4996)
#endif

typedef
DWORD
(WINAPI *PGetProcessId)(
    IN  HANDLE Process);
typedef
NTSTATUS
(WINAPI *PNtQueryInformationProcess)(
    IN  HANDLE ProcessHandle,
    IN  PROCESSINFOCLASS ProcessInformationClass,
    OUT PVOID ProcessInformation,
    IN  ULONG ProcessInformationLength,
    OUT PULONG ReturnLength OPTIONAL);
typedef
ULONG
(WINAPI *PRtlNtStatusToDosError)(
   NTSTATUS Status);

// Note: Win32 APIs consistently treat process and thread ids as 32 bit values,
//    even on Win64
// But the underlying native NT APIs treat process and thread ids as pointer
//    sized values (DWORD_PTR or HANDLE).
// This function follows the Win32 type
// This function returns 0xffffFFFFul in case of any error
DWORD WINAPI GetProcessIdAnyWinVer(HANDLE hProcess)
{
   HMODULE                    hMod;
   PGetProcessId              pGetProcessId;
   PNtQueryInformationProcess pNtQueryInformationProcess;
   PRtlNtStatusToDosError     pRtlNtStatusToDosError;
   PROCESS_BASIC_INFORMATION  basicInf;
   NTSTATUS                   ntStatus;
   ULONG                      replySiz;

   // The "magic" handle to the current process needs to be special cased
   if (hProcess == GetCurrentProcess())
      return GetCurrentProcessId();

   #if defined(_M_IX86) || defined(_X86_) || defined(x86) || defined(__BORLANDC__)
   // Win9x was only ever released for the IA32 (x86) architecture
   if (_osver & 0x8000)
   {
      DWORD_PTR               obsfucator;
      const DWORD_PTR        *pProcess;
      const DWORD_PTR        *pProcessMe;
      const DWORD_PTR        *pHandleTable;

      __try {
         if (_winver >= 0x040Au)
         {
            // This is Win98/WinMe, use undocumented information published in
            //    the "Remote Library" codeproject.com article.
            //    http://www.codeproject.com/KB/winsdk/Remote.aspx
            // This code is almost the same as the Win95 code, with only minor
            //    differences
            obsfucator  = ((DWORD_PTR)( NtCurrentTeb() )); // NtCurrentTeb is in winnt.h
            obsfucator -= 0x08u;
            obsfucator ^= GetCurrentThreadId();
            pProcessMe = ((const DWORD_PTR*)(GetCurrentProcessId() ^ obsfucator));
            if (*(const BYTE *)pProcessMe != 6ul)
               goto unexpectedFail;

            // FIXME: Serialize access to the handle table, in case another thread
            //    (or someone calling DuplicateHandle) causes the handle table of
            //    this process to grow during the next steps)
            pHandleTable = (const DWORD_PTR*)(pProcessMe[0x11u]);
            if (!pHandleTable)
               goto unexpectedFail;
            hProcess = ((HANDLE)( ((DWORD_PTR)hProcess) >> 2u ));
            if ( ((DWORD_PTR)hProcess) >= pHandleTable[0] )
               goto badhandle;
            pProcess = ((const DWORD_PTR*)( pHandleTable[((DWORD_PTR)hProcess) * 2u + 2u] ));
            if (!pProcess)
               goto badhandle;
            if (*(const BYTE *)pProcess != 6ul)
               goto unexpectedFail;
            // FIXME: End serialization of access to the handle table
         }
         else
         {
            // This is Win95, use undocumented information published in
            //    "Windows 95 programming secrets" by Matt Pietrek
            // This code is almost the same as the Win98/Me code, with only minor
            //    differences
            obsfucator  = ((DWORD_PTR)( NtCurrentTeb() )); // NtCurrentTeb is in winnt.h
            obsfucator -= 0x10u;
            obsfucator ^= GetCurrentThreadId();
            pProcessMe = ((const DWORD_PTR*)(GetCurrentProcessId() ^ obsfucator));
            if (pProcessMe[0] != 5ul)
               goto unexpectedFail;

            // FIXME: Serialize access to the handle table, in case another thread
            //    (or someone calling DuplicateHandle) causes the handle table of
            //    this process to grow during the next steps)
            pHandleTable = (const DWORD_PTR*)(pProcessMe[0x11u]);
            if (!pHandleTable)
               goto unexpectedFail;
            if ( ((DWORD_PTR)hProcess) >= pHandleTable[0] )
               goto badhandle;
            pProcess = ((const DWORD_PTR*)( pHandleTable[((DWORD_PTR)hProcess) * 2u + 2u] ));
            if (!pProcess)
               goto badhandle;
            if (pProcess[0] != 5ul)
               goto unexpectedFail;
            // FIXME: End serialization of access to the handle table
         }

         return ((DWORD)( obsfucator ^ ((DWORD_PTR)pProcess) ));
        badhandle: ;
         SetLastError(ERROR_INVALID_HANDLE);
         return 0xffffFFFFul;
        unexpectedFail: ;
         SetLastError(ERROR_INTERNAL_ERROR);
         return 0xffffFFFFul;
      }
      __except(EXCEPTION_EXECUTE_HANDLER)
      {
         SetLastError(ERROR_INTERNAL_ERROR);
         return 0xffffFFFFul;
      }
   }
   #endif

   if (_winver >= 0x0501)
   {
      // This is at least NT 5.01 (XP), so GetProcessId() may be available
      hMod = GetModuleHandleW(L"KERNEL32.DLL");
      if ( ((DWORD_PTR)hMod) > ((DWORD_PTR)HINSTANCE_ERROR) )
      {
         pGetProcessId = (PGetProcessId)GetProcAddress(hMod, "GetProcessId");
         if (pGetProcessId)
            return pGetProcessId(hProcess);
      }
   }

   // This is an older NT release, such as XP gold (x86 or Itanium),
   //    Windows 2000, NT 4.x or 3.x
   hMod = GetModuleHandleW(L"NTDLL.DLL");
   if ( ((DWORD_PTR)hMod) > ((DWORD_PTR)HINSTANCE_ERROR) )
   {
      pNtQueryInformationProcess = (PNtQueryInformationProcess)
         GetProcAddress(hMod, "NtQueryInformationProcess");
      // API exported name may vary arbitrarily between these two
      if (!pNtQueryInformationProcess)
         pNtQueryInformationProcess = (PNtQueryInformationProcess)
            GetProcAddress(hMod, "ZwQueryInformationProcess");
      if (pNtQueryInformationProcess)
      {
         replySiz = 0;
         ntStatus = pNtQueryInformationProcess(
            hProcess, ProcessBasicInformation, &basicInf, sizeof(basicInf), &replySiz);
         if (ntStatus == 0 && replySiz == sizeof(basicInf))
            return ((DWORD)(basicInf.UniqueProcessId));

         // Report failure
         pRtlNtStatusToDosError = (PRtlNtStatusToDosError)
            GetProcAddress(hMod, "RtlNtStatusToDosError");
         if (pRtlNtStatusToDosError != NULL && ntStatus != 0)
            SetLastError(pRtlNtStatusToDosError(ntStatus));
         else
            SetLastError(ERROR_UNIDENTIFIED_ERROR);
         return 0xffffFFFFul;
      }
   }

   // Very old NT version or unexpected error   
   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
   return 0xffffFFFFul;
}

#ifdef TESTPROG

#include <stdio.h> // printf

int __cdecl main(int argc, char**argv)
{
   DWORD pid;
   DWORD pid2;
   HANDLE hProcess;
   DWORD err;
   BOOL anyok = 0;
   BOOL anybad = 0;

   (void)(argc);
   (void)(argv);

   pid = GetCurrentProcessId();
   hProcess = GetCurrentProcess();
         printf("my pid=%lu...", pid);
         pid2 = GetProcessIdAnyWinVer(hProcess);
         if (pid2 == pid)
         {
            printf("ok  ");
            anyok = 1;
         }
         else if (pid2 == 0xffffFFFFul)
         {
            printf("failed! err=%lu (0x%08lX)\n", GetLastError(), GetLastError());
            anybad = 1;
         }
         else
         {
            printf("WRONG: %lu\n", pid2);
            anybad = 1;
         }
   printf("\n");

      hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid);
      if (hProcess && hProcess != INVALID_HANDLE_VALUE)
      {
         printf("pid=%lu...", pid);
         pid2 = GetProcessIdAnyWinVer(hProcess);
         CloseHandle(hProcess);
         if (pid2 == pid)
         {
            printf("ok  ");
            anyok = 1;
         }
         else if (pid2 == 0xffffFFFFul)
         {
            err = GetLastError();
            printf("failed! err=%lu (0x%08lX)\n", err, err);
            anybad = 1;
         }
         else
         {
            printf("WRONG: %lu\n", pid2);
            anybad = 1;
         }
      }


   pid &= 0x80000003ul;
   
   for (pid += 4u; pid < 0xffffFFFCul; pid += 4u)
   {
      hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, pid);
      if (hProcess && hProcess != INVALID_HANDLE_VALUE)
      {
         printf("pid=%lu...", pid);
         pid2 = GetProcessIdAnyWinVer(hProcess);
         CloseHandle(hProcess);
         if (pid2 == pid)
         {
            printf("ok  ");
            anyok = 1;
         }
         else if (pid2 == 0xffffFFFFul)
         {
            err = GetLastError();
            printf("failed! err=%lu (0x%08lX)\n", err, err);
            anybad = 1;
         }
         else
         {
            printf("WRONG: %lu\n", pid2);
            anybad = 1;
         }
      }
   }


   if (anybad)
      printf("At least one test failed, see above\n");
   else if (anyok)
      printf("All tests ok!\n");
   else
      printf("Nothing tested, please check test program itself!\n");
   

   return ((anyok && !anybad) ? 0 : 2);
}


#endif


This message is hasty and is not to be taken as serious, professional or legally binding.
I work with low level C/C++ in user and kernel mode, but also dabble in other areas.

modified on Monday, January 07, 2008 5:39:42 AM

GeneralRe: Both approaches are broken, here is one that should not be Pin
Dmytro Ivanchykhin4-Jan-08 22:21
Dmytro Ivanchykhin4-Jan-08 22:21 
AnswerRe: Both approaches are broken, here is one that should not be Pin
Jakob Bohm7-Jan-08 0:36
Jakob Bohm7-Jan-08 0:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.