利用jna调用dll(史上最全)

Java学习 同时被 2 个专栏收录
4 篇文章 0 订阅
1 篇文章 0 订阅

内容说明

本文主要是我在做项目中,甲方用的java开发的平台,我们写算法嵌入到他们的系统中,本来以为直接用java写就OK了,可是他们要求用c++写说速度快(说实话只要不操作硬件,现在的java虚拟机运行java和c++的执行效率几乎一样)(没办法,只能使用java调用c++生成的dll),这里就不赘述生成dll的方法了,网上多的很。本文主要介绍利用jna调用dll的具体实现,以及在实现过程遇到的坑,基本上含盖了所有内容。
在这期间我使用过

jna介绍

大白话解释就是jna是用来调用dll的jar包,是对jni技术的一个升级,使用起来比jni方便许多。

用到的工具及资料

1.idea2019创建的java的Maven项目;
2.vs2019生成的dll
3.jna的jar包:因为例子是用Maven项目做的,jar包坐标如下:

		<dependency>
            <groupId>com.sun.jna</groupId>
            <artifactId>jna</artifactId>
            <version>3.0.9</version>
        </dependency>

4.jna的官方文档如下(看里面的数据类型转换就可以了,其他看我的例子就ok):
链接:https://java-native-access.github.io/jna/4.2.1/overview-summary.html.

有了上面的准备,下面就开始我们的例子了。

dll中的内容

首先用vs2019写的c++dll的程序如下,该例子主要演示java和c++中的char*、int、double的类型对应(其他的去上面链接的官方文档中寻找),以及对应参数是结构体以及结构体中嵌套结构体,函数返回值也为结构体以及结构体中嵌套结构体。

#define dllTest _declspec(dllexport)

#pragma once

#include <map>
#include <vector>
#include <iostream>
#include <string>

using namespace std;

struct myStruct
{
	int a;
	char* steel;
	int b;
};

struct myStructs
{
	myStruct mS[10];
	int count;
};

extern "C"
{

	dllTest myStruct allroundTest(int i, int j, char* s) {
		mystru.a = i;
		mystru.b = j;
		mystru.steel = s;
		return mystru;
	}

	dllTest myStructs* arrayFun(myStructs* ms) {
		return ms;
	}

	dllTest char* returnChar(myStructs* ms, int i) {
		char* res = ms->mS[i].steel;
		return res;
	}

	dllTest char* returnString(char* ms) {
		return ms;
	}

	dllTest int addNormal(myStruct ms) {
		return ms.b + ms.a;
	}

	dllTest int* test01(int* a) {
		return a;
	}

	dllTest void addPrt(myStruct* ms, int* ret) {
		*ret = ms->a + ms->b + 1;
	}

	dllTest int addRef(myStruct& ms) {
		return ms.a + ms.b + 2;

	}
}

java中利用jna模拟dll中的结构体(利用接口中的内部类模拟)

注意,其中对应结构体中的属性的顺序以及属性名必须和dll中保持一致,还有注意dll存放的位置,我是直接放到jdk的bin目录下,结构体中的ByValue以及ByReference分别对应c++中的引用和指针。

package com.tz;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.ptr.IntByReference;

public interface dllTestApi extends Library {
    
//需将dll放进jdk的bin目录下
    public static dllTestApi dta = (dllTestApi) Native.loadLibrary("PanAlgDLL", dllTestApi.class);

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

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

        public int a;
        public String steel;
        public int b;
        
    }

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

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

        public myStructur.ByValue[] structs = new myStructur.ByValue[10];
        public int count;
    }

    int addNormal(myStructur.ByValue ms);
    void addPrt(myStructur.ByReference pms, IntByReference sum);
    int addRef(myStructur.ByReference rms);
    myStructurs.ByReference arrayFun(myStructurs.ByReference ms);
    String returnString(String ms);
    IntByReference test01(IntByReference a);
    String returnChar(myStructurs.ByReference ms, int i);
    myStructur.ByValue allroundTest(int i, int j, String s);

}

调用dll主程序

下面是调用dll中的方法的测试程序:

package com.tz;

import com.sun.jna.ptr.IntByReference;

public class Test01 {
    public static void main(String[] args) {

        System.setProperty("jna.encoding", "GBK");

        dllTestApi.myStructur.ByReference pmysStructur = new dllTestApi.myStructur.ByReference();
        pmysStructur.a = 1;
        pmysStructur.b = 3;

        IntByReference ib = new IntByReference();
        dllTestApi.dta.addPrt(pmysStructur,ib);
        System.out.println(ib.getValue());

        System.out.println(dllTestApi.dta.addRef(pmysStructur));

        dllTestApi.myStructur.ByValue vmysStructur = new dllTestApi.myStructur.ByValue();
        vmysStructur.a = 1;
        vmysStructur.b = 3;

        System.out.println(dllTestApi.dta.addNormal(vmysStructur));
        IntByReference ibf = new IntByReference(2);
        ibf.setValue(3);
        ibf.setValue(4);

        IntByReference res = dllTestApi.dta.test01(ibf);
        int[] re = res.getPointer().getIntArray(0, 3);
        System.out.println(re[0]);

        dllTestApi.myStructur.ByValue pmys1 = new dllTestApi.myStructur.ByValue();
        pmys1.b = 1;
        pmys1.steel = "abcf";
        pmys1.a = 1;

        dllTestApi.myStructur.ByValue pmys2 = new dllTestApi.myStructur.ByValue();
        pmys2.a = 2;
        pmys2.steel = "asdg";
        pmys2.b = 2;

        dllTestApi.myStructurs.ByReference pmyss = new dllTestApi.myStructurs.ByReference();
        pmyss.structs[0] = pmys1;
        pmyss.structs[1] = pmys2;
        pmyss.count = 2;
        dllTestApi.myStructurs.ByReference ress = dllTestApi.dta.arrayFun(pmyss);
        System.out.println(ress.count);
        System.out.println(ress.structs[1].a);
        String rS = dllTestApi.dta.returnChar(pmyss, 0);
        System.out.println(rS);
 

        String str11 = dllTestApi.dta.returnString("666");
        System.out.println(str11);

        dllTestApi.myStructur.ByValue reess = dllTestApi.dta.allroundTest(6, 6, "tz");
        System.out.println(reess.a);
        System.out.println(reess.steel);
    }
}

利用jna调用dll需要注意的问题

1、想要调用dll中的方法,且调用的方法需要结构体数组参数或者返回值是结构体数组,我们知道c++方法对于结构体数组参数处理起来比较麻烦,所以我解决的办法就是加一个结构体,该结构体中包含结构体数组以及包含的个数,如上面的例子所示;
2、当java要接收dll方法返回结构体参数,尤其当结构体中包含char*时,我们需要在java中将结构体实例化当作参数传入要调用的dll中,并在dll中将要返回的结构体传给java中当作参数的结构对象,不然会报莫名其妙的错(我调试了好久才发现的)。

总结

以上就是java利用jna调用dll的小例子,例子虽小,五脏俱全,基本上涵盖了所有的内容。研究不易,如果该文章对您有帮助,希望

  • 3
    点赞
  • 0
    评论
  • 8
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页

打赏作者

Leo_TianZhuang

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值