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

本文详细介绍了如何使用Java的JNA库来调用C++编写的DLL动态链接库。从JNA的基本概念到DLL的内容解析,再到Java中模拟DLL结构体的实现,以及调用DLL主程序的示例代码,覆盖了所有关键步骤。在调用过程中需要注意结构体数组的处理方式和结构体参数的传递方式。文章最后总结了调用DLL时的注意事项。
摘要由CSDN通过智能技术生成

内容说明

本文主要是我在做项目中,甲方用的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的小例子,例子虽小,五脏俱全,基本上涵盖了所有的内容。研究不易,如果该文章对您有帮助,希望

  • 10
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JNAJava Native Access)是一个用于在Java程序中调用本地代码(如C、C++等)的库。它通过简化调用本地函数的过程,提供了一种简单而又直观的方式来将Java代码与底层的dll文件进行交互。 下面是一个简单的JNA调用dll的示例: 首先,需要下载并导入JNA库。可以从官方网站(https://github.com/java-native-access/jna)上下载最新版本的JNA库。将下载的jar文件导入到你的Java项目中。 接下来,我们先创建一个Java接口,用于定义我们要调用的本地函数,示例代码如下: ```java import com.sun.jna.Library; import com.sun.jna.Native; public interface MyDll extends Library { MyDll INSTANCE = Native.loadLibrary("mydll", MyDll.class); void helloWorld(); } ``` 在上面的代码中,我们定义了一个MyDll接口,它继承了JNA的Library接口。然后,我们使用Native.loadLibrary方法加载我们的dll文件,这里假设我们的dll文件名为"mydll"。 接下来,我们在Java代码中调用dll的函数,示例如下: ```java public class Main { public static void main(String[] args) { MyDll.INSTANCE.helloWorld(); // 调用dll中的helloWorld函数 } } ``` 在上面的代码中,我们通过MyDll.INSTANCE对象来调用dll中定义的helloWorld函数。这样,我们就能够在Java中成功调用dll函数了。 需要注意的是,在实际使用过程中,需要根据dll文件中函数的参数及返回值类型,在接口中定义对应的方法。 通过以上步骤,我们可以成功地使用JNA调用dll。这种方式非常方便,使得Java程序与本地代码的集成更加简单和高效。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值