32位与64位版本类型的条件编译的首选方法

我需要某个任务来枚举系统中的所有句柄。 到目前为止,我发现的最好的方法是使用带有SystemHandleInformation标志的underdocumented NtQuerySystemInformation作为类参数。

到现在为止还挺好。 但是,在64位Windows上以32位模式运行它,所需的结构如下:

 // 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; } 

而对于64位Windows(x64,我没有测试Itanium,我希望没有什么不同……),结构如下:

 // 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; } 

现在,我应该将Object_Pointer更改为IntPtr 。 我希望片刻我能用ProcessId做同样的事情,有一个参考说这实际上是一个HANDLE ,它实际上是一个64位的值。 但是, Reserved始终为零,因此我无法以相同的方式将其合并到IntPtr中。

这可能不是发生这种情况的唯一情况。 我正在寻找一种处理这种差异的最佳实践方法:

  • 使用像#if WIN32这样的常量(在IntPtr的引用源内部使用)在这里不起作用,除非我想维护单独的二进制文件。
  • 我可以编写两个不同的函数和两个不同的结构,创建一个包装器并在代码中使用if IntPtr.Size ==4 。 这适用于外部函数,但不适用于类型。
  • 我可以重载GetType但我不确定它在哪里引导(可能有助于编组?)。
  • 还要别的吗?

这些都不是理想的,但到目前为止,唯一简单的方法似乎是使用if IsWin64()语句给我的系统if IsWin64() 。 我希望听到比我更好的方法。

鉴于IntPtr的大小不同,为什么不尝试以下方法:

 [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; } 

这应该适用于32位和64位不变的。

这就是事情–SystemHandleInformation的结构只给你16位PID。 您可以在XP及更高版本上使用SystemExtendedHandleInformation。

  [StructLayout(LayoutKind.Sequential, Pack = 1)] public class SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX { public IntPtr Object; public IntPtr UniqueProcessId; public IntPtr HandleValue; public uint GrantedAccess; public ushort CreatorBackTraceIndex; public ushort ObjectTypeIndex; public uint HandleAttributes; public uint Reserved; } internal enum SYSTEM_INFORMATION_CLASS { SystemBasicInformation = 0, SystemPerformanceInformation = 2, SystemTimeOfDayInformation = 3, SystemProcessInformation = 5, SystemProcessorPerformanceInformation = 8, SystemHandleInformation = 16, SystemInterruptInformation = 23, SystemExceptionInformation = 33, SystemRegistryQuotaInformation = 37, SystemLookasideInformation = 45, SystemExtendedHandleInformation = 64, } [DllImport("ntdll.dll", CharSet=CharSet.Auto)] private static extern int NtQuerySystemInformation(int InfoType, IntPtr lpStructure, int StructSize, out int returnLength); public static void Main(string[] args) { Console.WriteLine(Environment.Is64BitProcess ? "x64" : "x32"); Console.WriteLine(); var infoSize = Marshal.SizeOf(typeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX)); Console.WriteLine("sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX): {0}", infoSize); int allSize = 1000 * infoSize; var buffer = Marshal.AllocHGlobal(allSize); var status = NtQuerySystemInformation((int)SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation, buffer, allSize, out allSize); Console.WriteLine("status: {0:x}, return len: {1}", status, allSize); if (status != 0) { allSize += 40 * infoSize; Marshal.FreeHGlobal(buffer); buffer = Marshal.AllocHGlobal(allSize); status = NtQuerySystemInformation((int)SYSTEM_INFORMATION_CLASS.SystemExtendedHandleInformation, buffer, allSize, out allSize); Console.WriteLine("status: {0:x}, return len: {1}", status, allSize); } Console.WriteLine(); var info = new SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX(); //for (var i = 0; i < allSize; i += infoSize) for (var i = 0; i < Math.Min(allSize, 20 * infoSize); i+= infoSize) // for testing purpose only 20 { Marshal.PtrToStructure(IntPtr.Add(buffer, i), info); Console.WriteLine("{0,16:x}, {1,16:x}, {2,16:x}, {3,6:x}, {4,8:x}", info.Object.ToInt64(), info.UniqueProcessId.ToInt64(), info.HandleValue.ToInt64(), info.GrantedAccess, info.HandleAttributes); } Marshal.FreeHGlobal(buffer); } 

输出:

 x32 sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX): 28 status: c0000004, return len: 1850052 status: 0, return len: 1850052 10219, 0, 6729b30, 4, 1fffff 0, 0, dfa0, 4, 2001f 0, 0, 8eb0, 4, f000f 0, 0, fca0, 4, 0 0, 0, 225b0, 4, 20019 0, 0, 98210, 4, f003f 0, 0, 6758e60, 4, 1f0001 0, 0, 98040, 4, 2001f 0, 0, 67534e0, 4, 1f0001 0, 0, 9c560, 4, 2001f 0, 0, 6834620, 4, 1fffff 0, 0, 99250, 4, f003f 0, 0, 9a7c0, 4, f003f 0, 0, 95380, 4, f003f 0, 0, 62d80, 4, f003f 0, 0, 15e580, 4, 20019 0, 0, 6f3b940, 4, 2a 0, 0, 20da30, 4, e 0, 0, 7b07a0, 4, 10 0, 0, 9af83a0, 4, 20019 x64 sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX): 40 status: c0000004, return len: 2647576 status: 0, return len: 2647856 10294, 0, fffffa8006729b30, 4, 4 70000001fffff, 0, fffff8a00000dfa0, 4, 8 2300000002001f, 0, fffff8a000008eb0, 4, c 30000000f000f, 0, fffff8a00000fca0, 4, 10 23000000000000, 0, fffff8a0000225b0, 4, 14 23000000020019, 0, fffff8a000098210, 4, 18 230000000f003f, 0, fffffa8006758e60, 4, 1c 240000001f0001, 0, fffff8a000098040, 4, 20 2300000002001f, 0, fffffa80067534e0, 4, 24 240000001f0001, 0, fffff8a00009c560, 4, 28 2300000002001f, 0, fffffa8006834620, 4, 2c 80000001fffff, 0, fffff8a000099250, 4, 30 230000000f003f, 0, fffff8a00009a7c0, 4, 34 230000000f003f, 0, fffff8a000095380, 4, 38 230000000f003f, 0, fffff8a000062d80, 4, 3c 230000000f003f, 0, fffff8a00015e580, 4, 40 23000000020019, 0, fffffa8006f3b940, 4, 44 700000000002a, 0, fffff8a00020da30, 4, 48 500000000000e, 0, fffff8a0007b07a0, 4, 4c 23000000000010, 0, fffff8a009af83a0, 4, 50