首先让我说看看我在整个论坛和网络上的许多链接中找到了固定{},Marshal.AllocHGlobal()和GCHandle.Alloc()的使用说明。但是,我还没有找到关于何时使用Marshal类与GCHandle类(使用和不使用fixed {})的简明解释。
我正在使用第三方.NET库,它在“Buffer”类中有一个名为 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()
这可能是故事的结尾(我还没有测试上面的代码),但我最终搜索了GCHandle类,这让我走上了.NET互操作性,pInvoke等的道路。
所以我的问题...... 1)为什么我不能使用:
IntPtr dataLineAddress = Marshal.AllocHGlobal( size * 2 );
并将其传递给ReadLine()?
2)我还可以使用以下代码片段(从网络上的示例中提取和调整):
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);
}
我感兴趣的是,任何人都可以阐明上述技术,并指出我在实施中的错误,并指出上述方法是否合适。最后,即使上述方法都是有效的,过去几年是否会对一种方法或另一种方法进行普遍推动?
提前致谢!! 夸大
答案 0 :(得分:3)
嗯,替代方案也可能有效。但Marshal.AllocHGlobal示例并不完整,您现在已将数据存储在非托管内存中。您仍然需要做一些工作才能将其置于托管对象(数组)中,以便您可以轻松访问它,您必须调用Marshal.Copy()。效率低,因为它复制数据两次。别忘了给Marshal.FreeHGlobal()打电话。
固定样本与供应商样本的作用相同,它隐含地固定内存。这里的重点是API采用IntPtr,而不是字节*。您必须更改编译设置以允许不安全关键字。它不是更有效率。
你不是以不同的方式做到这一点。