从Java调用.NET程序集:JVM崩溃

时间:2020-03-06 14:46:21  来源:igfitidea点击:

我有一个第三方.NET Assembly和一个大型Java应用程序。我需要从Java应用程序调用.NET类库提供的方法。该程序集不支持COM。
我已经在网上搜索过,到目前为止,我有以下内容:

Ccode(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

但是,如果我创建一个加载clib.dll的普通cpp应用程序并调用导出的函数Java_CallCS_callCS,则一切正常。
我已经在x86和x64环境中进行了尝试,结果是相同的。我没有尝试过其他版本的Java,但是我需要在1.5.0上运行的代码。

此外,如果我将clib.cpp修改为仅调用System方法,那么即使从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#编写)来完成任务。但是,对我来说,在其VM下运行整个Java应用程序是不可行的。

谢谢。

解决方案

我们是否看过ikvm.NET,它允许在.NET和Java代码之间进行调用?

好了,谜团解决了。

JVM崩溃是由未处理的System.IO.FileNotFoundException引起的。发生异常是因为在调用exe文件所在的文件夹中搜索了.NET程序集。

  • mscorlib.dll位于全局程序集缓存中,因此可以正常工作。
  • CPP应用程序exe与程序集位于同一文件夹中,因此它也可以工作。
  • cslib.dll程序集位于java.exe文件夹中,位于GAC中的NOR中,因此它无法正常工作。

看来,我唯一的选择是在GAC中安装.NET程序集(第三方dll确实有很强的名称)。

看一下jni4net,它将为我们完成艰苦的工作。