DLL入口函数DllMain

转载 2016年05月30日 22:40:40

每个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开始执行线程函数。

相关文章推荐

Dll入口函数参数详解...

DLL程序入口点函数:DllMain,注意:大小写是区别的(仅导出资源的DLL可以没有DllMain函数)。 函数原型: BOOL APIENTRY DllMain( HMODULE hModul...
  • friendan
  • friendan
  • 2012年06月13日 13:52
  • 15499

动态链接库(DLL)入口/出口点

链接库入口/出口点当动态链接库首次启动和结束时,我们呼叫了DllMain函数。DllMain的第一个参数是链接库的执行实体句柄。如果您的链接库使用需要执行实体句柄(诸如DialogBox)的资源,那么...
  • jjunjoe
  • jjunjoe
  • 2011年03月02日 09:59
  • 3077

关于DLL找不到函数入口点的问题

在隐式调用DLL时,运行时有时会出现 一个对话框。说某某函数找不到入口点。分析了一下,原因不外乎以下几种,供参考1、输入函数的DLL与LIB版本不匹配。检查一下二者是否是统一的。2、有否加载了一个库所...

DLL入口点函数DllMain

每个DLL都可以有一个入口点函数DllMain,系统会在不同的时刻调用此函数。以下是DllMain的一般形式: BOOL WINAPI DllMain( HINSTANCE hinstDLL...
  • guyue35
  • guyue35
  • 2015年05月08日 08:26
  • 392

dll动态链接库(2)---入口函数DllMain

1、动态库导出函数的查看: 使用Vc++自带的Depends工具进行查看,但是只能看到函数的名字,具体的函数参数及返回值看不到,所以要把动态库导出函数声明的头文件(.h文件)打包给> 。 ...

关于DLLMAIN()入口函数的讨论

  • 2010年11月21日 13:24
  • 61KB
  • 下载

ATL创建COM组件时找不到dllmain入口函数

当我们创建动态库时,有时需要在dllmain()入口函数中添加一些代码,比如当动态库映射到进程地址空间时DLL_PROCESS_ATTACH,我们需要初始化一个全局变量等。之前用ATL创建了一个COM...

WinAPI【Win32 系统入口函数介绍】WinMain DllMain

WinMain函数 WinMain函数的原型声明如下: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,...
  • prownd
  • prownd
  • 2012年10月16日 11:03
  • 475

DLL的进入点函数DllMain

  • 2014年02月14日 10:34
  • 82KB
  • 下载

Dll入口函数参数详解

DLL程序入口点函数:DllMain,注意:大小写是区别的(仅导出资源的DLL可以没有DllMain函数)。函数原型:BOOL APIENTRY DllMain( HMODULE hModule, ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:DLL入口函数DllMain
举报原因:
原因补充:

(最多只允许输入30个字)