2012-03-01 3 views
2

У меня есть функция C++ в DLL, которая берет указатель на структуру JPInfo, которая в функции заполняется данными, полученными от сервера, макет структуры C++ показано ниже:Отправка указателя на C# struct в C++ DLL

typedef struct JP 
{ 
    unsigned char type; 
    DWORD value; 
} JP; 

typedef struct JPInfo 
{ 
    JP jps[3]; 
    _int16 ConT; 
    _int16 CallT; 
    unsigned char ret; 
    unsigned char count; 
    unsigned char JPOffset; 
    unsigned char JPPeriod; 
} JPInfo; 

функция экспортируется в DLL, как так:

__declspec(dllexport) DWORD __stdcall GetJPInfo(JPInfo* jpi, DWORD time); 

функция принимает указатель на структуру JPInfo, я пытался подражать эту структуру в C#

[StructLayout(LayoutKind.Sequential, Size = 5), Serializable] 
public struct JP 
{ 
    byte type; 
    int value; 
} 

[StructLayout(LayoutKind.Sequential,Size=23),Serializable] 
public struct JPInfo 
{ 
    JP[] jps; 
    Int16 ConT; 
    Int16 CallT; 
    byte ret; 
    byte count; 
    byte JPOffset; 
    byte JPPeriod; 
} 

Я пытаюсь вызвать функцию из C#, как так:

[DllImport("DLLImp.dll")] 
    unsafe public static extern int GetJP(ref JPInfo jpi, int time); 
// then in main... 
JPInfo jpi = new JPInfo; 
GetJackpotValues(ref jpi, 4000); 

Я получаю необработанное исключение типа «System.ExecutionEngineException». Я не могу иметь массив фиксированных размеров структур JP в моей структуре JPInfo, поэтому я не знаю, как подойти к этому.

Спасибо.

+0

Старайтесь не указывать sie явно, а Marshaller по умолчанию делает это. (Размер = 23,5 и т. Д.) – Digvijay

ответ

2

Предполагая, что Структуры C++ упакованы, ваша C# Структура должна выглядеть следующим образом:

[StructLayout(LayoutKind.Sequential, Pack=1)] 
public struct JP 
{ 
    byte type; 
    uint value; 
} 

[StructLayout(LayoutKind.Sequential, Pack=1)] 
public struct JPInfo 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=3)] 
    JP[] jps; 
    Int16 ConT; 
    Int16 CallT; 
    byte ret; 
    byte count; 
    byte JPOffset; 
    byte JPPeriod; 
} 

С другой стороны, если они не упакованы затем удалите параметр Pack в атрибут StructLayout. Вы должны искать оператор #pragma pack в файле заголовка C++, чтобы понять, упакованы ли структуры C++.

Я предполагаю, что структуры C++ упакованы, потому что вы сказали, что они сопоставлены с данными, полученными с сервера.

Ваш импорт должен быть примерно так:

[DllImport("DLLImp.dll")] 
public static extern uint GetJP(ref JPInfo jpi, uint time); 

DWORD переводит uint, а не int и нет никакой необходимости в небезопасном коде здесь.

+0

Абсолютно совершенный! Спасибо Дэвиду. –

4

Вы пытались удалить атрибуты размера в своих структурах? Мне не приходилось указывать размер при выполнении чего-то подобного. Для ваших свойств массива, попробуйте приписывая их, как:

[StructLayout(LayoutKind.Sequential)] 
public struct JPInfo 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 
    JP[] jps; 
    Int16 ConT; 
    Int16 CallT; 
    byte ret; 
    byte count; 
    byte JPOffset; 
    byte JPPeriod; 
} 
+0

Хмм, я не получаю сообщение об ошибке, но структура не заполняется. В DLL выполняется прямой байт для копии байт, поэтому порядок элементов в структуре жизненно важен, делает способ, которым я объявлял struct gaurantee, что члены в структуре будут в том же порядке в памяти? –

+0

Да, это путь. Я бы также инициализировал массив при создании, сделав 'JP [] jps = new JP [3];'. – Krizz

+0

Задав LayoutKind.Sequential, память будет выложена в том порядке, в котором вы определяете свойства структуры в своем приложении .NET. Наличие динамического размера массива не имеет смысла для меня, поскольку вам нужно отправить точное распределение памяти по всему каналу. –

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