Define a function in native dll (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;
}
Point 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.
- On the native side use
CoTaskMemAlloc()andCoTaskMemFree(). - On the managed side use
Marshal.AllocCoTaskMem()andMarshal.FreeCoTaskMem().
Writing the client code (the managed part)
one can simple 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);
}
}
}
Point 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 following output.