了解使用fixed {},Marshal.AllocHGlobal()和GCHandle.Alloc()之间的区别

时间:2011-01-02 19:10:12

标签: c# pinvoke marshalling

首先让我说看看我在整个论坛和网络上的许多链接中找到了固定{},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);
}

我感兴趣的是,任何人都可以阐明上述技术,并指出我在实施中的错误,并指出上述方法是否合适。最后,即使上述方法都是有效的,过去几年是否会对一种方法或另一种方法进行普遍推动?

提前致谢!! 夸大

1 个答案:

答案 0 :(得分:3)

嗯,替代方案也可能有效。但Marshal.AllocHGlobal示例并不完整,您现在已将数据存储在非托管内存中。您仍然需要做一些工作才能将其置于托管对象(数组)中,以便您可以轻松访问它,您必须调用Marshal.Copy()。效率低,因为它复制数据两次。别忘了给Marshal.FreeHGlobal()打电话。

固定样本与供应商样本的作用相同,它隐含地固定内存。这里的重点是API采用IntPtr,而不是字节*。您必须更改编译设置以允许不安全关键字。它不是更有效率。

你不是以不同的方式做到这一点。