Предпочтительный подход для условной компиляции для 32-битных и 64-битных версий типов - PullRequest
5 голосов
/ 03 апреля 2012

Для выполнения определенной задачи мне необходимо перечислить все дескрипторы в системе.Наилучший подход, который я нашел до сих пор, это использование недокументированного NtQuerySystemInformation с флагом SystemHandleInformation для параметра класса.

Пока все хорошо.Однако при работе в 32-битном режиме в 64-битной Windows требуемая структура выглядит следующим образом:

// 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, но я не уверен, куда это ведет (может помочь с Marshalling?).
  • Что-нибудь еще?

Ничто из этого не кажется идеальным, но до сих пор единственный надежный способ, похоже, состоит в том, чтобы нагружать мою систему с помощью операторов if IsWin64().Я хотел бы услышать лучшие подходы, чем мой.

Ответы [ 2 ]

3 голосов
/ 03 апреля 2012

В том-то и дело - структуры SystemHandleInformation предоставляют только 16-битные PID. Вы можете использовать SystemExtendedHandleInformation на XP и выше.

  [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
2 голосов
/ 03 апреля 2012

Учитывая, что размер 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-битных неизмененных.

...