c++中静态库和动态库的创建和使用以及java调用动态库
·
环境
windows10
Visual Studio 2022
graalvm17
静态库
- 静态库的创建
创建空的C++项目,项目名Project1
头文件中写入
//文件:mydll.h
#pragma once //这个意思大概是只引入一次
//下面使用宏的方式来判断是否引入了静态库
#ifndef MYDLL_H
#define MYDLL_H
//添加内容
#include <iostream>
using namespace std;
namespace cbb {
template<typename T> T max(T& a, T& b);
class People {
public:
string name;
int age;
void sayHello();
};
}
#endif // !MYDLL_H
创建cpp文件
//文件:mydll.cpp
#include <iostream>
#include "mydll.h"
using namespace std;
namespace cbb {
template<typename T> T max(T& a, T& b) {
if (a >= b)
{
return a;
};
return b;
};
void People::sayHello() {
cout << "hello" << endl;
};
}
然后去修改项目的类型(属性-》配置属性-》常规-》配置类型-》静态库)

最后就是生成里面重新生成解决方案,可以在控制台中生成了Project1.lib,此时静态库就做好了。
已启动重新生成...
1>------ 已启动全部重新生成: 项目: Project1, 配置: Debug x64 ------
1>mydll.cpp
1>Project1.vcxproj -> D:\app\C_data\c3\Project1\x64\Debug\Project1.lib
========== “全部重新生成”: 1 成功,0 失败,0已跳过 ==========
小结:
静态库做好后一共有两个文件,一个是mydll.h,一个是Project1.lib.(其中h文件是给使用者提供参考的,但并不能看到具体的实现代码,lib文件并不能查看内容,存放的是头文件的实现部分。)
因此创建静态库时,头文件应该和项目名字一样,这样h文件和lib文件名字就一样了,就不会让别人看不懂他们的关系。
- 静态库的使用
创建控制台程序,并且添加连接器
使用include引入头文件,使用pragma引入lib

动态库
- 动态库的创建。
创建空项目dm,修改属性里配置类型为 动态库(dll)
创建dm.h文件
// dm.h文件
#pragma once
#ifndef DM_H //使用if语句,避免频繁引入
#define DM_H
#ifdef _DM_H_API //dll项目中预处理器中添加_DM_H_API,这样即可动态选择是导入还是导出
#define DM_H_API extern "C" __declspec(dllexport)
#else
#define DM_H_API extern "C" __declspec(dllimport)
#endif
//使用C的方式进行导出或导入,避免函数名字乱码,所以使用 extern "C"
//dll项目中是导出__declspec(dllexport),其他项目使用时要导入 __declspec(dllimport)
//添加方法
#include <iostream>
using namespace std;
DM_H_API string sayHello();
#endif // !DM_H
dm.cpp中添加实现,这里不再赘述。
2.动态库的使用
创建控制台程序调用dll
隐式方式调用,(和静态库调用一样)
#include <iostream>
#include "../dm/dm.h"
#pragma comment(lib,"../dm/x64/Debug/dm.lib")
// 引入h文件,然后引入lib。和静态库文件不同的是:需要将dll文件放置到项目目录下
using namespace std;
int main()
{
string hell= sayHello();
cout << hell << endl;
}
动态调用方式
// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include "../dm/dm.h" // 动态调用时无需引入lib。h文件也可以不引入。但为了查看函数时方便,一般会引入
//#pragma comment(lib,"../dm/x64/Debug/dm.lib")
#include <Windows.h>
using namespace std;
typedef string(*PsayHello)(); //声明方法,这个方法和h文件内的方法一样,不同的是这是个指针方法。
//把h文件内的方法粘贴过来,直接在函数名前加上*号就行了
int main()
{
HMODULE hDLL= LoadLibrary(L"dm.dll"); //加载库
PsayHello psayHello=(PsayHello) GetProcAddress(hDLL, "sayHello"); //得到库方法
string hell= psayHello(); //调用方法
FreeLibrary(hDLL); //释放内存
cout << hell << endl;
}
小结:动态库一共包含三个文件,头文件h,链接文件lib,以及内容的实现dll。静态调用时需要引入h和lib,但同时也需要引入dll,否则将找不到实现的内容。动态调用时只需引入dll文件即可,无需h和lib
java调用动态库
使用Jna来调用库
- 导入java包
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.2.0</version>
</dependency>
- 编写接口
package com.example;
import com.sun.jna.*;
public interface HelloDll extends Library {
//加载dll文件
HelloDll INSTANCE= (HelloDll)Native.loadLibrary("d:/dm.dll",HelloDll.class);
//添加方法,这个方法要和dll内的一致,指针类型需要特殊对待
//参考 https://www.linuxidc.com/Linux/2014-04/99688p2.htm
int add(int a,int b);
String sayHello();
}
- 使用
package com.example;
public class App
{
public static void main( String[] args )
{
// System.setProperty("jna.encoding", "GBK");
//String sayHello = HelloDll.INSTANCE.sayHello();
//报错:Exception in thread "main" java.lang.Error: Invalid memory access 经查询大概是参数类型不对
// System.out.println(sayHello);
//调用dll的add方法
int add = HelloDll.INSTANCE.add(11, 12);
System.out.println(add);
}
}
测试Jna时修改了dll文件(加入了一个add方法)
#define DM_H
#ifdef _DM_H_API
#define DM_H_API extern "C" __declspec(dllexport)
#else
#define DM_H_API extern "C" __declspec(dllimport)
#endif
//添加方法
#include <iostream>
using namespace std;
DM_H_API string sayHello();
DM_H_API int add(int a,int b);
#endif // !DM_H
在调用sayHello方法时,出现了错误,有人知道这是为什么吗? 难道真的不能用String来接收吗????
更多推荐
所有评论(0)