У меня есть экспортированная функция C ++ в DLL:
int MyMethod(ulong pid, MyStruct* struct);
MyStruct описывается как класс:
class MyStruct
{
public:
uchar nVersion;
uchar nModuleType;
uchar nMachine64;
uchar nReserved;
ulong data1;
ulong data2;
ulong data3;
};
Я пытаюсь импортировать эту функцию в мой код C # следующим образом:
[DllImport("mydll.dll", EntryPoint = "#24")]
private static extern int _MyMethod(long pid, ref MyStruct struct);
Класс в C #:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
stuct MyStruct
{
public byte nVersion;
public byte nModuleType;
public byte nMachine64;
public byte nReserved;
public ulong data1;
public ulong data2;
public ulong data3;
}
И я получаю System.AccessViolationException
:
MyStruct struct = new MyStruct();
_MyMethod(4728, ref struct);
В чем дело?
ОБНОВИТЬ:
System.Runtime.InteropServices.Marshal.SizeOf(struct)
возвращает 32. Почему? Я думал, что это должно быть 4 * 1 + 8 * 3 = 28
В C # мы имеем class
эс и struct
s. Все class
типы являются ссылочными, но struct
типы являются типами значений. Это означает, что когда у вас есть что-то вроде class MyStruct
а ты пишешь MyStruct s
на самом деле это что-то вроде указателя на базовый класс, и когда вы передаете его по ссылке, вы фактически передаете адрес этого указателя, поэтому он не имеет ничего общего с C ++, который ожидает указатель на main struct
, Согласно этому решению ваша проблема заключается в преобразовании class
в struct
,
long
а также ulong
в C # есть 64-битные типы, в то время как они 32-битные в C ++ (по крайней мере, MSVC), поэтому, когда вы объявляете свою функцию так, чтобы ее первый параметр был long
вы отправляете дополнительное 32-битное значение, которое может переопределить следующий параметр и сделать его недействительным:
Stack:
32 bit: [first 32 bit of the first parameter]
32 bit: [second 32 bit of the first parameter]
32 bit: [address of your structure]
Поэтому при вызове функции она будет принимать неверный параметр в качестве адреса структуры. так что просто измените определение вашей функции на:
[DllImport("mydll.dll", EntryPoint = "#24")]
private static extern int _MyMethod(int pid, ref MyStruct struct);
Ваша структура для:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
stuct MyStruct
{
public byte nVersion;
public byte nModuleType;
public byte nMachine64;
public byte nReserved;
public uint data1;
public uint data2;
public uint data3;
}
может быть источником вашей ошибки является первый параметр функции, потому что функция ожидает 32-битное значение, а вы предоставляете 64-битное, а на самом деле вы предоставляете 2, 32-битное значение для функции, которая вызывает функцию
SizeOf () возвращает 32 из-за требований выравнивания для ulong, 8-байтового типа значения. Значение по умолчанию для StructLayoutAttribute.Pack равно 8, так же как и упаковка по умолчанию, используемая в собственном коде. Таким образом, data1 выравнивается по смещению 8, и между nReserved и data1 есть 4-байтовый разрыв. Так что 4 х 1 + 4 + 3 х 8 = 32.
Вы, вероятно, получили этот пробел, потому что в нативном коде C ++, скомпилированном с помощью компилятора MSVC, ulong составляет 4 байта. То же, что и Uint в C #. Так что исправьте объявление структуры, замените ulong на uint.
Следующая проблема, причина AV, заключается в том, что вы объявили структуру как класс в C #. Который является ссылочным типом, который всегда передается по ссылке. Ваше текущее объявление эквивалентно MyStruct ** в коде C ++. Либо удалите ссылка в объявлении или объявить его как структуру вместо класса.