簡體   English   中英

Java .NET互操作

[英]Java .NET interop

好吧,我一直在挖掘這一段時間,我正在尋找輸入。

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

但是,我需要能夠加載.NET庫,這一直是瘋狂的沮喪。 我的第一個注意事項是使用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對象並以這種方式調用它,唉:

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

失敗:

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#代碼:

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已注冊,我可以用oleview.exe瀏覽它,但是我不能用vbScript調用它...我對那個很困惑,所以我完全沒有想法,這真的是整天絞盡腦汁。

擺脫COM了,但我需要保持implmentation相當簡單的(庫不會被我們所開發的,所以我不想一堆C / C ++代碼放到的VB6開發圈) 。

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

任何想法都將非常感謝,謝謝。

編輯:

我不能使用System.LoadLibrary,不要讓我卸載像Native.LoadLibrary這樣的庫與指定的類。

如果你有單一的方法來揭露你的方法是合理的。 定義通過JNI到C ++ / CLI,然后.NET比嘗試使用COM對象處理此類通信更加可靠,更易於維護。

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

如果您有這樣的要求或只是想知道可能性,請查看第三方Java到.NET Bridges,如:

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

JNBridge的重量更輕,更貴。 但它有一些專用的插件,適用於BizTalk等企業系統。 另一方面,Javonet是一款非常輕便的jar文件解決方案,價格非常便宜。 另一個主要的區別是Javonet在沒有代理類的情況下工作,所以你不必生成任何你只用反射風格調用.NET的包裝器,而通過JNBridge,你可以生成代理類,為你提供強類型的接口,但它需要更多的時間和精力。 在我看來,它會降低靈活性,因為我喜歡控制在引擎蓋下發生的事情,如果你願意,你可以輕松地制作自己的強類型包裝。

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

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

下面你可以找到使用.NET Random類的Javonet的示例代碼(重要的是要注意,使用第三方橋,您不僅可以訪問自定義DLL,還可以訪問完整的.NET框架):

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

        System.out.println(value); 
}

結束了讓JNI正確地使用C ++代碼,我將C ++編譯為32位,但我正在運行一個64位JVM,這導致了這個非常模糊的錯誤。

我也遇到了來自.NET的錯誤(庫不在GAC中),所以一定要把它正確地捕獲/報告給Java,看來未捕獲的異常不能用Java包裝我相信。

我可能很快就會在網上發布這個資源,因為許多JNI < - > .NET互操作教程都過於復雜(通常添加看似極其不必要的層)。

我不知道這是否有幫助,但是開源項目IKVM允許你做相反的事情,將你的Java應用程序轉換為.Net:

IKVM.NET是Mono和Microsoft .NET Framework的Java實現。 它包括以下組件:

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

您的COM互操作代碼看起來幾乎正確。 但是,在您定義類的默認接口之前,您不能實例化后端綁定的coclass,如下所示:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM