Search code examples
c#winapiprocesspinvoke

OpenProcess failed to open existing process via id (Last Error code: 1008)?


I'm trying to use OpenProcess to open all existing processes via the process ID. But somehow it works just the first call, while the next calls show that it does not work with an error code reported as 1008 (An attempt was made to reference a token that does not exist).

Here is the code:

[DllImport("kernel32.dll", SetLastError=true)]
public static extern IntPtr OpenProcess(ProcessAccessFlags access, bool inheritHandle, int procId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

[Flags]
public enum ProcessAccessFlags : uint
{
    All = 0x001F0FFF,
    Terminate = 0x00000001,
    CreateThread = 0x00000002,
    VirtualMemoryOperation = 0x00000008,
    VirtualMemoryRead = 0x00000010,
    VirtualMemoryWrite = 0x00000020,
    DuplicateHandle = 0x00000040,
    CreateProcess = 0x000000080,
    SetQuota = 0x00000100,
    SetInformation = 0x00000200,
    QueryInformation = 0x00000400,
    QueryLimitedInformation = 0x00001000,
    Synchronize = 0x00100000
}

foreach (var proc in Process.GetProcesses()) {
    var procHandle = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VirtualMemoryOperation, false, proc.Id);
    var eCode = Marshal.GetLastWin32Error(); 
    //checking the last error code using Marshal.GetLastWin32Error() 
    //shows that it succeeds the first time with error code of 0
    //Then all the next calls show error code of `1008`.
    if(procHandle != IntPtr.Zero) CloseHandle(procHandle);
}

I've tried googling for the error but not sure what could be wrong here. It would be nice if you can let me know what's wrong. Thank you!

UPDATE: As I said it seems to work just for the first process in the loop. BUT I highly doubt that it actually does not work even for that case because from what I see the procHandle keeping a totally different value from the proc.Handle, unless the handle returned by OpenProcess is another kind of handle and not the same to proc.Handle (if so it's really weird). So if what I'm currently doubting is true, that means OpenProcess totally does not work at all. It's simply useless in this case and still not sure in which context we can use it.


Solution

  • Your error checking is broken. Success is indicated by OpenProcess returning a non-zero value. The error code is only meaningful if OpenProcess fails, that is if OpenProcess returns zero.

    So, you must only ask for the error code when the function call fails, as indicated by its return value. You check the error code without checking the return value, which is a mistake. Your code should be more like this:

    foreach (var proc in Process.GetProcesses())
    {
        var procHandle = OpenProcess(ProcessAccessFlags.QueryInformation | ProcessAccessFlags.VirtualMemoryOperation, false, proc.Id);
        if (procHandle == IntPtr.Zero)
        {
            // api call failed, can read error code
            var eCode = Marshal.GetLastWin32Error();
        }
        else
        {
            // api call succeeded, do stuff with handle
            CloseHandle(procHandle);
        }
    }