VS2019 使用 C/C++ 动态链接库 并 进行调用

 

vs2019生成dll并调用的实现示例:https://www.jb51.net/article/179759.htm

 

vs2017创建linux c++程序:https://blog.csdn.net/qingyulove/article/details/86659726

vs2019编写Linux c/c++项目:https://blog.csdn.net/mmmsss987/article/details/103518996

Visual Studio 2019 基于Linux平台的C++开发:https://www.cnblogs.com/sgawscd/p/12916544.html

 

 

1. VS 中生成动态链接库的三种方式(导出函数)

 

开发环境:VS2019

 

创建动态链接库项目

新建项目,搜索 DLL ,选择 “ 具有导出项的(DLL)动态链接库 ”,

输入项目名称,选择项目所在目录,然后点击 创建

生成如下图所示的文件结构:

 

 

导出动态链接库

 

方法一 :声明导出

 

1、以 C++ 的方式声明导出。

在 CPP_DLL.cpp 文件中添加下面的函数,在函数声明前添加 _declspec(dllexport) 关键字

// C++ 的方式声明导出
_declspec(dllexport) int addFunc(int a, int b);
int addFunc(int a, int b)
{
    return a + b;
}

示例截图:

 

2、以 C 的方式声明导出。

在 CPP_DLL.cpp 文件中添加下面的函数,在函数声明前添加 extern "C"  _declspec(dllexport) 关键字

// C 的方式声明导出
extern "C"
{
	_declspec(dllexport) int subFunc(int a, int b);
	int subFunc(int a, int b)
	{
		return a + b;
	}

}

示例截图:

然后点击 “ 生成解决方案 ” ,就可以在工程目录的 debug 目录或者 release 目录下(这取决你生成的是debug版本还是release版本)生成了动态链接库的相关文件。第三方调用时关键的文件为 .lib文件.dll文件 以及工程目录下的 .h头文件

 

 

方法二: 模块定义文件导出

在项目中定义CPP_DLL.def 文件,该文件为模块导出文件

在 CPP_DLL.cpp 文件中添加下面的函数

LIBRARY
EXPORTS
  mulFunc
  divFunc

示例截图:

 

如果是 VS 平台,必须要在 连接器 中添加 .def 文件

然后点击 “ 生成解决方案 ” ,就可以在工程目录的 debug 目录或者 release 目录下(这取决你生成的是debug版本还是release版本)生成了动态链接库的相关文件。第三方调用时关键的文件为 .lib文件.dll文件 以及工程目录下的 .h头文件

对应 的 DLL 和 lib 文件

 

 

 

2. 调用前面开发的动态链接库

 

1. 新建一个C/C++项目(test)

 

 

2. 将第三方库的 .h文件、.lib文件、.dll文件 复制进工程项目中

        .dll文件是程序运行需要载入的动态链接库,VS中调试时可以通过 项目->属性->调试->环境 栏目添加.dll文件的 path 而成功调试,但在独立运行.exe程序是须将.dll文件放到同一目录下。

        因此建议直接将 .dll文件 放入debug目录下或release目录下.h头文件.lib库文件 可以随意放置,只要是能够通过路径找到即可,为了方便管理,建议建立文件夹,放置在项目目录下。

 

 

3. 在项目中调用第三方库

 

有三种方法可以调用第三方库。

 

(1)直接在代码前添加引用

因为直接引用 CPPDLL.h 头文件,所以需要把 动态链接库的 函数声明放在头文件中。

修改 CPP_DLL 的 .h 文件 和 cpp 文件,把 函数 声明放在 .h 中,函数定义放在 cpp 文件中。

CPP_DLL.h

// C++ 的方式声明导出
_declspec(dllexport) int addFunc(int a, int b);

// C 的方式声明导出
extern "C"
{
	_declspec(dllexport) int subFunc(int a, int b);
}

int mulFunc(int a, int b);
double divFunc(double a, double b);

CPP_DLL.cpp

int addFunc(int a, int b)
{
    return a + b;
}

int subFunc(int a, int b)
{
	return a - b;
}


// def 文件形式
int mulFunc(int a, int b)
{
	return a * b;
}

double divFunc(double a, double b)
{
	return a / b;
}

重新生成 DLL 文件,并将 DLL  、lib 、.h 文件拷贝到对应目录

 

C++ 测试代码:

#include <iostream>
#include "./CPP_DLL.h"   //通过相对路径或绝对路径添加头文件
#pragma comment (lib,"./CPPDLL.lib")  // 添加 lib 文件


int main()
{
    std::cout << "Hello World!\n";
    std::cout << addFunc(1, 2) << std::endl;
    std::cout << subFunc(3, 4) << std::endl;
    std::cout << mulFunc(5, 6) << std::endl;
    std::cout << divFunc(7, 8) << std::endl;
}

运行结果截图:

 

 

(2)在解决方案管理面板中添加头文件和资源文件

添加一个现有项头文件,在文件夹中找到第三方库的头文件( CPP_DLL.h ),添加进新建立的项目。
添加一个现有项资源文件,在文件夹中找到第三方库的库文件( CPPDLL.lib ),添加进新建立的项目。

 

 

(3)在 项目属性 -> 设置 中 添加 头文件库文件

  • 项目->属性->VC++目录->包含目录 中添加第三方库的 头文件
  • 库目录 下 添加 第三方库 的 库文件(.lib文件)
  • 项目->属性->链接器->输入->附加依赖项中输入 库文件名称

在函数中调用第三方库中的函数

#include <iostream>


int main()
{
    std::cout << "Hello World!\n";
    std::cout << addFunc(1, 2) << std::endl;
    std::cout << subFunc(3, 4) << std::endl;
    std::cout << mulFunc(5, 6) << std::endl;
    std::cout << divFunc(7, 8) << std::endl;
}

 

 

4. 直接在代码里 load 动态库dll文件即可

这种方法不需要 include .h文件,不需要添加 lib库 和 lib库路径,

  • 引入 windows.h(必须)
  • 在 main 函数写下列语句调用 dll

        因为 C++ 声明 的 动态链接库会发生 Name Mangling,导致 编译后的函数名字会发生变化,所以需要使用 工具 查看 编译编译后的 动态链接库 对应的函数名。

        而 extern "C" 声明的 和 def 文件声明的,编译后的函数名不会发生变化,可以直接使用。

VS2019 自带的工具 dumpbin.exe 可以查看编译后的 动态链接库对应的 函数名。

打开命令行,输入命令 dumpbin -exports CPPDLL.dll

结果截图:

所以 addFunc 不能直接使用,只能用被 name Mangling 后的名字 ,这里  addFunc 编译后的名字是 ?addFunc@@YAHHH@Z

示例程序代码:

#include <iostream>
#include <windows.h>


// 加、减、乘 都是 int 类型
typedef int(*lpFunc)(int a, int b); //后边为参数,前面为返回值

// 除法 是 double 类型
typedef double(*lpFuncD)(double a, double b); //后边为参数,前面为返回值


int main()
{
    std::cout << "Hello World!\n";

	HMODULE hModule;
	hModule = LoadLibrary(L"CPPDLL.dll"); //调用DLL	

	lpFunc lpfunc = NULL;

	// GetProcAddress为获取该函数的地址 
	// "?addFunc@@YAHHH@Z" 这个就是 C++  Name Mangling后的 addFunc 的函数名
	lpfunc = (lpFunc)GetProcAddress(hModule, "?addFunc@@YAHHH@Z");
    std::cout << lpfunc(1, 2) << std::endl;

	/* 使用 C extern 和 def 文件定义的动态链接库,函数名不会发生变化 */
	lpfunc = (lpFunc)GetProcAddress(hModule, "subFunc");
	std::cout << lpfunc(3, 4) << std::endl;

	lpfunc = (lpFunc)GetProcAddress(hModule, "mulFunc");
	std::cout << lpfunc(5, 6) << std::endl;

	lpFuncD lpfuncd = NULL;
	lpfuncd = (lpFuncD)GetProcAddress(hModule, "divFunc");
	std::cout << lpfuncd(7, 8) << std::endl;
	
	//释放
	FreeLibrary(hModule);	
}

运行结果:

 

 

方法 5:使用 lib 文件 和 dll 文件

  • CPPDLL.dll 文件放到 debug 目录下,
  • 然后在项目中引入 CPPDLL.lib 文件。 链接器 -> 输入 -> 附加依赖项 -> 编辑

示例代码:

#include <iostream>


// addFunc 是使用 C++ 方式声明的,
_declspec(dllimport) int addFunc(int a, int b);

//subFunc 是 使用 extern "C" 声明的
extern "C" _declspec(dllimport) int subFunc(int a, int b);

// mulFunc 和 divFunc 是 使用 def 声明的
_declspec(dllimport) int mulFunc(int a, int b);
_declspec(dllimport) double divFunc(double a, double b);


int main()
{
    std::cout << "Hello World!\n";

    std::cout << addFunc(1, 2) << std::endl;
    std::cout << subFunc(3, 4) << std::endl;
    std::cout << mulFunc(5, 6) << std::endl;
    std::cout << divFunc(7, 8) << std::endl;

    return 0;
}

运行结果:

还可以结合 第一种方法,使用  #pragma comment (lib,"./CPPDLL.lib")  //添加 lib 文件 

这样就不用 手动设置 添加 lib 文件了

#include <iostream>
#pragma comment (lib,"./CPPDLL.lib")


// addFunc 是使用 C++ 方式声明的,
_declspec(dllimport) int addFunc(int a, int b);  // 声明 addFunc 函数

//subFunc 是 使用 extern "C" 声明的
extern "C" _declspec(dllimport) int subFunc(int a, int b);  // 声明 subFunc 函数

// mulFunc 和 divFunc 是 使用 def 声明的
_declspec(dllimport) int mulFunc(int a, int b);             // 声明 mulFunc 函数
_declspec(dllimport) double divFunc(double a, double b);    // 声明 divFunc 函数


int main()
{
    std::cout << "Hello World!\n";

    std::cout << addFunc(1, 2) << std::endl;
    std::cout << subFunc(3, 4) << std::endl;
    std::cout << mulFunc(5, 6) << std::endl;
    std::cout << divFunc(7, 8) << std::endl;

    return 0;
}

 

 

 

 

 

使用VS2015编译和调用动态链接库dll 1. 首先建工程,选择dll,记得勾上“导出符号” 后面不用自己搞那些宏定义会省事很多。 建立工程myDll,记得勾上“导出符号” 类型选择dll 2. IDE自动生成的代码已经把整个架构弄好了,其中和项目同名的.h和.cpp文件就是我们自己写代码的地方了。我想写的dll是导出一个类,在这里我就直接在它自动生成的CmyDll类上面改了。 myDll.h myDll.cpp 在mydll.h和mydll.cpp中给类添加成员函数 //mydll.h class MYDLL_API CmyDll { public: CmyDll(void); // TODO: 在此添加您的方法。 int myFunction(int a, int b); }; //mydll.cpp int CmyDll::myFunction(int a, int b) { return a*b; } 3.编译的时候我选择了release,这里可以用默认的debug也行 在mydll.h和mydll.cpp中给类添加成员函数 最后生成解决方案后产生的mydll.lib和mydll.dll就是我们需要的二进制文件了。lib文件是编译是要用的,而dll调用这个库的程序运行时需要的。 调用dll 1.重新建立一个工程 这回选择普通的控制台程序就行了。我建了个名为myDllCall的工程。 2.把库的头文件include进来,以及连接lib文件 其中 include进来的 myDll.h 和 **#pragma comment()**的lib根据自己的路径写。 #include "stdafx.h" #include "../../myDll/myDll/myDll.h" //头文件 #pragma comment(lib,"../../myDll/Release/myDll.lib") //调用自己写的外部库 #include int main() { CmyDll mydll; int a, b; std::cin >> a >> b; std::cout << mydll.myFunction(a, b) <> a >> b; std::cout << mydll.myFunction(a, b) << std::endl; return 0; } 3.dll放到可执行文件同一目录下面 刚刚的代码直接编译没问题,运行会报错. 直接编译没问题,运行会报错 原因是dll要和生成的可执行文件在同一个目录下,我把mydll.dll放进去之后就解决了。 我们成功的在自己的工程里调用了外部的类 可以看到我们成功的在自己的工程里调用了外部的类。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值