【问题标题】:Java to C# through JNI fails to load C# dllJava 通过 JNI 到 C# 无法加载 C# dll
【发布时间】:2016-09-15 17:20:02
【问题描述】:

我正在围绕 C# 项目构建 Java 包装器。我正在使用 C++ 在 Java 和 C# 之间进行切换。我的问题是,当我运行我的 Java 应用程序时,我收到“无法加载文件或程序集 'MyC#DLL,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null' 或其依赖项之一。系统无法找到指定的文件。”错误。如果我删除 C++ 中对 C# 代码的调用,则加载正常,就 Java 到 C++ 部分而言,但是当我尝试调用 C# 时,dll 无法加载。我在包装 C++ 代码之外创建了一个 C++ 测试类,以尝试调用,并且一切正常。 C# dll 加载并按预期运行。所以我猜这是我的 Java 项目设置的问题,但我似乎找不到它。

我尝试使用 Process Monitor 来确保 C# dll 没有加载,但事实并非如此。 c++ 包装器确实加载正确。

我的 Java 代码正在项目文件夹中执行,但其他所有内容(C++ 和 C#)都在同一目录中。任何帮助表示赞赏。

Java 代码:

public final class MyClass{

static {
    try
    {
        System.load("C:\\Dir\\CppBridge.dll");
    }
    catch(Exception e)
    {
        System.out.println("-!-!- Error loading library -!-!-");
    }

}

private static native String getXML();

public static List<Site> getXMLFromC#()
{
    String xml = MyClass.getXML();
}}

C++ 代码(Methods.h):

public ref class Wrapper
{
    public: MyPackage::C#Project^ api;
    public: Wrapper()
    {
        api = gcnew MyPackage::C#Project;
    }

    public: char* getXML()
    {
        char* error;
        try
        {
            System::String^ xml = api->getXML();
            return (char*)Marshal::StringToHGlobalAnsi(xml).ToPointer();
        }
        catch (Exception^ e)
        {
            char* error = (char*)Marshal::StringToHGlobalAnsi("Error:" + e->Message).ToPointer();
        }
        return error;
    }
};

C++ 代码 (CppBridge.h)

#include <jni.h>
/* Header for class MyC#Class*/

#ifndef _Included_MyC#Class
#define _Included_MyC#Class
#ifdef __cplusplus
extern "C" {
#endif
    /*
    * Class:     MyC#Class
    * Method:    getUserSites
    * Signature: String, String, String, String, String, boolean
    */
    JNIEXPORT jstring JNICALL Java_MyPackage_getXML(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

C++ 代码 (CppBridge.cpp)

using namespace System::Runtime::InteropServices; //Marshal

class CppBridge
{
    public: CppBridge() {};
};

JNIEXPORT jstring JNICALL Java_MyPackage_getXML(JNIEnv *jn, jobject jobj)
{
    jstring error;
    try
    {
        Methods::Wrapper^ wrapper = gcnew Methods::Wrapper();
        char* xml = wrapper->getXML();
        jstring result = jn->NewStringUTF(xml);
        return result;
    }
    catch (Exception^ e)
    {
        char* result = (char*)Marshal::StringToHGlobalAnsi("Source: "+ e->Source + " | Message: " + e->Message).ToPointer();
        error = jn->NewStringUTF(result);
    }
    return error;
}

【问题讨论】:

    标签: java c# c++ java-native-interface


    【解决方案1】:

    一年前我也遇到过同样的问题,原因很简单:java.exe 找不到 C# DLL,因为 java.exe 只在 java.exe 和系统 GAC 的同一文件夹中搜索 C# DLL。

    那么解决这个问题,有两种方法:

    1. 将你的 C# DLL 及其依赖项放在 java.exe 的同一个文件夹中

    2. 签署您的 C# DLL 并使其成为强名称,然后将其安装到 GAC

    要了解 java.exe 如何搜索 DLL,请使用 Microsoft 的工具 procmon

    【讨论】:

    • Dang,我试过这个,但把它们放在 JDK bin 而不是 JRE bin 中。谢谢你让我看的更仔细。
    • 进程是从 java.exe(或 javaw.exe)创建的并不重要。一旦运行 .NET,它就与加载 .NET 的任何其他进程相同:读取相同类型的配置文件(命名为 java.exe.config)(如果存在),同样的 assembly resolution procedure 适用,同样的可以使用工具。 Fusion Log Viewer 是专用工具,但 procmon 是一个不错的选择。
    • @TomBlodget 感谢您的解释。现在我知道原因了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多