使用JNI调用第三方.NET DLL

4
我正在尝试从JAVA程序中调用一个第三方.NET DLL(从这里获取)。在查看这里这里后,我设法使整个程序编译并运行。但是,在运行.NET代码时出现异常:

Java运行环境检测到致命错误

只有当我尝试从.NET DLL内部访问另一个.NET对象和方法时才会发生这种情况:

JNIEXPORT void JNICALL Java_test_broadcast
(JNIEnv *, jobject)
{
   // Instantiate the MC++ class.
   IManagedWrapper* t = IManagedWrapper::CreateInstance();

   // The actual call is made. 
   t->Broadcast();
}

void ManagedWrapper::Broadcast(std::string message)
{
   //Uncommenting the following line will raise the error
   //IXDBroadcast^ broadcast = XDBroadcast::CreateBroadcast(XDTransportMode::WindowsMessaging);
}

我已成功创建了一个连接到上述代码并按预期工作的.NET DLL。
如何从Java代码中调用.NET对象和方法?

1
谷歌向我展示了:JNI4NET在不使用regasm.exe的情况下从Java代码调用.Net Dlls。如果你有意愿和毅力,它很可能会向你展示更多解决方案。 - Hovercraft Full Of Eels
谢谢!在发帖之前我找了两天,但是我从来没有遇到你发布的第二个链接。那个解决了我的问题! - Eldad
我想知道是否有人拥有@HovercraftFullOfEels提到的第二个链接中的代码 - 它已经从页面上消失了。 - Konrads
2个回答

4
我最终按照评论中的@"Hovercraft Full Of Eels"的链接:在不使用regasm.exe的情况下从Java代码调用.Net Dlls进行了跟随。
我使用了C++\CLI来桥接本地和托管代码,效果非常好。主要问题是我的桥接DLL在JVM下运行,而我尝试加载的DLL不在JRE\bin目录中。为了解决这个问题,我从C++/CLI代码动态加载了.Net程序集(基于此文)。
static Assembly^ MyResolveEventHandler( Object^ sender, ResolveEventArgs^ args )
{
    //Retrieve the list of referenced assemblies in an array of AssemblyName.
    Assembly^ MyAssembly;
    Assembly^ objExecutingAssemblies;
    String^ strTempAssmbPath = "";

    objExecutingAssemblies = Assembly::GetExecutingAssembly();
    array<AssemblyName ^>^ arrReferencedAssmbNames = objExecutingAssemblies->GetReferencedAssemblies();

    //Loop through the array of referenced assembly names.
    for each (AssemblyName^ strAssmbName in arrReferencedAssmbNames)
    {
        //Check for the assembly names that have raised the "AssemblyResolve" event.
        if (strAssmbName->FullName->Substring(0, strAssmbName->FullName->IndexOf(",")) == args->Name->Substring(0, args->Name->IndexOf(",")))
        {
            //Build the path of the assembly from where it has to be loaded.                
            strTempAssmbPath = pathBase + args->Name->Substring(0, args->Name->IndexOf(",")) + ".dll";
            break;
        }

    }
    //Load the assembly from the specified path.                    
    MyAssembly = Assembly::LoadFrom(strTempAssmbPath);

    //Return the loaded assembly.
    return MyAssembly;
}

我有完全相同的情况(通过JNI将JVM转换为DLL,然后C ++尝试使用托管的C#DLL并失败),但我从未收到AssemblyResolve事件的回调。 - NateS

1
这正是本地Java到.NET桥在后台执行的操作。根据您需要使用的.NET代码量和.NET对象的复杂性(您拥有哪种方法,是否使用泛型,是否拥有数组等...),您可能还需要考虑使用这样的桥梁。如果您深入研究这种情况,那么手动通过C++/CLI进行操作时会出现更多限制。如果您需要快速可靠的生产环境解决方案,我建议您检查以下内容: 这些桥梁中的每一个都将为您覆盖所有本地通信,并提供非常简单易用的接口,使.NET可以在您的JAVA应用程序中加载任何DLL甚至使用整个.NET Framework。
根据您的需求,我认为Javonet是最易于使用且功能强大、灵活性高的选择,如果您需要可靠的商业解决方案、良好的支持和易于使用的API,在5分钟内就能完成任务(非商业和学术用途免费)。JNBridge生成强类型代理类的负担更重,同样非常强大,特别适合商业用途,尤其是如果您需要他们的专用连接器之一(会影响价格,但取决于您的需求)。JNI4NET是一个很好的开源项目,我认为适用于非关键、非商业应用程序,但值得一试。
有了这样的桥梁,您不必担心任何额外的实现,只需复制.NET dll并在JAVA中使用即可。您可以在此处查看:http://www.youtube.com/watch?v=n6XfzrHTdK4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接