我正在关注提供here的pinvoke代码,但是稍微有点害怕可变长度数组的编组为size = 1,然后通过计算偏移而不是索引到数组来逐步执行它。有没有更好的方法?如果没有,我应该怎么做才能使它对32位和64位安全?
[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 :(得分:2)
我觉得它看起来没问题 - 无论如何,无论如何在无人管理的土地上进行探讨都是好的。
但是,我想知道为什么开头是tokenInformation.ToInt64() + IntPtr.Size
而不是tokenInformation.ToInt64() + 4
(因为GroupCount字段类型是int而不是IntPtr)。这是用于包装/对齐结构还是只是有点可疑?我不知道在这里。
使用tokenInformation.ToInt64()
很重要,因为在64位计算机上,如果IntPtr值大于int可以存储的值,将爆炸(OverflowException)。但是,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);
快乐的编码。
答案 1 :(得分:0)
不是猜测偏移量,而是通常更好地使用Marshal.OffsetOf(typeof(TOKEN_GROUPS), "Groups")
来获取数组开头的正确偏移量。