简体   繁体   English

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

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

Anyone know if its possible to gracefully test for and handle a missing .dll file in a Delphi application? 任何人都知道是否可以在Delphi应用程序中优雅地测试和处理丢失的.dll文件? For example, my code has this function declaration: 例如,我的代码有这个函数声明:

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

...which of course requires the dll file KL2DLL32.DLL to be found on the system, otherwise my application wont start. ...当然需要在系统上找到dll文件KL2DLL32.DLL,否则我的应用程序将无法启动。 Im wondering if theres some different way to code this, so my application could test for the dll file's existence, and then handle accordingly. 我想知道是否有一些不同的方式来编码这个,所以我的应用程序可以测试dll文件的存在,然后相应地处理。 Obviously, the goal would be have my application still start normally even if the dll file isn't there. 显然,目标是让我的应用程序仍然正常启动,即使dll文件不存在。 Thanks. 谢谢。

Your import results in the function being linked using what is known as load-time or implicit linking. 导入导致使用所谓的加载时或隐式链接链接的函数。 That is the executable contains meta data that tells the OS loader to load the DLL, and then bind to the functions that you named. 这是可执行文件包含元数据,告诉OS加载程序加载DLL,然后绑定到您命名的函数。 If this load-time linking process fails, then the executable cannot be loaded. 如果此加载时链接过程失败,则无法加载可执行文件。

You have a couple of options to avoid load-time linking, and thereby allow your program to be resilient to linking failures. 您有两个选项可以避免加载时链接,从而使您的程序能够适应链接故障。

Delay-loading the DLL 延迟加载DLL

Add the delayed directive to your function import. delayed指令添加到函数导入中。 The documentation says: 文件说:

To postpone the loading of the library that contains the function to the moment the function is actually needed, append the delayed directive to the imported function: 要将包含该函数的库的加载推迟到实际需要该函数的时刻,请将延迟指令附加到导入的函数:

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

delayed ensures that the library that contains the imported function is not loaded at application startup, but rather when the first call to the function is made. delay确保在应用程序启动时不加载包含导入函数的库,而是在第一次调用函数时加载。

The documentation contains other useful topics that go into more detail, and cover how to handle errors: 该文档包含更详细的其他有用主题,并介绍了如何处理错误:

Explicit loading and binding to the DLL 显式加载和绑定到DLL

The delayed directive is merely a concise way to get the compiler to arrange explicit loading of your DLL. delayed指令只是让编译器安排显式加载DLL的简明方法。 You can do the same yourself manually using LoadLibrary and GetProcAddress . 您可以使用LoadLibraryGetProcAddress手动执行相同的操作。

  1. Call LoadLibrary to load the DLL. 调用LoadLibrary以加载DLL。 Either supply a full path to the DLL, or just its name. 提供DLL的完整路径,或仅提供其名称。 In the latter case you rely on the DLL search order to locate the DLL. 在后一种情况下,您依靠DLL搜索顺序来定位DLL。 The call to LoadLibrary yields a module handle. LoadLibrary的调用产生了一个模块句柄。
  2. Call GetProcAddress to obtain the address of a named function pointer. 调用GetProcAddress以获取指定函数指针的地址。 You must supply the module handle from step 1. 您必须从步骤1提供模块句柄。
  3. Call the function pointer returned from step 2. 调用从步骤2返回的函数指针。
  4. When you no longer need to call the function, use FreeLibrary to unload the DLL. 当您不再需要调用该函数时,请使用FreeLibrary卸载DLL。

At each step of the way you must check the function return values in case of error. 在每个步骤中,必须在出现错误时检查函数返回值。 How to handle errors is documented for each Win32 API function in the MSDN documentation (as linked to above). 如何处理错误,请记录MSDN文档中的每个Win32 API函数(如上所述)。 For example, if the DLL cannot be found, then LoadLibrary returns 0 . 例如,如果找不到DLL,则LoadLibrary返回0 You must detect that and deal with the consequences accordingly. 您必须检测到并相应地处理后果。

Discussion 讨论

Although the delayed directive is very convenient, I personally have never used it. 虽然delayed指令非常方便,但我个人从未使用它。 In my experience, whenever I have needed to link explicitly I've always found that I needed some extra flexibility that is not offered by delayed . 根据我的经验,每当我需要明确链接时,我总是发现我需要一些delayed不提供的额外灵活性。 Perhaps my needs are special, but do not be surprised if you find yourself leaning towards explicit calls to LoadLibrary and GetProcAddress . 也许我的需求很特殊,但如果你发现自己倾向于显式调用LoadLibraryGetProcAddress ,也不要感到惊讶。

As an example, just today I found myself using LoadLibraryEx because I wanted to pass the LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR flag. 作为一个例子,就在今天我发现自己使用LoadLibraryEx因为我想传递LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR标志。 That sort of fine grained control is not available when you use delayed . 当您使用delayed时,这种细粒度控制不可用。

When the function is declared like that, there's nothing your program can do about a missing DLL. 当声明这样的函数时,你的程序对丢失的DLL没有任何作用。 The OS attempts to resolve the imported DLL function before any bit of your program's code begins to execute, so there's no code you can write that would do anything about it. 操作系统尝试在程序代码的任何位开始执行之前解析导入的DLL函数,因此没有可编写的代码可以对其执行任何操作。

As of Delphi 2010, though, you can change the function's declaration to use the new delayed loading feature. 但是,从Delphi 2010开始,您可以更改函数的声明以使用新的延迟加载功能。 Add the delayed directive to the end of the declaration: delayed指令添加到声明的末尾:

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

If you're using an older Delphi version, then your only option is to load the DLL and the function at run time, and then handle the errors. 如果您使用的是较旧的Delphi版本,那么您唯一的选择是在运行时加载DLL和函数,然后处理错误。

Another benefit of using delayed is that there are SetDliNotifyHook2 and SetDliFailureHook2 functions that allow you to assign hooks so you can handle run-time load notifications and failures, respectively. 使用延迟的另一个好处是SetDliNotifyHook2SetDliFailureHook2函数允许您分配挂钩,以便分别处理运行时加载通知和失败。
So, if a given DLL, or even a given function, is not found at runtime, you can log an error, even substitute it with another DLL handle or function pointer to satisfy the load. 因此,如果在运行时未找到给定的DLL或甚至给定的函数,则可以记录错误,甚至将其替换为另一个DLL句柄或函数指针以满足负载。

Both options are discussed in more detail in another question centering on using a DLL only when required . 仅在需要时使用DLL的另一个问题中更详细地讨论了这两个选项。

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

相关问题 Delphi XE8在应用程序启动时优雅地处理ETetheringException - Delphi XE8 gracefully handle ETetheringException at application startup Delphi XE2将Application.MainForm.Handle分配给DLL中的Application.Handle - Delphi XE2 assigning Application.MainForm.Handle to Application.Handle inside a DLL "如何在不传递句柄参数的情况下使用 Delphi 在 dll 项目中获取主机应用程序句柄" - How can I get host application handle in dll project with Delphi without passing handle parameter DLL中的Ole导致Delphi应用程序错误 - Delphi Application Error with Ole in a DLL PowerBuilder应用程序调用Delphi DLL - PowerBuilder application call the Delphi DLL Delphi XE2:“项目”中缺少DLL应用程序的LIB前缀/后缀/版本设置 选项 - Delphi XE2: LIB prefix/suffix/version setting for DLL application is missing in Project | Options Delphi:什么是Application.Handle? - Delphi: What is Application.Handle? 如何在Delphi中调试DLL文件 - How to debug a DLL file in Delphi 如何创建一个独立的(没有DLL文件依赖项)C ++ Builder控制台应用程序,如Delphi应用程序? - How create an standalone (without DLL file dependencies) C++Builder console application like a Delphi application? 来自 DLL 的 Application.handle - Application.handle from DLL
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM