Передача указателя на класс в неуправляемый код C ++ из C #

У меня есть экспортированная функция 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

5

Решение

В C # мы имеем classэс и structs. Все 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-битное значение для функции, которая вызывает функцию

1

Другие решения

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 ++. Либо удалите ссылка в объявлении или объявить его как структуру вместо класса.

1

По вопросам рекламы [email protected]