Reputation: 87
I have the following C struct
struct XYZ
{
void *a;
char fn[MAX_FN];
unsigned long l;
unsigned long o;
};
And I want to call the following function from C#:
extern "C" int func(int handle, int *numEntries, XYZ *xyzTbl);
Where xyzTbl is an array of XYZ of size numEntires which is allocated by the caller
I have defined the following C# struct:
[StructLayoutAttribute(Sequential, CharSet = CharSet.Ansi)]
public struct XYZ
{
public System.IntPtr rva;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 128)]
public string fn;
public uint l;
public uint o;
}
and a method:
[DllImport(@"xyzdll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 func(Int32 handle, ref Int32 numntries,
[MarshalAs(UnmanagedType.LPArray)] XYZ[] arr);
Then I try to call the function :
XYZ xyz = new XYZ[numEntries];
for (...) xyz[i] = new XYZ();
func(handle,numEntries,xyz);
Of course it does not work. Can someone shed light on what I am doing wrong ?
Upvotes: 3
Views: 1861
Reputation: 210352
I don't believe you can use LPArray
when you have a managed structure. Just take that out, and use [In]
and [Out]
(if needed) instead.
IIRC, if you use LPArray
, that would try to pass a pointer to the first element, which is illegal because the structure isn't blittable. You'd need to remove the [MarshalAs(...)]
entirely.
Edit:
I don't remember, but you might need to initialize the string fields before passing them... I'll check that when I get the chance.
Upvotes: 0
Reputation: 13897
I would marshal this manually. First, make xyzTbl an IntPtr
.
[DllImport(@"xyzdll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 func(Int32 handle, ref Int32 numntries, IntPtr xyzTb);
Rather than allocating the XYZ array like you are doing - allocate enough unmanaged memory to store the table.
IntPtr unmanaged =
Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XYZ)) * numEntries);
Call your func(handle, ref numEntries, unmanaged);
The job then is to unmarshal the unmanaged memory back into managed types.
IntPtr[] entries = new IntPtr[numEntries];
List<XYZ> xyz = new List<XYZ>();
Marshal.Copy(unmanaged, entries, 0, numEntries);
foreach (IntPtr entry in entries)
xyz.Add(Marshal.PtrToStructure(entry, typeof(XYZ)));
Marsha.FreeHGlobal(unmanaged);
Upvotes: 0
Reputation: 38106
[StructLayoutAttribute(Sequential, CharSet = CharSet.Ansi)]
public struct XYZ
{
public System.IntPtr rva;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 128)]
public string fn;
public uint l;
public uint o;
}
Shouldn't those uint
be ulong
? Also, MAX_FN is 128 right ?
XYZ xyz = new XYZ[numEntries];
for (...) xyz[i] = new XYZ();
XYZ is a value type (struct), so the second line here is redundant (structs are always initialized)
[DllImport(@"xyzdll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 func(Int32 handle, ref Int32 numntries,
[MarshalAs(UnmanagedType.LPArray)] XYZ[] arr);
[MarshalAs(UnmanagedType.LPArray)]
is redundant, the compiler will see it's a struct array.
Upvotes: 1
Reputation: 14160
Check this one: Marshal C++ struct array into C# , probably it would help.
Upvotes: 0