Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
825 views
in Technique[技术] by (71.8m points)

c# - How can I pass MemoryStream data to unmanaged C++ DLL using P/Invoke

I need your help with the following scenario:

I am reading some data from hardware into a MemoryStream (C#) and I need to pass this data in memory to a dll implemented in unmanaged C++ (using pointer ??). The data read (into stream) is very large (megabytes). I understand that I can P/Invoke this dll but what I am not sure is how to pass the pointer / reference of the stream data to the C++ API ?

I must admit I am confused as I am new to C# - do I need to use unsafe / fixed since data is large or these are irrelevant as MemoryStream object is managed by GC ? Some example code / detailed description would be very helpful. Thanks

Signature of unmanaged API:

BOOL doSomething(void * rawData, int dataLength)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If it's just expecting bytes you can read the MemoryStream into a byte array and then pass a pointer to that to the method.

You have to declare the external method:

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

Then, read the bytes from the MemoryStream into a byte array. Allocate a GCHandle which:

Once allocated, you can use a GCHandle to prevent the managed object from being collected by the garbage collector when an unmanaged client holds the only reference. Without such a handle, the object can be collected by the garbage collector before completing its work on behalf of the unmanaged client.

And finally, use the AddrOfPinnedObject method to get an IntPtr to pass to the 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();
   }
 }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...