I'm required for a certain task to enumerate all handles in the system. The best approach I found so far is using the underdocumented NtQuerySystemInformation
with the SystemHandleInformation
flag for the class parameter.
So far so good. However, running it in 32 bit mode on 64 bit Windows, the required structure is as follows:
// 32-bit version
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct SYSTEM_HANDLE_INFORMATION
{
public uint ProcessID;
public byte ObjectTypeNumber;
public byte Flags;
public ushort Handle;
public uint Object_Pointer;
public UInt32 GrantedAccess;
}
And for 64 bit Windows (x64, I didn't test Itanium, which I hope isn't different...), the structure is as follows:
// 64-bit version
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct SYSTEM_HANDLE_INFORMATION
{
public int Reserved; // unknown, no documentation found
public uint ProcessID;
public byte ObjectTypeNumber;
public byte Flags;
public ushort Handle;
public long Object_Pointer;
public UInt32 GrantedAccess;
}
Now, I should change the Object_Pointer
to an IntPtr
. I hoped for a moment I could do the same with ProcessId
, there was a reference saying this was actually a HANDLE
which is actually a 64-bit value. However, Reserved
is always zero, so I cannot merge that into an IntPtr
the same way.
This is probably not the only scenario where this happens. I'm looking for a best practice way of dealing with such differences:
#if WIN32
(used internally in the reference source of IntPtr) wouldn't work here unless I want to maintain separate binaries.if IntPtr.Size ==4
in code. This works for external functions, but doesn't work well with types.GetType
but I'm not sure where that leads (might help with Marshalling?).None of these seem ideal, but so far, the only foolproof way seems to be to lard my system with if IsWin64()
statements. I'd love to hear better approaches than mine.
Given IntPtr's size is different, why not try the following:
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct SYSTEM_HANDLE_INFORMATION
{
public IntPtr ProcessID; // mask with 0xffffffff
public byte ObjectTypeNumber;
public byte Flags;
public ushort Handle;
public IntPtr Object_Pointer; // again good for 32/64bit
public UInt32 GrantedAccess;
}
This should work for both 32 and 64 bit unaltered.