2011-06-16 179 views
5

好吧,我一直在挖掘這一點,並正在尋找輸入。Java .NET互操作

我需要一個可以加載和卸載本機庫的Java應用程序,很簡單,C/C++/Java/Scripts/Executables/etc。使用JNI和其他內置功能並不是真正的問題。

但是,我需要能夠加載.NET庫,這一直是令人沮喪的。我的第一個attept是使用JNI和調用C++封裝爲低於:

的Java:

this.Lib = (LibHandler)Native.loadLibrary("MyLib", LibHandler.class); 

的CPP:

#include <jni.h> 
#using <MyLibCSharp.dll> 
#include <vcclr.h> 
#include <msclr\marshal.h> 

using namespace msclr::interop; 
using namespace System::Runtime::InteropServices; 
using namespace System; 

extern "C" 
{ 
    JNIEXPORT jstring JNICALL Java_Test(JNIEnv * env) 
    { 
     marshal_context^context = gcnew marshal_context(); 
     const char* str4 = context->marshal_as<const char*>(CSharp::Class1::Test()); 

     jstring js = env->NewStringUTF(str4); 


     return js; 
    } 

    JNIEXPORT jstring JNICALL Java_Test2(JNIEnv * env, jobject jobj) 
    { 
     marshal_context^context = gcnew marshal_context(); 
     const char* str4 = context->marshal_as<const char*>(CSharp::Class1::Test()); 

     jstring js = env->NewStringUTF(str4); 


     return js; 
    } 
} 

這將汽車無故障,甚至被系統加載,我可以交換文件,以便MyLib.dll實際上是C#之一,它成功加載它(但未能找到任何函數,因爲它不是一個本地C庫,我不認爲.NET可以像C++一樣導出),所以我沒有文件位置問題。

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'MyLib.dll': The specified module could not be found. 
    at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:163) 
    at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:236) 
    at com.sun.jna.Library$Handler.<init>(Library.java:140) 
    at com.sun.jna.Native.loadLibrary(Native.java:379) 
    at com.sun.jna.Native.loadLibrary(Native.java:364) 
    at EntryPoint.main(EntryPoint.java:31) 

我想我會嘗試編譯C#庫作爲一個COM對象,並調用它的方式,唉:

Exception in thread "main" com.jacob.com.ComFailException: Can't co-create object 
    at com.jacob.com.Dispatch.createInstanceNative(Native Method) 
    at com.jacob.com.Dispatch.<init>(Dispatch.java:99) 
    at com.jacob.activeX.ActiveXComponent.<init>(ActiveXComponent.java:58) 
    at EntryPoint.main(EntryPoint.java:33) 

C#代碼:

ActiveXComponent comp = new ActiveXComponent("MyLib.Class1"); 

與失敗:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 



namespace MyLib 
{ 
    [Guid("4F3A0A13-4D2B-4DE6-93EA-D6861C230290"), 
    ComVisible(true)] 
    public interface ITest 
    { 
     [DispId(1)] 
     string Test(); 
    } 

    [Guid("A78C5820-3E4B-49B3-8C8E-63DD12346410"), 
    InterfaceType(ComInterfaceType.InterfaceIsIDispatch), 
    ComVisible(true)] 
    public interface ITestEvents 
    { 
    } 

    [Guid("3ECD46AE-E8F4-4B62-B9DC-DD7F6CB435E2"), 
    ClassInterface(ClassInterfaceType.None), 
    ComSourceInterfaces(typeof(ITestEvents)), 
    ComVisible(true)] 
    public class Class1 : ITest 
    { 
     public string Test() 
     { 
      return "This is my C# DLL COM returning a string! heh!"; 
     } 
    } 
} 

我可以看到COM是註冊表ered,我可以用oleview.exe來瀏覽它,但是我不能從vbScript中調用它...我對這個問題感到困惑,所以我完全沒有想法,這真的是一整天都在絞盡腦汁。

我想要脫離COM,但我需要保持相當簡單(庫不會由我們開發,所以我不想丟棄一堆C/C++代碼到VB6開發者的一圈)。

我會回到CLI C++實現方法,因爲它很簡單,幾乎任何人都可以做到。

任何想法將不勝感激,謝謝。

編輯:

我不能使用的System.loadLibrary,不會讓我卸載庫,例如Native.LoadLibrary與分配的種類呢。

+0

下面你可以使用.NET Random類找到Javonet的示例代碼(它注意到,與第三方橋你不僅可以自定義DLL,但完整的.NET框架的訪問是非常重要的)可能的重複[調用C#代碼從Java?](http://stackoverflow.com/questions/50398/calling-c-sharp-code-from-java) – Unsigned 2014-01-15 04:44:31

回答

6

最終獲得JNI與C++代碼工作正常,我正在編譯C++爲32位,但是我正在運行一個64位的JVM,這導致了這個非常模糊的錯誤。我也遇到了來自.NET的錯誤(庫不在GAC中),所以一定要正確地捕捉/報告給Java,似乎未捕獲的異常不能用Java封裝。我相信。

我很可能很快就會在線發佈此資源,因爲許多JNI < - > .NET互操作教程的方式過於複雜(通常會添加看似極其不必要的圖層)。

4

我不知道這是否會有所幫助,但開源項目IKVM允許你做相反,Java應用程序轉換到.NET:

IKVM.NET is an implementation of Java for Mono and the Microsoft .NET Framework. It includes the following components:

* A Java Virtual Machine implemented in .NET 
* A .NET implementation of the Java class libraries 
* Tools that enable Java and .NET interoperability 
+1

糾正我,如果我錯了,但不是IKVM與我想要的相反嗎?我把我的Java應用程序,並基本上變成了一個。NET的一個......是啊,我想在這一點上,我可以調用.NET庫,但是這將打破我們的跨平臺支持(不是我們需要* nix系統上的.NET庫,但這基本上要求我們有一個叉在我的Java程序中,我認爲這有點傻)。 如果沒有真正的其他方式,我想我可以走這條路。 – StrangeWill 2011-06-16 20:40:33

+0

好吧,以及我試圖將.NET DLL轉換爲.jar,並以此結束:「線程中的異常」main「java.lang.NoClassDefFoundError:cli/System/Object」,[Googling it](http:/ /comments.gmane.org/gmane.comp.java.ikvm.devel/2437)表明它不能這樣做。我正在使用ikvmstub來轉換我的DLL,有沒有另一種方法我應該這樣做? – StrangeWill 2011-06-17 13:09:54

+0

不幸的是,你說得對,我發現這樣一句話:「由ikvmstub生成的jar文件包含與.NET類對應的Java類和接口,但不包含任何實際代碼,它們只包含足以滿足Java編譯器,並允許它鍵入檢查Java應用程序。「這是我找到它的頁面:http://sourceforge.net/apps/mediawiki/ikvm/index.php?title=Tutorial – yms 2011-06-17 13:38:55

1

你的COM互操作代碼看起來幾乎是正確的。但是,你不能實例化的組件類後期綁定,直到你定義的類默認界面是這樣的:

[Guid("3ECD46AE-E8F4-4B62-B9DC-DD7F6CB435E2"), 
ClassInterface(ClassInterfaceType.None), 
ComDefaultInterface(typeof(ITest)), 
ComSourceInterfaces(typeof(ITestEvents)), 
ComVisible(true)] 
public class Class1 : ITest 
+0

非常感謝,COM interop仍然非常有用,我相信我會遇到將來再次實施它的問題。 – StrangeWill 2011-06-20 15:10:16

5

如果你有一個方法來暴露你的做法是合理的。明確地說,通過JNI到C++/CLI,然後.NET比使用COM對象處理這種通信更加可靠和易於維護。

無論如何,對於那些有更復雜的要求,如調用任何方法,傳遞ref/out參數,調用泛型方法,獲取設置字段,訂閱.NET事件處理異常,獲取索引屬性等..等等..我認爲自定義本地包裝將無法工作,至少不是合理的時間和成本。

如果你有這樣的要求或只是要了解possbilities的,請看一看第三方Java到.NET橋樑喜歡:

這些正如前面提到的IKVM,兩個更適合這種情況。這些橋讓你直接在你的JAVA代碼中使用任何.NET庫。他們處理所有提到的操作/場景等等,包括內置的數據類型轉換和其他已知陷阱機制。

JNBridge是一個更輕,更昂貴的點燃。但是它有一些專用插件用於BizTalk等企業系統。另一方面,Javonet是一個非常簡單的jar文件解決方案,其價格非常簡單,只需一個API。另一個主要區別是Javonet沒有代理類工作,所以你不必生成任何你只是用反射風格調用.NET的包裝器,而通過JNBridge你可以生成代理類,它爲你提供強類型的接口,但它需要更多的時間和精力。在我看來,它有點降低了靈活性,因爲我喜歡對這種情況進行控制,並且在Javonet下可以輕鬆製作自己的強類型包裝(如果您喜歡)。

我認爲這還不是很受歡迎,但對於單機解決方案來說,它是一種很好的方法,可以無縫地覆蓋.NET和JAVA與本機性能之間的差距。這是Web服務執行時間百分比的一小部分,並且不需要任何高級別的客戶端 - 服務器基礎架構。在我的測試中,它比直接在.NET中執行特定代碼花費的時間多30%(這非常有吸引力)。

很高興聽到你解決你的問題,我希望這篇文章能幫助其他人解決Java與.NET之間的互操作問題。

public void GenerateRandomNumber() throws JavonetException 
{ 
     NObject objRandom = Javonet.New("System.Random"); 
     int value = objRandom.invoke("Next",10,20); 

     System.out.println(value); 
}