2008-10-09 4 views
25

Я имею следующую структуру в C++:фельдмаршала C++ структура массива в C#

#define MAXCHARS 15 

typedef struct 
{ 
    char data[MAXCHARS]; 
    int prob[MAXCHARS]; 
} LPRData; 

и функцию, что я п/ссылаться на, чтобы получить массив из 3 этих структур:

void GetData(LPRData *data); 

в C++ я бы просто сделать что-то вроде этого:

LPRData *Results; 
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData)); 
GetData(Results); 

И это будет работать нормально, но в C# я не могу заставить его работать. Я создал C# структура, как это:

public struct LPRData 
{ 

    /// char[15] 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
    public string data; 

    /// int[15] 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
    public int[] prob; 
} 

И если я инициализировать массив 3 из тех (и все их подрешеток) и передать его в этом:

GetData(LPRData[] data); 

Это возвращает с успехом, но данные в массиве LPRData не изменились.

Я даже пытался создать RAW-байтовый массив, размер 3 LPRData и передают, что в прототипе функции, как это:

GetData (байт [] данных);

Но в этом случае я получу строку «данных» из самой первой структуры LPRData, но после нее ничего не останется, включая массив «prob» из той же LPRData.

Любые идеи о том, как правильно обращаться с этим?

ответ

23

Я хотел бы попробовать добавить некоторые атрибуты для вашей структуры decloration

[StructLayout(LayoutKind.Sequential, Size=TotalBytesInStruct),Serializable] 
public struct LPRData 
{ 
/// char[15] 
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
public string data; 

/// int[15] 
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
public int[] prob; 
} 

* Примечание TotalBytesInStruct не предназначен для представления переменной

JaredPar также верно, что с помощью класса IntPtr могут оказаться полезными , но это было довольно долго, так как я использовал PInvoke, поэтому я ржавый.

13

Один трюк при работе с указателями - это просто использовать IntPtr. Затем вы можете использовать Marshal.PtrToStructure на указателе и приращении в зависимости от размера структуры, чтобы получить ваши результаты.

static extern void GetData([Out] out IntPtr ptr); 

LPRData[] GetData() 
{ 
    IntPtr value; 
    LPRData[] array = new LPRData[3]; 
    GetData(out value); 
    for (int i = 0; i < array.Length; i++) 
    { 
     array[i] = Marshal.PtrToStructure(value, typeof(LPRData)); 
     value += Marshal.SizeOf(typeof(LPRData)); 
    } 
    return array; 
} 
+2

следует строка 11 либо: изменение '+ = `в` = `и` `ToInt32` к ToInt64`, если 64-разрядное; или, удалите `значение.ToInt32()`? – maxwellb 2010-07-08 19:20:03

+0

@maxwellb, да. Код, написанный, не является 64-битным. – JaredPar 2010-07-08 19:59:45

2

Вы отметили параметр GetData с помощью OutAttribute?

Сочетание InAttribute и OutAttribute особенно полезен при нанесении на массивы и отформатирован, не-blittable типов. Вызывающие абоненты видят изменения , которые вызывающий делает для этих типов только при применении обоих атрибутов.

2

Похожая тема обсуждалась на this question, и один из выводов состоит в том, что CharSet именованный параметр должен быть установлен в CharSet.Ansi.В противном случае мы будем создавать массив wchar_t вместо массива char. Таким образом, правильный код будет выглядеть следующим образом:

[Serializable] 
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct LPRData 
{ 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
    public string data; 

    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
    public int[] prob; 
} 
Смежные вопросы