繁体   English   中英

可以在Delphi应用程序中优雅地处理丢失的dll文件?

[英]possible to handle missing dll file gracefully in Delphi application?

任何人都知道是否可以在Delphi应用程序中优雅地测试和处理丢失的.dll文件? 例如,我的代码有这个函数声明:

function KFUNC(Arg1, Arg2, Arg3, Arg4: DWord): longint stdcall; external 'KL2DLL32.DLL' name '_KFUNC@16';

...当然需要在系统上找到dll文件KL2DLL32.DLL,否则我的应用程序将无法启动。 我想知道是否有一些不同的方式来编码这个,所以我的应用程序可以测试dll文件的存在,然后相应地处理。 显然,目标是让我的应用程序仍然正常启动,即使dll文件不存在。 谢谢。

导入导致使用所谓的加载时或隐式链接链接的函数。 这是可执行文件包含元数据,告诉OS加载程序加载DLL,然后绑定到您命名的函数。 如果此加载时链接过程失败,则无法加载可执行文件。

您有两个选项可以避免加载时链接,从而使您的程序能够适应链接故障。

延迟加载DLL

delayed指令添加到函数导入中。 文件说:

要将包含该函数的库的加载推迟到实际需要该函数的时刻,请将延迟指令附加到导入的函数:

 function ExternalMethod(const SomeString: PChar): Integer; stdcall; external 'cstyle.dll' delayed; 

delay确保在应用程序启动时不加载包含导入函数的库,而是在第一次调用函数时加载。

该文档包含更详细的其他有用主题,并介绍了如何处理错误:

显式加载和绑定到DLL

delayed指令只是让编译器安排显式加载DLL的简明方法。 您可以使用LoadLibraryGetProcAddress手动执行相同的操作。

  1. 调用LoadLibrary以加载DLL。 提供DLL的完整路径,或仅提供其名称。 在后一种情况下,您依靠DLL搜索顺序来定位DLL。 LoadLibrary的调用产生了一个模块句柄。
  2. 调用GetProcAddress以获取指定函数指针的地址。 您必须从步骤1提供模块句柄。
  3. 调用从步骤2返回的函数指针。
  4. 当您不再需要调用该函数时,请使用FreeLibrary卸载DLL。

在每个步骤中,必须在出现错误时检查函数返回值。 如何处理错误,请记录MSDN文档中的每个Win32 API函数(如上所述)。 例如,如果找不到DLL,则LoadLibrary返回0 您必须检测到并相应地处理后果。

讨论

虽然delayed指令非常方便,但我个人从未使用它。 根据我的经验,每当我需要明确链接时,我总是发现我需要一些delayed不提供的额外灵活性。 也许我的需求很特殊,但如果你发现自己倾向于显式调用LoadLibraryGetProcAddress ,也不要感到惊讶。

作为一个例子,就在今天我发现自己使用LoadLibraryEx因为我想传递LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR标志。 当您使用delayed时,这种细粒度控制不可用。

当声明这样的函数时,你的程序对丢失的DLL没有任何作用。 操作系统尝试在程序代码的任何位开始执行之前解析导入的DLL函数,因此没有可编写的代码可以对其执行任何操作。

但是,从Delphi 2010开始,您可以更改函数的声明以使用新的延迟加载功能。 delayed指令添加到声明的末尾:

function KFUNC(Arg1, Arg2, Arg3, Arg4: DWord): longint stdcall;
  external 'KL2DLL32.DLL' name '_KFUNC@16' delayed;

如果您使用的是较旧的Delphi版本,那么您唯一的选择是在运行时加载DLL和函数,然后处理错误。

使用延迟的另一个好处是SetDliNotifyHook2SetDliFailureHook2函数允许您分配挂钩,以便分别处理运行时加载通知和失败。
因此,如果在运行时未找到给定的DLL或甚至给定的函数,则可以记录错误,甚至将其替换为另一个DLL句柄或函数指针以满足负载。

仅在需要时使用DLL的另一个问题中更详细地讨论了这两个选项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM