JNA调用.dll或.so动态链接库文件

本文中使用的.dll和.so文件以及Java调用的代码资源:
https://download.csdn.net/download/werewolf2017/11014740

1. 编译一个dll文件或so文件

1.1 C++代码

熟悉C/C++的,可以忽略该步骤。对C/C++不熟悉,编译dll和so文件只是按部就班。
.dll文件是Windows系统的动态链接库文件,.so文件是Linux操作系统的动态链接库文件。
若想直接使用本文中的.dll和.so文件以及Java调用的代码,可以直接从https://download.csdn.net/download/werewolf2017/11014740 中下载。
首先在ide中新建dll项目,此处使用的IDE是Dev-C++。如下图所示。
使用Dev-C++新建dll项目
main.cpp代码如下:

#include "main.h"  
  
int add(int a,int b){  
    return a + b;  
}  
int factorial(int n){  
    int i;  
    int r = 1;  
    for(i=1;i<n+1;i++)  
        r = r*i;  
    return r;  
}  
  
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)  
{  
    switch (fdwReason)  
    {  
        case DLL_PROCESS_ATTACH:  
            // attach to process  
            // return FALSE to fail DLL load  
            break;  
  
        case DLL_PROCESS_DETACH:  
            // detach from process  
            break;  
  
        case DLL_THREAD_ATTACH:  
            // attach to thread  
            break;  
  
        case DLL_THREAD_DETACH:  
            // detach from thread  
            break;  
    }  
    return TRUE; // succesful  
}  

main.h的代码如下:

#ifndef __MAIN_H__  
#define __MAIN_H__  
  
#include <windows.h>  
  
/*  To use this exported function of dll, include this header 
 *  in your project. 
 */  
  
#ifdef BUILD_DLL  
    #define DLL_EXPORT __declspec(dllexport)  
#else  
    #define DLL_EXPORT __declspec(dllimport)  
#endif  
 
#ifdef __cplusplus  
extern "C"  
{  
#endif  
  
int add(int a,int b);  
int factorial(int n);  
  
#ifdef __cplusplus  
}  
#endif  
  
#endif // __MAIN_H__  

1.2 生成.dll文件

创建好main.cpp和main.h文件后,编译便得到和项目名相同的dll文件。此处项目名为DLLMain,所以编译后得到DLLMain.dll文件。

1.3 生成.so文件

要生成so文件,可以在Linux系统下,执行gcc命令编译得到。命令如下:

gcc main.h main.cpp -fPIC -shared -o hello.so

执行命令后,在main.h和main.cpp的同一级目录下,会生成hello.so文件。

Tips :部分博客中提到,使用JNA调用.so文件时,编译出来的so文件名必须lib开头。其实这个是没有这个要求的,具体可往下看。

2. 调用.dll文件和.so文件

2.1 .dll和.so文件的放置路径问题

Windows系统下,被调用的.dll文件放在classpath下即可被加载到。在maven项目中,放在resource目录下即可。如下图所示。
.dll文件的路径
Linux操作系统下,.so文件直接放在classpath下是不能加载成功的。
默认情况下,JNA会从/usr/lib目录下加载.so文件。可通过添加 -Djna.library.path=xxx 来指定JNA加载.so文件的目录路径,其中xxx表示.so文件所在的目录的路径。例如,hello.so所在的目录为/root/sotest/lib,则可指定:

-Djna.library.path=/root/sotest/lib

2.2 引入JNA依赖包

此处使用maven:

<dependency>
	<groupId>net.java.dev.jna</groupId>
	<artifactId>jna</artifactId>
	<version>4.2.2</version>
</dependency>

2.3 调用的demo

import com.sun.jna.Library;
import com.sun.jna.Native;

public class TestSo {
	public interface ITestLib extends Library {
		// Windows下,libName是.dll文件名
		String libName = "DLLMain";
		// Linux下,libName是.so的含后缀的文件名。
		// 若不加后缀名,则编译.so文件时,文件名必须以lib开头。具体说明可往下看。
		// String libName = "hello.so";
		ITestLib INSTANCE = (ITestLib) Native.loadLibrary(libName, ITestLib.class);

		/**
		 * ========= 以下是DLLMain.dll或hello.so中的对应的接口方法 =========
		 */

		/**
		 * 加法
		 *
		 * @param a
		 * @param b
		 * @return
		 */
		public int add(int a, int b);
		
		/**
		 * 阶乘
		 *
		 * @param n
		 * @return
		 */
		public int factorial(int n);
	}

	public static void main(String[] args) {
		int c = ITestLib.INSTANCE.add(10, 20);
		System.out.println("10+20=" + c);
		int d = ITestLib.INSTANCE.factorial(10);
		System.out.println("10!=" + d);
	}
}

2.4 运行结果

运行结果

2.5 关于libName的注意点

Native.loadLibrary(String libName, class interfaceclass)方法中,libName的值有一些注意点,在上面代码中已经有提到,此处再作一次总结。
Windows操作系统下,libName的值是.dll文件去后缀文件名,例如,本文中的DLLMain.dll对应的libName的值是DLLMain。
Linux操作系统下,libName的值是.so文件的完整文件名,例如,本文中的hello.so对应的libName是hello.so。不过,若libName写成带.so后缀的形式,那么,在编译.so文件时,文件名需要以lib开头,即libhello.so,对应的libName是hello(注意,不是libhello)。

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
可以通过JNAJava Native Access)来调用C++的.h文件JNA是一个Java库,它允许Java应用程序在运行时动态地访问本地代码库,包括动态链接库(.dll)和共享对象(.so)。以下是使用JNA调用C++的.h文件的一些步骤: 1. 定义一个Java接口,该接口包含您要调用的C++函数的声明。在Java接口使用JNA提供的注释来指定函数的原型和库名称。例如: ```java import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Pointer; public interface MyLibrary extends Library { MyLibrary INSTANCE = (MyLibrary) Native.loadLibrary("mylibrary", MyLibrary.class); int myFunction(int arg1, int arg2, Pointer arg3); } ``` 这个接口定义了一个名为MyLibrary的库,该库包含一个名为myFunction的函数,该函数接受两个整数参数和一个指向指针的指针参数。 2. 在Java代码实现该接口。您需要实现接口声明的所有方法。在实现方法时,您需要使用JNA的函数调用机制来调用C++函数。例如: ```java public class MyApp { public static void main(String[] args) { int arg1 = 123; int arg2 = 456; byte[] buffer = new byte[1024]; Pointer arg3 = new Memory(buffer.length); int result = MyLibrary.INSTANCE.myFunction(arg1, arg2, arg3); String message = new String(arg3.getByteArray(0, result)); System.out.println(message); } } ``` 这个例子展示了如何调用myFunction函数,并将一个指针参数传递给它。在这个例子,我们使用JNA的Memory类来创建指针参数。 3. 使用C++编译器将你的.h文件编译成动态链接库(.dll或.so文件),并将其放置在Java代码可以访问的位置。 4. 运行Java代码,并检查它是否能够正确地调用C++函数。 这是一个基本的示例,可以让您开始使用JNA调用C++的.h文件。但是请注意,这只是一个概述,实际上可能需要更多的工作来使它正常工作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值