您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
DLL入口点函数DllMain
 
作者:shentao17792 来源:blog.csdn.net 发布于:2016-12-9
  734  次浏览      20
 

每个DLL都可以有一个入口点函数DllMain,系统会在不同的时刻调用此函数。以下是DllMain的一般形式:

BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;

case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;

case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;

case DLL_PROCESS_DETACH:
// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}

以上代码摘自MSDN,几乎所有的DllMain都以这种形式呈现。

先来看一下这个函数传递进来的参数:

1、 HINSTANCE hinstDLL

这个参数是该DLL实例的句柄,也就是此DLL映射到进程地址空间后,在该进程地址空间中的位置。

2、 DWORD fdwReason

此参数标示了调用DllMain函数的原因。有四种值,就是函数中case后的取值。各个取值的含义,稍后论述。

3、 LPVOID lpReserved

保留。

现在我们来讨论一下fdwReason的四种取值,这些取值,也直接反映了操作系统会在何种情况下调用DllMain。

1、DLL_PROCESS_ATTACH

当系统第一次将一个DLL映射到进程地址空间中时,会调用DllMain,并为fdwReason传入DLL_PROCESS_ATTACH。

注意,只有在第一次映射的时候,才会这样。如之后,另一线程再次显式加载此DLL,则操作系统只是增加该DLL的使用计数,而不会再次使用DLL_PROCESS_ATTACH来调用DllMain。

对DLL_PROCESS_ATTACH的处理,代表了DLL的初始化。

DllMain的返回值,也是针对DLL_PROCESS_ATTACH消息的。对于其余的三种取值,不起作用。

对于隐式加载,如DllMain返回FALSE,则程序会启动失败。对于显式加载,则会使LoadLibrary返回NULL。

2、DLL_PROCESS_DETACH

当系统将一个DLL从进程地址空间中撤销映射时,则会向DllMain传入DLL_PROCESS_DETACH。我们应当在此处放置一些清理代码。

当使用FreeLibrary时,如该线程的使用计数为0时,操作系统才会使用DLL_PROCESS_DETACH来调用DllMain。如使用计数大于0,则只是单纯的减少该DLL的计数。

3、DLL_THREAD_ATTACH

当进程创建一个线程,则系统会检查当前已映射到该进程空间中的所有DLL映像,并用DLL_THREAD_ATTACH来调用每个DLL的DllMain。

只有当所有DLL都完成了对DLL_THREAD_ATTACH的处理后,新线程才会执行它的线程函数。

另外,主线程不可能用DLL_THREAD_ATTACH来调用DllMain,因为主线程必然是在进程初始化的时候,用DLL_PROCESS_ATTACH调用DllMain的。

4、DLL_THREAD_DETACH

线程若要终止,会调用ExitThread,但是此函数不会立即终止线程,而是会利用DLL_THREAD_DETACH来调用当前进程地址空间中的所有DLL镜像的DllMain.

当每个DLL的DllMain都处理完后,系统才会真正的结束线程。

最后看一下DllMain的序列化调用

举个例子:

进程中有两个线程,A与B。进程的地址空间中,映射了一个名为SomeDll.dll的DLL。两个线程都准备通过CreateThread来创建另两个线程,C和D。

当线程A调用CreateThread来创建线程C的时候,系统会用DLL_THREAD_ATTACH来调用SomeDll.dll的DllMain,当线程C执行其中代码的时候,线程B调用CreateThread来创建线程D。

这时,系统同样会用DLL_THREAD_ATTACH来调用SomeDll.dll的DllMain,这次是让线程D来执行其中的代码。

但是此时,系统会对DllMain执行序列化,它会将线程D挂起,直至线程C执行完DllMain中的代码返回为止。

当C线程执行完DllMain中的代码并返回时,可以继续执行C的线程函数。此时,系统会唤醒线程D,让D执行DllMain中的代码。当返回后,线程D开始执行线程函数。

   
734 次浏览       20
相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]
Visual C++编程命名规则
任何时候都适用的20个C++技巧
C语言进阶
串口驱动分析
轻轻松松从C一路走到C++
C++编程思想
更多...   


C++并发处理+单元测试
C++程序开发
C++高级编程
C/C++开发
C++设计模式
C/C++单元测试


北京 嵌入式C高质量编程
中国航空 嵌入式C高质量编程
华为 C++高级编程
北京 C++高级编程
丹佛斯 C++高级编程
北大方正 C语言单元测试
罗克韦尔 C++单元测试
更多...