Проблема с импортом DLL в Inno-Setup

Я импортирую C ++ DLL в сценарий установки innosetup. Код DLL выглядит следующим образом:

void __stdcall SetFbParam(char *dbFileName,char *dbTableName,char *dbParamName,char *dbParamValue){
//of no use here and doesn't change anything}

В Innosetup я импортирую его, используя

procedure FBset(dbFileName,dbTableName,dbParamName,dbParamValue: String;);

external 'SetFbParam@files:MyDll.dll stdcall setuponly';

Однако при запуске установщика я всегда получаю сообщение об ошибке выполнения, в котором говорится, что он не может импортировать мою dll. Я пробовал это с различными соглашениями о вызовах, но это всегда терпит неудачу. Если это важно, я запускаю Win7 x64 с включенным UAC (установщик запрашивает повышение прав и после этого вылетает).

Точное сообщение:
Ошибка
Ошибка выполнения (при -1: 0):
Невозможно импортировать
dll: C: \ Users \ Nevod \ AppData \ Local \ Temp \ is-6LOEC.tmp \ MyDll.dll

DLL есть.

Спасибо!


person nnevod    schedule 23.08.2010    source источник
comment
Не заставляйте нас угадывать сообщение об ошибке во время выполнения.   -  person Hans Passant    schedule 23.08.2010
comment
Точное сообщение: Ошибка Ошибка выполнения (при -1: 0): Невозможно импортировать dll: C: \ Users \ Nevod \ AppData \ Local \ Temp \ is-6LOEC.tmp \ MyDll.dll DLL есть.   -  person nnevod    schedule 23.08.2010
comment
И функция, которую вы импортируете, тоже экспортируется?   -  person deemok    schedule 27.08.2010


Ответы (3)


MyDll.dll 32-битная?

Зависит ли MyDll.dll от других библиотек DLL в том же каталоге? Если это так, вам необходимо указать имена этих DLL после «MyDll.dll», чтобы убедиться, что они извлечены до загрузки MyDll.dll, и вам, вероятно, понадобится опция «loadwithalteredsearchpath» также. Пример из справки:

procedure ADllFunc(hWnd: Integer; lpText, lpCaption: String; uType: Cardinal);
external 'ADllFunc@files:A.dll,B.dll stdcall loadwithalteredsearchpath'; //A.dll depends on B.dll
person Jordan Russell    schedule 27.08.2010

(Я знаю, что он старый, но, возможно, и этот)

Скорее всего, имя функции искажено в C ++ DLL. У меня была такая же проблема, и я смог решить ее, перекомпилировав dll. Короче:

Если вы экспортируете из C ++ что-то вроде:

void __stdcall foo() 

вы получите функцию с именем (Visual Studio):

?foo@@YGXXZ

Чтобы предотвратить искажение имени, вы должны использовать директиву экспорта "C". Пример (Visual Studio)

extern "C" __declspec( dllexport ) void __stdcall foo()

Однако я обнаружил, что Visual Studio продолжит искажать, и вы получите что-то вроде:

_foo@0

Здесь объясняется единственный способ получить чистые имена: Экспорт C ++ DLL: Decorated / Искаженные имена

И виноват действительно __stdcall. Если вы удалите это из своей декларации:

extern "C" __declspec( dllexport ) void foo()

вы снова получите чистый экспорт, даже без файла DEF. ИМО, этого должно быть достаточно, поскольку приведенный выше код объявляет экспортируемую функцию "C", а соглашение о вызовах по умолчанию для C - stdcall. Однако у меня не было времени и желания проверить это, поскольку добавить файл DEF намного проще, чем перемещаться по asm-коду и проверять указатели стека :)

person Yalos    schedule 14.11.2013
comment
Вы спасаете жизнь, я бы никогда не подумал, что проблема в stdcall. - person caesay; 14.05.2016

Чтобы использовать библиотеки DLL в разделе [Код] InnoSetup, убедитесь, что:

  • DLL находится в 32-битном режиме (даже если установщик построен для 64-битной версии и работает в 64-битном режиме)
  • экспортируемые функции имеют модификатор extern "C" __declspec( dllexport )
  • используйте соглашение о вызовах cdecl, потому что stdcall искажает имя (http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx). Конечно, можно указать искаженное имя в операторе импорта InnoSetup. Но кажется проще просто использовать cdecl
person rkudinov    schedule 13.03.2015
comment
Используйте соглашение о вызовах cdecl, потому что stdcall искажает имя, не могли бы вы уточнить это, пожалуйста? - person TLama; 14.03.2015
comment
Я не уверен, почему, и у меня не было времени поиграть с этим, но по некоторым причинам DLL, скомпилированная с помощью stdcall, экспортировала имя примерно так: _function@8 при компиляции той же DLL просто изменилось общее соглашение о вызовах проект на cdecl изменил экспортируемое имя на function. Провел тесты с VS2010 - person rkudinov; 15.03.2015
comment
Вы встречали так называемое искажение имен, но я думаю, это не повод предполагать, что вы сделали. Я считаю, что вы можете stop VS to do that. - person TLama; 15.03.2015
comment
Ссылка, которую вы предоставили, объясняет, как жить с этим в клиенте, а не как это остановить. Я немного покопался в этом и обнаружил, что это нормальное поведение для __stdcall: msdn.microsoft.com/en-us/library/zxk0tw93.aspx Конечно, можно указать искаженное имя в операторе импорта InnoSetup. Но кажется проще просто использовать cdecl - person rkudinov; 16.03.2015
comment
Вы правы, я подумал, что это проще (все же неплохо было бы упомянуть, почему вы это предлагаете). - person TLama; 17.03.2015