java调用c++接口(dll或so动态库)jna的使用

1.什么是jna

jna是Java native access的简称,用他可以调用C、C++接口

2.jna pom坐标

 <dependency>
    <groupId>net.java.dev.jna</groupId>
     <artifactId>jna</artifactId>
     <version>5.5.0</version>
 </dependency>
 <dependency>
     <groupId>net.java.dev.jna</groupId>
     <artifactId>jna-platform</artifactId>
     <version>5.5.0</version>
 </dependency>

3.jna使用

3.1.准备工作:准备一个C++的dll或者so

3.1.1 代码准备(以下为C++代码)

TestDll.cpp:

在这里插入图片描述
代码:

// TestDll.cpp : 定义 DLL 的导出函数。
//

#include "pch.h"
#include "framework.h"
#include "TestDll.h"
#include <iostream>
#include <stdio.h>
using namespace std;


// 这是导出变量的一个示例
TESTDLL_API int nTestDll=0;

// 这是导出函数的一个示例。
TESTDLL_API int fnTestDll(void)
{
    return 0;
}
//普通函数测试
TESTDLL_API int add(int a,int b)
{
    int value = a + b;
    cout << "dll add value=" ; 
    printf("%d", value);
    return value;
}
//被回调函数
TESTDLL_API void jn1() {
    printf("*****************111111**************");
}
//被回调函数
TESTDLL_API void jn2() {
    printf("*****************222222**************");
}

//被回调函数
TESTDLL_API void jn3() {
    printf("*****************333333**************");
}
//测试回调函数
TESTDLL_API void callt(void(*p)(), void(*k)()) {
    p();
    k();
}

// 这是已导出类的构造函数。
CTestDll::CTestDll()
{
    return;
}

TestDll.h:
在这里插入图片描述
代码:

// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 TESTDLL_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// TESTDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef TESTDLL_EXPORTS
#define TESTDLL_API __declspec(dllexport)
#else
#define TESTDLL_API __declspec(dllimport)
#endif

// 此类是从 dll 导出的
class TESTDLL_API CTestDll {
public:
	CTestDll(void);
	// TODO: 在此处添加方法。
};

extern TESTDLL_API int nTestDll;

TESTDLL_API int fnTestDll(void);

extern "C" TESTDLL_API int add(int a, int b);

extern "C" TESTDLL_API void jn1();

extern "C" TESTDLL_API void jn2();

extern "C" TESTDLL_API void jn3();

extern "C" TESTDLL_API void callt(void(*p)(), void(*k)());

3.1.2.打包

打包需要用到vs2019
1.打开新项目
在这里插入图片描述
2.选择具有导出功能的dll
在这里插入图片描述
3.命名随意,然后点创建
4.把上一步的代码拷进去
在这里插入图片描述
5.导出dll
在这里插入图片描述
点生成,然后生成解决方案
在这里插入图片描述
控制台里面有生成路径,直接去文件夹下可以找到
在这里插入图片描述

3.2.java调用

3.2.1.准备环境

将生成的dll放在C:\Windows\System32目录下(linux的so需要放在usr/lib下)

3.2.2.创建接口集成jna里的Library,并根据C++的函数,声明抽象方法

在这里插入图片描述
代码如下

package com.jna;

import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinNT;

/**
 * 功能简述
 *
 * @author yangsx
 * @version 1.0.0
 * @date 2021-09-07
 */
public interface MyDll extends Library {
    MyDll mydll = (MyDll)Native.load("TestDll.dll",MyDll.class);

    //int FACE_GATE_CustomCommand(WinNT.HANDLE hServer, byte[] pData, int nDataLen);

    int add(int a,int b);

    void jn3();

    void callt(Callback callback1, Callback callback2);

    interface SCBack1 extends Callback {
        void jn1();
    }

    interface SCBack2 extends Callback {
        void jn2();
    }
}

注意,回调函数需要直接传入Callback的实例
由于C++的类型与java有所不同,这里贴出对照表
在这里插入图片描述

3.2.3.普通方法测试

在这里插入图片描述

可以看到java和C++的打印都有,接口调用成功
代码如下

package com.jna;

/**
 * 功能简述
 *
 * @author yangsx
 * @version 1.0.0
 * @date 2021-09-07
 */
public class Main {
    public static void main(String[] args) {
        int add = MyDll.mydll.add(1, 2);
        System.out.println("MyDll.mydll.add:"+add);
       /* MyDll.mydll.jn3();
        MyDll.SCBack1 SCBack1= new SCBack1_Impl();
        MyDll.SCBack2 SCBack2= new SCBack2_Impl();
        MyDll.mydll.callt(SCBack1,SCBack2);*/


    }
}

3.2.3.回调函数调用

把上述代码引掉的部份打开进行测试
效果如下
在这里插入图片描述
这里传入了SCBack1和SCBack2的实现类,贴一下代码

package com.jna;

/**
 * 功能简述
 *
 * @author yangsx
 * @version 1.0.0
 * @date 2021-09-08
 */
public class SCBack1_Impl implements MyDll.SCBack1 {
    @Override
    public void myBack1() {
        System.out.println("myBack1:回调成功!");
    }

}
package com.jna;

/**
 * 功能简述
 *
 * @author yangsx
 * @version 1.0.0
 * @date 2021-09-08
 */
public class SCBack2_Impl implements MyDll.SCBack2 {
    @Override
    public void myBack2() {
        System.out.println("myBack2:回调成功!");
    }
}

可以看到我们控制台打印了myBack1:回调成功!和myBack2:回调成功!而且都是我们java代码里写的方法。

3.2.4.linux环境下的注意事项

1.so需要放在lib包下,而且打包的时候需要达成libTestDll.so的形式
2.linux的加载和windows也不一样,加载so需要写成
MyDll mydll = (MyDll)Native.load(“TestDll”,MyDll.class);
前面的lib和后面的so都不需要

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
如果C++DLL动态库中的接口函数的返回值是通过出参(引用返回)的方式返回的,你可以使用JNI来处理这种情况。在Java中,你可以使用JNI提供的`Pointer`类来传递指针,并使用JNI提供的方法来访问和操作C++DLL动态库中的数据。 下面是一个示例,展示了如何在Java调用C++DLL动态库中的接口函数,并通过出参返回结果: ```java import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; public class MyJNI { public interface MyDll extends Library { MyDll INSTANCE = (MyDll) Native.loadLibrary("mydll", MyDll.class); void myFunction(IntByReference result); } public static void main(String[] args) { IntByReference result = new IntByReference(); MyDll.INSTANCE.myFunction(result); int returnValue = result.getValue(); System.out.println("Returned value: " + returnValue); } } ``` 在上述示例中,我们使用JNA库来简化JNI的使用。首先,我们定义了一个`MyDll`接口,用于加载C++DLL动态库。接着,我们定义了一个`myFunction`方法,它接受一个`IntByReference`对象作为参数,并将结果存储在该对象中。在`main`方法中,我们创建了一个`IntByReference`对象,并将其传递给`myFunction`方法。最后,我们可以通过调用`getValue()`方法来获取返回的结果。 在编译和运行上述Java代码之前,你需要确保将C++代码编译为DLL动态库,并将其与Java代码放在同一个目录下。另外,你需要引入JNA库的依赖,以便使用`com.sun.jna`包下的类和方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值