Передача указателя структуры, который содержит массив в качестве параметра в C # - PullRequest
0 голосов
/ 23 декабря 2011

У меня есть функция на C ++ и экспортируется в DLL.функция

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.Но я не знаю, как правильно его определить.

Заранее спасибо!

Ответы [ 3 ]

3 голосов
/ 23 декабря 2011

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

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

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

3 голосов
/ 23 декабря 2011

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

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

Для получения дополнительной информации см. Буферы фиксированного размера .

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

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

и назовите это:

DevInfo info = new DevInfo();
int id = LOGIN(ref info)
0 голосов
/ 23 декабря 2011

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

Используйте функцию 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));
...