DLL的入口点函数

一、基本介绍
系统在不同的时候调用这个入口点函数,这些调用是通知性质的,
用来执行一些与进程或者线程有关的清理工作。如果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通知,由于这个原因,在进行线程相关清理的时候必须及其
小心。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
dev-c 是一个用于开发 C/C++ 程序的集成开发环境(IDE),而 DLL 则是动态链接库(Dynamic Link Library)的缩写,它可以被多个程序共享使用。在 dev-c 中,我们可以通过编写和使用 DLL 来实现代码的复用和模块化。 DLL入口指的是 DLL 中的一个特定函数,也被称为导出函数(Export Function),它是 DLL 的调用接口,类似于我们在程序中定义的 main 函数。当其他程序需要使用 DLL 中的功能时,会调用 DLL入口函数来执行所需的操作。 在 dev-c 中,我们可以使用不同的方式来获取和调用 DLL入口函数。一种常见的方法是使用 Windows API 中的 LoadLibrary 函数来加载 DLL,并使用 GetProcAddress 函数获取 DLL 中的入口函数地址。然后我们就可以通过函数指针来调用 DLL入口函数了。 例如,假设我们有一个名为 test.dllDLL,其中包含一个名为 MyFunction 的入口函数。我们可以在 dev-c 中编写以下代码来加载并调用 DLL 中的函数: ```c #include <windows.h> #include <stdio.h> int main() { HINSTANCE hDll = LoadLibrary("test.dll"); if (hDll != NULL) { typedef void (*MYFUNCTION)(); MYFUNCTION MyFunction = (MYFUNCTION) GetProcAddress(hDll, "MyFunction"); if (MyFunction != NULL) { MyFunction(); } else { printf("无法获取 DLL入口函数地址!"); } FreeLibrary(hDll); } else { printf("无法加载 DLL!"); } return 0; } ``` 以上就是在 dev-c 中使用 DLL 入口函数的简单示例。需要注意的是,DLL入口函数需要在编译 DLL 时进行导出定义,否则其函数地址将无法被获取。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值