Java .NET互操作

Str*_*ill 6 .net c# java com dll

好吧,我一直在挖掘这一段时间,我正在寻找输入.

我需要一个可以加载和卸载本机库的Java应用程序,这很简单,C/C++/Java/Scripts/Executables /等.使用JNI和其他内置功能并不是真正的问题.

但是,我需要能够加载.NET库,这一直是疯狂的沮丧.我的第一个注意事项是使用JNI并调用C++包装器,如下所示:

Java的:

this.Lib = (LibHandler)Native.loadLibrary("MyLib", LibHandler.class);
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这将连续无法由系统加载,我可以交换文件,以便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)
Run Code Online (Sandbox Code Playgroud)

我想我会尝试将C#库编译为COM对象并以这种方式调用它,唉:

ActiveXComponent comp = new ActiveXComponent("MyLib.Class1");
Run Code Online (Sandbox Code Playgroud)

失败:

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)
Run Code Online (Sandbox Code Playgroud)

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!";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以看到COM已注册,我可以用oleview.exe浏览它,但是我不能用vbScript调用它...我对那个很困惑,所以我完全没有想法,这真的是整天绞尽脑汁.

摆脱COM了,但我需要保持implmentation相当简单的(库不会被我们所开发的,所以我不想一堆C/C++代码放到的VB6开发圈) .

我可以回到CLI C++实现方法,因为它很简单,几乎任何人都可以做到.

任何想法都将非常感谢,谢谢.

编辑:

我不能使用System.LoadLibrary,不要让我卸载像Native.LoadLibrary这样的库与指定的类.

Str*_*ill 6

结束了让JNI正确地使用C++代码,我将C++编译为32位,但我正在运行一个64位JVM,这导致了这个非常模糊的错误.

我也遇到了来自.NET的错误(库不在GAC中),所以一定要把它正确地捕获/报告给Java,看来未捕获的异常不能用Java包装我相信.

我可能很快就会在网上发布这个资源,因为许多JNI < - > .NET互操作教程都过于复杂(通常添加看似极其不必要的层).


Prz*_*ski 6

如果你有单一的方法来揭露你的方法是合理的.定义通过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); 
}
Run Code Online (Sandbox Code Playgroud)