Java通过JNI调用C++动态链接库dll,并打在jar包内——JNA-JNI(一)

系列文章:
Java通过JNI调用C++动态链接库dll,并打在jar包内 ——JNA-JNI(一)
Java使用JNA调用C++动态链接库——JNA-JNI(二)
Mac M1 Xcode创建动态链接库dylib(c++)——JNA-JNI(三)
JNA调用dll(c++)附带解析xml——JNA-JNI(四)
JNA参数类型转换(含接收、发送结构体)——JNA-JNI(五)

目录

  • Java通过JNI调用C++动态链接库dll,并打在jar包内——JNA-JNI(一)
    • JNI介绍
    • 创建JAVA项目
    • C++对应的JAVA对象类
    • windows环境下制作C++动态链接库
    • JAVA程序调用
    • 打jar包
    • windows平台下遇到的问题

JNI介绍

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

xx.dll就像中介一样,Java通过调用这个中介Dll中的自定义方法,间接调用真正的第三方Dll

项目以windows为例,后缀为dll,若为linux,后缀修改为so即可。

创建JAVA项目

这里我用的是spring(为了扩展),使用纯java也是可以的。项目结构如下:

C++对应的JAVA对象类

  • 类的内容
public class Demo {public native void sayHello(int x,int y);
}
  • 生成.class文件
javac Demo.java
  • 生成.h文件

错误: 找不到 ‘Demo’ 的类文件。

切换到目录src\main\java\这个目录下,重新执行

javah com.example.demo.Demo

执行成功之后会在com包同级目录下出现一个xx.h的文件。

windows环境下制作C++动态链接库

使用VS2017来演示

  • 新建空项目

  • 将.h文件复制过来并添加

    无法打开包括文件:“xxx.h”: No such file or directory.错误。

    • 出现此问题的原因:把头文件复制,直接选择项目粘贴进来,虽然解决方案资源管理器里显示此头文件,但是编译就出现上面的错误,找不到头文件。
    • 打开项目目录,发现里面不存在刚才复制的头文件,这是微软的BUG,需要打开项目目录把文件复制过来。
    • 所以引用头文件的正确顺序是,先把头文件复制到项目目录里,然后选择打开VS,选择项目右键->添加->现有项,选择复制到项目里的头文件。
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class com_example_demo_Demo */#ifndef _Included_com_example_demo_Demo
#define _Included_com_example_demo_Demo
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     com_example_demo_Demo* Method:    sayHello* Signature: (II)V*/
JNIEXPORT void JNICALL Java_com_example_demo_Demo_sayHello(JNIEnv *, jobject, jint, jint);#ifdef __cplusplus
}
#endif
#endif
  • 编写接口实现cpp文件
#include <iostream>
#include "com_example_demo_Demo.h"
using namespace std;JNIEXPORT void JNICALL Java_com_example_demo_Demo_sayHello(JNIEnv *env, jobject obj, jint x, jint y)
{cout << "x:" << x << "; y:" << y << "x+y=" << x+y << endl;
}
  • 修改项目属性

    直接生成方案会出新以下问题,其实是初始化项目后,没有修改为dll类型。

    在配置中修改后即可。

  • 配置包含目录
    添加JDK/include路径,因为jni.h在这个路径下,或者直接将jni.h也复制到项目的头文件里。

  • 配置dll对应x64还是x86

    需要注意的是,生成的dll动态链接库,需要和系统位数对应,VS默认是32位的,如果服务器是64位的,需要手动修改平台再生成。

  • 生成dll链接库

    点击生成解决方案,在项目文件夹下会生成.dll文件

  • 项目结构

JAVA程序调用

这里直接在main函数里调用了

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);System.load("C:\\xx\\Project6.dll");Demo demo = new Demo();demo.sayHello(2,3);}}

打jar包

  1. 将dll文件放在java项目的src/main/resources/native/目录下

  2. 添加文件解析函数

@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class);//加载动态链接库,注意和SpringBoot的启动String systemType = System.getProperty("os.name");if (systemType.toLowerCase().indexOf("win") != -1)loadNative("Project6");elseloadNative("Project6");Demo demo = new Demo();demo.sayHello(2, 3);}private synchronized static void loadNative(String nativeName) {String systemType = System.getProperty("os.name");String fileExt = (systemType.toLowerCase().indexOf("win") != -1) ? ".dll" : ".so";File path = new File(".");//将所有动态链接库dll/so文件都放在一个临时文件夹下,然后进行加载//这是应为项目为可执行jar文件的时候不能很方便的扫描里面文件//此目录放置在与项目同目录下的natives文件夹下String sysUserTempDir = path.getAbsoluteFile().getParent() + File.separator + "natives";System.out.println("------>>native lib临时存放目录 : " + sysUserTempDir);String fileName = nativeName + fileExt;InputStream in = null;BufferedInputStream reader = null;FileOutputStream writer = null;File tempFile = new File(sysUserTempDir + File.separator + fileName);if(!tempFile.getParentFile().exists())tempFile.getParentFile().mkdirs() ;if (tempFile.exists()) {tempFile.delete();}try {//读取文件形成输入流in = TaskApplication.class.getResourceAsStream("/native/" + fileName);if (in == null)in = TaskApplication.class.getResourceAsStream("native/" + fileName);TaskApplication.class.getResource(fileName);reader = new BufferedInputStream(in);writer = new FileOutputStream(tempFile);byte[] buffer = new byte[1024];while (reader.read(buffer) > 0) {writer.write(buffer);buffer = new byte[1024];}} catch (IOException e) {e.printStackTrace();} finally {try {if (in != null)in.close();if (writer != null)writer.close();} catch (IOException e) {e.printStackTrace();}}System.load(tempFile.getPath());System.out.println("------>> 加载native文件 :" + tempFile + "成功!!");}
}
  • 主入口函数的代码主要是进行加载操作,也可以在需要使用到的地方在进行加载。

  • 加载的时候进行了如下操作:

    • 1、将所有动态链接库dll/so文件都放在一个临时文件夹下。
    • 2、读取临时文件IO流进行加载。
  • 因为项目为可执行jar文件的时候不能很方便的扫描里面文件,此目录代码放置在与项目同目录下的natives文件夹下。

  1. 运行jar包

windows平台下遇到的问题

  1. LNK1104:无法打开“kernel32.lib”

    原文链接:https://blog.csdn.net/Beyond111223/article/details/82913628

    找到“kernel32.lib”的路径,一般如下:

    打开:项目---->属性---->配置属性---->VC++ 目录---->库目录

    添加路径 C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib

  2. LNK1158:无法运行“rc.exe”

    • 项目属性-常规-平台工具集里,将Visual Studio 2013 (v120)替换为Visual Studio 2013 - Windows XP (v120_xp)。

    • 打开系统环境变量列表(我的电脑—>属性—>高级—>环境变量),在系统变量栏里看Path,添加:C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin\;

      其他可能需要的目录,来自https://www.cnblogs.com/Jimnny/p/3574368.html

      C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\;
      C:\Program Files (x86)\Windows Kits\8.0\Windows Performance Toolkit\;
      C:\Program Files\Microsoft SQL Server\110\Tools\Binn\;
      C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\;
      C:\Users\(用户名)\AppData\Local\Microsoft\MSBuild\v4.0\;
      
  3. Can’t load IA 32-bit .dll on a AMD 64-bit platform

    原因:xx.dll是32位的不支持64位的平台(jdk环境)

    解决方法:VS使用x64重新编译(VS默认是32位)

    • step 1

    • step 2

    • step 3 把ARM改为x64,其他不动

    • step 4

    • step 5 运行

  4. getresourceasstream方法获取值为null

    解决方法:重新配置一下pom.xmlbuild,刷新maven库

    <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
    </build>
    
  5. 离线环境打包失败

    方法:使用打包命令

    mvn clean install -Dmaven.test.skip=true
    

Java通过JNI调用C++动态链接库dll,并打在jar包内 ——JNA-JNI(一)相关推荐

  1. linux查看jar包内容命令,【达内Java教程】用linux查看jar包内文件命令

    深圳java培训(sz.java.tedu.cn)专家教你用linux查看jar包内文件命令 jar vtf fileName.jar 用法: jar {ctxui}[vfm0Me] [jar-fil ...

  2. JAVA通过JNI调用C++动态链接库CLL(二)

    简介 使用Visual Studio 2017新建c++动态链接库dll项目 编写JniDemo.h中getName实现并生成DLL 编写JniDemo.h在JniDemo.c实现getName方法 ...

  3. JAVA通过JNI调用C++动态链接库CLL(一)

    简介 使用eclipse新建JAVA项目并生成.h头文件 新建项目JniDemo 新建测试类JniTest并声明一个native的方法 使用Javah命令生成native方法的声明的C/C++头文件 ...

  4. Java程序启动同时复制resources下文件到jar包同级目录

    Java代码调用.exe,包括获取exec()中的日志并打印,可以看我之前的博客 一.Java调用exe打包成jar的调用方式有俩种: Java程序中resources下的exe等文件,是可以同时打包 ...

  5. Java如何读取JAR包外的properties文件及打成jar包后无法读取到jar包内的properties文件

    项目中,经常把一部分功能独立出来,做一个java  project,然后打成jar包供其他项目引用.这时候,如果jar包中需要读取配置文件信息,则很少把该配置打进jar包,因为它不方便修改,更多都是采 ...

  6. Java通过JNI调用C++的DLL库

    2019独角兽企业重金招聘Python工程师标准>>> Java通过JNI实现调用C++程序 好久没碰JNI这个东西了,刚工作的时候自己写过点东西,这么些年很少用到,最近一个项目又用 ...

  7. java 使用jacob 调用中控考勤机dll(详细配置)

    根据网上内容搜索以及不断尝试,总结出以下java使用jacob调用中控考勤机sdk方法 1.jacob-1.18版本 2.jdk1.732位(经过测试jacob目前只支持32位jdk,64位下报错): ...

  8. Shell-通过shell启动Java类中的main方法 + 通过Shell启动jar包

    文章目录 概述 shell启动Java类中的main方法 启动脚本分析 启动脚本 shell启动jar包 概述 Java程序 运行在linux主机上, 通过shell脚本启动为进程. Java程序中 ...

  9. maven导出Java方法_eclipse导出maven工程的可执行jar包

    一.eclipse导出maven工程的可执行jar包 建立两个maven工程 ZKServer 和ZKClient 注意:用maven进行开发管理的话,默认的打出来的jar包是不能运行的,需要在pom ...

最新文章

  1. linux下如何修改系统时间
  2. 用pycharm写python_使用Pycharm编写第一个python程序
  3. 嵌入式linux 分区挂载,嵌入式linux系统的开发——文件系统的分区和挂载
  4. PHP开发环境MAMP for Windows
  5. 如何找出孔洞位置进行填充_电伴热带破损位置如何快速找出
  6. OPENCV用户手册之图像处理部分(之四):滤波器与色彩转换(中文翻译)
  7. 谷歌邮箱lmap服务器填什么_常用邮箱SMTP服务器设置
  8. redis配合LUA脚本
  9. 彻底解决360安全卫士广告问题-终极解决方案(含360后台广告程序下载解决方案)
  10. cad计算机清空按键,cad delete键不能用怎么办-解决cad按delete键不能删除的方法 - 河东软件园...
  11. 给定3个数字,求出这3个数字中的最大值,并将最大值输出
  12. 1 入门:投身新领域
  13. Hive SQL— 连续发单天数
  14. ANSYS-材料的选择
  15. MFC下ODBC方式连接数据库
  16. Jetson TX1 开发教程(1)--配置与刷机
  17. node.js使用Sequelize实现多表连接查询
  18. 中国古代十大名曲背后的掌故(转载)
  19. 微型计算机简单并行接口实验心得,实验二 简单并行接口
  20. 【CF】3B Lorry

热门文章

  1. html:点击图片放大到全屏,再次点击缩回
  2. Email清教徒十大手则
  3. 如何在css文件中使用本地ttf/woff/woff2字体?
  4. 输出linux内核版本信息,查看linux内核和版本信息
  5. 误删暂存代码的恢复方法
  6. Python str isdigit()方法
  7. ubuntu安装mysql-python报错
  8. 详解git push后出现src refspec dev does not match any
  9. matlab求点介数程序,matlab_bgl 一个很有用的计算网络中每个节点介数的程序,对 分析 Cloud Computing 云 266万源代码下载- www.pudn.com...
  10. 解决‘parent.relativePath‘ of POM xxx points at yyy instead of zzz please verify your project structure