У меня есть сторонняя сборка .NET и большое Java-приложение. Мне нужно вызывать методы, предоставляемые библиотекой классов .NET из приложения Java. Сборка не поддерживает COM.
Я искал в сети, и до сих пор у меня есть следующее:
код C # (cslib.cs):
using System;
namespace CSLib
{
public class CSClass
{
public static void SayHi()
{
System.Console.WriteLine("Hi");
}
}
}
скомпилировано с (с использованием .net 3.5, но то же самое происходит при использовании 2.0):
csc /target:library cslib.cs
код C ++ (clib.cpp):
#include <jni.h>
#using <CSLib.dll>
using namespace CSLib;
extern "C" _declspec(dllexport) void Java_CallCS_callCS(JNIEnv* env, jclass cls) {
CSLib::CSClass::SayHi();
}
скомпилировано с использованием инструментов VC 2008, но то же самое происходит при использовании инструментов 2003:
cl /clr /LD clib.cpp
mt -manifest clib.dll.manifest -outputresource:clib.dll;2
Java-код (CallCS.java):
class CallCS {
static {
System.loadLibrary("clib");
}
private static native void callCS();
public static void main(String[] args) {
callCS();
}
}
Когда я пытаюсь запустить класс Java, происходит сбой Java VM при вызове метода (он может загрузить библиотеку):
#
# An unexpected error has been detected by Java Runtime Environment:
#
# Internal Error (0xe0434f4d), pid=3144, tid=3484
#
# Java VM: Java HotSpot(TM) Client VM (10.0-b19 mixed mode, sharing windows-x86)
# Problematic frame:
# C [kernel32.dll+0x22366]
#
...
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j CallCS.callCS()V+0
j CallCS.main([Ljava/lang/String;)V+0
v ~StubRoutines::call_stub
Однако, если я создаю простое приложение cpp, которое загружает clib.dll и вызывает экспортированную функцию Java_CallCS_callCS, все в порядке.
Я пробовал это на обеих средах x86 и x64, и результат тот же. Я не пробовал другие версии Java, но мне нужен код для запуска на 1.5.0.
Более того, если я изменю clib.cpp так, чтобы он вызывал только системные методы, все отлично работает даже с Java:
#include <jni.h>
#using <mscorlib.dll>
using namespace System;
extern "C" _declspec(dllexport) void Java_CallCS_callCS(JNIEnv* env, jclass cls) {
System::Console::WriteLine("It works");
}
Подвести итог:
- Я СПОСОБЕН вызывать системные методы из Java -> clib.dll -> mscorlib.dll
- Я способен вызывать любые методы из CPPApp -> clib.dll -> cslib.dll
- Я не в состоянии вызвать любые методы из Java -> clib.dll -> cslib.dll
Мне известен обходной путь, который использует 1. выше - я могу использовать отражение, чтобы загрузить ассемблер и вызывать нужные методы, используя только системные вызовы, но код запутывается, и я надеюсь на лучшее решение.
Я знаю о проекте dotnetfromjava, который использует метод отражения, но предпочитаю не добавлять больше сложности, чем необходимо. Я буду использовать что-то вроде этого, если нет другого пути, однако.
Я также посмотрел на ikvm.net, но, насколько я понимаю, он использует свою собственную JVM (написанную на C #), чтобы творить чудеса. Однако запуск всего Java-приложения под его виртуальной машиной для меня не вариант.
Спасибо.