Delphi DLL是否预定用于加载程序锁?

Ren*_*ann 7 delphi dll dynamic-linking

有一个DLL,由主(桌面)应用程序动态加载Windows.LoadLibrary.那是因为有很多类似的DLL,并且只需要在运行时加载很少的单个DLL.因此静态链接不是一种选择.

问题是,在加载其中一个DLL时,主应用程序每隔一段时间就会挂起.请注意,问题很可能发生在每一个问题上.可能是因为他们有很多共同的代码库.

问题似乎是装载机锁定(请参阅此SO答案).我发现了一张共同的代码,即在所使用的由所有的DLL在启动时begin...end所述的-section library-单元(即project.dpr),其中GetModuleHandleGetProcAddress使用.

我发现,这是一个完全没有DLL的东西,因为begin...endDLL的项目文件的部分实际上是库的DllMain函数,并且调用这样的函数会导致死锁(命名加载器锁).我在本微软最佳实践指南中读到了这一点.

所以我重建了我的代码,这些调用稍后在调用Windows.LoadLibrary完成后调用.

不幸的是,悬挂问题仍然存在.:-(

然后我运行调试器,逐步完成在执行一行代码之前调用的每个初始化.我确定,许多第三方代码违反了DLL初始化代码中要做什么和不做什么的指南:

  • TMS组件包
  • JEDI组件库
  • OmniThreadLibrary
  • Indy组件

所有上述动态加载其他DLL在initialization代码或请求过程指针通过GetProcAddress.我认为这些调用导致我的DLL加载时挂起.

是的,只有少数Delphi开发人员知道危险initialization吗?我该怎么办?

Dav*_*nan 7

这是一个常见的问题,我认为这对Delphi程序员来说并不特别具体.如果您有LoadLibrary在初始化部分或实际上FreeLibrary在最终部分中调用的代码,那么该代码在库中使用是不安全的.

请注意,我不熟悉您提到的所有库,并且根本不确认它们都具有initialization在库中不安全的段代码.我认为这是你需要确认的东西 - 我想坚持这个答案中的概念,而不是评论特定的Delphi库.

我会说虽然打电话给我们GetModuleHandle并且GetProcAddress很好DllMain.我这么说是因为你GetProcAddress具体提到了.通过调用GetModuleHandle,然后通过调用获取函数地址来获取模块句柄是绝对正常的GetProcAddress.因此,如果一些可疑图书馆这样做,并且不打电话LoadLibrary,那么他们可能没问题.

无论如何,根据上述附带条件,您需要安排任何DllMain违反Microsoft规定的规则的代码在安全的时间调用,而不是来自DllMain.不幸的是,这些规则充其量是模糊的.微软DllMain文档中说出以下内容:

入口点功能应该只执行简单的初始化或终止任务.它不能调用LoadLibrary或LoadLibraryEx函数(或调用这些函数的函数),因为这可能会在DLL加载顺序中创建依赖循环.这可能导致在系统执行其初始化代码之前使用DLL.类似地,入口点函数在进程终止期间不得调用FreeLibrary函数(或调用FreeLibrary的函数),因为这可能导致在系统执行其终止代码后使用DLL.

因为在调用入口点函数时保证Kernel32.dll被加载到进程地址空间中,所以在Kernel32.dll中调用函数不会导致在执行初始化代码之前使用DLL.因此,入口点函数可以调用Kernel32.dll中不加载其他DLL的函数.例如,DllMain可以创建同步对象,如关键部分和互斥体,并使用TLS.不幸的是,Kernel32.dll中没有安全功能的完整列表.

最后一段给你很少的指导.为了确保您的图书馆能够强大,您需要按照以下方针做一些事情:

  1. 安排您控制的源代码的任何单元的每个初始化部分向中央注册表注册初始化和完成过程.
  2. 在可执行项目中,您在注册时调用初始化过程,并在程序终止时以相反的顺序调用终结过程.
  3. 在库项目中,您推迟调用这些初始化和完成过程.从DLL的使用者可以调用的DLL导出一对函数,以请求调用这些初始化和终结过程.

这是我对我的图书馆采取的方法,它已经很好地服务了我很多年.

这种方法涉及相当多的工作,并且具有修改第三方库的缺点.但是,如果这些库在交付使用时无法正常工作,您还有什么选择?

也许在较慢的时间内,您可以联系任何您认为与库中使用不兼容的库的开发人员.尝试说服他们更改代码,使其与库中的使用兼容.从Remy对您的问题的评论中可以看出,图书馆开发人员可能完全没有意识到这个问题,并且非常愿意做出改变.