您的位置:首页 > 其它

Windows库程序之动态库程序

2015-06-04 16:14 323 查看
上两篇我们讲到如何使用C、C++语言编写静态库程序以及在.c和.cpp环境下的调用方式,今天我们来说说动态库程序的编写一、动态库特点a.运行进独立存在b.不会链接到执行程序c.使用时加载二、与静态库的比较:a.由于静态库是将代码嵌入到使用程序中,多个程序使用时,会有多份代码,所以代码体积会增在,动态库的代码只需要存在一份,,其他程序通过函数地址使用,所以代码体积小,(不过现在的硬盘那么大,还怕这点体积,哈哈)b.静态库发生变化后,新的代码需要重新链接嵌入到执行程序中,动态库发生变化后,如果库中函数的定义(或地址)未变化,其它使用DLL的程序不需要重新链接。三、我们来说说动态库的创建哈a.建立项目b.添加库程序(Win32 Dynamic-link Library)c.库程序导出,-提供给使用者库中的函数信息等(如果函数的信息,地址没有导出,别人就没法使用,我们写的dll也就没用啦)库函数的导出方式:(声明导出1)使用_declspec(dllexport)导出函数,注意:动态库编译链接后,也会有LIB文件,是作为动态库函数映射使用,与静态库不完全相同。(声明导出2)C的导出方式:extern "C" _declspec(dllexport) int Add(...);(模块定义文件.def)例如:LIBRARY DLLFUNC;库名EXPORTS;库导出表CDll_add@1 ;导出函数d.库函数的使用 --隐式链接,1) 头文件和函数原型,可以在函数原型的定义前,增加declspec(dllimport).例如_declspec(dllimport) int Add(...);如果库函数使用C格式导出,需要在函数定义增加extern "C"。导入动态库的LIB文件, 在程序中使用函数隐式链接的情况,DLL可以存放的路径:(1).与执行文件中同一个目录下(2).当前工作目录(3).Windows目录(4).Windows/System32(5).Windows/System(6).环境变量PATH指定目录使用C编写动态库C环境调用cdll.c 源文件
_declspec(dllexport) int CDll_add(int num1,int num2)<span style="white-space:pre">	</span>//此外如果不导出的话,在调用处编译通过不了
{
return num1+num2;
}

_declspec(dllexport) int CDll_sub(int num1,int num2)
{
return num1-num2;
}
使用C环境调用cdll.dllusecdll.c//隐式链接使用
#pragma comment(lib,"..\\cdll\\cdll.lib")

int main(void)
{
int num1 = 100;
int num2 = 1000;

int nSum = CDll_add(num1,num2);
int nSub = CDll_sub(num1,num2);

printf("nSum = %d,nSub = %d\r\n",nSum,nSub);

return 0;
}
使用C++编写动态库CPP环境调用cppdll.cpp源文件
/*_declspec(dllexport) */int CppDll_add(int num1,int num2)<span style="white-space:pre">	</span>//即可就以声明导出,也可以通过模块定义文件,上面我们用过声明导出,现在我们使用模块定义文件{return num1+num2;}/*_declspec(dllexport) */int CppDll_sub(int num1,int num2){return num1-num2;}/*_declspec(dllexport) */int CppDll_mul(int num1,int num2){return num1*num2;}
cppdll.def
LIBRARY cppdllEXPORTSCppDll_add @1CppDll_sub @2CppDll_mul @3
使用源文件usecppdll.cpp
#include <iostream>using namespace std;_declspec(dllimport) int CppDll_add(int num1,int num2);<span style="white-space:pre">	</span>//以声明导入在动态库中导出函数_declspec(dllimport) int CppDll_sub(int num1,int num2); //同上_declspec(dllimport) int CppDll_mul(int num1,int num2);<span style="white-space:pre">	</span>//同上#pragma comment(lib,"..\\cppdll\\cppdll.lib")int main(void){int num1 = 100;int num2 = 1000;cout<<"C++ Dll function use"<<endl;int nSum = CppDll_add(num1,num2);int nSub = CppDll_sub(num1,num2);int nMul = CppDll_mul(num2,num1);cout<<"nSum = "<<nSum<<" nSub = "<<nSub<<" nMul = "<<nMul<<endl;return 0;}
以上两种方式调用动态库我们均采用的隐式链接,接下来我们来采用显示链接的调用方法显示链接动态库程序(显示调用时,dll库程序必须要使用模块定义文件导出)1)定义函数指针类型2)加载动态库HMODULE LoadLibrary(LPCTSTR lpFileName //动态库文件名或都全路径); 返回DLL的实例句柄(HINSTANCE)3)获取函数地址FARPROC GetProcAddress(HMODULE hModule,//DLL句柄LPCSTR lpProcName//函数名称);成功返回函数地址4)使用函数,拿到了函数地址就可以使用啦哈哈5)卸载动态库,使用记得释放自己加载的资源哈BOOL FreeLibrary(HMODULEhModule //DLL的实例句柄);看例子代码示例哈:
#include <cstdio>#include <WINDOWS.H>typedef int (*DLL_ADD)(int num1,int num2);typedef int (*DLL_SUB)(int num1,int num2);typedef int (*DLL_MUL)(int num1,int num2);int main(void){HINSTANCE hDll = LoadLibrary("cppdll.dll");printf("hDll: %d\r\n",hDll);DLL_ADD lpAddFun = (DLL_ADD)GetProcAddress(hDll,"CppDll_add");printf("lpAddFun: %p\r\n",lpAddFun);int nSum = lpAddFun(100,200);printf("nSum = %d\r\n",nSum);DLL_SUB lpSubFun = (DLL_SUB)GetProcAddress(hDll,"CppDll_sub");printf("lpSubFun: %p\r\n",lpSubFun);int nSub = lpSubFun(100,200);printf("nSub = %d\r\n",nSub);DLL_MUL lpMulFun = (DLL_MUL)GetProcAddress(hDll,"CppDll_mul");printf("lpMulFun: %p\r\n",lpMulFun);int nMul = lpMulFun(100,200);printf("nMul = %d\r\n",nMul);FreeLibrary(hDll);return 0;}
总结:两种链接方式对比:1)在库函数定义不变的情况下:隐式链接,由于库函数地址是在程序编译链接时设置,所以当动态库变化后,使用程序需要重新编译链接。显示链接,由于库函数地址是在程序执行时,动态从中查询,所以库变化后,不需要重新编译链接。2)动态库加载隐式链接,动态库是在程序启动时就被加载,当DLL不存在,程序无法启动。显式链接,动态库只在使用LoadLibrary函数时,才会被加载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: