Я пытаюсь использовать C++ DLL (сторонняя библиотека, реализующая протокол EMI, с доступным исходным кодом) в .NET. Я успешно выполнил сортировку, вызвал функции и заставил все работать нормально.
Проблема возникает, когда я хочу выполнить сортировку из IntPtr обратно в .NET Struct, вот код (измененный, как было предложено - удалено «ref» и изменено AllocHGlobal, чтобы выделить только размер emiStruct):
private EMI emiStruct;
private IntPtr emiIntPtr;
emiIntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(emiStruct));
Marshal.StructureToPtr(emiStruct, emiIntPtr, false);
EMIStruct.Error result = emi_init(emiIntPtr, hostname, portNumber, password, shortNumber, windowSize, throughput);
Marshal.PtrToStructure(emiIntPtr, emiStruct);
Последняя строка (PtrToStructure) вызывает исключение «Попытка чтения или записи в защищенную память. Часто это указывает на то, что другая память повреждена».
Кроме того, я вижу вывод отладки:
A first chance exception of type 'System.AccessViolationException' occurred in mscorlib.dll
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0xc3fffff8.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x01fffff7.
First-chance exception at 0x7c970441 in XXXXX.exe: 0xC0000005: Access violation reading location 0x00001f1d.
Я предполагаю, что проблема где-то в выделении памяти для указателя emiIntPtr. Хотя, когда я запускаю код и возникает проблема с подключением к серверу (например, сервер не найден), последующая маршалинг в Struct emiStruct выполняется правильно (без исключений). Проблема возникает только тогда, когда соединение успешно установлено и сервер отправляет ответ.
Кроме того, я написал пример приложения на C++, используя ту же библиотеку DLL, которую я пытаюсь использовать в .NET, и это приложение (когда я его компилирую) работает нормально — это означает, что DLL C++ должна быть в порядке и не вызывать сбоев.
Кроме того, я нашел несколько подсказок, чтобы проверить / снять отметку с нескольких свойств для компилятора проекта (используя JIT, скомпилировать его для процессора x86 и т. Д.), К сожалению, ничего из этого не помогло.
Есть ли у вас какие-либо предложения, в чем может быть проблема или как правильно выполнить инициализацию IntPtr в .NET и сопоставление между IntPtr и Struct?
Спасибо всем за ваши ответы:
Здесь я добавляю заголовок C++ функции emi_init:
FUNC( init)( EMI* emi, /* out */
const char* hostname, /* in */
unsigned short port, /* in */
const char* password, /* in */
const char* origin_addr, /* in */
int window_sz, /* in */
int throughput); /* in */
А вот объявление C# emi_init (я удалил атрибут "ref" для emiPtr, как было предложено):
[System.Runtime.InteropServices.DllImport("emi.dll", EntryPoint = "_emi_init")]
public static extern EMIStruct.Error emi_init(
System.IntPtr emiPtr,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string hostname,
ushort port,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string password,
[System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] string origin_addr,
int window_sz, int throughput);
Тем не менее, все еще получаю то же исключение.