Data structures can be passed between managed C# code and unmanaged C/C++ dynamic link libraries but it can be a little complicated. The trick is to define structures that match between the two different languages; and perhaps write wrapper functions that hide away the complexity of the memory marshaling code. I will show a couple of simple examples of passing a system time data structure from C/C++ to C# and vice versa here.
The C/C++ definition of the system time structure is as follows:
typedef struct _SYSTEMTIME { WORD wYear; WORD wMonth; WORD wDayOfWeek; WORD wDay; WORD wHour; WORD wMinute; WORD wSecond; WORD wMilliseconds; } SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
The matching C# equivalent of the system time structure can be defined as shown below.
private struct SYSTEMTIME { public UInt16 wYear; public UInt16 wMonth; public UInt16 wDayOfWeek; public UInt16 wDay; public UInt16 wHour; public UInt16 wMinute; public UInt16 wSecond; public UInt16 wMilliseconds; }
Example 1: Passing a structure from C/C++ to C#
If the C/C++ function has the following signature:
HRESULT GetDateTime( HANDLE hClient, SYSTEMTIME* pSysTime );
Then the following wrapper functions can be used to call the C/C++ function.
[DllImport("MyDynamicLinkLib.dll")] private static extern int GetDateTime(IntPtr hClient, IntPtr pSysTime); public static int GetDateTime(IntPtr hClient, out DateTime sysTime) { int hr = 0; IntPtr pSysTime = IntPtr.Zero; SYSTEMTIME theTime = new SYSTEMTIME(); sysTime = new DateTime(); pSysTime = Marshal.AllocHGlobal( Marshal.SizeOf(theTime)); hr = GetDateTime(hClient, pSysTime); theTime = (SYSTEMTIME) Marshal.PtrToStructure(pSysTime, typeof(SYSTEMTIME)); Marshal.FreeHGlobal(pSysTime); sysTime = new DateTime(theTime.wYear, theTime.wMonth, theTime.wDay, theTime.wHour, theTime.wMinute, theTime.wSecond, theTime.wMilliseconds); return hr; }
To use the wrapper functions, simply do something like the following:
IntPtr hClient = IntPtr.Zero; DateTime dt = new DateTime(); int ret = GetDateTime( hClient, out dt);
Example 2: Passing a structure from C# to C/C++
If the C/C++ function has the following signature,
HRESULT SetDateTime( HANDLE hClient, SYSTEMTIME* pSysTime );
Then the following wrapper functions can be used to call the C/C++ function.
[DllImport("MyDynamicLinkLib.dll")] private static extern int SetDateTime(IntPtr hClient, IntPtr pSysTime); public static int SetDateTime(IntPtr hClient, DateTime sysTime) { int hr = 0; IntPtr pSysTime = IntPtr.Zero; SYSTEMTIME theTime = new SYSTEMTIME(); theTime.wYear = (ushort) sysTime.Year; theTime.wMonth = (ushort) sysTime.Month; theTime.wDay = (ushort) sysTime.Day; theTime.wDayOfWeek = (ushort) sysTime.DayOfWeek; theTime.wHour = (ushort) sysTime.Hour; theTime.wMinute = (ushort) sysTime.Minute; theTime.wSecond = (ushort) sysTime.Second; theTime.wMilliseconds = (ushort) sysTime.Millisecond; pSysTime = Marshal.AllocHGlobal(Marshal.SizeOf(theTime)); hr = SetDateTime(hClient, pSysTime); Marshal.FreeHGlobal(pSysTime); return hr; }
Do the following to call the wrapper functions.
DateTime dt = new DateTime(); int hr = SetDateTime(hClient, dt);