[英]Delphi XE8 gracefully handle ETetheringException at application startup
[英]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的简明方法。 您可以使用LoadLibrary
和GetProcAddress
手动执行相同的操作。
LoadLibrary
以加载DLL。 提供DLL的完整路径,或仅提供其名称。 在后一种情况下,您依靠DLL搜索顺序来定位DLL。 对LoadLibrary
的调用产生了一个模块句柄。 GetProcAddress
以获取指定函数指针的地址。 您必须从步骤1提供模块句柄。 FreeLibrary
卸载DLL。 在每个步骤中,必须在出现错误时检查函数返回值。 如何处理错误,请记录MSDN文档中的每个Win32 API函数(如上所述)。 例如,如果找不到DLL,则LoadLibrary
返回0
。 您必须检测到并相应地处理后果。
讨论
虽然delayed
指令非常方便,但我个人从未使用它。 根据我的经验,每当我需要明确链接时,我总是发现我需要一些delayed
不提供的额外灵活性。 也许我的需求很特殊,但如果你发现自己倾向于显式调用LoadLibrary
和GetProcAddress
,也不要感到惊讶。
作为一个例子,就在今天我发现自己使用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和函数,然后处理错误。
使用延迟的另一个好处是SetDliNotifyHook2
和SetDliFailureHook2
函数允许您分配挂钩,以便分别处理运行时加载通知和失败。
因此,如果在运行时未找到给定的DLL或甚至给定的函数,则可以记录错误,甚至将其替换为另一个DLL句柄或函数指针以满足负载。
在仅在需要时使用DLL的另一个问题中更详细地讨论了这两个选项。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.