Проблемы с импортом Win32 DLL (DllMain)

У меня есть собственная DLL, которая является подключаемым модулем для другого приложения (которое я практически не контролирую). Все работает просто отлично, пока я не свяжу дополнительный файл .lib (связывает мою DLL с другой DLL с именем ABQSMABasCoreUtils.dll). Этот файл содержит некоторые дополнительные API из родительского приложения, которые я хотел бы использовать. Я даже не написал никакого кода для использования какой-либо из экспортированных функций, но простое связывание этой новой DLL вызывает проблемы. В частности, я получаю следующую ошибку при попытке запустить программу:

Не удалось правильно инициализировать приложение (0xc0000025). Нажмите OK, чтобы закрыть приложение.

Кажется, я где-то читал, что это обычно происходит из-за того, что функция DllMain возвращает FALSE. Кроме того, в стандартный вывод записывается следующее сообщение:

ОШИБКА: попытка выделения памяти перед инициализацией компонента

Я почти на 100% уверен, что это сообщение об ошибке исходит от приложения и не является какой-либо ошибкой Windows.

Изучив это немного подробнее (т. е. переворачивая все известные мне переключатели), я связался с включенным /MAP и нашел это в результирующем файле .map:

 0001:000af220       ??3@YAXPEAX@Z              00000001800b0220 f   ABQSMABasCoreUtils_import:ABQSMABasCoreUtils.dll
 0001:000af226       ??2@YAPEAX_K@Z             00000001800b0226 f   ABQSMABasCoreUtils_import:ABQSMABasCoreUtils.dll
 0001:000af22c       ??_U@YAPEAX_K@Z            00000001800b022c f   ABQSMABasCoreUtils_import:ABQSMABasCoreUtils.dll
 0001:000af232       ??_V@YAXPEAX@Z             00000001800b0232 f   ABQSMABasCoreUtils_import:ABQSMABasCoreUtils.dll

Если я уберу эти имена с помощью «undname», они дадут следующее (тот же порядок):

void __cdecl operator delete(void * __ptr64)
void * __ptr64 __cdecl operator new(unsigned __int64)
void * __ptr64 __cdecl operator new[](unsigned __int64)
void __cdecl operator delete[](void * __ptr64)

Я не уверен, что понимаю, как что-то из ABQSMABasCoreUtils.dll может существовать в этом файле .map или почему моя DLL даже пытается загрузить ABQSMABasCoreUtils.dll, если у меня нет кода, который ссылается на эту DLL. Может ли кто-нибудь помочь мне собрать эту информацию и выяснить, почему это не работает? Что бы это ни стоило, я подтвердил через «dumpbin», что родительское приложение импортирует ABQSMABasCoreUtils.dll, поэтому оно загружается, несмотря ни на что. Я также пытался отложить загрузку этой DLL в свою DLL, но это не изменило результатов.

ИЗМЕНИТЬ

Я дважды проверил, и все задействованные файлы 64-битные.


person brady    schedule 27.05.2010    source источник
comment
Вы пытались использовать LoadLibrary вместо статической привязки библиотеки импорта? Если вы сделаете это, ваше основное приложение уже инициализировано, и у вас будет некоторое преимущество.   -  person Oleg    schedule 28.05.2010
comment
Я думал об этом, но в конечном итоге я буду использовать большое количество функций из этой библиотеки. Разве мне не придется использовать GetProcAddress для каждого из них? Я бы предпочел избежать этого, если это возможно.   -  person brady    schedule 28.05.2010
comment
C0000025 = СТАТУС_НЕПРОДОЛЖАЕМОЕ_ИСКЛЮЧЕНИЕ. Попробуйте запустить приложение в Windbg и посмотрите, где оно вылетает; может быть, это даст вам подсказку.   -  person Luke    schedule 28.05.2010


Ответы (4)


У меня была точно такая же проблема. Это проблема с API Abaqus, а не с загрузкой DLLS.

Я думаю, это потому, что API Abaqus переопределяет функции создания и удаления (как вы, кажется, заметили). Если вы вызываете new или delete в своей программе до инициализации Abaqus API, например, вызывая odb_initializeAPI();, вы получаете

ОШИБКА: попытка выделения памяти перед инициализацией компонента

сообщение об ошибке и программа вылетает.

В моей программе вызов odb_initializeAPI(); до первого new решил проблему.

person David Dibben    schedule 12.11.2010
comment
Прошло некоторое время с тех пор, как я исправил это, но у меня была немного другая проблема. На самом деле я обращался к ODB в пользовательской подпрограмме, поэтому я использовал getActiveOdb(). Я получал эту ошибку, потому что я компилировал с зависимостью от msvcr90.dll, а Abaqus использовал msvcr80.dll. Но я рад, что вы опубликовали это выше - трудно найти быструю помощь в Интернете для пользовательских подпрограмм и постпроцессоров Abaqus. - person brady; 14.11.2010
comment
@brady Как вы определили и устранили проблему с зависимостями? Я считаю, что msvcr100.dll конфликтует с msvcr80.dll в моей программе. Я был бы очень признателен за помощь в этом. - person Derek; 10.09.2012
comment
Я не помню, как я это определил - я, вероятно, использовал утилиту dumpbin /imports и заметил избыточные библиотеки времени выполнения C++. Чтобы решить эту проблему, мне пришлось собрать Visual C++ 8.0 (Visual Studio 2005), который был поддерживаемым компилятором C++ для этой версии Abaqus. Вы можете просмотреть поддерживаемые компиляторы здесь: Системные требования Abaqus. Выберите подходящую версию и нажмите «Системные требования», выберите свою платформу и найдите требования к компилятору C++. - person brady; 11.09.2012
comment
@brady Я использую Visual Studio 2010. Я установил небольшую утилиту под названием Daffodil, которая позволяет вам ссылаться на более старые версии библиотек CRT (VS 2010 поддерживает собственный многоцелевой таргетинг). Я запустил Dependency Walker, и единственная включенная библиотека CRT — это v80 (msvcr80.dll). Я думал, что это решит мою проблему, но я все еще не могу запустить программу. Трассировка стека от отладчика показывает, что программа аварийно завершает работу внутри Abaqus DLL. - person Derek; 11.09.2012
comment
@ Дерек, может быть, он падает по другой причине. Дает ли функция, в которой происходит сбой, какие-либо подсказки? Вы обращаетесь к ODB из пользовательской подпрограммы или создаете свой собственный исполняемый файл постобработки? Если второе, я бы рекомендовал вам использовать утилиту abaqus make. Кроме того, от кого-то, кто много работал с Abaqus (пользовательские подпрограммы, исполняемые файлы, Python и т. д.) в Windows и Linux, рекомендуется использовать поддерживаемые компиляторы, если это вообще возможно. Тем более, что ваша сборка становится все более сложной и зависит от большего количества библиотек и т. д. - person brady; 13.09.2012
comment
@brady Большое спасибо за все ваши комментарии. У нас есть другой интерфейс ODB, который использует неподдерживаемый компилятор, что меня смущает, но это не относится к делу. Наконец-то я понял, что у нас есть статический фабричный объект, который динамически выделяется до того, как запустится что-либо в основном файле. Я пытался узнать, как это работает. Я сделал ошибку, думая, что перед первой строкой основного файла ничего не будет выделено. Теперь мне нужно выяснить, как инициализировать API перед этим статическим объектом. - person Derek; 13.09.2012
comment
Я исправил свою проблему! См. stackoverflow.com/questions/ 12408787/ для получения подробной информации. - person Derek; 14.09.2012

Ну, конечно, вы будете ссылаться на импорт этой библиотеки. Трудно написать программу на C++ без использования оператора new или delete. Иметь дело со сторонним программным обеспечением, которое считает, что ему необходимо переопределить версию CRT этих операторов, достаточно сложно, невозможно, когда оно не позволит вам вызывать их, пока не решит, что пришло время. Откажитесь от всякой надежды или обратитесь за помощью к продавцу.

person Hans Passant    schedule 27.05.2010
comment
Часто ли большие программы на C++ переопределяют такие распространенные операторы? Это кажется довольно глупым. Можно ли обойти это с помощью /DEFAULTLIB? - person brady; 28.05.2010
comment
Это распространено только в глупых программах и библиотеках классов в стиле фундамента, которые рассчитывают на то, что весь код будет связан с ними. Вы не можете обойти это. Взлом .lib принесет только горе, когда какой-то код использует распределитель, а другой нет. Это автоматическая утечка памяти или AV. - person Hans Passant; 28.05.2010

Одна из возможных причин ошибки при загрузке ABQSMABasCoreUtils.dll заключается в том, что не удалось найти какой-либо модуль зависимостей (включая библиотеки DLL с отложенной загрузкой). Используйте Dependency Walker (см. http://www.dependencywalker.com/) для проверки всех зависимостей ABQSMABasCoreUtils.dll.

У меня есть два предложения:

  1. Убедитесь, что вы можете загрузить ABQSMABasCoreUtils.dll относительно LoadLibrary. Вам не нужно вызывать какую-либо функцию из ABQSMABasCoreUtils.dll. Использование LoadLibrary я не вижу в качестве конечного решения. Это всего лишь диагностический тест. С помощью теста вы можете убедиться, что у вас есть какая-то общая проблема с загрузкой ABQSMABasCoreUtils.dll в вашу программу или у вас есть какая-то проблема с инициализацией процесса.
  2. Если загрузка ABQSMABasCoreUtils.dll относительно LoadLibrary не удалась, используйте функцию профилирования Dependency Walker для протоколирования всех вызовов, выполненных во время загрузки ABQSMABasCoreUtils.dll. Еще одним способом может быть использование Process Monitor (см. http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx), чтобы проследить, какие операции с файлами и реестром будут выполняться во время загрузки ABQSMABasCoreUtils.dll.

Если LoadLibrary не сбой, то у вас действительно проблема с инициализацией DLL. Обычно проблема возникает, если DLL внутри DllMain пытается использовать функцию из другой DLL, которая еще не инициализирована (еще не возвращается из DllMain). Прежде чем приступать к диагностике этой проблемы, надо попробовать исключить более простые проблемы с LoadLibrary.

person Oleg    schedule 28.05.2010

Похоже, что ABQSMABasCoreUtils.dll импортирует 64-битные функции. Ваша dll тоже 64-битная? Если нет, то проблема в том, что нельзя смешивать библиотеки DLL, скомпилированные для разных архитектур, в одном процессе.

person mdma    schedule 27.05.2010
comment
Если бы это было так, код не смог бы скомпилироваться, а не во время выполнения. - person Billy ONeal; 28.05.2010