Java 到 C# 使用 JNI 导致 StackOverflowException

问题描述 投票:0回答:1

1。总结问题:

我想通过调用 Java 方法来调用 C# 方法来检查许可证文件。此许可证检查是使用 C# dll 执行的。我正在使用 JNI 和 C++ 包装器。我将在下面提供必要的源代码。 C# dll 有一个方法

public static string GetLicenseStatus()
实现,我为它编写了一个包装器,现在我正试图从 Java 应用程序调用这个方法。 我正在使用 Eclipse Adoptium(64 位)的 jdk-17.0.2.8-hotspot 和 IntelliJ IDEA 作为 Java IDE 和 Visual Studio 2022 for C# 项目。

在 Java 方法调用之后,我希望它返回一个字符串(0-4 之间的数字,无效,有效,过期,...)但是当执行/访问 C# 代码时它会导致 StackOverflowException。

2。描述你尝试过的东西

我还尝试在 C++ 方法中只返回一个值,而不调用任何 C# 代码;这很好用。所以 JNI <--> C++ 包装器工作正常.

我还尝试在 C# 主类中运行 C# 源代码,这也工作正常。所以没有错误的 C# 代码。

值得一提的是,我可能还尝试创建自己的 C# dll 以确认该问题与许可证 dll 无关(这就是我之前写过“Visual Studio 中的 C# 项目”的原因)。这个 dll 非常基础,只是检查虚拟用户名和密码。即使当我试图在函数中返回 true 时,当从 Java 调用它时,它也会在 Java IDE 中再次导致 StackOverflowException。它在尝试使用

gcnew
实例化对象时遇到此错误。我自己创建的 C# 类和 C# 许可证 dll 被添加为 C++ 项目中的参考。

也许还值得一提:

  • 我假设 C# dll 依赖于另一个 dll 来处理许可证检查。
  • 我观察到 Visual Studio 出于某种原因无法识别导入的头文件。我必须在 Visual Studio 中手动添加它们并将粘贴代码复制到手动创建的文件中。

3。显示一些代码

“Authenticator.java”:

package org.example;

public class Authenticator {
    static {
        System.loadLibrary("CppAuthenticator");
    }

    public native boolean authenticate(String username, String password);
    public native String getLicenseStatus();

    public static void main(String[] args) {
        System.out.println("Program start");
        Authenticator authenticator = new Authenticator();
        System.out.println("Authenticator created");
        /**boolean valid = authenticator.authenticate(args[0], args[1]);
        System.out.println("Is valid?: "+valid);
        if(!valid) {
            System.err.println("Not valid!");
            System.exit(1);
        }
        else {
            System.out.println("Valid");
        }**/
        System.out.println("License Check...");
        System.out.println("Status: "+authenticator.getLicenseStatus());
    }
}

“CppAuthenticator.cpp”

#include "pch.h"

#include <msclr\marshal.h>
#include "CppAuthenticator.h"
#include "org_example_Authenticator.h"
// this is the main DLL file.
#include <string>

using System::Text::Encoding;

String^ toString(const char* chars) {
    int len = (int)strlen(chars);
    array<unsigned char>^ a = gcnew array<unsigned char> (len);
    int i = 0;
    while (i < len) {
        a[i] = chars[i];
    }
    return Encoding::UTF8->GetString(a);
}

bool authenticate(const char* username, const char* password) {
    SharpAuthenticator::Authenticator^ a = gcnew SharpAuthenticator::Authenticator();   // Fails here
    return a->Authenticate(toString(username), toString(password));
}

JNIEXPORT jboolean JNICALL Java_org_example_Authenticator_authenticate
(JNIEnv* env, jobject c, jstring username, jstring password) {
    jboolean isCopyUsername;
    const char *c_username = env->GetStringUTFChars(username, &isCopyUsername);
    jboolean isCopyPassword;
    const char* c_password = env->GetStringUTFChars(password, &isCopyPassword);
    jboolean result = authenticate(c_username, c_password);
    env->ReleaseStringUTFChars(username, c_username);
    env->ReleaseStringUTFChars(password, c_password);
    return result;
}


String^ getLicenseStatus() {
    return LicenseCheck::ValidateLicense::GetLicenseStatus();                       // Fails here
}

JNIEXPORT jstring JNICALL Java_org_example_Authenticator_getLicenseStatus
(JNIEnv* env, jobject c) {
    String^ cliString = getLicenseStatus();
    msclr::interop::marshal_context context;
    const char* utf8String = context.marshal_as<const char*>(cliString);
    jstring result = env->NewStringUTF(utf8String);
    return result;
}

“SharpAuthenticator.cs”:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SharpAuthenticator
{
    public class Authenticator
    {
        public bool Authenticate(String username, String password)
        {
            return username == "user" && password == "pass";
        }
        public bool Authenticate1()
        {
            return false;
        }
    }
}

这是我在 Visual Studio 中的项目结构(“org_example_Authenticator.h”代码是使用“javac -h ...”创建的 - 命令位于上述 JDK 的 bin 文件夹中。)

以下是 Visual Studio 中的 C++ 项目属性:

这里是我自己创建的上面提到的虚拟 dll 的 C# 项目属性:

java c# c++ dll java-native-interface
1个回答
0
投票

这是一个愚蠢的错误...我花了 1.5 天的时间才发现我忘记在“CppAuthenticator.cpp”的

i
方法的 while 循环中增加
toString
。 这里是正确的工作方法:

String^ toString(const char* chars) {
    int len = (int)strlen(chars);
    array<unsigned char>^ a = gcnew array<unsigned char> (len);
    int i = 0;
    while (i < len) {
        a[i] = chars[i];
        i++;
    }
    return Encoding::UTF8->GetString(a);
}
© www.soinside.com 2019 - 2024. All rights reserved.