个人DLL探究学习记录

经过几天的学习和探究DLL,总算是实现了一些dll了,下面是个人的学习记录吧:

首先分享几个学习时参考的博客,感觉都写得不错:

http://www.cnblogs.com/chio/archive/2007/11/03/948480.html

http://www.blogjava.net/wxb_nudt/archive/2007/09/11/144371.html

http://www.2cto.com/kf/201109/103452.html

前2个注重理论,最后一个全是代码,但是示例性很强,看了理论,看最后那个博客就基本明白了。

首先介绍了dll到底是什么,在这之前首先要明白库是什么,库就是放了一大堆函数,类,全局变量之类的仓库,可供不同的程序调用。

Windows程序设计第5版讲到有3种库文件:.lib的有2种,.dll的一种,.lib的首先是静态链接库,这种库编译链接的时候会绑定你的exe,就像printf(),scanf()这些函数的库就是这种了,另外一个.lib是和.dll配套出现的,.dll是动态链接库,它不会绑定到exe中,它配套的.lib内部是没有代码的,是用来告诉编译器.dll的地址,符号之类的信息。

在这里着重讲解.dll

首先看下DLL.h

#ifdef DLL_H
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif

EXPORT int MyAdd(int a,int b);
extern EXPORT int G;
EXPORT class Math
{
public:
	EXPORT int Mul(int a,int b);
};

在头文件中

#ifdef DLL_H
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __declspec(dllimport)
#endif
这段预编译还是挺重要的,意思大概就是如果定义了DLL_H就定义EXPORT为__declspec(dllexport),函数,变量,类之前有这个修饰就表明是一个导出量,Dll中有导出量给供其他程序使用,也有内部量,供Dll内部使用,想供其他程序使用就用__declspec(dllexport)修饰。而对于引用dll的函数的应用程序则需要用__declspec(dllimport)来修饰是引用Dll的。有了这段预编译,如果一个文件在一开始#define DLL_H的,那么那个文件就肯定是具体实现那些那些导出量内容的文件了。

所以DLL.cpp的内容:

#define DLL_H

#include"dll.h"
#include<Windows.h>

int MyAdd(int a,int b)
{
	return a+b;
}
int G=113;
int Math::Mul(int a,int b)
{
	return a*b;
}

bool APIENTRY DllMain(HANDLE hMoudle,DWORD dwReason,void* lpReserved)
{
	return true;
}
定义了DLL_H,所以在dll.h中的EXPORT就是__declspec(dllexport),表明是导出量,再在Dll,cpp中实现这些导出量,另外还有一个DllMain这个函数,这个函数是dll被载入载出的时候都会调用一次,是dll的进入点与退出点,总是返回true就没问题了吧,大概,可能。


这样之后编译链接得到的
Dll.dll和Dll.lib(这个.lib就包含了Dll.dll中的函数名称啦,内存地址之类的信息,用于代替.dll在应用程序中被编译)



上面都是Dll的创建,创建之后的引用又怎样呢?

引用dll有显示引用和隐式引用2种:

显示引用就是用LoadLibrary---->GetProcAddress----->FreeLibrary这3个API函数来做了

例如想用刚才dll中的MyAdd函数:

typedef int (*pFunc)(int,int);
HINSTANCE hInst=LoadLibraryA("F:\\DllTest\\Dll\\Debug\\Dll.dll");
	if(hInst!=NULL)
	{
		pFunc FunAdd=(pFunc)GetProcAddress(hInst,"MyAdd");
		if(FunAdd!=NULL)
		{
			int ans=FunAdd(2,3);
			printf("%d\n",ans);
		}
	}
首先定义一个函数指针pFunc,接着loadlibrary来加载DLL,获取DLL的实例句柄,用GetProcAddress来获取想要的函数的地址,就能调用了,这里要注意一点,单上上面的代码是会出错的,因为C++编译器会进行一种名字重整的步骤,你起名叫做MyAdd,但是内部存的名字却不是这样的,想要避免这种情况就一定要在Dll.h的函数声明前面加个extern "C"来讲明用c的方式来编译,这样内部存的名字就是MyAdd,但是这样就不支持函数重载了,我也认为这是显示引用的局限,而且每次都得调用3个API函数也显得麻烦

我个人偏爱于隐式引用:

#include<stdio.h>
#include<Windows.h>
#include"F:\DllTest\Dll\Dll\dll.h"
#pragma comment(lib,"F:\\DllTest\\Dll\\Debug\\Dll.lib")
//typedef int (*pFunc)(int,int);
int main()
{
	printf("%d\n",G);
	G=100;
	printf("%d\n",G);
	system("pause");
	
	/*HINSTANCE hInst=LoadLibraryA("F:\\DllTest\\Dll\\Debug\\Dll.dll");
	if(hInst!=NULL)
	{
		pFunc FunAdd=(pFunc)GetProcAddress(hInst,"MyAdd");
		if(FunAdd!=NULL)
		{
			int ans=FunAdd(2,3);
			printf("%d\n",ans);
		}
	}*/
}
#pragma comment(lib,"XXXX.lib");这句用于重定位导入量到dll的地址,这个应用程序.cpp没有定义DLL_H,所以它包含头文件的时候EXPORT为__declspec(dllimport),所以main函数里面的G就是导入量,extern EXPORT int G;前面的extern表明G的定义在dll中,没了extern会出现重定义的问题。隐式引用比较方便,一个重定位之后,dll里面的导出量就随便用了,比显示调用方便很多吧。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值