C# Interop - Marshal struct element between C# and C++

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
<span style="color:#333333; font-family:Segoe UI,Lucida Grande,Verdana,Arial,Helvetica,sans-serif; font-size:14px; text-align:left I need to use several native dll
<span style="color:#333333; font-family:Segoe UI,Lucida Grande,Verdana,Arial,Helvetica,sans-serif; font-size:14px; line-height:20px; text-align:left struct<span style="color:#333333; font-family:Segoe UI,Lucida Grande,Verdana,Arial,Helvetica,sans-serif; font-size:14px; text-align:left written
in C++ in my application: <br/>

<pre class="prettyprint #define MAX_NO_DEVICES 3typedef struct
{
unsigned int nrOfDevices;
unsigned long Flags [MAX_NO_DEVICES];
unsigned long Type [MAX_NO_DEVICES];
unsigned long ID [MAX_NO_DEVICES];
unsigned long LocId [MAX_NO_DEVICES];
char SerialNumber[MAX_NO_DEVICES][16];
char Description [MAX_NO_DEVICES][64];
}tDeviceInfo;

typedef struct
{
int idNr [MAX_NO_DEVICES];
CString acmSerialNr[MAX_NO_DEVICES];
} tDeviceToIdMap;[/code]
<span style="color:#333333; font-family:Segoe UI,Lucida Grande,Verdana,Arial,Helvetica,sans-serif; font-size:14px; line-height:20px; text-align:left These struct will be pass into the unmanaged code, where they get assigned value to the struct element <br/>

<pre class="prettyprint extern "C" __declspec(dllexport) void DetectAcmDevices (tDeviceInfo& result);

extern "C" __declspec(dllexport) bool MapAcmDevices (tDeviceToIdMap map);[/code]
<span style="color:#333333; font-family:Segoe UI,Lucida Grande,Verdana,Arial,Helvetica,sans-serif; font-size:14px; line-height:20px; text-align:left In my C# client application, i defined the interface as following
<pre class="prettyprint [DllImport(AcmDll,CallingConvention=CallingConvention.Cdecl, EntryPoint = "DetectAcmDevices")]
private static extern void DetectAcmDevices(ref tDeviceInfo result);

[DllImport(AcmDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "MapAcmDevices")]
private static extern bool MapAcmDevices(tDeviceToIdmap acmMap);[/code]
and defined the structures in C# with following definition<br/>

<pre class="prettyprint [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct tDeviceInfo
{
public uint nrOfDevices;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public uint[] Flags;

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3)]
public uint[] Type;

[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 3)]
public uint[] ID;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public uint[] LocID;

[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr, SizeConst = 3)]
public string[] SerialNumbers;

[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr, SizeConst = 3)]
public string[] Description;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct tDeviceToIdmap
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public int[] idNr;

[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr, SizeConst = 3)]
public string[] acmSerialNr;
}[/code]
I tried to run the program with the following test
<pre style="font-family:Consolas; background-color:white <span style="color:blue namespace ConsoleApplication1
{
<span style="color:blue class <span style="color:#2b91af Program
{
<span style="color:blue static <span style="color:blue void Main(<span style="color:blue string[] args)
{
<span style="color:blue try
{
<span style="color:#2b91af tDeviceInfo deviceInfo = <span style="color:blue new <span style="color:#2b91af tDeviceInfo();
<span style="color:green // call the API detect method
<span style="color:#2b91af AcmApi.DetectAcmDevices(<span style="color:blue ref deviceInfo);

<span style="color:green // check no of device
<span style="color:#2b91af Console.WriteLine(<span style="color:#a31515 "Number of detected device: {0}", deviceInfo.nrOfDevices);

<span style="color:blue for (<span style="color:blue int i = 0; i < deviceInfo.nrOfDevices; i++)
{
<span style="color:#2b91af Console.WriteLine(<span style="color:#a31515 "Serial Number Found {0}: {1}", i, deviceInfo.SerialNumbers);
}

<span style="color:#2b91af tDeviceToIdmap mapping = <span style="color:blue new <span style="color:#2b91af tDeviceToIdmap();
<span style="color:green // call API to map the device serial numbers to id
<span style="color:#2b91af AcmApi.MapAcmDevices(mapping);
}
<span style="color:blue catch (<span style="color:#2b91af Exception ex)
{
<span style="color:#2b91af Console.WriteLine(ex.Message);
}

<span style="color:#2b91af Console.ReadLine();
}
}
}[/code]
I get folllowing error
Additional Information: The runtime has encountered a fatal error. The address of the error was at 0x6225e0e5, on thread 0x1344. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user
code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack. <br/>
<span style="color:#333333; font-family:Segoe UI,Lucida Grande,Verdana,Arial,Helvetica,sans-serif; font-size:14px; line-height:20px; text-align:left <br/>
I think i have to use a different way to marshal string array in C#.<br/>
Could anyone please help me marshalling CString array and 2-D char array of struct element in C#?<br/>
Thanks for any help.<span style="color:#333333; font-family:Segoe UI,Lucida Grande,Verdana,Arial,Helvetica,sans-serif; font-size:14px; text-align:left
<br/>

View the full article
 
Back
Top