使用jna,实现java代码调用dll程序

本文详细介绍了如何使用Java的JNA库调用C/C++编写的dll程序,包括各种数据类型的映射转换,如bool、char、short、int、float、double、long以及字符串和结构体等。同时,对比了JNI和JNA在性能和编程便捷性上的差异,指出JNA在编程上更简单,但JNI性能更优。文章还提供了C++头文件的接口定义和Java代码示例,展示了具体的调用过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用JNA,实现java代码调用dll程序

性能上 JNIJNA 有优势,编程上 JNA JNI 更方便,看情况进行取舍。针对 JNIJNA 的区别,在文末会有介绍。

本次我们使用 JNA 来实现java调取 C/C++ 函数。

一、常见数据类型的映射转换

C/C++类型Java 类型原生表现
boolboolean32位(同平台有关,可定制)
boolbyte如果在结构体中只能映射成byte
charbyte8位整数
wchart_tchar平台依赖
shortshort16位整数
intint32位整数
floatfloat32位浮点数
doubledouble64位浮点数
longNativeLong如果在结构体中只能映射成NativeLong
long long,_int64long64位整数
const char*String\0结尾的字符数组
char**String[]字符串数组
const wchar_t*WString\0结尾的数组(unicode字符串)
wchar_t**WString[]字符串数组(unicode)
void*Pointer表示指向任何东西的指针
char*Pointer表示指向任何东西的指针
char*&Pointer表示指向任何东西的指针
int&IntByReference表示指向int类型的指针
char*ByteByReference表示指向char类型的指针
int*IntByReference表示指向int类型的指针
float*FloatByReference或Pointer表示指向float类型的指针
double*DoubleByReference或Pointer表示指向double类型的指针
char&PointerByReference表示指向指针的指针
void **PointerByReference表示指向指针的指针
char**PointerByReference表示指向指针的指针
pointer array[] (基本类型的数组)32位或64位的指针
void**Pointer[]空指针数组
struct*/structStructure结构体指针或者结构体
struct[]Structure[]结构体数组,临接内存
void (*FP)()Callback函数指针
unionUnion联合,等同于结构体
注意点:
  • Structure 子类中的公共字段的顺序,必须与C 语言中的结构的顺序一致。否则会报错!
  • 在结构体中,bool不能映射成boolean,否则会引发内存访问错误。因为在C、C++中的结构体中bool只占一个字节,所以只能映射成byte。如果作为函数的返回值类型,可以映射成boolean。
  • long 在结构体中不能映射成java中的long类型,只能映射成Jna的NativeLong
  • 建议使用对应的ByReference对象替代Pointer,使用Pointer有时可能会得到一个垃圾值(正常情况下两种方式结果一样),如果C中函数执行失败时没有对指针的值进行处理,使用Pointer就会得到一个垃圾值。

二、代码演示

隔了段时间整理的文档,代码有点脏,具体映射写法可以直接跳到三开始看 _

1.代码结构
E:
│  MANIFEST.MF
│  pom.xml
│          
├─src
│  ├─main
│  │  ├─java 
│  │  │      RankLogicGraphTest.java 
│  │  │      Test.java
│  │  └─resources
│  │      └─lib11
│  │              RankLogicGraph.dll
│  │              
│  └─test
│      └─java
2.Java代码——POM文件,添加依赖,引用JNA
 <dependency>
     <groupId>com.sun.jna</groupId>
     <artifactId>jna</artifactId>
     <version>3.0.9</version>
</dependency>
3.Java代码——定义接口类RankLogicGraphTest.java
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.WString;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;

public interface RankLogicGraphTest extends Library {
    //注1——"RankLogicGraph"
    RankLogicGraphTest INSTANCE = (RankLogicGraphTest) Native.loadLibrary("RankLogicGraph", RankLogicGraphTest.class);

    class ST_MyTest extends Structure {
        public int m_num;
        String[] y;
    }
    
    void rankLogicGraphTest();

    String rankLogicGraphAlgorithmJNA(String request);

    void testChar(byte request);

    void testWCharT(char request);

    void testShort(short request);

    void testInt(int request);

    void testFloat(float request);

    void testDouble(double request);

    void testLong(NativeLong request);

    void testString(String request);

    void testConstWCharTx(WString request);

    void testCharXX(String[] request);

    void testWCharTXX(WString[] request);

    void testVoidXX(Pointer[] request);

    void testStruct(ST_MyTest request);

    void testIntRef(IntByReference logicGraphInfo);

    void testIntx(IntByReference logicGraphInfo);

    void testCharRef(PointerByReference logicGraphInfo);

    void rankLogicGraphAlgorithm(String logicGraphInfo, String[] result);

    void rankLogicGraphAlgorithm(Pointer logicGraphInfo, PointerByReference result);

    void rankLogicGraphReleaseResult();

    void rankLogicGraphReleaseResult(PointerByReference result);

    void test11(Pointer pointer, int num);

    int test2(Pointer pointer);

    void testNewCharXRef(Pointer ptrNewCh, int nNum);

    void releasePtrRef(Pointer ptrRelease);
 
    void testNewCharXX(PointerByReference ptrNewCh, int nNum);

    void releasePtr(PointerByReference ptrRelease);
}
4.Java代码——定义测试类Test.java,java调用代码
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.PointerByReference;
import java.io.File;

public class Test {
    static {
        //指定dll的路径,注2:RankLogicGraph.dll
        File file1 = new File("src/main/resources/lib11/RankLogicGraph.dll");
        //系统加载dll
        System.load(file1.getAbsolutePath());
    }

    public static void main(String[] args) throws InterruptedException
    {
        System.setProperty("jna.encoding", "GBK");
        System.out.println("***************************");
        String request = "";
        
        RankLogicGraphTest.INSTANCE.rankLogicGraphTest(); 

        RankLogicGraphTest.ST_MyTest ssss = new RankLogicGraphTest.ST_MyTest();
        ssss.m_num = 12;
        String[] s = {"49","11"};
        ssss.y = s;
        RankLogicGraphTest.INSTANCE.testStruct(ssss);
        System.out.println("-------------");

        String ss = RankLogicGraphTest.INSTANCE.rankLogicGraphAlgorithmJNA(request);
        System.out.println("rankLogicGraphAlgorithmJNA 返回:" + ss.length() + "---" + ss);

        byte b = 97;
        RankLogicGraphTest.INSTANCE.testChar(b);
    }
}
注意点:
  • 注1和注2处,RankLogicGraph 必须和引用的dll名称 保持一致,否则无法找到RankLogicGraph.dll
5.C++头文件定义
#pragma once 
#ifdef RANK_LOGIC_GRAPH_LIB
#ifdef __cplusplus
#define RANK_LOGIC_GRAPH_API  extern "C" __declspec(dllexport)
#else
#define RANK_LOGIC_GRAPH_API __declspec(dllexport)
#endif
#else
#ifdef __cplusplus
#define RANK_LOGIC_GRAPH_API extern "C" __declspec(dllimport)
#else
#define RANK_LOGIC_GRAPH_API __declspec(dllimport)
#endif
#endif

#include <string>

struct ST_MyTest
{
    ST_MyTest() : m_num(5), m_pCh("Struct Test!")
    {
        
    }
    int m_num;
    char y[50];
};

// c、c++接口
RANK_LOGIC_GRAPH_API void  rankLogicGraphAlgorithm2(const std::string& logicGraphInfo, std::string& result);

// java接口,返回结果开辟的内存,需要接口释放,或者再调用接口时释放之前的内存
RANK_LOGIC_GRAPH_API void  rankLogicGraphAlgorithm(const char* logicGraphInfo, char** result);
RANK_LOGIC_GRAPH_API void  rankLogicGraphReleaseResult();

// java接口,返回的结果开辟了足够空间的固定内存,每次调用接口都使用固定内存
RANK_LOGIC_GRAPH_API char* rankLogicGraphAlgorithmJNA(const char* logicGraphInfo);

RANK_LOGIC_GRAPH_API void  rankLogicGraphTest();

RANK_LOGIC_GRAPH_API void testChar(char logicGraphInfo);
RANK_LOGIC_GRAPH_API void testWCharT(wchar_t logicGraphInfo);
RANK_LOGIC_GRAPH_API void testShort(short logicGraphInfo);
RANK_LOGIC_GRAPH_API void testInt(int logicGraphInfo);
RANK_LOGIC_GRAPH_API void testFloat(float logicGraphInfo);
RANK_LOGIC_GRAPH_API void testDouble(double logicGraphInfo);
RANK_LOGIC_GRAPH_API void testLong(long logicGraphInfo);

RANK_LOGIC_GRAPH_API void testIntRef(int& logicGraphInfo);
RANK_LOGIC_GRAPH_API void testIntx(int* logicGraphInfo);
RANK_LOGIC_GRAPH_API void testCharRef(char& logicGraphInfo);
RANK_LOGIC_GRAPH_API void testString(const char* logicGraphInfo);
RANK_LOGIC_GRAPH_API void testConstWCharTx(const wchar_t* logicGraphInfo);

RANK_LOGIC_GRAPH_API void testCharXX(char** logicGraphInfo);
RANK_LOGIC_GRAPH_API void testWCharTXX(wchar_t** logicGraphInfo);

RANK_LOGIC_GRAPH_API void testVoidX(void* logicGraphInfo);
RANK_LOGIC_GRAPH_API void testVoidXX(void** logicGraphInfo);
RANK_LOGIC_GRAPH_API void testStructX(ST_MyTest* logicGraphInfo);
RANK_LOGIC_GRAPH_API void testStruct(ST_MyTest logicGraphInfo);

RANK_LOGIC_GRAPH_API void test1(void** pHandle, int num);
RANK_LOGIC_GRAPH_API int test2(void* pHandle);

RANK_LOGIC_GRAPH_API void test11(void* pHandle, int num);

RANK_LOGIC_GRAPH_API void testNewCharXRef(char*& ptrNewCh, int nNum);
RANK_LOGIC_GRAPH_API void  releasePtrRef(char*& ptrRelease);

RANK_LOGIC_GRAPH_API void testNewCharXX(char** ptrNewCh, int nNum);
RANK_LOGIC_GRAPH_API void testNewCharXX2(char** ptrNewCh, int nNum);
RANK_LOGIC_GRAPH_API void  releasePtr(char** ptrRelease);

三、C++与java代码映射拆分

C/C++类型Java 类型原生表现
boolboolean32位(同平台有关,可定制)
//Java接口定义
void testBool(boolean request);  
//C++头文件定义
RANK_LOGIC_GRAPH_API void testBool(bool b); 
//Java调用
RankLogicGraphTest.INSTANCE.testBool(true); 
C/C++类型Java 类型原生表现
charbyte8位整数
//Java接口定义
void testChar(byte request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testChar(char logicGraphInfo);
//Java调用
byte b = 97;
RankLogicGraphTest.INSTANCE.testChar(b);
C/C++类型Java 类型原生表现
wchart_tchar平台依赖
//Java接口定义
void testWCharT(char request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testWCharT(wchar_t logicGraphInfo);
//Java调用
char c1 = 'a';
RankLogicGraphTest.INSTANCE.testWCharT(c1);
C/C++类型Java 类型原生表现
shortshort16位整数
//Java接口定义
void testShort(short request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testShort(short logicGraphInfo);
//Java调用
short s1 = 34;
RankLogicGraphTest.INSTANCE.testShort(s1);
C/C++类型Java 类型原生表现
intint32位整数
//Java接口定义
void testInt(int request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testInt(int logicGraphInfo);	
//Java调用
int i1 = 13;
RankLogicGraphTest.INSTANCE.testInt(i1);
C/C++类型Java 类型原生表现
floatfloat32位浮点数
//Java接口定义
void testFloat(float request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testFloat(float logicGraphInfo);
//Java调用
float f1 = 23.1f;
RankLogicGraphTest.INSTANCE.testFloat(f1);
C/C++类型Java 类型原生表现
doubledouble64位浮点数
//Java接口定义
void testDouble(double request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testDouble(double logicGraphInfo);
//Java调用
double b1 = 123;
RankLogicGraphTest.INSTANCE.testDouble(b1); 
C/C++类型Java 类型原生表现
longNativeLong
//Java接口定义
void testLong(NativeLong request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testLong(long logicGraphInfo);
//Java调用
NativeLong n1 = new NativeLong(124);
RankLogicGraphTest.INSTANCE.testLong(n1);
C/C++类型Java 类型原生表现
const char*String\0结尾的字符数组
//Java接口定义
void testString(String request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testString(const char* logicGraphInfo);
//Java调用
String str1 = "abcd1";
RankLogicGraphTest.INSTANCE.testString(str1);
C/C++类型Java 类型原生表现
const wchar_t*WString\0结尾的数组(unicode字符串)
//Java接口定义
void testConstWCharTx(WString request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testConstWCharTx(const wchar_t* logicGraphInfo);
//Java调用
WString ws = new WString("qq");
RankLogicGraphTest.INSTANCE.testConstWCharTx(ws); 
C/C++类型Java 类型原生表现
char**String[]字符串数组
//Java接口定义
void testCharXX(String[] request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testCharXX(char** logicGraphInfo);
//Java调用
String[] sss = {"111", "222", "333"};
RankLogicGraphTest.INSTANCE.testCharXX(sss);
C/C++类型Java 类型原生表现
wchar_t**WString[]字符串数组(unicode)
//Java接口定义
void testWCharTXX(WString[] request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testWCharTXX(wchar_t** logicGraphInfo);
//Java调用
WString[] ws1 = {new WString("ss"), new WString("ww"), new WString("qq")};
RankLogicGraphTest.INSTANCE.testWCharTXX(ws1);
C/C++类型Java 类型原生表现
void**Pointer[]空指针数组
//Java接口定义
void testVoidXX(Pointer[] request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testVoidXX(void** logicGraphInfo); 
//Java调用
Pointer p = new Memory(Native.getNativeSize(Integer.class));
Pointer[] ps = {p};
RankLogicGraphTest.INSTANCE.testVoidXX(ps);
C/C++类型Java 类型原生表现
struct*/structStructure结构体指针或者结构体
//Java接口定义
void testStruct(ST_MyTest request);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testStruct(ST_MyTest logicGraphInfo);
//Java调用
RankLogicGraphTest.ST_MyTest ssss = new RankLogicGraphTest.ST_MyTest();
ssss.m_num = 12;
String[] s = {"49","11"};
ssss.y = s;
RankLogicGraphTest.INSTANCE.testStruct(ssss);
C/C++类型Java 类型原生表现
int&IntByReference表示指向int类型的指针
//Java接口定义
void testIntRef(IntByReference logicGraphInfo);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testIntRef(int& logicGraphInfo);
//Java调用
IntByReference pId = new IntByReference();
pId.setValue(11);
RankLogicGraphTest.INSTANCE.testIntRef(pId); 
C/C++类型Java 类型原生表现
int*IntByReference表示指向int类型的指针
//Java接口定义
void testIntx(IntByReference logicGraphInfo);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testIntx(int* logicGraphInfo);
//Java调用
IntByReference pId1 = new IntByReference();
pId1.setValue(22);
RankLogicGraphTest.INSTANCE.testIntx(pId);
C/C++类型Java 类型原生表现
char&PointerByReference表示指向指针的指针
//Java接口定义
void testCharRef(PointerByReference logicGraphInfo);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testCharRef(char& logicGraphInfo);
//Java调用
IntByReference intByReference = new IntByReference(100);
Pointer pInt = intByReference.getPointer();
PointerByReference pointer = new PointerByReference(pInt);
RankLogicGraphTest.INSTANCE.testCharRef(pointer); 
C/C++类型Java 类型原生表现
char**PointerByReference表示指向指针的指针
//Java接口定义
void testNewCharXX(PointerByReference ptrNewCh);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testNewCharXX(char** ptrNewCh);
//Java调用
Pointer pPara3 = new Memory(1024);
PointerByReference pp1 = new PointerByReference(pPara3);
RankLogicGraphTest.INSTANCE.testNewCharXX(pp1);
C/C++类型Java 类型原生表现
char*Pointer表示指向任何东西的指针
//Java接口定义
void testNewCharXRef(Pointer ptrNewCh);
//C++头文件定义
RANK_LOGIC_GRAPH_API void testNewCharXRef(char*& ptrNewCh);
//Java调用
Pointer pPara2 = new Memory(1024);
RankLogicGraphTest.INSTANCE.testNewCharXRef(pPara2);
C/C++类型Java 类型原生表现
void*Pointer表示指向任何东西的指针
//Java接口定义
void testP(Pointer pointer, int num);
//C++头文件定义
RANK_LOGIC_GRAPH_API void test11(void* pHandle);
//Java调用
pPara = Pointer.NULL;//指针置空
RankLogicGraphTest.INSTANCE.testP(pPara);

四、JNI 和 **JNA**的区别:

JNI:
JNI允许Java代码和其他语言(尤其C/C++)写的代码进行交互,只要遵守调用约定即可。首先看下JNI调用C/C++的过程,注意写程序时自下而上,调用时自上而下。步骤非常的多,很麻烦。

img

JNA:
JNA框架解决了既需要编写java代码,又要编写C语言的代理方法及很多数据类型的转换的问题,它提供一组Java工具类用于在运行期动态访问系统本地共享类库而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射,大大降低了Java调用本体共享库的开发难度。

JNA调用C/C++的过程大致如下:

在这里插入图片描述

JNA 调用比 JNI 调用更方便!

JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问动态链接库中的函数。

原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。

JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射,你不再需要编写C动态链接库。

也许这也意味着,使用JNA技术比使用JNI技术调用动态链接库会有些微的性能损失。但总体影响不大,因为JNA也避免了JNI的一些平台配置的开销!

JNA 调用比 JNI 调用性能有损失!

总之,JNA 在编程方面比 JNI 更方便,但是性能上 JNI 比**JNA ** 有优势,看情况进行取舍。

附录:

https://blog.csdn.net/wangzhongyudie/article/details/117228932
https://www.cnblogs.com/gmhappy/p/11864037.html
https://blog.csdn.net/ctwy291314/article/details/84626829
https://blog.csdn.net/xb_2015/article/details/111462459
https://github.com/java-native-access/jna/blob/master/www/Mappings.md

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高考我军

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

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值