Отображение IntPtr в Struct через Marshal.PtrToStructure, вызывающее «Исключение нарушения доступа» - PullRequest
0 голосов
/ 23 августа 2011

Я пытаюсь использовать 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, и это приложение (когдаЯ компилирую это) работает просто отлично - это значит, что C ++ DLL должна быть в порядке и не вызывать сбоев.

Кроме того, я нашел несколько советов, чтобы проверить / снять галочку с нескольких свойств для компилятора проекта (используя 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 (IВы удалили атрибут «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);

Однако все равно получаю то же исключение.

Ответы [ 2 ]

1 голос
/ 23 августа 2011

Вы используете Marshal.PtrToStructure неправильно.

Второй аргумент требует тип, iow typeof(EMI).

Возвращаемое значение содержит результирующую структуру.

Таким образом, решение должно быть:

var s = (EMI) Marshal.PtrToStructure(emiIntPtr, typeof(EMI));
0 голосов
/ 23 августа 2011

Полагаю, вы неправильно объявили первый параметр в C #. Вы объявили его как ref IntPtr, который эквивалентен EMI ** в C ++. Но я уверен, что объявление C ++, которое вы, к сожалению, не включили, гласит: EMI *. Так что просто удалите ссылку и все должно быть хорошо.

Я ожидаю, что emi_init не читает из параметра EMI, т. Е. Имеет семантику. В этом случае вам не нужен вызов StructureToPtr перед вызовом emi_init.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...