2012-04-03 17 views
5

Wymagane jest dla określonego zadania wyliczenie wszystkich uchwytów w systemie. Najlepszym podejściem, jakie do tej pory znalazłem, jest używanie nieudokumentowanego NtQuerySystemInformation z flagą SystemHandleInformation dla parametru klasy.Preferowane podejście do kompilacji warunkowej dla wersji 32-bitowych i 64-bitowych typów

Jak dotąd tak dobrze. Jednak uruchomienie go w trybie 32-bitowym na 64-bitowym systemie Windows, wymagana struktura jest następująca:

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

A dla 64-bitowych systemów Windows (x64, nie przetestować Itanium, które mam nadzieję, że nie jest inaczej. ..), których struktura jest następująca:

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

teraz należy zmienić Object_Pointer do IntPtr. Miałem nadzieję, że przez chwilę będę mógł zrobić to samo z ProcessId, było odniesienie mówiąc, że faktycznie był to HANDLE, który jest w rzeczywistości wartością 64-bitową. Jednak Reserved ma zawsze wartość zero, więc nie mogę tego scalić w taki sam sposób.

Prawdopodobnie nie jest to jedyny scenariusz, w którym tak się dzieje. Szukam praktyka sposób radzenia sobie z takimi różnicami najlepiej:

  • przy stałej jak #if WIN32 (używany wewnętrznie w źródle referencyjnym IntPtr) nie będzie tu pracować, chyba że chcą utrzymać oddzielne pliki binarne.
  • Potrafię napisać dwie różne funkcje i dwie różne struktury, utworzyć opakowanie i użyć kodu if IntPtr.Size ==4. Działa to dla funkcji zewnętrznych, ale nie działa dobrze z typami.
  • Mogę przeciążać GetType, ale nie jestem pewien, gdzie to prowadzi (może pomóc w Marshalling?).
  • Coś jeszcze?

Żadne z nich nie wydaje się idealne, ale jak na razie jedyną niezawodną metodą wydaje się być smalenie mojego systemu za pomocą instrukcji if IsWin64(). Chciałbym usłyszeć lepsze podejście niż moje.

+3

Ten rodzaj kodu jest jak seks nastoletnich, jeden błąd i będziesz go wspierać przez resztę swojego życia. Użyj klasy Process, aby uruchomić narzędzie Handle.exe SysInternals, przynajmniej możesz poprosić kogoś innego, aby to wspierał. –

+0

@HansPassant: LOL! Tak, rozważałem użycie dowolnego narzędzia SysInternal, ale nie, nie pasuje do mojego scenariusza. Dzięki za wskaźnik. – Abel

Odpowiedz

2

Biorąc pod uwagę wielkość IntPtr jest inny, to dlaczego nie spróbować wykonać następujące czynności:

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

ten powinien pracować zarówno 32 jak i 64 bit niezmienione.

+0

Tak, próbowałem to kilka razy, ale przynosi zły ProcessID. Może to dobry pomysł, powinienem wtedy rozwinąć strukturę przy pomocy metody 'GetProcessId()' która demaskuje i oznaczyć ProcessID jako prywatny. – Abel

+0

@Abel: W 64-bitach, po prostu cofnij 32-bitowe.Nie byłem pewien co do kwestii endianowych :) – leppie

+0

Otrzymuje proces ID 4 (system) jako "0x0000000400000000", który jest "17179869184", z sekwencji bajtów '00 00 00 00 04 00 00 00'. Więc tak, endianizm jest problemem (w tym sensie, że przeszkadzają wiodące zarezerwowane zera). '0x0000000400000000 >> 32' działa w obudowach 64-bitowych. – Abel

3

To wszystko - Struktury SystemHandleInformation dają tylko 16-bitowe PIDy. Możesz użyć SystemExtendedHandleInformation na XP i wyżej.

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

wyjściowa:

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

To po prostu doskonałe. Pytałem o ogólnie lepsze podejście do radzenia sobie z bitness, ale otrzymałem odpowiedzi na moje bardziej szczegółowe pytanie. Nie wiedziałem o rozszerzonej wersji, dzięki! – Abel

Powiązane problemy