Let’s assume you have a user defined structure “EMPLOYEE” in a win32 DLL (let say it “Win32Native.dll”) as shown below.
typedef struct _EMPLOYEE
{
int Age ;
int Sex;
double Salary ;
char* FirstName ;
char* LastName ;
} EMPLOYEE;
Define some functions in native dll (let say it “Win32Native.dll”) as shown below.
extern "C" __declspec(dllexport) void ModifyArrayOfEmployeeStruct(int nSize, EMPLOYEE* pArray);
Implementing Functions
extern "C" __declspec(dllexport) void ModifyArrayOfEmployeeStruct( int nSize, EMPLOYEE* pArray)
{
int result = 0;
EMPLOYEE* pCur = pArray;
STRSAFE_LPSTR temp1, temp2 ;
for ( int i = 0; i < nSize; i++ )
{
size_t nLen1 = 0;
size_t nLen2 = 0;
StringCchLengthA( pCur->FirstName, STRSAFE_MAX_CCH, &nLen1 );
StringCchLengthA( pCur->LastName, STRSAFE_MAX_CCH, &nLen2 );
nLen1 = sizeof(char) * ( nLen1 + 11 ); // To accomodate "<Modified>"
nLen2 = sizeof(char) * ( nLen2 + 11 ); // To accomodate "<Modified>"
temp1 = (STRSAFE_LPSTR)CoTaskMemAlloc( nLen1 );
temp2 = (STRSAFE_LPSTR)CoTaskMemAlloc( nLen2 );
StringCchCopyA( temp1, nLen1, (STRSAFE_LPCSTR)"<Modified>" );
StringCbCatA( temp1, nLen1, (STRSAFE_LPCSTR)pCur->FirstName);
StringCchCopyA( temp2, nLen2, (STRSAFE_LPCSTR)"<Modified>" );
StringCbCatA( temp2, nLen2, (STRSAFE_LPCSTR)pCur->LastName);
// CoTaskMemFree must be used instead of delete to free memory.
CoTaskMemFree( pCur->FirstName );
CoTaskMemFree( pCur->LastName );
pCur->FirstName = (char *)temp1;
pCur->LastName = (char *)temp2;
pCur->Age += 1 ;
pCur->Salary += 1000.0 ;
pCur++;
}
}
Point of Interest
If you want to use a heap that is shared between native and managed, it is more common to use the COM heap.
CoTaskMemAlloc() and CoTaskMemFree().
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.Runtime.InteropServices;
using System.Text;
namespace MarshallingTest
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Employee
{
public int Age;
public int Sex;
public double Salary;
public String FirstName;
public String LastName;
}
class Program
{
[DllImport("Win32Native.dll")]
public static extern int ModifyArrayOfEmployeeStruct(
int nSize,
[In, Out] Employee[] empArr);
static void Main(string[] args)
{
int nCnt = 5; // Number of Items in Structure Array
Employee[] emp = new Employee[nCnt];
emp[0].FirstName = "Ramesh"; emp[0].LastName = "Sharma"; emp[0].Age = 42; emp[0].Salary = 40000; emp[0].Sex = 0;
emp[1].FirstName = "Shalini"; emp[1].LastName = "Verma"; emp[1].Age = 30; emp[1].Salary = 25000; emp[1].Sex = 1;
emp[2].FirstName = "Ramesh"; emp[2].LastName = "Sharma"; emp[2].Age = 51; emp[2].Salary = 35000; emp[2].Sex = 0;
emp[3].FirstName = "Aarushi"; emp[3].LastName = "Shukla"; emp[3].Age = 25; emp[3].Salary = 20000; emp[3].Sex = 0;
emp[4].FirstName = "Malini"; emp[4].LastName = "Kapoor"; emp[4].Age = 33; emp[4].Salary = 30000; emp[4].Sex = 1;
Console.WriteLine("\nEmployee Array Before Call");
for (int nI = 0; nI < nCnt; nI++)
{
StringBuilder sb = new StringBuilder( "First Name=[" );
sb.Append(emp[nI].FirstName);
sb.Append("] Last Name=[");
sb.Append(emp[nI].LastName );
sb.Append("] Age=[");
sb.Append(emp[nI].Age .ToString ());
sb.Append("] Salary=[");
sb.Append(emp[nI].Salary.ToString ("F2"));
sb.Append("] Sex=[");
sb.Append(((emp[nI].Sex == 0) ? "Male" : "Female"));
sb.Append("]");
Console.WriteLine(sb.ToString ());
}
// Call the Function.
ModifyArrayOfEmployeeStruct(emp.Length, emp);
Console.WriteLine("\nEmployee Array After Call");
for (int nI = 0; nI < nCnt; nI++)
{
StringBuilder sb = new StringBuilder("First Name=[");
sb.Append(emp[nI].FirstName);
sb.Append("] Last Name=[");
sb.Append(emp[nI].LastName);
sb.Append("] Age=[");
sb.Append(emp[nI].Age.ToString());
sb.Append("] Salary=[");
sb.Append(emp[nI].Salary.ToString("F2"));
sb.Append("] Sex=[");
sb.Append(((emp[nI].Sex == 0) ? "Male" : "Female"));
sb.Append("]");
Console.WriteLine(sb.ToString());
}
}
}
}
Point of Interest
compile and execute you will get following output.