【问题标题】:How to prevent 'The code execution cannot proceed because xxx.dll was not found' error if DLL is not present如果 DLL 不存在,如何防止“代码执行无法继续,因为找不到 xxx.dll”错误
【发布时间】:2019-07-24 18:34:53
【问题描述】:

我们在 Delphi 10 中开发了一个 DLL,我们在一些旧版 Delphi 6 应用程序中使用它。 DLL 中的新功能仅适用于少数客户,因此不需要推广到我们的所有客户。如果我们尝试在没有 DLL 的情况下部署 Delphi 6 应用程序,我们会收到错误“代码执行无法继续,因为找不到 xxx.dll。”。我们在应用程序开始运行的那一刻得到错误。如果 DLL 不存在,有没有办法防止这个错误?在我们的 Delphi 6 代码中,我们已经使用 FileExists(xxx.dll) 来查看是否应该使 DLL 中的功能可用,因此如果 dll 不存在,我们没有应用程序崩溃的风险。

我们也很想知道 Delphi 6 应用程序在何处/何时检查 DLL 是否存在,因为它发生在 Application.Initialize 之前,这是 DPR 文件中的第一行代码。

【问题讨论】:

    标签: delphi dll


    【解决方案1】:

    这种类型的故障是由statically(又名:隐式)链接 DLL 引起的。如果您选择使用静态链接,则没有选项 - DLL必须存在于尝试运行应用程序的系统上。

    有两种方法可以选择显示 DLL。

    一种方法是重写受影响的代码部分,以将dynamic linking(又名:explicit)用于您的 DLL,而不是静态链接。对于 Delphi 6,很遗憾,这是您的唯一选择

    另一个选项,如果您仅针对 Windows并且如果您使用 Delphi 2010 或更高版本进行编译,则可以通过使用 delayed 指令装饰您的导入声明来使用延迟加载:

     function GetSomething: Integer; external 'somelibrary.dll' delayed;
    

    这实际上只是在动态加载之上的语法糖,但它确实提供了一种更简单的途径,可以将静态链接代码迁移到动态链接模型,而无需大量重写。

    From Embarcadero

    延迟指令在运行应用程序的目标操作系统上不存在导入的例程的情况下很有用。静态导入的例程要求操作系统在应用程序启动时查找并加载库。如果在加载的库中找不到该例程,或者该库不存在,则操作系统会暂停应用程序的执行。使用延迟指令使您能够在运行时检查操作系统是否支持所需的 API;只有这样你才能调用导入的例程。

    注意:尝试调用无法解决的延迟例程会导致运行时错误(或异常,如果加载了 SysUtils 单元)。

    无论是延迟加载还是动态加载,您都需要捕获解析 DLL 的失败并优雅地拒绝用户访问 DLL 提供的任何功能。

    【讨论】:

    • 请注意,delayed 关键字在内部使用“动态链接”,RTL 提供了notifyfailure 挂钩,因此用户代码可以在运行时对delayed 操作/失败做出反应。
    • @RemyLebeau 是的,确实。我已经扩展了一点以澄清这一点。
    • Allen tells " ..(导入)在已发布的 PE 规范之后生成到“延迟导入”部分。”。我从中了解到,这种机制不仅仅是语法糖,而且如果 dll 可以在启动时绑定,则可能根本不需要调用 GetProcAddress,如 MSVC 链接器documentation 中所述。当然,我理解的可能是错误的。
    • @SertacAkyuz 那篇文章的另一行:This is different than similar functionality available in ILink32 from C++Builder wherein you can only specify an entire dll in which all references are delay loaded. 这听起来更像是你在 MSVC 文档中所说的——绑定整个 DLL 而不是只挑选导入我们需要(这是你可以用delayed; 指令做的所有事情)。它应该很容易检查 - 我希望我们应该能够在堆栈跟踪中找到 GetProcAddress 如果它被调用。明天可以这样做......
    • 也许你是对的。我试图测试...在没有“delayhlp.cpp”的情况下,我在 kernel32 中的 GetProcAddress 上放置了一个断点。它被多次击中,但您可以在其中几个的跟踪中看到“__delayLoadHelper”。后来我尝试使用 MS 的“bind.exe”,稍后在我链接的文章的 cmets 中提到。在调试器可以创建进程之前,这使得可执行文件无法使用,立即 AV。
    猜你喜欢
    • 2023-03-08
    • 2020-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多