JAVA使用JNI调用C++动态链接库

使用JNI连接DLL动态链接库,并调用其中的函数

首先 C++中写好相关函数,文件名为test.cpp,使用g++编译为DLL文件,指令如下:

g++ -shared -Wl,--kill-at,--output-def,test.def -o test.dll test.cpp
#如果cpp中要调用其他dll,需要在命令后面添加相关lib描述

这样就在当路径下同时生成了test.def 和 test.dll 文件

顺便说一下,.lib文件可以通过.def文件生成,生成方法是用VS中的

lib /def:xxx.def /MACHINE:x86(或者X64)命令

得到.dll文件后,JAVA理论上就可以使用JNI调用了

public class JNIDemo1 {

    public static native short  connectCNC(String ip);
public static native void writeData(); static {
System.loadLibrary("melwin");
System.loadLibrary("melcfg");
System.loadLibrary("melsmem");
System.loadLibrary("chgapivl");
System.loadLibrary("meldev");
System.loadLibrary("melmdldr");
System.loadLibrary("melvnckd");
System.loadLibrary("ncMocha");
System.loadLibrary("nccom");
System.loadLibrary("ncapi32");
System.loadLibrary("test");
}//系统会自己判断后缀。 public static void main(String[] args) { short res=connectCNC("192.168.200.1"); if(res==0){
System.out.println("Connect Success!\tData Writing...\n");
writeData();
}else{
System.out.println("Connect Fail.code:"+res);
}
}
}

两个native函数是要调用的C++函数

需要在主类中使用native关键字事先定义

加载lib文件的后缀不要描述,让JAVA根据OS平台自己判断

加载lib的命令有先后顺序之分,一定要按照调用层级来书写命令顺序

如果不清楚dll之间的调用顺序,可以下载“DLL依赖查看工具”来解析DLL

加载dll时会报错no test in java.library.path

原因是JNI找不到你的dll文件在哪里,这时候要调整一下eclipse项目工程的build path

修改jdk中的native library location,指向你的dll路径,截图如下:

如果编译dll的g++是64位的,jdk是32位的,会报错

Can't load AMD 64-bit .dll on a IA 32-bit platform

反之会报错

Can't load  IA 32-bit .dll on a AMD 64-bit platform

遇到这类问题,不需要尝试去更换g++编译器,因为引用到的外部dll大部分都是32位的

而我们的JDK可以同时安装32位和64位的,在系统中并不冲突

所以应该去下载对应架构的JDK重新编译执行java文件

编译好java文件后,不要急着运行,还有一些工作要回到C++中完成

编译得到.class文件,一般eclipse保存一下没有语法错误就生成好.class文件了

cmd到src根目录,使用javah命令生成.h头文件,你也可以直接编写.h头文件,格式如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_saiyang_newflypig_jnidemo_JNIDemo1 */ #ifndef _Included_com_saiyang_newflypig_jnidemo_JNIDemo1
#define _Included_com_saiyang_newflypig_jnidemo_JNIDemo1
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_saiyang_newflypig_jnidemo_JNIDemo1
* Method: connectCNC
* Signature: (Ljava/lang/String;)S
*/
JNIEXPORT jshort JNICALL Java_com_saiyang_newflypig_jnidemo_JNIDemo1_connectCNC
(JNIEnv *, jclass, jstring); JNIEXPORT void JNICALL Java_com_saiyang_newflypig_jnidemo_JNIDemo1_writeData
(JNIEnv *, jclass); #ifdef __cplusplus
}
#endif
#endif

函数名不要搞错了,JNI要通过这些规范去寻找相关函数

可以在规范函数中直接调用自己写的其他任意纯净格式的函数

.h头文件有了,自然就要修改一下cpp文件:

#define BUILD_MIT_DLL

#include <stdio.h>
#include <string> #include "melncapi.h"
#include "ncmcapi.h"
#include "melsect.h"
#include "melssect.h"
#include "meltype.h" #include "test.h" using namespace std; void readData();
void writeData();
short connectCNC(string);
char* jstring2char(JNIEnv*,jstring); int main(){
DWORD res=connectCNC("192.168.200.1");
if(res != ) {
printf("Fail...code:%d\n",res);
}
else {
printf("Connect Success!\n");
writeData();
} return ;
} short connectCNC(string ip){
MELDEVICEDATA MelIoctlData;
DWORD dwStatus=;
MelIoctlData.uniDeviceInfo.Tcp.lPortNo = ;
memset(MelIoctlData.uniDeviceInfo.Tcp.IPAddr, , );
strcpy(MelIoctlData.uniDeviceInfo.Tcp.IPAddr, ip.data());
MelIoctlData.dwDeviceType = DEVICETYPE_TCP; // long OldTimeOut = 0, TimeOut = 2;
// dwStatus = melIoctl(NULL, ADR_MACHINE(1), DEV_GET_COMMTIMEOUT, &OldTimeOut);
// if(dwStatus == 0)
// melIoctl(NULL, ADR_MACHINE(1), DEV_SET_COMMTIMEOUT, &TimeOut);
dwStatus = melIoctl(NULL, ADR_MACHINE(), DEV_SET_COMMADDRESS, &MelIoctlData);
return dwStatus;
} void readData(){
//long lSectionNum = M_SEC_PLC_DEV_WORD;
//M_SEC_PLC_DEV_BIT、M_SEC_PLC_DEV_CHAR、M_SEC_PLC_DEV_WORD
long lSectionNum = M_SEC_PLC_DEV_BIT;
long lAddress = ADR_MACHINE();
long lAxisFlag = ;
short lGetData = ;
short y=; while(scanf("%d",&y),y!=-){
long lSubSectionNum = M_SSEC_PLLNG_Y_1SHOT(y);
DWORD dwStatus = melGetData(NULL, lAddress, lSectionNum, lSubSectionNum, lAxisFlag, &lGetData, T_LONG);
printf("%d\n", lGetData);
}
} void writeData(){
long lSectionNum = M_SEC_PLC_DEV_BIT;
long lAddress = ADR_MACHINE();
long lAxisFlag = ;
short lSetData;
short xNum; while(scanf("%d",&xNum),xNum!=-){
scanf("%d",&lSetData);
long lSubSectionNum = M_SSEC_PLLNG_X_1SHOT(xNum);
DWORD dwStatus = melSetData(NULL, lAddress, lSectionNum, lSubSectionNum, lAxisFlag, &lSetData, T_LONG);
if(dwStatus == ) {
printf("Write Success!\n");
}else{
printf("Write Fail!code:%d\n",dwStatus);
}
}
} JNIEXPORT jshort JNICALL Java_com_saiyang_newflypig_jnidemo_JNIDemo1_connectCNC(JNIEnv* env, jclass, jstring ip){
return connectCNC(jstring2char(env,ip));
} JNIEXPORT void JNICALL Java_com_saiyang_newflypig_jnidemo_JNIDemo1_writeData(JNIEnv *, jclass){
writeData();
} /**
* 返回值 char* 这个代表char数组的首地址
* Jstring2CStr 把java中的jstring的类型转化成一个c语言中的char 字符串
*/
// jstring To char*
char* jstring2char(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > )
{
rtn = (char*)malloc(alen + );
memcpy(rtn, ba, alen);
rtn[alen] = ;
}
env->ReleaseByteArrayElements(barr, ba, );
return rtn;
}

这下就大功告成了,还记的我们一开始执行的g++命令编译dll吗

重新执行一遍,生成.dll后,执行java程序,应该就可以调用了。

JAVA使用JNI调用C++动态链接库的更多相关文章

  1. 关于Java通过JNI调用C 动态链接库(DLL)

    JNI介绍 用JNI实现Java和C语言的数据传递 JNI原理分析和详细步骤截图说明 jni的JNIEnv指针和jobject指针 JNI实现回调| JNI调用JAVA函数|参数和返回值的格式 Jni ...

  2. Java通过jni调用动态链接库

    (1)JNI简介 JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++).从Java1.1开始,JNI标准成为java ...

  3. Java通过JNI调用dll详细过程(转)

    源:Java通过JNI调用dll详细过程 最近项目有这样一个需求,在已有的CS软件中添加一个链接,将当前登录用户的用户名加密后放在url地址中,在BS的login方法里通过解密判断,如果为合法用户则无 ...

  4. ubuntu下Java通过JNI调用C

    下面看一个实例,如下: public class TestJNI { static { System.loadLibrary("diaoyong"); // 程序在加载时,自动加载 ...

  5. Java通过JNI调用C

    Java调用C有多种方式,本文介绍笔者最近的学习过程,避免今后再犯类似的错误. 首先,Java肯定是调用C的动态链接库,即通过编译器编译后的dll/so文件. 下面介绍gcc编译dll的方法. 一般情 ...

  6. JAVA的JNI调用

    由于JNI调用C和调用C++差不多,而且C++中可以混合写C代码,所以这里主要是写关于JNI调用C++的部分. 一般步骤: 先是写普通的Java类,其中包括本地方法调用.  然后编译这个Java类,调 ...

  7. 第39篇-Java通过JNI调用C/C++函数

    在某些情况下,Java语言需要通过调用C/C++函数来实现某些功能,因为Java有时候对这些功能显的无能为力,如想使用X86_64 的 SIMD 指令提升一下业务方法中关键代码的性能,又或者想要获取某 ...

  8. Cocos2d-x java 通过jni调用c++的方法

    前面博客说到,cocos2d-x c++界面层运行在一个GLThread线程里面,严格的说是运行在Cocos2dxGLSurfaceView(继承自GLSurfaceView) 里面.opengl的渲 ...

  9. Java通过JNI调用C/C++

    From:http://www.cnblogs.com/mandroid/archive/2011/06/15/2081093.html JNI是JAVA标准平台中的一个重要功能,它弥补了JAVA的与 ...

随机推荐

  1. CentOS用yum安装X Window

    安装X图形界面系统 yum list 列出所有可安装的软件包 可以通过 yum grouplist 来查看可能批量安装哪些列表 先装X windows #yum groupinstall 'X Win ...

  2. Java 性能要点:自动装箱/ 拆箱 (Autoboxing / Unboxing)

    [编者按]本文作者为 Ali Kemal TASCI,最早于2016年4月9日发布于DZONE社区.文章主要介绍通过改进 Java 1.5 就已存在的骨灰级特性大幅度提高应用性能. 本文系 OneAP ...

  3. ZOJ3784 String of Infinity(AC自动机&&强连通分量)

    题意:给你n个禁止串,然后你只能用字符表的前m个字符去写一个无限长的串,要求是不能包含禁止串,而且串在后面不能出现循环 比赛的时候想的是先建一个自动机,然后将自动机确定化,不能到达的状态全部弄出来.但 ...

  4. Mybatis批量插入oracle,mysql

    oracle  <insert id="addUserData" parameterType="java.util.List"> INSERT IN ...

  5. Changing the Overridden Method’s Characteristics

    修改重写方法的特征 在大多数情况下,我们重写(override)一个 virtual 方法是为了改变它的实现.然后,有时我们却想改变该 virtual 方法的其他的特征,这往往会带来一系列问题. 1) ...

  6. 使用git整体流程

    一.git提交代码走meger请求的整体流程 工作中使用git推代码时,如果走merge请求,那么也就是说拉代码时拉公共代码库的代码,但是提交时需要先提交到自己的代码库,然后在gitlab上提交mer ...

  7. 【zoj2562】反素数

    题意:给定一个数N,求小于等于N的所有数当中,约数最多的一个数,如果存在多个这样的数,输出其中最小的一个.(1 <= n <= 10^16) 题目:http://acm.hust.edu. ...

  8. 线段树(区间合并) POJ 3667 Hotel

    题目传送门 /* 题意:输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边 输入 2 a b:将[a,a+b-1]的房间清空 线段树(区间合并):lsum[]统计从左端点起最长连续空房间 ...

  9. 程序空间(Program memory)

    The computer program memory is organized into the following: Data Segment (Data + BSS + Heap) Stack ...

  10. 天使投资、VC 以及 PE 的区别是什么?

    如果满足于“阶段不同”这个简单的回答,那你可能错过了一个思考资本与企业发展之间关系的机会. 首先要交待一下,在大众语境中,angel/VC/PE三者都可认为是VC,也就是人们常说的风险投资,在国内官方 ...