//////////////////////////使用固定的{},Marshal.AllocHGlobal()和GCHandle.Alloc()的描述
使用固定的{},Marshal.AllocHGlobal()和GCHandle.Alloc()的描述.然而,我还没有找到一个简明扼要的说明,说明何时使用元帅类与GCHandle类(使用和不使用fixed {}).
我正在使用第三方.NET库,它在“缓冲区”类中有一个名为Readline()的方法.手册显示以下功能原型:
bool ReadLine(int x1,int y1,int x2,int y2,System.IntPtr bufData,out int numRead);
对bufData的描述说:…内存区域必须有大于或等于行长度的字节数乘以
BytesPerPixel属性.
现在稍后在用户手册中,他们给出了一个访问缓冲区的示例(我已经调整了一点我的具体示例):
// Create an array large enough to hold one line from buffer
int size = 640;
byte[] dataLine = new byte[size * 2]; // 2 bytes per pixel
// Pin the array to avoid Garbage collector moving it
GCHandle dataLineHandle = GCHandle.Alloc(dataLine, GCHandleType.Pinned);
IntPtr dataLineAddress = dataLineHandle.AddrOfPinnedObject();
我可以按照上面的“示例”代码:
// Read one line of buffer data
success = buffer.ReadLine(0, 0, 639, 0, dataLineAddress, out numRead);
// Unpin the array
dataLineHandle.Free()
这可能是故事的结尾(而且我还没有测试上面的代码),但是我最后在Google的GCHandle类中搜索到了这个类,这让我走下了.NET互操作性,pInvoke等的路径.
所以我的问题…
1)为什么我不能使用:
IntPtr dataLineAddress = Marshal.AllocHGlobal( size * 2 );
并将其传递到ReadLine()?
2)我还可以使用以下代码片段(从Web上的示例中提取和调整):
int size = 640;
byte[] dataLine= new byte[size * 2]; // 2 bytes per pixel
// prevent garbage collector from moving buffer around in memory
fixed (byte* fixedDataLine = dataLine)
{
// get IntPtr representing address of first buffer element
IntPtr dataLineAddress= Marshal.UnsafeAddrOfPinnedArrayElement(fixedDataLine , 0);
success = buffer.ReadLine(0, 0, 639, 0, dataLineAddress, out numRead);
}
我会感兴趣的是,任何人都可以了解上述技巧,并指出我的执行错误,并指出上述方法是否合适.最后,即使上述方法都是有效的,过去几年是否普遍推行一种方法呢?
那么替代方案也可能会起作用.但是,Marshal.AllocHGlobal示例不完整,您现在已将数据存入非托管内存.你仍然需要做一些工作,让它进入一个托管对象(数组),这样你可以轻松访问它,你必须调用Marshal.Copy().效率低,因为这两次复制数据.不要忘了打电话给Marshal.FreeHGlobal().
固定样本与供应商样本相同,它隐含地引导存储器.这里的尴尬是API接受IntPtr,而不是字节*.并且您必须更改编译设置以允许不安全的关键字.否则效率不高.