1. 编写java类,用该类将DLL对外提供的函数服务进行声明,其中java方法均申明为native,其方法名可以自定义,函数体不用实现。具体代码如下:
package com.aizizai.calldll; public class MyNative { public MyNative() {
} static { System.loadLibrary("hellodll"); } public native static void HelloWord(); public native static int CheckSign(String cstrPubKey,String cstrSignResult,String encryptStr); public native static void get(); public native static void set(); } |
其中,hellodll为动态库的名称,不需要写扩展名。CheckSign函数的入参是三个字符串。
2. 用javah工具,通过java类生成.h头文件。这个.h头文件是C++动态库中的头文件,C++程序实现需要用到它。
1) 用javac MyNative.java 编译MyNative.class文件
2) 用javah MyNative编译出com_aizizai_calldll_MyNative.h文件,其内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_aizizai_calldll_MyNative */
#ifndef _Included_com_aizizai_calldll_MyNative #define _Included_com_aizizai_calldll_MyNative #ifdef __cplusplus extern "C" { #endif /* * Class: com_aizizai_calldll_MyNative * Method: HelloWord * Signature: ()V */ JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_HelloWord (JNIEnv *, jclass);
/* * Class: com_aizizai_calldll_MyNative * Method: CheckSign * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_aizizai_calldll_MyNative_CheckSign (JNIEnv *, jclass, jstring, jstring, jstring);
/* * Class: com_aizizai_calldll_MyNative * Method: get * Signature: ()V */ JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_get (JNIEnv *, jclass);
/* * Class: com_aizizai_calldll_MyNative * Method: set * Signature: ()V */ JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_set (JNIEnv *, jclass);
#ifdef __cplusplus } #endif #endif |
JNIEXPORT、JNICALL等是jni的关键字。Jstring是jni特有的数据类型,介于java与C++的数据类型之间,jstring不能和char*等同,需要做一定的转换。这边补充一个jni数据类型jint,它对应java入参int类型,其无需转化,可以在C++中当int使用。
3. 编写C++代码实现.h头文件声明的函数,代码如下:
#include "stdafx.h" #include "com_aizizai_calldll_MyNative.h"
JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_HelloWord(JNIEnv *, jclass) { } JNIEXPORT jint JNICALL Java_com_aizizai_calldll_MyNative_CheckSign(JNIEnv * env, jclass, jstring cstrPubKey, jstring cstrSignResult, jstring encryptStr) { const char* cstrPubKey_c; const char* cstrSignResult_c; const char* encryptStr_c; cstrPubKey_c = env->GetStringUTFChars(cstrPubKey, false);//入参由jstring转成char cstrSignResult_c = env->GetStringUTFChars(cstrSignResult, false); encryptStr_c = env->GetStringUTFChars(encryptStr, false); //输出入参 int num = MultiByteToWideChar(0,0, cstrPubKey,-1,NULL,0); wchar_t*widestr = new wchar_t[num]; MultiByteToWideChar(0,0, cstrPubKey,-1,widestr,num); OutputDebugString(widestr); delete []widestr;
return 1; } JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_get(JNIEnv *, jclass) { } JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_set(JNIEnv *, jclass) { } |
编译后生成动态库,命名成hellodll,放入到java.library.path目录中。
4. 用java调用动态库输出结果:
public class DllTest {
public static void main(String[] args) {
String encryptStr = "";// String cstrSignResult = "";// String cstrPubKey ="";//
MyNative myna = new MyNative(); int a = myna.CheckSign(cstrPubKey,cstrSignResult,encryptStr); System.out.println(a); }
} |
常见错误:
1. Jni传递中文时乱码
Java内部使用的16bit的unicode编码(utf-16),中英文都是两个字节;jni使用的utf-8编码,utf-8是变长unicode编码,中文三个字节,ascii一个字节;C++汉字两个字节(GB2312),ascii一个字节。下面提供一个utf8转gb2312的方法:
char* U2G(const char* utf8) { int len = MultiByteToWideChar(CP_UTF8,0,utf8,-1,NULL,0); wchar_t * wstr = new wchar_t[len +1]; memset(wstr,0,len+1); MultiByteToWideChar(CP_UTF8,0,utf8,-1,wstr,len); len = WideCharToMultiByte(CP_ACP,0,wstr,-1,NULL,0,NULL,NULL); char * str = new char[len +1]; memset(str,0,len+1); WideCharToMultiByte(CP_ACP,0,wstr,-1,str,len,NULL,NULL); if(wstr) delete [] wstr; return str; } |
2. 包含jni头文件
在jdk安装目录中找到jni的三个头文件C:\ProgramFiles\Java\jdk1.7.0_25\include下的jni.h;C:\Program Files\Java\jdk1.7.0_25\include\win32下:jawt_md.h、jni_md.h。然后放入到vs的include目录下,我本机目录是C:\ProgramFiles (x86)\Microsoft Visual Studio 10.0\VC\include。
3. Javah编译.h文件时的路径问题
在javah编译.h文件时常会遇到如下错误:
正确方法是退至src根目录,然后在编译类前加上全路径。
常见错误如下:
4. loadlibrary路径
获取java.library.path
System.out.println(System.getProperty("java.library.path"));
5. 32位dll不能在64位调用
编译出来的hellodll,被java调用时出错
解决方法:
修改vs的方案生成配置,“生成”->“配置管理器”->“活动解决方案平台”->“x64”,如果没有x64选项,则选择新建。
参考内容:
http://www.cnblogs.com/liuling/p/2013-12-20.html
http://www.cnblogs.com/babietongtianta/p/3143900.html
1. 编写java类,用该类将DLL对外提供的函数服务进行声明,其中java方法均申明为native,其方法名可以自定义,函数体不用实现。具体代码如下:
package com.aizizai.calldll; public class MyNative { public MyNative() {
} static { System.loadLibrary("hellodll"); } public native static void HelloWord(); public native static int CheckSign(String cstrPubKey,String cstrSignResult,String encryptStr); public native static void get(); public native static void set(); } |
其中,hellodll为动态库的名称,不需要写扩展名。CheckSign函数的入参是三个字符串。
2. 用javah工具,通过java类生成.h头文件。这个.h头文件是C++动态库中的头文件,C++程序实现需要用到它。
1) 用javac MyNative.java 编译MyNative.class文件
2) 用javah MyNative编译出com_aizizai_calldll_MyNative.h文件,其内容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_aizizai_calldll_MyNative */
#ifndef _Included_com_aizizai_calldll_MyNative #define _Included_com_aizizai_calldll_MyNative #ifdef __cplusplus extern "C" { #endif /* * Class: com_aizizai_calldll_MyNative * Method: HelloWord * Signature: ()V */ JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_HelloWord (JNIEnv *, jclass);
/* * Class: com_aizizai_calldll_MyNative * Method: CheckSign * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_aizizai_calldll_MyNative_CheckSign (JNIEnv *, jclass, jstring, jstring, jstring);
/* * Class: com_aizizai_calldll_MyNative * Method: get * Signature: ()V */ JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_get (JNIEnv *, jclass);
/* * Class: com_aizizai_calldll_MyNative * Method: set * Signature: ()V */ JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_set (JNIEnv *, jclass);
#ifdef __cplusplus } #endif #endif |
JNIEXPORT、JNICALL等是jni的关键字。Jstring是jni特有的数据类型,介于java与C++的数据类型之间,jstring不能和char*等同,需要做一定的转换。这边补充一个jni数据类型jint,它对应java入参int类型,其无需转化,可以在C++中当int使用。
3. 编写C++代码实现.h头文件声明的函数,代码如下:
#include "stdafx.h" #include "com_aizizai_calldll_MyNative.h"
JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_HelloWord(JNIEnv *, jclass) { } JNIEXPORT jint JNICALL Java_com_aizizai_calldll_MyNative_CheckSign(JNIEnv * env, jclass, jstring cstrPubKey, jstring cstrSignResult, jstring encryptStr) { const char* cstrPubKey_c; const char* cstrSignResult_c; const char* encryptStr_c; cstrPubKey_c = env->GetStringUTFChars(cstrPubKey, false);//入参由jstring转成char cstrSignResult_c = env->GetStringUTFChars(cstrSignResult, false); encryptStr_c = env->GetStringUTFChars(encryptStr, false); //输出入参 int num = MultiByteToWideChar(0,0, cstrPubKey,-1,NULL,0); wchar_t*widestr = new wchar_t[num]; MultiByteToWideChar(0,0, cstrPubKey,-1,widestr,num); OutputDebugString(widestr); delete []widestr;
return 1; } JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_get(JNIEnv *, jclass) { } JNIEXPORT void JNICALL Java_com_aizizai_calldll_MyNative_set(JNIEnv *, jclass) { } |
编译后生成动态库,命名成hellodll,放入到java.library.path目录中。
4. 用java调用动态库输出结果:
public class DllTest {
public static void main(String[] args) {
String encryptStr = "";// String cstrSignResult = "";// String cstrPubKey ="";//
MyNative myna = new MyNative(); int a = myna.CheckSign(cstrPubKey,cstrSignResult,encryptStr); System.out.println(a); }
} |
常见错误:
1. Jni传递中文时乱码
Java内部使用的16bit的unicode编码(utf-16),中英文都是两个字节;jni使用的utf-8编码,utf-8是变长unicode编码,中文三个字节,ascii一个字节;C++汉字两个字节(GB2312),ascii一个字节。下面提供一个utf8转gb2312的方法:
char* U2G(const char* utf8) { int len = MultiByteToWideChar(CP_UTF8,0,utf8,-1,NULL,0); wchar_t * wstr = new wchar_t[len +1]; memset(wstr,0,len+1); MultiByteToWideChar(CP_UTF8,0,utf8,-1,wstr,len); len = WideCharToMultiByte(CP_ACP,0,wstr,-1,NULL,0,NULL,NULL); char * str = new char[len +1]; memset(str,0,len+1); WideCharToMultiByte(CP_ACP,0,wstr,-1,str,len,NULL,NULL); if(wstr) delete [] wstr; return str; } |
2. 包含jni头文件
在jdk安装目录中找到jni的三个头文件C:\ProgramFiles\Java\jdk1.7.0_25\include下的jni.h;C:\Program Files\Java\jdk1.7.0_25\include\win32下:jawt_md.h、jni_md.h。然后放入到vs的include目录下,我本机目录是C:\ProgramFiles (x86)\Microsoft Visual Studio 10.0\VC\include。
3. Javah编译.h文件时的路径问题
在javah编译.h文件时常会遇到如下错误:
正确方法是退至src根目录,然后在编译类前加上全路径。
常见错误如下:
4. loadlibrary路径
获取java.library.path
System.out.println(System.getProperty("java.library.path"));
5. 32位dll不能在64位调用
编译出来的hellodll,被java调用时出错
解决方法:
修改vs的方案生成配置,“生成”->“配置管理器”->“活动解决方案平台”->“x64”,如果没有x64选项,则选择新建。
参考内容:
http://www.cnblogs.com/liuling/p/2013-12-20.html
http://www.cnblogs.com/babietongtianta/p/3143900.html