Java. NET взаимодействия - PullRequest
6 голосов
/ 17 июня 2011

Хорошо, я некоторое время копался в этом и ищу информацию.

Мне нужно 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, но мне нужно, чтобы реализация была достаточно простой (библиотеки не будут разрабатываться нами, поэтому я не хочу отбрасывать кучу C / C ++ код на коленях разработчиков VB6).

Хорошо бы вернуться к методу реализации CLI C ++, поскольку это так просто, что почти каждый может это сделать.

Любые идеи будут очень признательны, спасибо.

Edit:

Я не могу использовать System.LoadLibrary, не позволяю мне выгружать библиотеки, как это делает Native.LoadLibrary с назначенным классом.

Ответы [ 4 ]

6 голосов
/ 28 октября 2013

Если у вас есть один метод, чтобы раскрыть ваш подход, это разумно.Безусловно, переходя от JNI к C ++ / CLI, а затем .NET - гораздо более надежное решение, и его легче поддерживать, чем пытаться обрабатывать такое взаимодействие с использованием COM-объектов.

В любом случае для тех, у кого есть более сложные требования, такие как вызов любого метода,Передача аргументов ref / out, вызов универсальных методов, получение полей настройки, подписка .NET-событий, обрабатывающих исключения, получение индексированных свойств и т. д. и т. д. Я думаю, что собственное внутреннее обертывание не будет работать, по крайней мере, не по рациональному времени и затратам.

Если у вас есть такие требования или вы просто хотите знать о возможностях, обратите внимание на сторонние мосты Java-.NET, такие как:

Эти два больше подходят для этого случая, как упоминалось IKVM.Эти мосты позволяют вам использовать ЛЮБУЮ библиотеку .NET непосредственно в вашем коде JAVA.Они обрабатывают все упомянутые операции / сценарии и многое другое, в том числе встроенные преобразования типов данных и другие механизмы для известных ловушек.

JNBridge - более тяжелый и более дорогой.Однако у него есть несколько специальных плагинов для корпоративных систем, таких как BizTalk.С другой стороны, Javonet - это очень легкое решение с одним jar-файлом, за полцены с очень простым API.Другое существенное отличие заключается в том, что Javonet работает без прокси-классов, поэтому вам не нужно генерировать какие-либо обертки, которые вы просто называете .NET со стилем отражения, тогда как с помощью JNBridge вы можете генерировать прокси-классы, которые дают вам строго типизированный интерфейс, но это требует больше времени и усилий.,По моему мнению, это немного снижает гибкость, так как мне нравится контролировать то, что происходит под капотом, и с помощью Javonet вы можете легко сделать свой собственный строго типизированный пакет, если хотите.

Я думаю, что это не популярноТем не менее, для решения с одной машиной это отличный подход, который плавно перекрывает разрыв между .NET и JAVA с собственной производительностью.Это доля процента времени выполнения, занимаемая веб-сервисами, и не требует высокоуровневых клиент-серверных инфраструктур.В моих тестах это занимает примерно на 30% больше времени, чем выполнение конкретного кода непосредственно в .NET (это очень привлекательно).

Приятно слышать, что вы решаете ваш случай, и я надеюсь, что этот пост поможет другим с Javaк проблемам взаимодействия .NET.

Ниже вы можете найти пример кода Javonet с использованием класса .NET Random (важно отметить, что со сторонним мостом вы получаете доступ не только к вашей пользовательской DLL, но и к полной .NET Framework):

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

        System.out.println(value); 
}
6 голосов
/ 18 июня 2011

Закончилась корректная работа JNI с кодом C ++, я компилировал C ++ как 32-битный, но у меня 64-битная JVM, которая вызывала эту крайне неопределенную ошибку.

Я также столкнулся с ошибками в .NET (библиотеки не было в GAC), поэтому убедитесь, что вы правильно отловили / сообщили об этом в Java, кажется, что непонятные исключения не могут быть перенесены в Java, я считаю.

Вероятно, я скоро опубликую это онлайн как ресурс, так как многие учебники по JNI <-> .NET очень сложны (обычно добавляя то, что кажется крайне ненужными слоями).

4 голосов
/ 17 июня 2011

Я не знаю, помогает ли это, но проект с открытым исходным кодом IKVM позволяет вам сделать обратное, преобразовав ваше Java-приложение в .Net:

IKVM.NETявляется реализацией Java для Mono и Microsoft .NET Framework.Включает в себя следующие компоненты:

* A Java Virtual Machine implemented in .NET
* A .NET implementation of the Java class libraries
* Tools that enable Java and .NET interoperability
1 голос
/ 18 июня 2011

Ваш код взаимодействия COM выглядит почти правильно.Однако вы не можете создать экземпляр класса с поздним связыванием, пока не определите интерфейс по умолчанию для класса следующим образом:

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