2011-12-23 5 views
0

У меня есть функция на C++ и экспортирована в DLL. функцияПередача указателя структуры, который содержит массив как параметр в C#

LONG LOGIN(LPDEVINFO info); 

структура из LPDEVINFO является:

struct{ 
     BYTE sSerialNumber[20]; 
} *LPDEVINFO; 

пройти LPDEVINFO параметр, я определил класс в управляемом коде:

class DEVINFO{ 
    Byte[] sSerialNumber = new Byte[20]; 
} 

, а затем P/Invoke например:

[DllImport ('MyDll.dll')] 
public static extern Int32 LOGIN(DEVINFO info); 

, а затем вызвать его в C#:

DEVINFO info = new DEVINFO(); 
Int id = LOGIN(info) 

Когда я запускаю этот код, я получил следующее сообщение об ошибке:

An unhandled exception of type 'System.AccessViolationException' occurred in WindowsFormsApplication1.exe 

Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. 

Я думаю, что проблема вызвана массивом sSerialNumber. Но я не знаю, как правильно определить его.

Заранее благодарен!

+0

Если 'LONG' определен как 64-разрядный целочисленный тип в C++, вам придется либо экспортировать эту функцию как' extern Int64 LOGIN (DEVINFO info); 'или' extern long LOGIN (информация DEVINFO); '. Что касается класса 'DEVINFO', я бы сделал его структурой и применил атрибут' [MarshalAs (UnmanagedType.ByValArray, SizeConst = 20)] 'к массиву байтов. [см. этот ответ] (http://stackoverflow.com/questions/1354275/marshaling-a-byte-array-to-ac-sharp-structure) –

+0

@Jim 'LONG' - 32-битное целое число в C и C++ в Windows , –

+0

А, я видел, как это переопределено. Я не знаю, почему это было бы. –

ответ

3

fixed Используйте ключевое слово, чтобы объявить структуру, которая содержит буфер фиксированного размера:

public unsafe struct DevInfo 
{ 
    public fixed byte sSerialNumber[20]; 
} 

Для получения дополнительной информации см Fixed Size Buffers.

Кроме того, чтобы передать-структуру с помощью указателя (соответствующего LPDEVINFO на родной стороне), объявить функцию следующим образом:

[DllImport ('MyDll.dll')] 
public static extern Int32 LOGIN(ref DevInfo info); 

и назвать его:

DevInfo info = new DevInfo(); 
int id = LOGIN(ref info) 
+0

с ключевым словом «исправлено», я получаю сообщение об ошибке CS0214: указатели и буферы фиксированного размера могут использоваться только в небезопасном контексте – englefly

+0

@englefly Вам, вероятно, придется помещать 'unsafe' в объявление структуры (меняет мой ответ) и (возможно) в коде, который его использует. Вам также необходимо включить небезопасный код в свойствах проекта C#. –

0

Функция ожидает указатель на структуру, а не фактическую структуру.

Используйте функцию Marshal.StructureToPtr(), чтобы преобразовать вашу структуру в IntPtr.

Пример в C#:

[DllImport("MyDll.dll")] 
public static extern Int32 LOGIN(IntPtr info); 

... 

DEVINFO info = new DEVINFO(); 
IntPtr infoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(info)); 
Marshal.StructureToPtr(info, infoPtr, false); 
LOGIN(infoPtr); 

Если это параметр OUT, то вам необходимо прочитать из нее после того, как функция вызывается, поскольку она изменяется вызываемым, то вы используете Marshal.PtrToStructure читать его обратно в управляемую структуру, как следующим образом:

DEVINFO info = (DEVINFO)Marshal.PtrToStructure(infoPtr, typeof(DEVINFO)); 
+1

Использование 'class', а не struct, в соответствии с кодом в вопросе означает, что будет передан указатель. Это не проблема. –

+0

Ответ Брэдли лучше. Я просто использовал StructureToPtr для странных сценариев взаимодействия, таких как указатели на массивы указателей на структуры, где простой функции ref не хватило. –

+0

Использование класса просто отлично. Я делаю это все время. –

3

Я хотел бы использовать UmanagedType.ByValArray здесь:

class DEVINFO { 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=20)] 
    public byte[] sSerialNumber; 
} 

Иначе все выглядит хорошо. В частности, это вполне нормально сделать с помощью class, а не struct.

+0

Я озадачен нисходящей стороной ответа и ответа на вопрос Брэдли. Я не вижу ничего плохого ни с одним из них. Если что-то не так, я хотел бы исправить это. –

+0

Да, так я и решил. –

+0

спасибо. Он отлично работает! – englefly

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