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

时间:2012-04-03 11:46:17

标签: c# .net interop pinvoke marshalling

我需要某个任务来枚举系统中的所有句柄。到目前为止,我发现的最佳方法是使用带有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()语句给我的系统加油。我很想听到比我更好的方法。

2 个答案:

答案 0 :(得分:3)

就是这样 - 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

答案 1 :(得分:2)

鉴于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位不变的。