Call from C # to function C, which takes an array of structures allocated by the caller

I have the following C structure

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 numEntires size XYZ array that is allocated by the caller

I defined the following C # structure:

[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 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, this will not work. Can someone shed light on what I am doing wrong?

+3
source share
4 answers
[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;
}

Should they uintbe ulong? Also, is MAX_FN equal to 128?

XYZ xyz = new XYZ[numEntries];
for (...) xyz[i] = new XYZ(); 

XYZ is the value type (struct), so the second line is redundant here (structures 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 an array of structures in it.

+1
source

, LPArray, . [In] [Out] ( ).

IIRC, LPArray, , , blittable. [MarshalAs(...)].


Edit:

, , , ... , .

0
0

. xyzTbl a IntPtr.

[DllImport(@"xyzdll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern Int32 func(Int32 handle, ref Int32 numntries, IntPtr xyzTb);

XYZ, , .

IntPtr unmanaged = 
    Marshal.AllocHGlobal(Marshal.SizeOf(typeof(XYZ)) * numEntries);

Calling func(handle, ref numEntries, unmanaged);Then the job should disconnect unmanaged memory back to 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);
0
source

Source: https://habr.com/ru/post/1783066/


All Articles