从DllMain调用LoadLibrary

Aby*_*byx 2 language-agnostic windows dll winapi loadlibrary

MSDN说:

它不能调用LoadLibrary或LoadLibraryEx函数(或调用这些函数的函数),因为这可能会在DLL加载顺序中创建依赖循环.这可能导致在系统执行其初始化代码之前使用DLL.

我试图LoadLibrary从DllMain 打来电话,什么也没发生.

我看到的唯一问题是加载的DLL将在我的DllMain执行的其余部分之前使用我的DLL中的函数.

为什么我不能在DllMain中调用LoadLibrary?

编辑:

好吧,我意识到我不能在DllMain中调用LoadLibrary只是因为我必须像其他信徒一样相信 MSDN(我在那里看到了一些错误的东西,但我也应该忘记它们).
并且因为在较新版本的Windows中可能会发生某些事情(尽管过去十年没有任何变化).

但是,任何人都可以显示一个代码,它会重现在LoadLibraryDllMain中调用时发生的事情吗?在任何现有的Windows操作系统?
不只是在另一个内部调用一个单例初始化函数,而是LoadLibrary在DllMain中?

Aar*_*otz 14

你赞成继续这样做的论点似乎是:

微软表示不这样做,但我的单个测试案例似乎有效,因此我不明白为什么没有人应该这样做.

你在一个很大的假设下运行:你假设Windows加载器的底层实现永远不会改变.如果在"Windows 8"中更改加载程序以使您的代码无法正常工作,该怎么办?现在微软因此受到指责,他们必须包含另一个兼容性黑客来解决他们告诉 不要写的代码.

遵循指南.他们并不只是为了让你的生活更加艰难,他们在那里保证你的代码在未来的Windows上和现在一样好用.


小智 13

有简单的,甚至不那么简单的情况,从DllMain调用LoadLibrary非常安全.但设计是DllMain被信任不会更改已加载模块的列表.

尽管拥有加载程序锁确实限制了DllMain中可以执行的操作,但它只与LoadLibrary规则间接相关.加载程序锁定的相关目的是序列化访问已加载模块的列表.虽然NTDLL在一个线程中在此列表上工作,但拥有加载程序锁可确保列表不会被在另一个线程中执行的NTDLL代码更改.但是,装载机锁是一个关键部分.它不会阻止同一线程重新获取加载程序锁并更改列表.

如果NTDLL在列表上工作时完全保留自己,这无关紧要.但是,NTDLL规定在此工作中涉及其他代码,如初始化新加载的DLL时.每次NTDLL在列表上工作时都会调用外部,可以选择进行设计.从广义上讲,有两种选择.一种是稳定列表并释放加载程序锁,调用外部,然后获取加载程序锁并恢复列表上的工作,就像从头开始一样,因为外部调用可能已经改变了它.另一种方法是保持加载器锁定并信任被调用的代码,不要做任何改变列表的事情.因此,LoadLibrary在DllMain中成为禁区.

并不是加载器锁做任何事情来阻止 DllMain调用LoadLibrary,甚至加载器锁本身使得这样的调用不安全.相反,通过保留加载程序锁,NTDLL 信任 DllMain不要调用LoadLibrary.

相反,请考虑关于不等待同步对象的DllMain规则.在这里,装载机锁具有直接作用,使其不安全.等待DllMain中的同步对象设置了死锁的可能性.所需要的只是另一个线程已经拥有你正在等待的对象,然后这个另一个线程调用任何等待加载器锁定的函数(例如,LoadLibrary,还有像看似无害的GetModuleHandle这样的函数).

想要延长或打破DllMain规则可能是恶作剧甚至是彻头彻尾的愚蠢.但是,我必须指出,对于那些质疑这些规则有多么强大或有意义的人来说,至少部分归咎于微软.毕竟,有些并不总是被清楚而有力地记录下来,而且当我最后看时,他们仍然没有记录在他们肯定需要的所有情况下.(我想到的例外是,至少在Visual Studio 2005之前,编写DLL的MFC程序员被告知将他们的初始化代码放在CWinApp :: InitInstance中,但没有被告知此代码受DllMain规则约束.)

此外,对于任何来自微软的人来说,好像DllMain规则应该被毫无疑问地遵循,这样做会有点富裕.微软自己的程序员违反规则,并且在违反规则后继续存在导致严重的现实问题的例子.


Mar*_*gen 9

http://msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx中所述:

DllMain中的线程保持加载程序锁定,因此不能动态加载或初始化其他DLL.

干杯

  • @Praetorian:它不会死锁.它可能会崩溃.崩溃可能会在以后发生.如果从DllMain调用LoadLibrary,则无法保证DllInitialization将以正确的顺序发生.你可能会很幸运,它会起作用.但你可能会悲惨地失败.你无法知道将会发生什么. (6认同)
  • @Abyx - 有什么意义?同一页面特别禁止从`DllMain`调用`LoadLibrary(Ex)`.应该很清楚,如果你这样做,你就是靠自己. (4认同)