-
-
[旧帖]
[原创]DllMain函数必定是DLL被加载后第一个被调用的函数吗?
0.00雪花
-
发表于:
2010-10-8 15:50
2439
-
[旧帖] [原创]DllMain函数必定是DLL被加载后第一个被调用的函数吗?
0.00雪花
我们知道一个动态链接库一般由一个DllMain函数和若干导出函数组成。
比如对于Demo.DLL,含有DllMain以及导出函数FunctionA。当某个EXE使用该DLL时通常有两种方法,静态链接和动态链接。
1)静态链接
需要.H和.LIB文件,访问时直接调用导出函数即可。DLL会随着EXE的加载而同时加载。
2)动态链接
通过LoadLibrary和GetProcAddess,访问导出函数。
这时我们会问,两种方式下DllMain是在什么时机点被调用呢?
答案也很好分析及证实,如下:
1)静态链接
Demo.DLL的DllMain调用时机在EXE的入口函数《WinMain》之前被调用。
2)动态链接
Demo.DLL的DllMain调用时机在EXE的代码《LoadLibrary("Demo.DLL")》期间被调用。
到此为止,我们发现DllMain函数总是在导出函数被调用之前,就已经执行完毕。但是事实上有没有在一种情况下,导出函数调用时机比DllMain函数的调用时机还要早呢?
答案是肯定的,在某种特定的条件下,完全可以做到这种调用顺序。
举例如下:
1)存在EXE【Demo.EXE】以及两个DLL【DemoA.DLL】【DemoB.DLL】。
2)Demo.EXE静态链接这两个DLL,同时假定静态链接两个DLL的顺序为DemoA->DemoB。
3)DemoA中的DllMain中执行如下代码:
LoadLibrary("DemoB"), GetProcAddess("DemoBFunctionB"),调用DemoBFunctionB。
这时会发现DemoB.DLL的导出函数的调用时机早于其DllMain函数的调用。
由此可以得出像以下的DLL设计构架是不一定能保证其正确性的。(在这摔过跟头,因此记忆犹新TAT)
//全局数据
DLLMain()
{
//初始化全局数据
}
FunctionA()
{
//使用全局数据
}
最后我们来分析一下其原因,这得从
DLL的静态链接和动态链接的执行顺序来说起。
1)静态链接
EXE会按照链接顺序,依次加载各个DLL到内存中,然后再依次调用各个DLL的DllMain函数。在DLL被加载到内存之后,其后面的LoadLibrary仅仅是增加该DLL的引用计数而已。
2)动态链接
EXE会按照编码顺序,依次加载各个DLL到内存中,并且在各DLL加载期间调用其DllMain函数。
这样由于Windows对于静态链接和动态链接的处理方式不同而引起的。至于为什么微软不设计成静态链接的情况下也在DLL被加载到内存之后,立即调用其DllMain函数就不得而知了。
个人觉得改善后的设计更好点,至少不会出现这种问题,或许也有我考虑不到的原因存在也说不定。
这篇文章的重点是通过问题,共享一下Windows下对于DLL的两种执行方式,
注意红字部分噢。
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!