Define a function in native DLL (let say it “Win32Native.dll”) as shown below.
extern "C" __declspec(dllexport) void FetchStringArray( int nCount, char* ppStrArray[])
{
int result = 0;
STRSAFE_LPSTR temp;
size_t cchDest = 40;
const size_t alloc_size = sizeof(char) * 40;
for ( int nI = 0; nI < nCount; nI++ )
{
char *pszFormat = "from DLL >> [returned String %d]";
STRSAFE_LPSTR temp = (STRSAFE_LPSTR)CoTaskMemAlloc( alloc_size );
StringCchPrintfA(temp, cchDest, pszFormat, nI);
CoTaskMemFree( ppStrArray[nI] );
ppStrArray[nI] = (char *) temp;
}
}
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 based application:
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace MarshallingTest
{
class Program
{
[DllImport("Win32Native.dll")]
public static extern void FetchStringArray(int nCount, [In, Out] String[] arrStr);
static void Main(string[] args)
{
int nSize = 10;
String[] arrStr = new String[nSize];
FetchStringArray(nSize, arrStr);
Console.WriteLine("Returned String Array");
for (int nI = 0; nI < nSize; nI++)
{
Console.WriteLine(arrStr[nI]);
}
}
}
}
Point of Interest
- namespace System.Runtime.InteropServices; defines the declarations necessary for Interop operations, like DllImport,
- DllImport defines the DLL entry point.
Compile and execute you will get following output.
More than 10 years of experience in designing and development of GUIs and Middleware for industrial control systems.