【问题标题】:Runtime exception when calling dll function with parameter in Inno Setup在 Inno Setup 中使用参数调用 dll 函数时出现运行时异常
【发布时间】:2009-06-05 17:19:53
【问题描述】:

我在 Inno Setup 的 DLL 中成功调用了一个函数,但是在返回时我得到一个运行时错误...异常:地址 XXXXXXX 的访问冲突。写地址XXXXXX。

函数声明为:

function CompleteInstall(szIntallPath: String) :  Integer;
external 'CompleteInstall@files:InstallHelper.dll stdcall setuponly';

又叫:

procedure CurStepChanged(CurStep: TSetupStep);
begin
   if CurStep = ssPostInstall then begin
      CompleteInstall('Parm1'); // ExpandConstant('{app}')
   end;
end;

如果我将函数更改为不带参数,则没有问题。如果我将其更改为采用单个整数参数或将其声明为函数并将函数更改为具有整数参数的 void 函数,它仍然会发生。

被调用的函数除了返回什么都不做:

__declspec(dllexport) int CompleteInstall(char* szInstallPath)
{
    //AfxMessageBox ("Got here" /*szInstallPath*/, MB_OK);
    return 1;
}

【问题讨论】:

    标签: visual-c++ inno-setup


    【解决方案1】:

    您的调用约定不匹配。要么让 DLL 函数也使用stdcall

    __declspec(dllexport) __stdcall int CompleteInstall(char* szInstallPath)
    {
        //AfxMessageBox ("Got here" /*szInstallPath*/, MB_OK);
        return 1;
    }
    

    或更改函数声明以使用cdecl 而不是stdcall

    function CompleteInstall(szIntallPath: String) : Integer;
        external 'CompleteInstall@files:InstallHelper.dll cdecl setuponly';
    

    【讨论】:

    • 这是个好主意。我在 Visual Studio 2008 中的项目设置设置为 _stdcall(C++...高级...调用约定到 __stdcall /Gz)会导致无法导入运行时错误(在 iss 脚本中使用了 stdcall)。我再次尝试,似乎在 .iss 脚本中使用 __cdecl 并且 c++ 代码是唯一有效的方法。感谢您的帮助。
    • @AlanKley,你真的不应该改变 everything 的调用约定,只需要这个函数。这就是将 __stdcall 添加到 C 端的函数声明中所做的事情。无论如何,函数的实现和调用者对调用约定的假设必须一致。
    【解决方案2】:

    尽管根据 mghie(参见 cmets),在这种情况下它不应该有什么不同,但您可能希望使用 PChar 而不是 String,因为这将更准确地等效于 C 声明 @987654323 @。

    String 是一种 Pascal 原生类型,其管理方式通常与 PChar 完全不同(尽管在 Inno 的 PascalScript 中显然没有那么多)。

    【讨论】:

    • -1,在 Inno Setup 上下文中的错误答案。请参阅 CodeDll.iss 示例,即 MessageBox() API 函数的声明。在 Inno Setup 脚本 DLL 函数声明中 do 使用 String 而不是 PChar。
    • 仅仅因为该示例使用 String 而不是 PChar 并不一定会使我的陈述出错。在调用需要字符串参数的 API 函数时,我总是在 InnoSetup 脚本中使用 PChar,并且从来没有遇到过任何问题。虽然我没有看过 CodeDll.iss 示例......奇怪......没想到它会起作用......你真的尝试过将“String”更改为“PChar”吗?
    • 抱歉,我的评论可能不够清楚。我希望 PChar 和 String 一样好用,它们应该在脚本引擎中产生相同的内部表示。但是,这个答案对 OP 没有帮助,因为如果他使用 PChar 而不是 String,他遇到的问题将以同样的方式表现出来。在 Inno Setup 脚本的上下文中,这些 等效的。这是一件奇怪的事情,但它就是这样。 OTOH,无论如何,对从 DLL 导出的函数使用真正的 String 类型是个坏主意。
    • 在仔细查看 RemObjects Pascal 脚本中的 uPSRuntime.pas 之后,我必须同意你的观点,它们并不完全等价。 CodeDll.iss 示例只是以差异无关紧要的方式使用它们(两者都被视为指向第一个字符的 const 指针),我也从未以任何其他方式使用它们。我认为只有在不同的模块中发生字符串的分配和重新/释放时,差异才会有意义。对于在 DLL 中长度没有改变的变量,这无关紧要。你用过这样的DLL函数吗?
    • 只要字符串的长度没有改变,String 和 PChar 都被视为指向以空字符结尾的字符串中的第一个字符的指针。只要这是可写内存,就可以更改内容。对 DLL 参数使用 String 是一个坏主意,因为这样 DLL 和主机应用程序都需要使用相同的内存管理器。如果参数是 PChars,则可以将它们声明为字符串并将其读取。写给他们(作为字符串)会导致崩溃。在 PS 内部可能总是会改变长度,所以它们确实应该是 String,而不是 PChar。有关详细信息,请参阅 uPSRuntime.pas 中的源代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多