DLL编程和调用
DLL 程序的入口函数是 DllMain(),就像 DOS 程序的入口函数是main()、Win32 程序的入口函数是 WinMain() 一样。
BOOL APIENTRY DllMain(
HANDLEhModule,
DWORD ul_reason_for_call,
LPVOIDlpReserved
);
编写一个简单的DLL
#include<objbase.h> // 也可以 #include <windows.h>
#include<stdio.h>
_declspec(dllexport)intadd(inta,intb){
returna+b;
}
_declspec(dllexport)intsub(inta,intb){
returna-b;
}
extern"C"_declspec(dllexport)VOIDMsgBox(char*Msg);
BOOLAPIENTRYDllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
){
switch(ul_reason_for_call)
{
caseDLL_PROCESS_ATTACH:
{
MsgBox("DLL_PROCESS_ATTACH");
break;
}
caseDLL_PROCESS_DETACH:
{
MsgBox("DLL_PROCESS_DEATTACH");
break;
}
caseDLL_THREAD_ATTACH:
{
break;
}
caseDLL_THREAD_DETACH:
{
break;
}
}
}
VOIDMsgBox(char*Msg)
{
charszModuleName[MAX_PATH]= {0};
GetModuleFileName(NULL,szModuleName,MAX_PATH);
MessageBox(NULL,Msg,szModuleName,MB_OK);
}
编译生成ConsoleA2.dll和ConsoleA2.lib文件。
其中extern “C”表示函数以C方式导出。
DLL调用两种方法
静态调度
(1)在工程属性设置中加入该库的静态库(.lib);
(2)将该库的头文件(.h)加入到工程中;
(3)将动态库(.dll)放到工程中相应目录下;
#include <Windows.h>
extern "C"VOID MsgBox(char* Msg);
#pragma comment(lib,"ConsoleA2")
int main(intargc,char*argv[])
{
MsgBox("Hello Frist DLL!");
return0;
}
动态调度
动态调用法要用WindowsAPI中的LoadLibrary()和GetProcAddress()来调入dll库,指出库中函数位置。
GetProcAddress函数检索指定的动态链接库(DLL)中的输出库函数地址。
#include <Windows.h>
typedef VOID(*PFUNMSG)(char*);
int main(intargc,char*argv[])
{
HMODULE hModule = LoadLibrary("ConsoleA2.dll");
if( hModule == NULL)
{
MessageBox(NULL,"ConsoleA2.dll 不存在","DLL LOAD FAILED",MB_OK);
return-1;
}
PFUNMSG ms=(PFUNMSG)GetProcAddress(hModule,"MsgBox");//获取Dll的导出函数
(*ms)("Hello Frist DLL!");
return0;
}
TIPS
VS2012设置生成DLL
右键项目属性->配置属性->常规->配置类型选择
动态库(.dll)即可。
lib与dll区别
lib是编译时需要的,dll是运行时需要的。如果要完成源代码的编译,有lib就够了。如果也使动态连接的程序运行起来,有dll就够了。在开发和调试阶段,当然最好都有。
一般的动态库程序有lib文件和dll文件。lib文件是必须在编译期就连接到应用程序中的,而dll文件是运行期才会被调用的。如果有dll文件,那么对应的lib文件一般是一些索引信息,具体的实现在dll文件中。如果只有lib文件,那么这个lib文件是静态编译出来的,索引和实现都在其中。静态编译的lib文件有好处:给用户安装时就不需要再挂动态库了。但也有缺点,就是导致应用程序比较大,而且失去了动态库的灵活性,在版本升级时,同时要发布新的应用程序才行。
在动态库的情况下,有两个文件,一个是引入库(.LIB)文件,一个是DLL文件,引入库文件包含被DLL导出的函数的名称和位置,DLL包含实际的函数和数据,应用程序使用LIB文件链接到所需要使用的DLL文件,库中的函数和数据并不复制到可执行文件中,因此在应用程序的可执行文件中,存放的不是被调用的函数代码,而是DLL中所要调用的函数的内存地址,这样当一个或多个应用程序运行是再把程序代码和被调用的函数代码链接起来,从而节省了内存资源。从上面的说明可以看出,DLL和.LIB文件必须随应用程序一起发行,否则应用程序将会产生错误。
一般的LIB文件是“导入库”,用来提供给link.exe,作为链接DLL——也就是“动态链接库”的依据。里面记录了类似下面的信息:
调用函数xxx(),连接到x.dll的0xABCDEFGH地址。
早期的LIB,是“静态链接库”,也是用来提供给link.exe,作为链接代码用的。里面的记录如下:调用xxx(),其代码是……;
DLL的LIB(导入库),不含可执行的具体代码(代码在DLL中)。而最早的LIB(静态链接库),里面含有代码。所以,可以看出来,如果一个函数被调用多次,使用DLL(动态链接技术),可以节省一些硬盘和内存空间!而用LIB(静态链接技术),每次调用,都会链接入相同的代码,造成一些空间上的浪费。不过它的好处是不需要进行一个“查找”工作(也就是找到LIB文件中说的DLL的“函数入口点”,就是例子里的0xABCDEFGH地址,可以获得更高的效率)。
dll的调用方式有静态和动态调用两种方式。
lib用于静态调用和头文件*.h结合使用。
如果你只有dll文件,又知道dll文件中函数的格式,也可以使用Loadlibrary,GetAddress函数来动态加载调用。