本文只是记载下学习C++动态链接库的过程以及记录学习过程中的一些程序,好开始。
先用VS2010创建一个dll的工程,好,只看图不说话,点击finish就完成创建了。。。
创建头文件developer_dll.h和源代码developer_dll.cpp两个文件,里面可以写你喜欢的函数以及类。
以下是我的.h和.cpp文件代码:
developer_dll.h:
#pragma once
#ifdef dev_dll_api
#else
#define dev_dll_api _declspec(dllimport)
#endif
namespace developer_dll_namespace
{
dev_dll_api void add(int a, int b);
dev_dll_api void subtract(int a, int b);
class dev_dll_api developer_dll_class
{
public:
void class_add(int a, int b);
void class_subtract(int a, int b);
protected:
private:
int x;
int y;
};
}
developer_dll.cpp:
#include
#define dev_dll_api _declspec(dllexport)
#include "developer_dll.h"
namespace developer_dll_namespace
{
void add(int a, int b)
{
std::cout<<"两者之和(调用普通函数):"<b)?(a-b):(b-a))<y)?(x-y):(x-y))<
好,搞定这两个就可以build生成.lib以及.dll文件了,看图:
然后就可以创建使用者的.h文件和.cpp文件来加载dll,在程序中加载DLL有两种方法,分别为隐式链接和动态加载dll,隐式链接需要(.lib、.dll、.h)文件,动态加载dll只需(.dll)文件就可以了。
创建源代码user_dll.cpp来测试dll。
将(.lib、.dll、.h)文件复制进来并且创建相应的文件夹。
在这里将lib的路径加进去,不然编译链接会出错。
下面是我的user_dll.cpp:
#include
#include
#include "developer_dllh/developer_dll.h"
#pragma comment(lib, "developer_dll.lib")
using namespace std;
using namespace developer_dll_namespace;
int main()
{
add(2,3);
subtract(2,3);
developer_dll_class users;
users.class_add(2,3);
users.class_subtract(2,3);
system("pause");
return 0;
}
运行测试一把:我的结果是这样的:
那如果我们只想导出类的部分函数要怎么导出:
这里我们可以利用depends这个软件来查看dll导出了哪些函数:
这里为什么函数名会是这样子呢,主要是C++为了实现重载实现了函数倾轧,函数名就按照一定的规则发生的变化,只要都是C++是可以正常调用的。如果要用C语言调用dll,就要添加extern “C”,但是它不能用于导出类的成员函数。如果是给其他语言调用则使用extern “C”也没有卵用。要避免这个问题就得使用模块定义文件.def,待会就测试这个怎么使用。
add(2,3);
subtract(2,3);
developer_dll_class users;
users.class_add(2,3);
//users.class_subtract(2,3); 这个成员函数没有导出,所以不能用了。
system("pause");
return 0;
好我们测试一把:
2、好下面来实现动态链接dll:
这里需要用到几个函数:
LoadLibrary:
[格式]:
[功能]:加载由参数 LibFileName 指定的 DLL 文件。
如果函数操作成功,将返回装载 DLL 库模块的实例句柄,否则,将返回一个错误代码。假如在应用程序中用 LoadLibrary 函数装入某一个 DLL 前, 其他应用程序已把该 DLL 装入内存中了,则系统将不再装入该 DLL 的另一个实例,而是使该 DLL 的“引用计数”加 1 。
GetProAccess:
[格式]:
int main()
{
HMODULE load_ex = LoadLibrary(_T("developer_dll.dll"));//返回一个句柄
if (load_ex)
{
addprt add = (addprt)GetProcAddress(load_ex,"?add@developer_dll_namespace@@YAXHH@Z");
if (add)
{
add(2,3);
}
subtractprt subtract = (subtractprt)GetProcAddress(load_ex,"?subtract@developer_dll_namespace@@YAXHH@Z");
if (subtract)
{
subtract(2,3);
}
}
如果该函数执行成功,则返回 DLL 中由参数 ProcName 指定的过程或函数的入口地址,否则返回 nil 。
FreeLibrary:
[功能]:返回参数 Module 指定的模块中,由参数 ProcName 指定的过程或函数的入口地址。
[格式]:
[说明]:将由参数 Module 指定的 DLL 文件从内存中卸载 1 次。
[说明]:Module 为 DLL 库的句柄。这个值由 LoadLibrary 返回。由于 DLL 在内存中只装载一次,因此调用 FreeLibrary 首先使 DLL 的引用计数减 1,如果计数减为 0 则卸载该 DLL。
上面函数说明是从这里摘下来的,感兴趣可以去阅读https://www.cnblogs.com/westsoft/p/5936092.html
现在测试以导出文件(.def)的方式导出dll,在工程里面添加.def文件。
下面是我的源文件:
//.cpp文件
#include
#include "developer_dllmd.h"
namespace developer_dll_namespace
{
void add(int a, int b)
{
std::cout<<"两者之和(调用普通函数):"<b)?(a-b):(b-a))<y)?(x-y):(y-x))<
//.h文件
#pragma once
namespace developer_dll_namespace
{
void add(int a, int b);
void subtract(int a, int b);
#if 0
class developer_dll_class
{
public:
void class_add(int a, int b);
void class_subtract(int a, int b);
protected:
private:
int x;
int y;
};
#endif
}
//.def文件
LIBRARY "developer_dllmd"
EXPORTS
add @1
export_subtract=subtract @2
下面编写user函数实现动态调用:
#include
#include
#include
#include
using namespace std;
typedef void (*addprt)(int a, int b);
typedef void (*subtractprt)(int a, int b);
int main()
{
HMODULE load_ex = LoadLibraryA("developer_dllmd.dll");//返回一个句柄
if (load_ex)
{
addprt add = (addprt)GetProcAddress(load_ex,"add");
if (add)
{
add(2,3);
}
addprt add1 = (addprt)GetProcAddress(load_ex,MAKEINTRESOURCEA(1));
if (add1)
{
cout<<"通过序号调用:"<<"\t";
add1(2,3);
}
else
{
cout<<"获取地址失败"<
FreeLibrary(load_ex);
system("pause");
return 0;
}
好测试一把,我们看下结果如何:
对于类的动态导出其实文中方法不太好,还有更好的方法下会解说。
好,文章到此结束,谢谢观看,欢迎提问,共同讨论和提高。