CUI控制台程序(不是DOS):main
GUI用户界面程序:WinMain
DLL程序入口点函数:DllMain,注意:大小写是区别的(仅导出资源的DLL可以没有DllMain函数)。
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
①hModule参数:指向DLL本身的实例句柄;
②ul_reason_for_call参数:指明了DLL被调用的原因,可以有以下4个取值:
■DLL_PROCESS_ATTACH:
当DLL被进程 <<第一次>> 调用时,导致DllMain函数被调用,同时ul_reason_for_call的值为DLL_PROCESS_ATTACH,如果同一个进程后来再次调用此DLL时,操作系统只会增加DLL的使用次数,不会再用DLL_PROCESS_ATTACH调用DLL的DllMain函数。
■DLL_PROCESS_DETACH:
当DLL被从进程的地址空间解除映射时,系统调用了它的DllMain,传递的ul_reason_for_call值是DLL_PROCESS_DETACH。
★如果进程的终结是因为调用了TerminateProcess,系统就不会用DLL_PROCESS_DETACH来调用DLL的DllMain函数。这就意味着DLL在进程结束前没有机会执行任何清理工作。
■DLL_THREAD_ATTACH:
当进程创建一线程时,系统查看当前映射到进程地址空间中的所有DLL文件映像,并用值DLL_THREAD_ATTACH调用DLL的DllMain函数。 新创建的线程负责执行这次的DLL的DllMain函数,只有当所有的DLL都处理完这一通知后,系统才允许线程开始执行它的线程函数。
■DLL_THREAD_DETACH:
如果线程调用了ExitThread来结束线程(线程函数返回时,系统也会自动调用ExitThread),系统查看当前映射到进程空间中的所有DLL文件映像,并用DLL_THREAD_DETACH来调用DllMain函数,通知所有的DLL去执行线程级的清理工作。
★注意:如果线程的结束是因为系统中的一个线程调用了TerminateThread,系统就不会用值DLL_THREAD_DETACH来调用所有DLL的DllMain函数。
③lpReserved参数:保留,目前没什么意义。
DLL只有将函数进行导出,这样其他的程序才可以进行调用。
DLL里面可以有2种函数:一种是导出函数,供被DLL调用的程序使用,比如说是EXE等;另外一种是供DLL内部调用使用,不提供导出。DLL导出函数的方式:*.def 文件或 __declspec(dllexport) 关键字:
创建一个动态链接库工程:DllTest,里面包含两个函数:Add()两个数相加,使用__declspec(dllexport)关键字导出。Dec()两个数相减,使用*.def 文件导出。
***大家在新建工程向导过程中,不要选择 “使用MFC” 选项,如果选上的话,会把DLL变为MFC规则DLL
1、使用__declspec(dllexport)关键字进行导出函数Add():
在DllTest.h头文件中进行导出函数的声明:
extern "C" _declspec(dllexport) int Dec(int a,int b);
在DllTest.cpp文件中对函数进行实现:
#include "stdafx.h"
#include "DllTest.h"
int Add(int a,int b)
{
return a+b;
}
2、使用 使用 *.def 文件导出函数Dec()。
首先新建一个def文件,命名为:DllTest.def。在其中进行导出函数的声明:
LIBRARY "DllTest"
EXPORTS
Add @1
*.def文件的格式说明:
*.def 文件必须至少包含下列模块定义语句:
■文件中的第一个语句必须是 LIBRARY 语句。此语句将 .def 文件标识为属于 DLL。LIBRARY 语句的后面是 DLL 的名称。链接器将此名称放到 DLL 的导入库中。
■EXPORTS 语句列出名称,可能的话还会列出 DLL 导出函数的序号值。通过在函数名的后面加上 @ 符和一个数字,给函数分配序号值。当指定序号值时,序号值的范围必须是从 1 到 N,其中 N 是 DLL 导出函数的个数。
■注释语句,在语句前面加分号 “;” 。
格式举例如下:
;DLLTest.def : Declares the module parameters for the DLL.
LIBRARY "DLLTest"
EXPORTS
add @1
fun @2
/**************************************************************************************************/
在DllTest.cpp中进行函数的实现:
int Dec(int a,int b)
{
return a-b;
}
对程序进行编译、生成。会生成:DllTest.dll、 DllTest.lib两个文件。在调用动态链接库时,这两个函数都是有用的。
3、使用Vc++自带的Depends工具进行查看函数是否导出成功。由于Depends工具只能看到函数的名字,具体的函数参数及返回值看不到,所以要把动态库导出函数声明的头文件(DllTest.h文件)打包给<<开发者>> ,这样开发者才能使用你的动态链接库中的导出函数。