Windows7 环境中借助jni实现Java 调用C++接口(一)
2018-03-23 18:51
393 查看
在软件开发过程中,常会出现Java语言需要调用C/C++语言接口的场景,例如:受JRE的限制,大部分系统底层接口均不能被Java程序直接调用,而C/C++则可以方便地调用这些接口,此时Java语言就可以通过调用C++接口,间接使用这些功能。本文以“获取用户按键”、“输出信息于控制台指定位置”两个接口,说明了Java程序借助Java本地方法(jni)调用C/C++接口的过程。
jdk8以上
Windows7以上操作系统
2.2 生成的C头文件如下:
3.2 加入步骤2中生成”jniM.h”文件,并建立“jniM.cpp”文件,加入工程:
3.3 在“jniM.cpp”中实现“jniM.h”中定义的方法,代码如下:
3.4 配置VS2013编译选项
C++编译目录包含jdk头文件所在路径:
C++编译模式为Release,同时根据运行机操作系统选择生成64位还是32位动态库
3.5编译生成dll文件:
开发环境
VisualStudio 2013jdk8以上
Windows7以上操作系统
步骤
1. Java侧定义jni接口
/* * jniM.java * Java native class */ class JniM { // 接口调用成功测试 public native void sayRunPlace(); // 获取用户按键 (当前只识别方向键、a、d、w、s、空格共9个按键) public native String getKeyCode(); // 在控制台(0,0)位置输出信息 public native void showPanel(String[][] args, int iHight, int iWide); }
2. 生成jni对应的C语言头文件
2.1 编译jniM.java,并生成C语言头文件jniM.h文件$javac jniM.java $javah JniM
2.2 生成的C头文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class JniM */ #ifndef _Included_JniM #define _Included_JniM #ifdef __cplusplus extern "C" { #endif /* * Class: JniM * Method: sayRunPlace * Signature: ()V */ JNIEXPORT void JNICALL Java_JniM_sayRunPlace (JNIEnv *, jobject); /* * Class: JniM * Method: getKeyCode * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_JniM_getKeyCode (JNIEnv *, jobject); /* * Class: JniM * Method: showPanel * Signature: ([[Ljava/lang/String;II)V */ JNIEXPORT void JNICALL Java_JniM_showPanel (JNIEnv *, jobject, jobjectArray, jint, jint); #ifdef __cplusplus } #endif #endif
3. 生成动态库文件
3.1 在VS2013中建立win32控制台工程3.2 加入步骤2中生成”jniM.h”文件,并建立“jniM.cpp”文件,加入工程:
3.3 在“jniM.cpp”中实现“jniM.h”中定义的方法,代码如下:
/*Cpp method archieve*/ #include "stdio.h" #include <conio.h> #include <string> #include <windows.h> #include "JniM.h" // C++string转为jstring,如无需要,可不实现该函数 jstring CStr2Jstring(JNIEnv* env, const char* pat) { //定义java String类 strClass jclass strClass = (env)->FindClass("Ljava/lang/String;"); //获取java String类方法String(byte[],String)的构造器,用于将本地byte[]数组转换为一个新String jmethodID ctorID = (env)->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V"); //建立byte数组 jbyteArray bytes = (env)->NewByteArray((jsize)strlen(pat)); //将char* 转换为byte数组 (env)->SetByteArrayRegion(bytes, 0, (jsize)strlen(pat), (jbyte*)pat); //设置String, 保存语言类型,用于byte数组转换至String时的参数 jstring encoding = (env)->NewStringUTF("GB2312"); //将byte数组转换为java String,并输出 return (jstring)(env)->NewObject(strClass, ctorID, bytes, encoding); } // Test Function JNIEXPORT void JNICALL Java_JniM_sayRunPlace(JNIEnv *, jobject) { printf("I'm running in C++.\n\n"); } // Get pushed key JNIEXPORT jstring JNICALL Java_JniM_getKeyCode(JNIEnv *env, jobject) { unsigned int uiKeyScanCode = _getch(); //Direction key if (0xE0 == uiKeyScanCode) { uiKeyScanCode = _getch() * 0x100 + uiKeyScanCode; } else if (0 == uiKeyScanCode) { std::string strTmp(""); return CStr2Jstring(env, strTmp.c_str()); } std::string strKeyValue(""); switch (uiKeyScanCode){ case 0x4be0: strKeyValue = "Left"; break; case 0x4de0: strKeyValue = "Right"; break; case 0x50e0: strKeyValue = "Down"; break; case 0x48e0: strKeyValue = "Up"; break; case 0x0061: strKeyValue = "a"; break; case 0x0064: strKeyValue = "d"; break; case 0x0073: strKeyValue = "s"; break; case 0x0077: strKeyValue = "w"; break; case 0x0020: strKeyValue = " "; break; default: strKeyValue = "Invalid"; break; } return CStr2Jstring(env, strKeyValue.c_str()); } // Show panel on console JNIEXPORT void JNICALL Java_JniM_showPanel(JNIEnv *env, jobject, jobjectArray jObjAry, jint, jint) { system("cls"); COORD pos = { 0, 0 }; //设定坐标 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); //函数句柄 SetConsoleCursorPosition(hOut, pos); int iLen = env->GetArrayLength(jObjAry); for (int iLoop = 0; iLoop < iLen; ++iLoop) { jarray jAry = (jarray)env->GetObjectArrayElement(jObjAry, iLoop); int iLenSnd = env->GetArrayLength(jAry); char* cStr = NULL; for (int iLoopSnd = 0; iLoopSnd < iLenSnd; ++iLoopSnd) { jstring jStr = (jstring)env->GetObjectArrayElement((jobjectArray)jAry, iLoopSnd); cStr = (char*)env->GetStringUTFChars(jStr, 0); if ('0' == *cStr) { printf(" "); } else if ('1' == *cStr) { printf("■"); } else { printf("%1s", cStr); } } } return; }
3.4 配置VS2013编译选项
C++编译目录包含jdk头文件所在路径:
C++编译模式为Release,同时根据运行机操作系统选择生成64位还是32位动态库
3.5编译生成dll文件:
4. Java侧加载动态库,并调用本地方法:
拷贝VS生成的动态库(.dll)文件到加载Java工程目录。Java示例代码如下:/* * jniDemo.java * Test class for Jni */ class JniDemo { // 加载动态库 static { System.loadLibrary("cppadp"); } public static void main(String[] args) { JniM oJniM = new JniM(); //Test Code oJniM.sayRunPlace(); // Get keyborad String strRslt; int count = 0; while (true){ count++; if (1 < count){ break; } strRslt = oJniM.getKeyCode(); System.out.println("User input is :" + strRslt); } // Show panel String pnlAry[][] = { {"0", "0", "1", "0", "0", "0", "\n"}, {"0", "0", "1", "1", "1", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"} }; oJniM.showPanel(pnlAry, 2, 7); waitSpecifiedTime(800); String pnlAry1[][] = { {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "1", "0", "0", "0", "\n"}, {"0", "0", "1", "1", "1", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"} }; oJniM.showPanel(pnlAry1, 2, 7); waitSpecifiedTime(800); String pnlAry2[][] = { {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "1", "0", "0", "0", "\n"}, {"0", "0", "1", "1", "1", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"}, {"0", "0", "0", "0", "0", "0", "\n"} }; oJniM.showPanel(pnlAry2, 2, 7); } // 延时函数 public static void waitSpecifiedTime(int iTmLen) { try { Thread.sleep(iTmLen); } catch (InterruptedException e) { e.printStackTrace(); } } }
使用注意
1.生成DLL文件的VS工程必须设置为Release模式;
2.生成的DLL文件版本,必须适配目标机操作系统的位数;
Created by 王彬相关文章推荐
- C++调用Java(借助JNI技术实现每日登陆的实现)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- Music Studio项目心得--JNI实现C++调用JAVA
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)
- 通过JNI实现Java和C++的相互调用(转)