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
package msg;
public class TestJNI {
public native boolean MasSentMessage(String a, String b);
public native int add(int a, int b);
public native String submit(String a, String b);
public native boolean testBoolean(String a, String b);
static {
System.loadLibrary("CPP");
}
public static void main(String[] args) {
TestJNI t = new TestJNI();
// System.out.println(t.MasSentMessage("user", "pass"));
// System.out.println(t.add(2, 20));
System.err.println(t.submit("user", "pass"));
// System.err.println(t.testBoolean("1", "pass"));
}
}
2,調用JDK裏的javah命令經過TestJNI.java類生成msg_TestJNI.h文件,javah設置以下,
3,在Visual Studio 2010新建一個C#項目CSharp(項目類型爲Visual C# -->Windows?類庫)
編輯C#文件以下:
C#代碼
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OJMain
{
public class OJEntrance
{
private int result;
public int Result
{
get { return result + 10; }
set { this.result = value; }
}
public string submit(string str1, string str2)
{
Console.WriteLine("成功調用了dll");
return "CSharp:" + str1 + ":" + str2;
}
public bool testBoolean(string str1, string str2)
{
if (str1.Equals("true"))
{
return true;
}
else
{
return false;
}
}
}
}
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代碼
// char* To jstring
jstring stringTojstring(JNIEnv* env, const char* pat)
{
jclass strClass = env->FindClass("Ljava/lang/String;");
jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = env->NewByteArray(strlen(pat));
env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = env->NewStringUTF("utf-8");
return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}
// jstring To char*
char* jstringTostring(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 > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
// jstring To String
String^ jstringToStr(JNIEnv* env, jstring jstr)
{
char* str = jstringTostring(env, jstr);
String^ value = gcnew String(str);
free(str);
return value;
}
// String To jstring
jstring strTojstring(JNIEnv* env, String^ rtn)
{
pin_ptr<const wchar_t> wch = PtrToStringChars(rtn);
size_t convertedChars = 0;
size_t sizeInBytes = ((rtn->Length + 1) * 2);
char *ch = (char *)malloc(sizeInBytes);
errno_t err = wcstombs_s(&convertedChars,
ch, sizeInBytes,
wch, sizeInBytes);
jstring js = stringTojstring(env, ch);
free(ch);
return js;
}
5.4 編寫C++的管理類, 完整代碼參見附件 CPP.rar(CPP.cpp)
Cpp代碼
#include "jni.h"
#include "jni_md.h"
#include "msg_TestJNI.h"
//引入c#的庫和命名空間
#using "CSharp.dll"
using namespace OJMain;
……
…..
JNIEXPORT jint JNICALL Java_msg_TestJNI_add
(JNIEnv *env, jobject obj, jint a, jint b)
{
//c#中的對象
OJEntrance ^o = gcnew OJEntrance();
o->Result = a + b;
return o->Result;
}
JNIEXPORT jstring JNICALL Java_msg_TestJNI_submit
(JNIEnv *env, jobject obj, jstring str1, jstring str2)
{
//c#中的對象
OJEntrance ^o = gcnew OJEntrance();
return strTojstring(env, o->submit(jstringToStr(env,str1), jstringToStr(env,str2)));
}
JNIEXPORT jboolean JNICALL Java_msg_TestJNI_testBoolean
(JNIEnv *env, jobject obj, jstring str1, jstring str2)
{
//c#中的對象
OJEntrance ^o = gcnew OJEntrance();
return o->testBoolean(jstringToStr(env,str1), jstringToStr(env,str2));
}
5.5利用Visual Studio 2010生成CPP.dll
6,JDK的bin目錄裏放置以下內容
C# 項目CSharp中生成的CSharp.dll ;
C++項目CPP中生成的CPP.dll;
7,在Java項目TestJNI中 運行TestJNI,調用C# dll。
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的狀況