2009-11-13 3 views
0

При вызове неуправляемой Dll из приложения C# я получаю AccessViolationException. Странная вещь заключается в том, что экспортированная функция не имеет аргументов, поэтому проблема не в Marshalling данных. Функция не получает аргументов и возвращает целое число. Также обратите внимание, что вызов конвенции не является проблемой. Точная функция с одинаковыми нулевыми аргументами и целочисленным возвращаемым значением (но с другим именем) работает просто отлично. Каковы оставшиеся кандидатские причины, по которым такой вызов может вызвать это исключение, учитывая тот факт, что исключающее и вызывающее соглашение исключается?AccessViolation при вызове неуправляемой dll

UPDATE: Функция dll верна, потому что, если она вызвана из другого неуправляемого кода с помощью простой связи, то она отлично работает.

ОБНОВЛЕНИЕ 2: Все скомпилировано и работает на 32 бит. Я пробовал Win XP SP2 и Vista. Вот интересный факт: в Vista Systems он работает как шарм. На XP это терпит неудачу.

ОБНОВЛЕНИЕ 3: Я не получил исходный код, но я узнал, что по существу это делает dll, поэтому я попытался воспроизвести проблему с моей собственной DLL. Вот история: оригинальная dll - это своего рода оболочка для ei.lib (библиотека интерфейса Erlang's c). Он экспортирует некоторые вспомогательные функции. Поэтому, чтобы воспроизвести проблему, я создал обертку dll вокруг ei.lib, которая экспортирует только одну функцию, а именно «test()». Я сделал это, поэтому я бы не возился с сортировкой и т. Д. Я хотел просто проверить инициализацию, соединение и отправку сообщения. Таким образом, функция test() моей dll просто вызывает ei_connect_init(), затем ei_connect() и finaly ei_reg_send(), с аргументами, жестко закодированными внутри. Проблема в том, что если я вызову эту DLL и использую функцию test() из другого неуправляемого кода, она работает нормально. Сообщение отправлено. Но когда я вызываю его из C# через DllImport, он работает только на Vista. Не на XP. В XP он не работает с AccessViolationException на .net-уровне. Я попытался проследить проблему, и я вижу, что изнутри моей dll любой вызов ei_connect() или любая попытка прочитать erl_errno (они определены в ei.lib) при запуске на XP и вызваны результатом управляемого кода при попытке для чтения или записи защищенной памяти, чтобы приложение вышло из строя. Он не может быть чем-то тривиальным, поскольку он работает на Vista, и он работает при вызове неуправляемого кода.

ответ

1

OK Я думаю, что знаю проблему: ei.lib использует TLS (локальное хранилище потоков). В файле ei_pthreads.c исходного кода й интерфейса есть этот фрагмент:

#ifdef __WIN32__ 
#ifdef USE_DECLSPEC_THREAD 
/* Define (and initialize) the variable __erl_errno */ 
volatile __declspec(thread) int __erl_errno = 0; 
#else 
static volatile DWORD errno_tls_index = TLS_OUT_OF_INDEXES; 
static LONG volatile tls_init_mutex = 0; 
#endif 
#endif 

USE_DECLSPEC_THREAD Если не определен, то, ниже в исходном файле, TLS Api используется вместо этого. Теперь из MSDN я обнаружил, что:

В операционных системах Windows, перед тем Windows Vista, __declspec(thread) имеет некоторые ограничения. Если DLL объявляет любые нелокальные данные или объект как __declspec(thread), это может привести к ошибке защиты, если динамически загружен . После загрузки DLL LoadLibrary это приводит к сбою системы всякий раз, когда код ссылается на нелокальные данные __declspec(thread). Поскольку глобальная переменная пространство для нить выделяются во время выполнения, размера этого пространства на основе расчета требований применения плюс требования всех библиотек DLL, которые статически связаны между собой. Когда вы используете LoadLibrary, вы не можете расширить это пространство, чтобы разрешить объявленные локальные переменные потока с __declspec(thread). Используйте API TLS , например TlsAlloc, в вашей DLL до выделяйте TLS, если DLL может быть , загруженный с помощью LoadLibrary.

Так, так как я использую интерфейс LIBS Эрла, поставляемую с скомпилированным бинарным распределением Эрланга для окон, интересно, если они определены USE_DECLSPEC_THREAD при составлении этих бинарных файлов. Если нет, то я в тупике, и я попробую сделать что-то еще, чтобы выполнить свою работу. Если они это определяли, я должен установить cygwin и перекомпилировать источники, не определяя его. (Хлоп ...).

ОКОНЧАТЕЛЬНОЕ ОБНОВЛЕНИЕ: Действительно, это была проблема. Мне пришлось установить cygwin и скомпилировать код erl_interface снова без определения USE_DECLSPEC_TRHEAD. Также есть еще один небольшой улов при перекомпиляции, требуется крошечное изменение, так что определение _WIN32_WINNT происходит до включения winbase.h, потому что после пропуска USE_DECLSPEC_THREAD код использует SwitchToThread, который определен в winbase.h, только если определено значение _WIN32_WINNT и с значение больше 0x400.

0

Это исключение возникает, когда неуправляемый код вызывает нарушение доступа к памяти. Убедитесь, что неуправляемая функция верна. Если у вас есть источник неуправляемого кода, вы можете также отключить отладчик, чтобы войти в неуправляемый код и посмотреть, где проблема.

+0

нет, это не проблема ... См. Мое обновление :( – Paralife

+0

также, у меня нет доступа к исходному коду, я попытаюсь получить хотя бы объект с информацией об отладке и дать отладчику снимок. – Paralife

+0

Does неуправляемая библиотека имеет некоторую функцию статической инициализации, которая должна быть вызвана перед использованием? Также убедитесь, что нет 32 <-> 64-разрядного несоответствия. Если неуправляемый код 32 бит, а управляемый работает как 64, вы также можете получить это исключение –

Смежные вопросы