2011-01-02 1 views
3

У меня есть следующие C структурыВызов из C# для функции 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); 

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

+1

К сожалению, что это за ошибка? – Mehrdad

+0

При вызове 'func' второй параметр нуждается в' ref' перед ним, так как это 'ref' в объявлении функции. – CodesInChaos

ответ

0

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

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


Edit:

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

+0

Привет, я попробовал ваше предложение, но оно не работает. Я думаю, что Marshalling требуется, поскольку C# и C++ представляют собой массивы по-разному. Могу ли я создать массив C# как контурный блок структур? – lifey

+0

@lifey: Хм ... в чем ошибка? Зная, что это действительно поможет. И да, маршалинг * * должен произойти, просто я не думаю, что вы явно указываете его как «LPArray». – Mehrdad

0

Проверьте это: Marshal C++ struct array into C#, возможно, это поможет.

+0

Спасибо Nickolay сообщение, о котором вы говорите, отличается. Мне нужно выделить массив struct в C# .... – lifey

+0

Да, на самом деле. Я также нашел http://msdn.microsoft.com/en-us/library/z6cfh6e6.aspx#cpcondefaultmarshalingforarraysanchor1, MSDN сообщает, что вы должны (возможно) также передать параметр SizeConst. –

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

не должны быть те uintulong? Кроме того, 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)] является излишним, компилятор будет видеть, что это массив структуры.

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

Позвоните своему 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

Этот вид ручного сортировки необходим только в том случае, если неуправляемый код содержит ссылку на память, переданную за пределы точки, в которой возвращается вызываемая функция. – CodesInChaos

+0

И ваш код завершения не очень надежный. Но, скорее всего, это касается только нескольких приложений. Обычно те, которые требуют чистой выгрузки AppDomains. – CodesInChaos

Смежные вопросы