一、Win32 DLL的创建和使用
1、从DLL中导出函数
_declspec(dllexport) int add(int a,int b)
{
return a+b;
}
_declspec(dllexport) int subtract(int a,int b)
{
return a-b;
}
二、隐式加载DLL
选择【Project\Settings】菜单打开工程设置对话框,选择link选项卡,在"Object/library modules"选项编辑诓中输入dll1.lib
1、利用extern声明外部函数
extern int add(int a,int b);
extern int subtract(int a,int b);
2、利用_declspec(dllimport)声明外部函数
_declspec(dllimport) int add(int a,int b);
_declspec(dllimport) int subtract(int a,int b);
注意:这样导出的一般放在.h文件中。
3、利用宏导出DLL
在.h文件中(Dll1.h)
#ifdef DLL1_API
#else
#define DLL1_API _declspec(dllimport)
#endif
DLL1_API int add(int a,int b);
DLL1_API int subtract(int a,int b);
在.cpp文件中
#define DLL1_API _declspec(dllexport)
#include "Dll1.h"
int add(int a,int b)
{
return a+b;
}
int subtract(int a,int b)
{
return a-b;
}
4、从DLL中导出C++类
在.h文件中(Dll1.h)
#ifdef DLL1_API
#else
#define DLL1_API _declspec(dllimport)
#endif
class DLL1_API Point
{
public:
void output(int x,int y);
}
在.cpp文件中
#define DLL1_API _declspec(dllexport)
#include "Dll1.h"
void Point::output(int x,int y)
{
HWND hwnd=GetForegroundWindow(); //返回调用者进程当前正在使用的那个窗口的句柄。
HDC hdc=GetDC(hwnd); //获取DC
char buf[20];
memset(buf,0,20);
sprintf(buf,"x=%d,y=%d",x,y);
TextOut(hdc,0,0,buf,strlen(buf)); //输出坐标
ReleaseDC(hwnd,hdc); //释放DC
}
在客户端使用
Point pt;
pt.output(5,3);
5、只导出类的某个方法
在.h文件中(Dll1.h)
#ifdef DLL1_API
#else
#define DLL1_API _declspec(dllimport)
#endif
class Point
{
public:
void DLL1_API output(int x,int y);
void test();
}
在.cpp文件中
#define DLL1_API _declspec(dllexport)
#include "Dll1.h"
void Point::output(int x,int y)
{
HWND hwnd=GetForegroundWindow(); //返回调用者进程当前正在使用的那个窗口的句柄。
HDC hdc=GetDC(hwnd); //获取DC
char buf[20];
memset(buf,0,20);
sprintf(buf,"x=%d,y=%d",x,y);
TextOut(hdc,0,0,buf,strlen(buf)); //输出坐标
ReleaseDC(hwnd,hdc); //释放DC
}
void Point::test()
{
}
三、解决名字改编问题
1、解决C++和C语言之间的命名改编
希望动态链接库文件在编译时,导出函数的名称不要发生改变。为了实现这一目的,在定义导出函数时,需要加上限定符:extern "C"
注意双引号中的"C"字母一定要大写。
在.h文件中(Dll1.h)
#ifdef DLL1_API
#else
#define DLL1_API extern "C" _declspec(dllimport)
#endif
DLL1_API int add(int a,int b);
DLL1_API int subtract(int a,int b);
在.cpp文件中
#define DLL1_API extern "C" _declspec(dllexport)
#include "Dll1.h"
int add(int a,int b)
{
return a+b;
}
int subtract(int a,int b)
{
return a-b;
}
利用限定符:extern "C"可以解决C++和C语言之间相互调用时函数命名的问题。但是这种方法有一个缺陷,就是不能用于导出一个类的
成员函数,只能用于导出全局函数这种情况。
2、通用的解决语言之间命名改编
通过一个称为模块定义文件(DEF)的方式来解决名字改编
.cpp文件中函数
int add(int a,int b)
{
return a+b;
}
int subtract(int a,int b)
{
return a-b;
}
然后建立一个.def的文件,选择【Project\Add To Project\Files...】菜单项,然后弹出"Insert Files into Project" 将.def
文件加入到工程中。其中.def文件中添加如下代码
LIBRARY Dll2
EXPORTS
add
subtract
当连接器在链接时,会分析DEF文件,当发现EXPORTS语句下面的add和subtract这两个符号名,并且他们与源文件中定义的add和
subtract函数的名字是一样的时候,它就会以add和subtract这两个符号名导出相应的函数。如果将要导出的符号名和源文件中
定义的函数名不一样,则可以安装下述语法指定导出函数:
entryname=internalname
其中等号左边的entryname项是导出的符号名,右边的internalname项是DLL中将要导出的函数的名字。
四、显式加载dll
HINSTANCE hInst;
hInst=LoadLibrary("Dll2.dll"); //动态加载DLL
typedef int (*ADDPROC)(int a,int b); //定义函数指针类型
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add"); //获取DLL的导出函数
if(!Add)
{
MessageBox("获取函数地址失败!");
return;
}
CString str;
str.format("5+3=%d",Add(5,3));
MessageBox(str);
1、调用约定
int _stdcall add(int a,int b)
{
return a+b;
}
int _stdcall subtract(int a,int b)
{
return a-b;
}
//客户端调用
HINSTANCE hInst;
hInst=LoadLibrary("Dll2.dll"); //动态加载DLL
typedef int (_stdcall *ADDPROC)(int a,int b); //定义函数指针类型
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,"add"); //获取DLL的导出函数
if(!Add)
{
MessageBox("获取函数地址失败!");
return;
}
CString str;
str.format("5+3=%d",Add(5,3));
MessageBox(str);
当DLL中导出函数采用的是标准调用约定时,访问该DLL的客户端程序也应采用该约定类型来访问相应的导出函数。
2、根据序号访问DLL中的导出函数
HINSTANCE hInst;
hInst=LoadLibrary("Dll2.dll"); //动态加载DLL
typedef int (*ADDPROC)(int a,int b); //定义函数指针类型
ADDPROC Add=(ADDPROC)GetProcAddress(hInst,MAKEINTRESOURCE(1)); //获取DLL的导出函数
if(!Add)
{
MessageBox("获取函数地址失败!");
return;
}
CString str;
str.format("5+3=%d",Add(5,3));
MessageBox(str);