首页 > 其他分享 >DLL的入口点函数

DLL的入口点函数

时间:2022-11-07 19:32:01浏览次数:38  
标签:调用 THREAD ATTACH 入口 DLL 点函数 线程 DETACH


一、基本介绍
系统在不同的时候调用这个入口点函数,这些调用是通知性质的,
用来执行一些与进程或者线程有关的清理工作。如果DLL需要这些通知,则需要在源代码
中实现这个入口点函数。
注意函数名区分大小写 DllMain
函数原型

BOOL WINAPI DllMain(
In HINSTANCE hinstDLL,
In DWORD fdwReason,
In LPVOID lpvReserved
);hinstDLL 是包含这个DLL实例的句柄
fdwReason 调用函数入口点的原因,后面详细介绍
lpvReserved:为零表示隐式载入,不为零表示显示载入

注意:
为了避免产生循环依赖,Dllmain中,避免调用从其他dll中导入的函数,以及LoadLibrary(Ex),和Freelibrary
套接字函数,COM、ODBC等
另外,如果创建全局或者静态C++对象,也会存在同样的问题,因为这些对象的构造函数和析构函数也会被调用

二、相关参数
1、DLL_PROCESS_ATTACH 通知
当系统第一次将一个DLL映射到进程的地址空间中的时候,会调用DllMain,并且传入1、DLL_PROCESS_ATTACH,
之后线程再调用LoadLibrary的时候,只是递增这个DLL的引用计数,不会再传入DLL_PROCESS_ATTACH来调用DllMain函数
DLL处理DLL_PROCESS_ATTACH的时候,根据需要进行初始化
关于返回值,如果传入参数是(DLL_THREAD_ATTACH或者DLL_THREAD_DETACH)的时候,系统将忽略DllMain返回值
关于程序调用,如果隐式调用失败,系统直接无法启动
在显示调用中,如果DLLMain函数返回为false,也就是初始化不成功,系统会从进程地址空间中撤销对DLL的映射,并让LoadLibrary返回NULL

2、DLL_PROCESS_DETACH 通知
当系统将一个DLL从进程的地址空间中撤销映射时,会调用DLL的DLLMain函数,并传入参数DLL_PROCESS_DETACH 。
DLL处理这个通知的时候,应该执行与进程相关的清理工作,比如调用HeapDestory来销毁堆。
撤销映射有两种方式,1、进程终止,2、某个线程调用了FreeLibrary或者FreeLibraryAndExitThread,如果调用的FreeLibrary,那么在
DLLMain处理完 DLL_PROCESS_DETACH通知之前,线程不会从调用中返回
需要注意的时候,DLL可能会阻碍进程的终止,当DLLMain收到DLL_PROCESS_DETACH通知的时候,只有每个DLL都处理完DLL_PROCESS_DETACH
的通知之后,操作系统才会真正地终止进程

3、DLL_THREAD_ATTACH通知
DLL已经被映射到进程地址空间之后当进程创建一个线程的时候,系统会检测映射到当前进程的地址空间所有DLL文件镜像,并用
DLL_THREAD_ATTACH来调用每个DLL的DLLMain函数,来进行初始化,当所有的DLL都完成对该通知的处理后,系统才开始 让新线程开始它的线程函数
另外注意的是只有在创建新的线程的时候,系统才调用DLL_THREAD_ATTACH来调用DLL的DllMain函数
此外,主线程也不会发送DLL_THREAD_ATTACH通知

4、DLL_THREAD_DETACH 通知
线程函数返回,系统会调用ExitThread来终止线程。但是系统不会理解终止该线程,而是让即将终止的线程用DLL_THREAD_DETACH
来调用所有已经映射DLL的DllMain函数,通知DLL执行和线程相关的清理。
注意,DLL可能会妨碍线程的终止,比如说当DLL收到DLL_THREAD_DETACH 通知的时候可能会进入无限循环,只有每个DLL都处理完,操作系统才真正终止线程
警告:如果线程终止,是因为系统中的某个线程调用了TerminalThread,那么系统不会用DLL_THREAD_DETACH来调用所有DLL的DLLMain函数
这意味着在线程终止之前,已经映射到进程地址空间 中的任何DLL将没有机会执行任何清理代码,这样会导致数据丢失,因此,像TerminateProcess一样,
除非万不得已,不要使用TerminalThread函数
如果在撤销对一个DLL的映射的时候,还有线程在运行,那么系统不会让任何线程用DLL_THREAD_DETACH 来调用DLLMain,不过我们可以选择
自己在DLL_PROCESS_DETACH 中来进行处理
前面的规则可能会导致下面几种情况,进程中的一个线程调用LoadLibrary来载入一个DLL,这个时候,系统调用DLL_PROCESS_ATTACH来调用该DLL的DllMain
函数,(注意线程不会得到DLL_THREAD_ATTACH通知),接着,载入该DLL的线程退出,注意,虽然虽然系统将这个进程连接到这个DLL的时候,不会像DLL发送
DLL_THREAD_ATTACH通知,但是当系统将该进程和DLL接触连接的时候,却会向这个DLL发送DLL_THREAD_DETACH通知,由于这个原因,在进行线程相关清理的时候必须及其
小心。


标签:调用,THREAD,ATTACH,入口,DLL,点函数,线程,DETACH
From: https://blog.51cto.com/u_11320078/5831087

相关文章