JNI 調用,C++ invoke C# dll return to java(見git代碼)

Java沒法直接調用C# dll,須要經過通過橋接的方式,進行中繼轉發一下請求。查閱大量資料,作了大量實驗,不停的調試、排錯以後,期間試過jni4net,不過這個插件須要 修改原有的C# DLL內容,還會生成一些額外的Java代碼,jni4net侵入性太多,將它排除。最後經過管理性的C++橋接方式,成功完成了Java調用C# DLL。java

國內不少文章都是隻有文章,沒有在文中附上完整的代碼工程,致使讀者作實驗時很是麻煩。而老外常常會帶上完整的代碼工程,這讓讀者作實驗時參考起來很是方便。本文附上完整的Java、C++、CSharp代碼工程,供你們參考。c#

 

實驗環境:多線程

64位 Win 7測試

jdk1.7.0_51this

Eclipse 4.3.1spa

Visual Studio 2010插件

 

 

具體的實現步驟以下:線程

1,新建一個Java項目TestJNI,定義一個Java客戶端類 TestJNI.java調試

 

Java代碼  收藏代碼code

  1. package msg;  

  2.   

  3. public class TestJNI {     

  4.          

  5.     public native boolean MasSentMessage(String a, String b);     

  6.       

  7.     public native int add(int a, int b);     

  8.     public native String submit(String a, String b);     

  9.     public native boolean testBoolean(String a, String b);     

  10.     static {     

  11.         System.loadLibrary("CPP");     

  12.     }     

  13.     public static void main(String[] args) {     

  14.         TestJNI t = new TestJNI();     

  15.           

  16. //        System.out.println(t.MasSentMessage("user", "pass"));    

  17. //        System.out.println(t.add(2, 20));     

  18.         System.err.println(t.submit("user", "pass"));  

  19. //        System.err.println(t.testBoolean("1", "pass"));  

  20.     }     

  21. }  

 

 

2,調用JDK裏的javah命令經過TestJNI.java類生成msg_TestJNI.h文件,javah設置以下, 

 
 

 

3,在Visual Studio 2010新建一個C#項目CSharp(項目類型爲Visual C# -->Windows?類庫)

編輯C#文件以下:

C#代碼  收藏代碼

  1. using System;  

  2. using System.Collections.Generic;  

  3. using System.Linq;  

  4. using System.Text;  

  5.   

  6. namespace OJMain  

  7. {  

  8.     public class OJEntrance  

  9.     {  

  10.         private int result;  

  11.         public int Result  

  12.         {  

  13.             get { return result + 10; }  

  14.             set { this.result = value; }  

  15.         }  

  16.         public string submit(string str1, string str2)  

  17.         {  

  18.            Console.WriteLine("成功調用了dll");  

  19.            return "CSharp:" + str1 + ":" + str2;  

  20.         }  

  21.         public bool testBoolean(string str1, string str2)  

  22.         {  

  23.             if (str1.Equals("true"))  

  24.             {  

  25.                 return true;  

  26.             }  

  27.             else  

  28.             {  

  29.                 return false;  

  30.             }  

  31.         }  

  32.     }  

  33. }  

 

 

4,利用Visual Studio 2010 生成dll。

若是調用C#項目的Java客戶端在64位的機器上,須要從新生成dll,在Visual Studio 2010的生成參數設置以下,將目標平臺設爲「Any CPU」



 

 

5,在Visual Studio 2010中新建一個win32 dll模式的C++項目CPP,爲了在Java和C#之間的調用創建通道並進行轉接。

 

5.1設置兩個項目屬性

一,項目屬性-->配置屬性--> 常規:「公共語言運行時支持」設爲「公共語言運行時支持(/clr)」

二,項目屬性-->配置屬性-->C/C++-->代碼生成:「運行庫」設爲「多線程DLL(/MD)」

 

5.2  C++源文件的目錄裏放置以下內容:

  • JDK目錄裏的兩個h文件(jni.h,jni_md.h);

  • Java項目中生成的msg_TestJNI.h;

  • C#項目CSharp中生成的CSharp.dll ;

5.3編寫jstring 和 string的相互轉換功能,完整代碼參見附件 CPP.rar(CPP.cpp)。

Cpp代碼  收藏代碼

  1. // char* To jstring  

  2. jstring stringTojstring(JNIEnv* env, const char* pat)  

  3. {   

  4.     jclass strClass = env->FindClass("Ljava/lang/String;");   

  5.     jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");   

  6.     jbyteArray bytes = env->NewByteArray(strlen(pat));   

  7.     env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);   

  8.     jstring encoding = env->NewStringUTF("utf-8");   

  9.     return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);   

  10. }  

  11. // jstring To char*  

  12. char* jstringTostring(JNIEnv* env, jstring jstr)  

  13. {  

  14.     char* rtn = NULL;  

  15.     jclass clsstring = env->FindClass("java/lang/String");  

  16.     jstring strencode = env->NewStringUTF("utf-8");  

  17.     jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");  

  18.     jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);  

  19.     jsize alen = env->GetArrayLength(barr);  

  20.     jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);  

  21.     if (alen > 0)  

  22.     {  

  23.         rtn = (char*)malloc(alen + 1);  

  24.         memcpy(rtn, ba, alen);  

  25.         rtn[alen] = 0;  

  26.     }  

  27.     env->ReleaseByteArrayElements(barr, ba, 0);  

  28.     return rtn;  

  29. }  

  30. // jstring To String  

  31. String^ jstringToStr(JNIEnv* env, jstring jstr)  

  32. {  

  33.     char* str = jstringTostring(env, jstr);  

  34.     String^ value = gcnew String(str);  

  35.     free(str);  

  36.     return value;  

  37. }  

  38.   

  39. // String To jstring  

  40. jstring strTojstring(JNIEnv* env, String^ rtn)  

  41. {  

  42.     pin_ptr<const wchar_t> wch = PtrToStringChars(rtn);  

  43.     size_t convertedChars = 0;  

  44.     size_t sizeInBytes = ((rtn->Length + 1) * 2);  

  45.     char *ch = (char *)malloc(sizeInBytes);  

  46.     errno_t err = wcstombs_s(&convertedChars,   

  47.         ch, sizeInBytes,  

  48.         wch, sizeInBytes);  

  49.     jstring js = stringTojstring(env, ch);  

  50.     free(ch);  

  51.     return js;  

  52. }  

 

5.4  編寫C++的管理類, 完整代碼參見附件 CPP.rar(CPP.cpp)

Cpp代碼  收藏代碼

  1. #include "jni.h"     

  2. #include "jni_md.h"  

  3. #include "msg_TestJNI.h"   

  4.   

  5. //引入c#的庫和命名空間  

  6. #using "CSharp.dll"  

  7. using namespace OJMain;   

  8. ……  

  9. …..  

  10. JNIEXPORT jint JNICALL Java_msg_TestJNI_add     

  11.   (JNIEnv *env, jobject obj, jint a, jint b)     

  12. {     

  13.     //c#中的對象     

  14.     OJEntrance ^o = gcnew OJEntrance();     

  15.     o->Result = a + b;     

  16.     return o->Result;     

  17. }  

  18.   

  19. JNIEXPORT jstring JNICALL Java_msg_TestJNI_submit  

  20.   (JNIEnv *env, jobject obj, jstring str1, jstring str2)    

  21. {     

  22.     //c#中的對象     

  23.     OJEntrance ^o = gcnew OJEntrance();     

  24.     return strTojstring(env, o->submit(jstringToStr(env,str1), jstringToStr(env,str2)));     

  25. }  

  26.   

  27. JNIEXPORT jboolean JNICALL Java_msg_TestJNI_testBoolean  

  28.   (JNIEnv *env, jobject obj, jstring str1, jstring str2)    

  29. {     

  30.     //c#中的對象     

  31.     OJEntrance ^o = gcnew OJEntrance();     

  32.     return o->testBoolean(jstringToStr(env,str1), jstringToStr(env,str2));    

  33. }  

 

5.5利用Visual Studio 2010生成CPP.dll

 

 

6,JDK的bin目錄裏放置以下內容

  • C# 項目CSharp中生成的CSharp.dll ;

  • C++項目CPP中生成的CPP.dll;

 

7,在Java項目TestJNI中 運行TestJNI,調用C# dll。

 

 

 

 

JNI java.lang.UnsatisfiedLinkError Can't find dependent libraries解決

java使用C++得DLL,DLL是使用VS2010編譯,在本機上測試經過,但測試人員測試時報java.lang.UnsatisfiedLinkError Can't find dependent libraries,這裏說明,庫得路徑都是對得,沒必要糾纏與找不到庫路徑。測試同事裝了VS2010後issue消失。
 在沒裝VS得虛擬機上重現issue,解決方法是VS2010編譯C++的DLL時去掉/MD選項:
修改DLL工程屬性:
property:
Configuration: Active(Release) Platform Active(x64)
C/C++ -> Code Generation -> Runtime Library
將 Multi-threaded DLL (/MD)去掉,留空白
從新編譯DLL,不用裝VS2010測試經過。

 

記得先複製.h文件到項目根目錄,而後再添加現有項,否則會出現找不到jni.h和XXXX.h的狀況

相關文章
相關標籤/搜索