Java使用JNA调用C/C++DLL库

1.0 使用Visual Studio 2019编写并生成动态链接库

1.1 创建新项目

在这里插入图片描述

1.2 配置编译平台

根据各自需求选择x64或x86(32位),要与JDK版本匹配才行,不然Java那边编译会报错。
在这里插入图片描述

1.3 编写测试代码

新建项目自带framework.h,pch.h,dllmain.cpp,pch.cpp,我这边只编写了pch.h,pch.cpp这两个文件生成测试接口。

IMPORT_DLL这个宏是声明函数输入,输出。函数、类、数据的声明前加上_declspec(dllexport)的修饰符,表示输出。__declspec(dllexport)在C调用约定、C编译情况下可以去掉输出函数名的下划线前缀。extern "C"使得在C++中使用C编译方式进行兼容。在"C++"下定义"C"函数,需要加extern "C"关键词。用extern "C"来指明该函数使用C编译方式。输出的"C"函数可以从"C"代码里调用。

这边主要测试函数调用,直接对结构体赋值,获取。

pch.h

#ifndef PCH_H
#define PCH_H

#include "framework.h"
#include <string.h>
#include <stddef.h>

#ifdef IMPORT_DLL
#else
#define IMPORT_DLL extern "C" _declspec(dllimport)
#endif

typedef struct {
	int a;
	int b;
	int c;
} CardStruct;

IMPORT_DLL void add();
IMPORT_DLL void set_struct(CardStruct *cs);
IMPORT_DLL CardStruct getCardStruct();

#endif

pch.cpp

#include "pch.h"
#include <iostream>

CardStruct mCs;

void add()
{
	mCs.c = mCs.a + mCs.b;
	std::cout << "C++ c: " << mCs.c << "\n";
}

CardStruct getCardStruct()
{
	return mCs;
}

void set_struct(CardStruct *cs)
{
	mCs.a = cs->a;
	mCs.b = cs->b;
	mCs.c = cs->c;
}

1.4 生成解决方案DLL提取位置

选择生成->生成解决方案
在这里插入图片描述

2.0 Java使用JNA进行DLL库调用

2.1 导入JNA jar包

创建一个Java程序,右键Build Path->Configure Build Path
我这边只导入了jna-4.0.0.jar,jna-platform-4.0.0.jar,版本差异可忽略。自行下载,能用就行。
在这里插入图片描述

2.2 导入DLL动态链接库

我这边直接放在项目根目录
在这里插入图片描述

2.3 Java端验证代码

public class Test {

	public interface CLibrary extends Library {
		CLibrary INSTANCE = (CLibrary) Native.loadLibrary("xxxDll", CLibrary.class);

		int add();
		int test();

		public static class ExtU_DEMO_T extends Structure {

			public static class ByReference extends ExtU_DEMO_T implements Structure.ByReference {
			}

			public static class ByValue extends ExtU_DEMO_T implements Structure.ByValue {
			}

			public int a;
			public int b;
			public int c;

			@Override
			protected List getFieldOrder() {
				List<String> Field = new ArrayList<String>();
				Field.add("a");
				Field.add("b");
				Field.add("c");
				return Field;
			}

		}
		void set_struct(ExtU_DEMO_T.ByReference csbr);
		ExtU_DEMO_T.ByValue getCardStruct();
	}

	public static void main(String[] args) {
		Test.CLibrary.ExtU_DEMO_T.ByReference tccb = new Test.CLibrary.ExtU_DEMO_T.ByReference();
		tccb.a = 12;
		tccb.b = 22;
		CLibrary.INSTANCE.set_struct(tccb);// 设值给DLL
		CLibrary.INSTANCE.add();// 进行运算
		System.out.println("java c: " + tccb.c);
		
		Test.CLibrary.ExtU_DEMO_T.ByValue tcet = CLibrary.INSTANCE.getCardStruct();
		System.out.println("getCardStruct a: " + tcet.a);
		System.out.println("getCardStruct b: " + tcet.b);
		System.out.println("getCardStruct c: " + tcet.c);
	}

}

运行结果:
java c: 0
getCardStruct a: 12
getCardStruct b: 22
getCardStruct c: 34
C++ c: 34

2.4 Java端指针方式操作DLL结构体

public static class AAA extends Structure {
	public AAA() {
		super();
	}

	public AAA(Pointer p) {
		super(p);
	}

	public static class ByReference extends AAA implements Structure.ByReference {
	}

	public static class ByValue extends AAA implements Structure.ByValue {
	}

	public int a;
	public int b;
	public int c;

	@Override
	protected List getFieldOrder() {
		List<String> Field = new ArrayList<String>();
		Field.add("a");
		Field.add("b");
		Field.add("c");
		return Field;
	}
}
// 获取指针地址
Pointer cs = lib.getGlobalVariableAddress("CardStruct");
// 传入指针
AAA a1 = new AAA(cs);
a1.read();
// 给结构体直接赋值
a1.a = 1;
a1.write();
a1.b = 2;
a1.write();
a1.c = 3;
a1.write();

2.5 另一种方式执行函数

这种方式就无需在Java端重复声明int add();

NativeLibrary lib = NativeLibrary.getInstance("xxx.dll");
Function initialize = lib.getFunction("add");
initialize.invoke(new Object[] {});

2.6 使用过程中需要注意事项

  • JDK版本要与DLL生成环境匹配,Java --version可查看jdk环境。
  • loadLibrary路径可调整,并非只能放在工程根目录。
  • extends Library后声明函数,变量要与DLL顺序要对上,据说顺序乱会出问题。
  • 经实际验证,只有通过指针方式才能直接对DLL立面的结构体进行赋值。不然只能改DLL,声明set函数才能赋值。

3.0 JNI与JNA的差异

编写JNI需要集成NDK环境进行编译,生成函数库的头文件,一般提供so/dll都会提供头文件,生成一个native环境下的头文件才能给Java端进行调用。JNI有许多JNI定义的变量类型,操作相对JNA要复杂很多。JNA(Java Native Access)是一个开源的Java框架,是Sun公司推出的一种调用本地方法的技术,是建立在经典的JNI基础之上的一个框架。之所以说它是JNI的替 代者,是因为JNA大大简化了调用本地方法的过程,使用很方便,基本上不需要脱离Java环境就可以完成。

之前写过的一篇关于JNI的博客(Linux环境下编写的demo):https://blog.csdn.net/u012169524/article/details/50830426

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值