Windows库程序之动态库程序

上两篇我们讲到如何使用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.dll

usecdll.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 cppdll
EXPORTS
  CppDll_add @1
  CppDll_sub @2
  CppDll_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(

HMODULE hModule //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函数时,才会被加载。




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值