【问题标题】:How can I pass MemoryStream data to unmanaged C++ DLL using P/Invoke如何使用 P/Invoke 将 MemoryStream 数据传递给非托管 C++ DLL
【发布时间】:2010-11-06 10:37:34
【问题描述】:

在以下情况下我需要您的帮助:

我正在将一些数据从硬件读取到 MemoryStream (C#) 中,我需要将内存中的这些数据传递给在非托管 C++ 中实现的 dll(使用指针 ??)。 读取的数据(进入流)非常大(兆字节)。我知道我可以 P/Invoke 这个 dll,但我不确定如何将流数据的指针/引用传递给 C++ API?

我必须承认我很困惑,因为我是 C# 的新手——我是否需要使用 unsafe / fixed 因为数据很大,或者这些与 MemoryStream 对象由 GC 管理无关?一些示例代码/详细描述将非常有帮助。谢谢

非托管 API 的签名:

BOOL doSomething(void * rawData, int dataLength)

【问题讨论】:

  • C++ dll 需要什么数据类型?
  • 它需要原始数据 - byte / void*。我可以根据需要更改 dll API。

标签: c# c++ parameter-passing memorystream


【解决方案1】:

如果它只是期望字节,您可以将 MemoryStream 读入字节数组,然后将指向该数组的指针传递给方法。

你必须声明外部方法:

[DllImport("mylibrary.dll", CharSet = CharSet.Auto)]
public static extern bool doSomething(IntPtr rawData, int dataLength);

然后,将 MemoryStream 中的字节读入一个字节数组。分配一个GCHandle 其中:

分配后,您可以使用 GCHandle 防止被管理对象 被垃圾收集 非托管客户端时的收集器 持有唯一的参考。没有这种 一个句柄,可以收集对象 由垃圾收集器之前 代表其完成工作 非托管客户端。

最后,使用 AddrOfPinnedObject 方法获取 IntPtr 以传递给 C++ dll。

private void CallTheMethod(MemoryStream memStream)
{
   byte[] rawData = new byte[memStream.Length];
   memStream.Read(rawData, 0, memStream.Length);
   
   GCHandle rawDataHandle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
   try
   {
     IntPtr address = rawDataHandle.AddrOfPinnedObject ();

     doSomething(address, rawData.Length);
   }
   finally
   {
     if (rawDataHandle.IsAllocated)
       rawDataHandle.Free();
   }
 }

【讨论】:

  • 谢谢。是的,这种方法基本上是用于压缩,因此它需要/对传递给它的原始数据进行操作。也只是好奇的不安全标记数据放在 C# 中的堆或堆栈上?
  • 非常感谢 scotty2012。感谢您的帮助
  • 哦,伙计,这甚至可以在 Silverlight 中使用。多么伟大。谢谢,斯科特。
  • 感谢您的回答。但是,如果您有 MemoryStream,则没有理由复制数据(MemoryStream 只是 byte[] 的包装)。相反,您可以使用MemoryStream.GetBuffer() 方法直接访问内部byte[] 数组。还是我错过了什么?
  • @NightOwl888 OP 要求将参数传递给doSomething(void * rawData, int dataLength)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-04
  • 1970-01-01
相关资源
最近更新 更多