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;
byte* newArray = (byte*)CoTaskMemAlloc( sizeof(byte) * nSize );
for ( int j = 0; j < nNewSize ; j++ )
{
newArray[j] = ( j+1 ) % 255 ;
result += newArray[j];
}
*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:
More than 10 years of experience in designing and development of GUIs and Middleware for industrial control systems.