65.9K
CodeProject is changing. Read more.
Home

Fetching a byte buffer from a native DLL

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1 vote)

Aug 15, 2013

CPOL
viewsIcon

5947

Fetching a byte buffer from a native DLL.

Define a function in nativeDLL(let say it “Win32Native.dll”) as shown below.

extern "C" __declspec(dllexport) int FetchByteArray ( int nSize, byte** ppnArray ) 
{ 
   int result = 0; 
   //   CoTaskMemAlloc must be used instead of the new operator because code on the managed side will call 
   //   Marshal.FreeCoTaskMem to free this memory. 
   byte* newArray = (byte*)CoTaskMemAlloc( sizeof(byte) * nSize ); 
   for ( int j = 0; j < nNewSize ; j++ ) 
   { 
       newArray[j] = ( j+1 ) % 255 ; 
       result += newArray[j]; 
   }
   // release the previous buffer, if any allocated.    if ( *ppnArray != NULL ) CoTaskMemFree( *ppnArray ); 
   *ppnArray = newArray; 
   return result; 
}
Points of Interest
  • CoTaskMemAlloc is used to allocated the memory required.
  • CoTaskMemFree is used to free any previously allocated buffer, if null is passed then, CoTaskMemFree is not called.

If you want to use a heap that is shared between native and managed, it is more common to use the COM heap.

Writing the client code (the managed part)

We can simply create a console base application which can use this DLL. Let’s name it MarshallingTest.

See the code snippet below.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text;
namespace MarshallingTest 
{ 
   class Program 
   { 
       [DllImport("Win32Native.dll")] 
       public static extern int FetchByteArray(int nSize, ref IntPtr arrInt); 
    
       static void Main(string[] args) 
       { 
           int nSize = 10; 
           IntPtr ptrArr = IntPtr.Zero;
           int nSum = FetchByteArray(nSize, ref ptrArr); 
           byte[] arrByte = new byte[nSize]; 
           Marshal.Copy(ptrArr, arrByte, 0, nSize);
           Console.WriteLine("\nReturned Buffer\n");
           for (int i = 0; i < nSize; i++) 
           { 
               Console.Write ( "{0:D2} ", arrByte[i] ); 
           } 
           
           Console.Write("\nSum of Buffer : {0}\n", nSum ); 
           Marshal.FreeCoTaskMem(ptrArr); 
       } 
   } 
}
Points of Interest
  • namespace System.Runtime.InteropServices; defines the declarations necessary for Interop operations, like DllImport.
  • DllImport defines the DLL entry point.
  • Marshal.Copy function used to copy buffer from managed buffer to unmanaged buffer and vice versa.
  • Marshal.FreeCoTaskMem frees the memory allocated by native DLL.

Compile and execute you will get the following output:

image