【发布时间】:2023-02-08 17:38:00
【问题描述】:
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 文件夹中。)
【问题讨论】:
-
C++<-->C# 也能正常工作吗? StackOverflowException 在哪里抛出?堆栈是什么样子的?
-
不幸的是,我不太熟悉设置 Visual Studio 项目。目前,C++ 项目未定义为控制台应用程序。作为下一步,我将在 VS 中创建一个带有 C++ 控制台应用程序的新项目,并添加现有的 SharpAuthenticator 项目以便能够回复您的问题。我一设法做到就让你知道。但是 C++ <--> C# 值得检查,我同意!
-
好的... C++ <--> C# 有效。我将返回值 (bool) 打印到我的 C++ 应用程序的控制台上,它显示“0”或“1”。
-
有没有人在其中一个屏幕截图的代码或属性参数中看到明显的错误?我会感谢每一点帮助。多谢!
-
我在 github 上发现了一个问题:github.com/dotnet/core/issues/766 并在下面查看作者的解决方案。看起来你不能简单地将 c++/cli 代码和 jni 代码放在同一个 dll 中。您需要创建一个 clr 来托管 .net dll。希望能帮助到你。
标签: java c# c++ dll java-native-interface