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++ 项目中的参考。
也许还值得一提:
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 文件夹中。)
这是一个愚蠢的错误...我花了 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);
}