Вызов из C # в функцию C, которая принимает массив struct, выделенный вызывающей стороной - PullRequest
3 голосов
/ 02 января 2011

У меня есть следующая структура C

struct XYZ
{
void            *a;
char            fn[MAX_FN];     
unsigned long   l;          
unsigned long   o;  
};

И я хочу вызвать следующую функцию из C #:

extern "C"  int     func(int handle, int *numEntries, XYZ *xyzTbl);

Где xyzTbl - это массив XYZ размера numEntires, который выделяется вызывающей стороной

Я определил следующую структуру C #:

[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;
}

и метод:

 [DllImport(@"xyzdll.dll", CallingConvention = CallingConvention.Cdecl)]
 public static extern Int32 func(Int32 handle, ref Int32 numntries,
     [MarshalAs(UnmanagedType.LPArray)] XYZ[] arr);

Затем я пытаюсь вызвать функцию:

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

Конечно, это не работает. Может кто-то пролить свет на то, что я делаю неправильно?

Ответы [ 4 ]

1 голос
/ 02 января 2011
[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;
}

Разве эти uint не должны быть ulong? Кроме того, MAX_FN 128 верно?

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

XYZ - это тип значения (структура), поэтому вторая строка здесь избыточна (структуры всегда инициализируются)

 [DllImport(@"xyzdll.dll", CallingConvention = CallingConvention.Cdecl)]
 public static extern Int32 func(Int32 handle, ref Int32 numntries,
 [MarshalAs(UnmanagedType.LPArray)] XYZ[] arr);

[MarshalAs(UnmanagedType.LPArray)] избыточен, компилятор увидит, что это массив struct.

0 голосов
/ 02 января 2011

Я бы собрал это вручную. Сначала сделайте xyzTbl 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);

Позвоните вашему func(handle, ref numEntries, unmanaged); Задача состоит в том, чтобы разархивировать неуправляемую память обратно в управляемые типы.

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 голосов
/ 02 января 2011

Отметьте это: Структурный массив Marshal C ++ в C # , возможно, это поможет.

0 голосов
/ 02 января 2011

Я не верю, что вы можете использовать LPArray, когда у вас есть управляемая структура.Просто возьмите это и используйте вместо этого [In] и [Out] (если необходимо).

IIRC, если вы используете LPArray, он попытается передать указатель на первый элемент, что недопустимопотому что структура не является легковесной.Вам нужно полностью удалить [MarshalAs(...)].


Редактировать:

Я не помню, но вам может потребоваться инициализировать строковые поля перед их передачей ...Я проверю это, когда у меня будет шанс.

...