有人知道在Delphi应用程序中是否可以优雅地测试和处理丢失的.dll文件吗?例如,我的代码有以下函数声明:
function KFUNC(Arg1, Arg2, Arg3, Arg4: DWord): longint stdcall; external 'KL2DLL32.DLL' name '_KFUNC@16';当然,...which需要在系统上找到dll文件KL2DLL32.DLL,否则我的应用程序将无法启动。我想知道是否有不同的方式来编写这个代码,这样我的应用程序就可以测试dll文件的存在,然后进行相应的处理。显然,目标是即使dll文件不存在,我的应用程序仍然可以正常启动。谢谢。
发布于 2015-09-28 16:39:17
导入将导致使用所谓的加载时间或隐式链接链接函数。也就是说,可执行文件包含元数据,它告诉OS加载程序加载DLL,然后绑定到您命名的函数。如果此加载时间链接过程失败,则无法加载可执行文件.
您有几种避免加载时间链接的选项,从而允许您的程序对链接失败具有弹性。
延迟加载DLL
将delayed指令添加到函数导入中。文件上说:
若要将包含函数的库的加载推迟到函数实际需要的时刻,请将延迟指令附加到导入的函数中: 函数ExternalMethod(const SomeString: PChar):整数;stdcall;外部'cstyle.dll‘延迟; 延迟确保包含导入函数的库不会在应用程序启动时加载,而是在第一次调用函数时加载。
这些文档包含其他有用的主题,这些主题将详细介绍如何处理错误:
显式加载和绑定到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时,这种细粒度控件是不可用的。
发布于 2015-09-28 16:39:01
当函数被这样声明时,您的程序无法处理缺少的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句柄或函数指针替换它以满足负载。
这两个选项将在another question centering on using a DLL only when required中进行更详细的讨论。
https://stackoverflow.com/questions/32827728
复制相似问题