Marshal struct with embeded array of struct

G

Guest

I am coding a managed C# wrapper for an unmanaged C DLL and I am unable to
marshal a structure that contains an array of structures. When executed, the
following code throws an ArgumentException with a description “Type
ErrorInjectionBuffer can not be marshaled as an unmanaged structure; no
meaningful size or offset can be computed.†I have also included snippets
from the .H file. Any assistance would be greatly appreciated.

[busapi.h] (partial)
#if defined(__WIN32__)
#include <windows.h>
#define CCONV _stdcall
#define NOMANGLE
#endif

#define BT_U16BIT unsigned short
#define BT_U8BIT unsigned char
#define BT_UINT unsigned int
#define BT_INT int

#define EI_COUNT 33 /* Number of error injection words supported by SW */
/* The HW supports one more, for the 33rd data word*/

typedef struct api_eibuf
{
BT_U16BIT buftype; // error injection buffer type
struct
{
BT_U8BIT etype; // error code (e.g. EI_NONE, EI_TWOBUS, etc)
BT_U8BIT edata; // error data (if req'd)
}
error[EI_COUNT];
}
API_EIBUF;

NOMANGLE BT_INT CCONV BusTools_EI_EbufRead(
BT_UINT cardnum, // (i) card number (0 - based)
BT_UINT errorid, // (i) number of error injection buffer to read
API_EIBUF * ebuf); // (o) pointer to resulting buffer values

NOMANGLE BT_INT CCONV BusTools_EI_EbufWrite(
BT_UINT cardnum, // (i) card number (0 - based)
BT_UINT errorid, // (i) number of error injection buffer to write
API_EIBUF * ebuf); // (i) pointer to buffer values to be written to
HW



[C#]
using System;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
class Class1
{
[DllImport(@"busapi32.dll", EntryPoint = "BusTools_EI_EbufRead")]
public static extern int BusTools_EI_EbufRead(
uint cardnum,
uint errorid,
[MarshalAs(UnmanagedType.LPStruct)]
ref ErrorInjectionBuffer ebuf
);

[DllImport(@"busapi32.dll", EntryPoint = "BusTools_EI_EbufWrite")]
public static extern int BusTools_EI_EbufWrite(
uint cardnum,
uint errorid,
[MarshalAs(UnmanagedType.LPStruct)]
ref ErrorInjectionBuffer ebuf
);

[STAThread]
static void Main(string[] args)
{
Console.WriteLine("SizeOf(struct ErrorInjectionBuffer) = " +
Marshal.SizeOf(typeof(ErrorInjectionBuffer)).ToString()); // Throws
ArgumentException
}
}

[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct ErrorInjectionBuffer
{
private const int ErrorInjectionCount = 33;

private ushort bufferType;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = ErrorInjectionCount)]
private ErrorInjectionData[] errors;
}

[Serializable]
[StructLayout(LayoutKind.Sequential)]
public struct ErrorInjectionData
{
private byte eType;
private byte eData;
}
}
 
G

Guest

There are 33 elements in the array. Other than flattening the array, is
there another way?
 
M

Mattias Sjögren

Daniel,
There are 33 elements in the array. Other than flattening the array, is
there another way?

Since the nested struct in this case is just two bytes, you could
replace the array with a ushort[], and then manually extract the high
and low bytes (eData and eType respectively) from each ushort value.



Mattias
 
G

Guest

Do you know if this functionality will be addressed in .NET 2.0?

Mattias Sjögren said:
Daniel,
There are 33 elements in the array. Other than flattening the array, is
there another way?

Since the nested struct in this case is just two bytes, you could
replace the array with a ushort[], and then manually extract the high
and low bytes (eData and eType respectively) from each ushort value.



Mattias
 
W

Willy Denoyette [MVP]

No it won't. Simply because a generic marshaller cannot handle all possible
mappings between unmanaged data structures and managed object lay-outs.
Note also that the CLR and the managed languages weren't designed for this
kind of operability with legacy C style data and code. If you need this
level of interop you should use managed C++ (or the upcomming CLI/C++) a
language that was designed for this.

Willy.

Daniel Brown said:
Do you know if this functionality will be addressed in .NET 2.0?

Mattias Sjögren said:
Daniel,
There are 33 elements in the array. Other than flattening the array, is
there another way?

Since the nested struct in this case is just two bytes, you could
replace the array with a ushort[], and then manually extract the high
and low bytes (eData and eType respectively) from each ushort value.



Mattias
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top