3

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 ?

2
  • 1
    By the way, what's the error? Commented Jan 2, 2011 at 8:31
  • When calling func the second parameter needs a ref in front of it, since it is ref in the function declaration. Commented Feb 13, 2011 at 11:06

4 Answers 4

1
[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.

Sign up to request clarification or add additional context in comments.

Comments

0

Check this one: Marshal C++ struct array into C# , probably it would help.

2 Comments

Thanks Nickolay the post you are talking about is different. I need to allocate the struct array in C#....
Yes, actually. I also found msdn.microsoft.com/en-us/library/…, MSDN tells that you should (probably) also pass SizeConst parameter.
0

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);

2 Comments

This kind of manual marshalling is only necessary if the unmanaged code keeps a reference to the memory passed in beyond the point where the called function returns.
And your finalization code isn't very robust either. But most likely that only matters in few applications. Typically those that require clean unloads of AppDomains.
0

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.

2 Comments

Hi, I tried your suggestion but it does not work. I think that Marshalling is required since C# and C++ represent arrays differently. Can I create C# array as contigious block of structs ?
@lifey: Hm... what is the error you get? Knowing that would really help. And yes, marshaling does need to happen, it's just that I don't think you specify it explicitly as LPArray.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.