VB DllMain DLL的进入、退出函数详解,VB DllMain DLL的进入、退出函数,VB DllMain DLL的进入、退出详解,VB DllMain DLL的进入函数详解,VB DllMain DLL的退出函数详解,VB DllMain DLL进入函数详解,VB DllMain DLL退出函数详解,VB DllMain DLL进入函数,VB DllMain DLL退出函数,VB DllMain DLL函数详解,VB DllMain DLL函数,VB DllMain函数,VB DllMain DLL,Dll入口点函数,VB DllMain,DllMain 简介,WinMain 入口函数,DLL入口函数,DllMain 入口函数,Const DLL_PROCESS_ATTACH As Long = 1 '当DLL被映射到进程的地址空间时,Const DLL_PROCESS_DETACH As Long = 0 '当DLL被从进程的地址空间解除映射时,Const DLL_THREAD_ATTACH As Long = 2 '当进程创建一线程时,Const DLL_THREAD_DETACH As Long = 3 '当线程调用了 ExitThread 结束线程时,DLL_PROCESS_ATTACH,DLL_PROCESS_DETACH,DLL_THREAD_ATTACH,DLL_THREAD_DETACH,系统调用 DllMain 函数的四种情况,DllMain(ByVal hinstDLL As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long。

VB DllMain DLL的进入、退出函数详解:

DllMain 简介:

    跟 exe 有个 main 或者 WinMain 入口函数一样,DLL 也有一个入口函数,就是 DllMain。以“DllMain”为关键字,来看看MSDN帮助文档怎么介绍这个函数的。

  The DllMain function is an optional method of entry into a dynamic-link library (DLL)。

    简要翻译:对于动态链接库,DllMain是一个可选的入口函数。

    这句话很重要,很多初学者可能都认为一个动态链接库肯定要有 DllMain 函数。其实不然,像很多仅仅包含资源信息的 DLL 是没有 DllMain 函数的。


系统调用 DllMain 函数的四种情况:

    当一个进程载入或卸载一个DLL时,DLLMAIN会被调用(DLLMAIN获得DLL_PROCESS_ATTACH消息),线程也是一样(获得DLL_THREAD_ATTACH消息)。

    在静态链接时,或动态链接时调用 LoadLibrary 和 FreeLibrary 都会调用 DllMain 函数。DllMain 的第三个参数 fdwReason 指明了系统调用 dll 的原因,它可能是:

    Const DLL_PROCESS_ATTACH  As Long = 1      '当DLL被映射到进程的地址空间时
    Const DLL_PROCESS_DETACH  As Long = 0      '当DLL被从进程的地址空间解除映射时
    Const DLL_THREAD_ATTACH   As Long = 2      '当进程创建一线程时
    Const DLL_THREAD_DETACH   As Long = 3      '当线程调用了 ExitThread 结束线程时

  以下从这四种情况来分析系统何时调用了DllMain。


DLL_PROCESS_ATTACH:

    当一个程序要调用 Dll 里的函数,首先要先把 DLL 文件映射到进程的地址空间。要把一个 DLL 文件映射到进程的地址空间,有两种方法:静态链接和动态链接的 LoadLibrary 或者 LoadLibraryEx。

  当一个 DLL 文件被映射到进程的地址空间时,系统调用该 DLL 的 DllMain 函数,传递的 fdwReason 参数为 DLL_PROCESS_ATTACH。这种调用只会发生在第一次映射时。如果同一个进程后来为已经映射进来的 DLL 再次调用 LoadLibrary 或者 LoadLibraryEx,操作系统只会增加 DLL 的使用次数,它不会再用 DLL_PROCESS_ATTACH 调用 DLL 的 DllMain 函数。不同进程用 LoadLibrary 同一个 DLL 时,每个进程的第一次映射都会用 DLL_PROCESS_ATTACH 调用 DLL 的 DllMain 函数。

  可参考 DllMainTest 的 DLL_PROCESS_ATTACH_Test 函数。


DLL_PROCESS_DETACH:

  当 DLL 被从进程的地址空间解除映射时,系统调用了它的 DLLMain,传递的fdwReason值是 DLL_PROCESS_DETACH。当 DLL 处理该值时,它应该执行进程相关的清理工作。   那么什么时候 DLL 被从进程的地址空间解除映射呢?两种情况:

  ◆FreeLibrary 解除 DLL 映射(有几个 LoadLibrary,就要有几个 FreeLibrary)
  ◆进程结束而解除 DLL 映射,在进程结束前还没有解除 DLL 的映射,进程结束后会解除 DLL 映射。(如果进程的终结是因为调用了 TerminateProcess,系统就不会用 DLL_PROCESS_DETACH 来调用 DLL 的 DllMain 函数。这就意味着 DLL 在进程结束前没有机会执行任何清理工作。)

  注意:当用 DLL_PROCESS_ATTACH 调用 DLL 的 DllMain 函数时,如果返回 FALSE,说明没有初始化成功,系统仍会用 DLL_PROCESS_DETACH 调用 DLL 的 DllMain 函数。因此,必须确保清理那些没有成功初始化的东西。

  可参考 DllMainTest 的 DLL_PROCESS_DETACH_Test 函数。


DLL_THREAD_ATTACH:

  当进程创建一线程时,系统查看当前映射到进程地址空间中的所有 DLL 文件映像,并用值 DLL_THREAD_ATTACH 调用 DLL 的 DllMain 函数。

  新创建的线程负责执行这次的 DLL 的 DllMain 函数,只有当所有的 DLL 都处理完这一通知后,系统才允许进程开始执行它的线程函数。

  注意跟 DLL_PROCESS_ATTACH 的区别,我们在前面说过,第 n(n>=2) 次以后把 DLL 映像文件映射到进程的地址空间时,是不再用 DLL_PROCESS_ATTACH 调用 DllMain 的。而 DLL_THREAD_ATTACH 不同,进程中的每次建立线程,都会用值 DLL_THREAD_ATTACH 调用 DllMain 函数,哪怕是线程中建立线程也一样。


DLL_THREAD_DETACH:

  如果线程调用了 ExitThread 来结束线程(线程函数返回时,系统也会自动调用 ExitThread),系统查看当前映射到进程空间中的所有 DLL 文件映像,并用 DLL_THREAD_DETACH 来调用 DllMain 函数,通知所有的 DLL 去执行线程级的清理工作。

  注意:如果线程的结束是因为系统中的一个线程调用了 TerminateThread,系统就不会用值 DLL_THREAD_DETACH 来调用所有 DLL 的 DllMain 函数。


DllMain 函数换名:

  在早期的 SDK 版本中,DllMain 是叫做 DllEntryPoint。其实有一件鲜为人知的事:一个 Dll 的入口函数名是可以自己定义的。下面我将以 VC++6.0 为例来演示如何更改。首先要说明一点,虽然 DllMain 可以换成其他函数名,但函数的参数和返回值必须和 DllMain 一样。而且这个函数要为 __stdcall 类型(DllMain 本身也是 __stdcall 类型)。

  打开 VC++ 菜单 Project\Settings\Link tab\ Output in the Category box,在 Entry-point symbol 中输入要替换 DllMain 的函数名(当然这个函数名是你程序中已经实现的函数)。Entry-point symbol 是干么的呢?可以以关键字“Entry-point symbol”搜索 MSDN 帮助文档查看,搜索时,打钩“仅搜索标题”会更快定位。

    按OK后,如果马上编译的话会出现如下错误:

    LIBCMTD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main

    Debug/Dll.dll : fatal error LNK1120: 1 unresolved externals

    打开 VC++ 菜单 Project\Settings\C/C++ 选项卡,在 Project Options:末尾的地方添加“/D”,要注意位置(/GZ 之前),我试了,要把 /D 放到 /GZ 后面也会链接错误,我也不懂为什么。按OK,再次编译,成功。大家可以自己测试下到底有没有更改成功,什么,如果测试?打出调式信息啊。

    DisableThreadLibraryCalls,看帮助就知道它是干么用的:The DisableThreadLibraryCalls function disables the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications for the dynamic-link library (DLL) specified by hLibModule. This can reduce the size of the working code set for some applications.

    翻译:DisableThreadLibraryCalls 函数禁止动态链接库(DLL)中 hLibModule 的 DLL_THREAD_ATTACH 和 DLL_THREAD_DETACH 通知消息,这样可以减少一些应用程序工作代码的大小。

VB DllMain 函数示例:
    '系统调用 DllMain 函数的四种情况
    '当一个进程载入或卸载一个DLL时,DLLMAIN会被调用(DLLMAIN获得DLL_PROCESS_ATTACH消息),线程也是一样(获得DLL_THREAD_ATTACH消息)

    Const DLL_PROCESS_ATTACH  As Long = 1                                           '当DLL被映射到进程的地址空间时
    Const DLL_PROCESS_DETACH  As Long = 0                                           '当DLL被从进程的地址空间解除映射时
    Const DLL_THREAD_ATTACH   As Long = 2                                           '当进程创建一线程时
    Const DLL_THREAD_DETACH   As Long = 3                                           '当线程调用了 ExitThread 结束线程时

    Public Function DllMain(ByVal hinstDLL As Long, ByVal fdwReason As Long, ByVal lpvReserved As Long) As Long 'Dll入口点函数
        Select Case fdwReason
            Case DLL_PROCESS_ATTACH
                '当DLL被映射到进程的地址空间时
            Case DLL_PROCESS_DETACH
                '当DLL被从进程的地址空间解除映射时
            Case DLL_THREAD_ATTACH
                '当进程创建一线程时
            Case DLL_THREAD_DETACH
                '当线程调用了 ExitThread 结束线程时
        End Select
        DllMain = 1
    End Function