原文地址:http://panxianjin.dream.blog.163.com/blog/static/12635274620099293578769/
1.写DLL
打开VC++6.0,选择建立工程的动态链接库工程,建立一个Dll1的工程,写两个简单的函数,
注意此时函数并没有导出,所以是不能访问的,也是不能调用的,此时dll内部结构如下
可见没有显示可调用的函数。一定要加上_declspec(dllexport)表示导出函数,可供外面调用
此时add方法是可调用的,sub方法是不可调用的,dll内部结构此时如下
可以看到?add@@....,导出成功,这是c++为了支持多态按一定规则改变了函数名。而sub函数没有加_declspec(dllexport),因此外面是不能访问的,因此内部没有sub函数的名字。下面我们用extern “c”来试一下,看看函数名字结构是否会变化
内部结构如下:
可见add方法的名字存储确实改变了,下面我们用标准调用的存储方式试一下,加关键字_stdcall,同时对sub函数也导出,作比较。
内部结构:
看到add和sub都导出了,按标准调用和普通c调用的函数名如上图所示,标准调用函数名多了个@8,表示函数参数为8字节。
2.调用dll。
因为dll调用分为隐式调用和动态加载,隐式调用在程序运行时加载所有的dll提供的方法,内存开销较大,而动态加载只在需要时加载dll,然后释放掉,比较灵活。
1)隐式加载:(需要dll文件及lib文件)
说明:这里的lib文件并非静态库的Lib文件,这里的lib文件只提供了对应dll文件的一些相应方法,程序加载时是调用dll文件。
首先,建立一个简单的控制台工程test,然后拷贝Dll1.dll和Dll1.lib到test目录下,然后在setting的link里加上Dll1.lib,
程序如下:
结果如下:
2)动态加载只需(Dll1.dll文件)
代码如下:
通过<windows.h>的LoadLibrary()函数和GetProcAddress()函数动态获得函数的指针,然后就可以根据函数名调用相应的函数,MAKEINIRESOURCE()是更据函数的排列次序转换为函数的名字,一般不用这个方法。
上面也知道由于编译dll时函数的名字存储变化不定,动态加载时怎么知道函数名字是怎样的?因此当编译dll文件时,我们编写然后加入一个模块文件“dll文件名.def",然后把该文件加载到工程中,其内容如下(右边):
LIBRARY Dll1可以不要,EXPORTS必要,而且下面规定了dll里导出的函数存储为add和sub,不管你是按C++也好,C也好,标准调用也好,我只以add和sub方式存储。源文件如下:
加模块后的dll内部函数存储结构如下:
结果只按模块定义的形式存储。
把整个类都导出(类里所有的公有方法和属性外界可以访问):
声明为: class _declspec(dllexport) A
{
public:
private:
};
只导出某一个方法:
class A
{
public:
_declspec(dllexport) void get...();
}