2011-05-20 59 views
4

我遵循提供的密碼代碼here,但是由於大小= 1的變長數組的編組而稍微害怕,然後通過計算偏移量而不是索引到數組中來逐步完成。沒有更好的方法嗎?如果不是,我該如何做到這一點,以確保32位和64位的安全?如何從GetTokenInformation()安全地爲32位和64位調用可變長度的結構數組? C#

[StructLayout(LayoutKind.Sequential)] 
    public struct SID_AND_ATTRIBUTES 
    { 
     public IntPtr Sid; 
     public uint Attributes; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    public struct TOKEN_GROUPS 
    { 
     public int GroupCount; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] 
     public SID_AND_ATTRIBUTES[] Groups; 
    }; 


public void SomeMethod() 
{ 
    IntPtr tokenInformation; 

    // ... 

    string retVal = string.Empty; 
    TOKEN_GROUPS groups = (TOKEN_GROUPS)Marshal.PtrToStructure(tokenInformation, typeof(TOKEN_GROUPS)); 
    int sidAndAttrSize = Marshal.SizeOf(new SID_AND_ATTRIBUTES()); 
    for (int i = 0; i < groups.GroupCount; i++) 
    { 
     // *** Scary line here: 
     SID_AND_ATTRIBUTES sidAndAttributes = (SID_AND_ATTRIBUTES)Marshal.PtrToStructure(
       new IntPtr(tokenInformation.ToInt64() + i * sidAndAttrSize + IntPtr.Size), 
       typeof(SID_AND_ATTRIBUTES)); 

    // ... 
} 

我看到here爲遠大於它很可能是在聲明數組的長度的另一種方法,但似乎有其自身的問題。

作爲一個側面的問題:當我在調試器中單步執行上面的代碼時,我無法評估tokenInformation.ToInt64()ToInt32()。我得到一個ArgumentOutOfRangeException。但是這行代碼執行得很好!?這裏發生了什麼?

+0

51%...你在哪看到的!?開玩笑 - 公平點我真的很懶。 – Rory 2011-05-20 11:00:47

+0

因此任何想法ToInt64()在32位和64位機器上都是安全的嗎? – Rory 2011-05-20 11:01:20

回答

2

我認爲這看起來沒問題 - 好吧,無論如何,任何在非託管土地上的戳穿都是可以的。

但是,我不知道爲什麼開始是tokenInformation.ToInt64() + IntPtr.Size而不是tokenInformation.ToInt64() + 4(因爲GroupCount字段類型是一個int而不是IntPtr)。這是爲了包裝/對齊結構還是隻是一些可疑的東西?我不知道這裏。

使用tokenInformation.ToInt64()非常重要,因爲在64位機器上將爆炸(OverflowException)如果IntPtr值大於int可以存儲的值。但是,CLR在兩種架構上都能處理得很好,並且它不會改變從IntPtr中提取的實際值(並因此返回到new IntPtr(...))。

想象一下這樣的(未經測試)功能作爲一個便利的包裝:

// unpacks an array of structures from unmanaged memory 
// arr.Length is the number of items to unpack. don't overrun. 
void PtrToStructureArray<T>(T[] arr, IntPtr start, int stride) { 
    long ptr = start.ToInt64(); 
    for (int i = 0; i < arr.Length; i++, ptr += stride) { 
     arr[i] = (T)Marshal.PtrToStructure(new IntPtr(ptr), typeof(T)); 
    } 
} 

var attributes = new SID_AND_ATTRIBUTES[groups.GroupCount]; 
PtrToStructureArray(attributes, new IntPtr(tokenInformation.ToInt64() + IntPtr.Size), sidAndAttrSize); 

編碼愉快。

+0

是的,我明白你的意思是關於IntPtr.Size。 TOKEN_GROUPS.GroupCount應該是uint(http://msdn.microsoft.com/zh-cn/library/aa379624(v=vs.85).aspx http://msdn.microsoft.com/zh-cn/library/aa383751 (VS.85).aspx)和IntPtr.Size在32位和64位系統上是8(http://msdn.microsoft.com/en-us/library/system.intptr.size.aspx) – Rory 2011-05-21 13:49:57

0

而不是猜測什麼是偏移量,是它通常更好地使用Marshal.OffsetOf(typeof(TOKEN_GROUPS), "Groups")來獲得正確的數組的開始偏移量。