【问题标题】:Problem with importing DLL into Inno-Setup将 DLL 导入 Inno-Setup 的问题
【发布时间】:2011-04-02 18:34:51
【问题描述】:

我在 innosetup 安装脚本中导入 C++ DLL。 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。我尝试了各种调用约定,但总是失败。 如果它有任何重要性,我正在运行带有 UAC 的 Win7 x64(安装程序请求权限提升并在此之后崩溃)。

确切的信息是:
错误
运行时错误(在 -1:0):
无法导入
dll:C:\Users\Nevod\AppData\Local\Temp\is-6LOEC.tmp\MyDll.dll

dll 在那里。

谢谢!

【问题讨论】:

  • 不要让我们猜测运行时错误消息。
  • 确切消息是:Error Runtime error (at -1:0): Cannot import dll:C:\Users\Nevod\AppData\Local\Temp\is-6LOEC.tmp\MyDll.dll dll在那里。
  • 而且你导入的函数实际上也导出了?

标签: c++ dll dllimport inno-setup


【解决方案1】:

为了在 InnoSetup 的 [代码] 部分中使用 DLL,请确保:

  • DLL 处于 32 位模式(即使安装程序是为 64 位构建并在 64 位模式下运行)
  • 导出的函数有 extern "C" __declspec( dllexport ) 修饰符
  • 使用 cdecl 调用约定,因为 stdcall 会破坏名称 (http://msdn.microsoft.com/en-us/library/zxk0tw93.aspx)。当然可以在 InnoSetup 导入语句中指定重整名称。但是使用 cdecl 似乎更容易

【讨论】:

  • “使用 cdecl 调用约定,因为 stdcall 会破坏名称”,请您详细说明一下吗?
  • 我不知道为什么,也没有时间玩它,但由于某些原因,使用 stdcall 编译的 DLL 导出的名称如下:_function@8 同时编译相同的 DLL只需将项目的整体调用约定更改为 cdecl,将导出的名称更改为function。我用VS2010做了测试
  • 你遇到过所谓的名字修改,但我猜这不是建议你所做的事情的理由。我相信你可以stop VS to do that
  • 您提供的链接解释了如何在客户端中使用它,而不是如何阻止它。我在其中挖掘了一点,发现这是 __stdcall 的正常行为:msdn.microsoft.com/en-us/library/zxk0tw93.aspx 当然可以在 InnoSetup 导入语句中指定损坏的名称。但是使用 cdecl 似乎更容易
  • 你说得对,我认为这更容易(仍然可以提及你为什么建议这样做)。
【解决方案2】:

(我知道它很旧,但也许其他一些也很受欢迎)

很可能函数的名称在 C++ DLL 中被破坏了。我有同样的问题,我能够通过重新编译dll来解决它。简而言之:

如果你从 C++ 导出类似的东西:

void __stdcall foo() 

你会得到一个名为(Visual Studio)的函数:

?foo@@YGXXZ

为防止名称混淆,您应该使用 export "C" 指令。示例(Visual Studio)

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

但是我发现 Visual Studio 会继续出错,你会得到类似的结果:

_foo@0

这里解释了我能够获得干净名称的唯一方法: C++ DLL Export: Decorated/Mangled names

罪魁祸首确实是__stdcall。如果您将其从声明中删除:

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

您将再次获得干净的导出,即使没有 DEF 文件。 IMO 这应该足够好了,因为上面的代码声明了一个“C”导出函数,并且 C 的默认调用约定是 stdcall。但是我没有时间和精力来验证这一点,因为添加 DEF 文件比导航 asm 代码和检查堆栈指针要容易得多:)

【讨论】:

  • 你是个救命稻草,我从没想过 stdcall 是问题所在。
【解决方案3】:

MyDll.dll 是 32 位的吗?

MyDll.dll 是否依赖于同一目录中的任何其他 DLL?如果是这样,您需要在“MyDll.dll”之后列出这些 DLL 的名称,以确保在加载 MyDll.dll 之前提取它们,并且您可能需要“loadwithalteredsearchpath”选项也是。来自help 的示例:

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

【讨论】:

    猜你喜欢
    • 2016-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多