DllMain详解
源码下载:
DLL – 动态链接库
DllMainTest – 测试DLL的DllMain
1 DLL的进入/退出函数
1.1 DllMain简介
跟exe有个main或者WinMain入口函数一样,DLL也有一个入口函数,就是DllMain。以“DllMain”为关键字,来看看MSDN帮助文档怎么介绍这个函数的。
The DllMain function is an optional method of entry into a dynamic-link library (DLL)。(简要翻译:对于一个Dll模块,DllMain函数是可选的。)这句话很重要,很多初学者可能都认为一个动态链接库肯定要有DllMain函数。其实不然,像很多仅仅包含资源信息的DLL是没有DllMain函数的。
1.2 何时调用DllMain
系统是在什么时候调用DllMain函数的呢?静态链接时,或动态链接时调用 LoadLibrary和FreeLibrary都会调用DllMain函数。DllMain的第三个参数fdwReason指明了系统调用Dll的原因,它可能是DLL_PROCESS_ATTACH、DLL_PROCESS_DETACH、DLL_THREAD_ATTACH和 DLL_THREAD_DETACH。以下从这四种情况来分析系统何时调用了DllMain。
1.2.1 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函数。
1.2.2 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函数。
1.2.3 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函数,哪怕是线程中建立线程也一样。
1.2.4 DLL_THREAD_DETACH
如果线程调用了ExitThread来结束线程(线程函数返回时,系统也会自动调用ExitThread),系统查看当前映射到进程空间中的所有DLL文件映像,并用DLL_THREAD_DETACH来调用DllMain函数,通知所有的DLL去执行线程级的清理工作。
注意:如果线程的结束是因为系统中的一个线程调用了TerminateThread,系统就不会用值DLL_THREAD_DETACH来调用所有DLL的DllMain函数。
1.3 为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”(图中蓝色高亮的地方),要注意位置,我试了,要把/D放到/GZ后面也会链接错误,我也不懂为什么,^_^。按OK,再次编译,成功。大家可以自己测试下到底有没有更改成功,什么,如果测试?打出调式信息啊。
1.4 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.
分享到:
相关推荐
Dll动态链接库有个入口函数DllMain,这是我对DllMain的详解。 DllMain的详解:见我的博客http://blog.csdn.net/benkaoya/archive/2008/06/02/2504781.aspx
### VC++ MFC DLL动态链接库编写详解 #### 一、引言 在软件开发领域,动态链接库(Dynamic Link Library,简称DLL)是Windows操作系统中的一个重要组成部分,它允许程序共享代码和其他资源。尽管现代软件架构更倾向...
《VC++深入详解》第19章主要探讨的是动态链接库(DLL)的使用和创建,这是Windows操作系统中不可或缺的一部分。动态链接库不同于静态库,它不直接运行,而是通过其他程序调用其函数来执行特定任务。动态链接库分为...
《VC++动态链接库创建和调用全过程详解》这篇文档主要涵盖了动态链接库(DLL)在VC++环境下的创建和使用。DLL是一种重要的软件开发工具,它可以被多个应用程序共享,从而减少内存占用和提高程序效率。以下是文档的...
【动态链接库详解-VC中创建和使用动态库】 动态链接库(DLL)在Windows操作系统中是一种可重用代码的机制,允许多个程序共享同一份代码库,从而节省内存并提高程序间的协同工作能力。VC++(Visual C++)提供了创建...
此外,`.dllmain`函数是插件的入口点,它会处理WinDBG的初始化和卸载事件。 最后,将插件编译成DLL后,可以使用`.load`命令在WinDBG中加载它,然后像调用其他内置命令一样调用你的插件函数。 总的来说,掌握WinDBG...
#### 二、`DllMain`函数详解 `DllMain`是DLL中的一个特殊函数,它是DLL加载到进程地址空间时首先被调用的函数。这个函数用于处理DLL的初始化和清理工作。 ##### 2.1 `DllMain`函数的作用 - **初始化和清理**:当...
5. **DLLMain函数**:BHO的入口点通常是DLLMain函数,负责初始化和清理工作。当IE加载BHO时,会调用这个函数。 6. **OnDocumentComplete**事件:这是BHO中一个重要的方法,当IE加载完一个页面后,会触发此事件,...
3. DLL入口点(DllMain)的编写:文档展示了如何编写DLL的入口点函数DllMain,这是DLL初始化和终止过程中必须的。在VC++中,DllMain是一个被系统调用的函数,用于处理DLL加载、卸载以及线程和进程的附加和分离事件。...
《PE结构与DLL加载详解》 在Windows操作系统中,Portable Executable(PE)文件格式是用于存放可执行程序、动态链接库(DLL)以及其他类型模块的主要格式。本资料集主要探讨了PE结构以及DLL的加载过程,对于深入...
2、打开dllmain.cpp,增加一个byte数组元素求和的函数: Cal(unsigned char* data,int length);编译,在工程名上右键选择“生成”;即生成Dll1.dll文件。 3、创建C#工程对,选择窗体类型工程。在界面上增加一个...
#### 最简单的DLL示例:DllMain函数详解 创建DLL的第一步是编写`DllMain`函数,它是DLL的入口点,类似于C程序中的`main`函数。`DllMain`函数接收三个参数: - `HANDLE hModule`:表示DLL的句柄,用于标识当前DLL的...
### 用Dev-C++制作动态链接库(DLL)详解 #### 概述 动态链接库(Dynamic Link Library,简称DLL)是一种在Windows操作系统下广泛使用的共享库格式。它允许程序和其他模块共享代码和数据,从而提高了软件开发的效率...
`DllMain`函数在DLL加载和卸载时进行初始化和清理工作。 在实际使用时,开发者需要在主应用程序中加载`Spy` DLL,并调用`StartHook`启动钩子,然后系统就会开始监控鼠标事件。每次鼠标左键被点击,`MouseProc`会被...
### MFC与其他库冲突问题详解 #### 背景与问题描述 在使用Microsoft Visual C++进行开发时,经常会遇到由于不同库之间链接顺序不当而导致的一系列编译错误。其中较为常见的一种错误便是由Microsoft Foundation ...
### 利用DirectShow开发自定义Filter的知识点详解 #### 一、DirectShow简介与COM组件基础 **DirectShow**是Microsoft Windows操作系统中用于处理多媒体流的一种架构和技术框架。它支持实时音频视频流的捕获、压缩...
6. **Error LNK2005**:这是一个链接错误,表明_DllMain@12已经在不同的地方定义。这可能是由于重复定义导致的。删除工程设置中的_USRDLL标志可以解决问题。 7. **R6010错误**:这个错误通常涉及运行时问题,比如...
#### 三、CVI生成DLL的步骤详解 1. **编写DLL源代码** - 首先,在CVI中创建一个新的源文件,例如命名为`dll.c`。 - 在该文件中实现DLL的入口点函数`DllMain`。此函数用于处理DLL加载和卸载等事件。示例代码如下: ...