从 C++ 调用 dll 实现的 JNI
Calling dll implemented JNI from C++
情况:
我有一个实现 JNI 的 dll,我想从 Cpp 应用程序调用其中的方法。
当前状态:
按照我的理解,一个实现了JNI的dll其实和JAVA没有任何关系,例如:
在Test.java,我写了
public native int Add(int a,int b);
并通过 Cpp In TestDll.Cpp 实现
JNIEXPORT jint JNICALL Java_SomeNamespace_Add(JNIEnv* _Env, jobject _Object, jint a, jint b)
{
return a+b;
}
我认为这样的程序与 JVM 无关,jint 结构似乎已在 jni.h 中完全定义。
所以,我想知道是否可以直接调用 Java_SomeNamespace_Add
而无需从 Cpp 应用程序创建 VM,如果可能的话,:
- 参数列表中的`JNIEnv*`和`jobject`应该是什么?
- 如何将 `jint` 变量转换为标准的 `int` 变量?
- 如何在不使用 _Env->FindClass("Ljava/lang/String;") 和以下代码的情况下将 `jstring` 变量转换为标准 `string` 变量?
一般来说,有一种原因会阻止您在没有 Java 的情况下加载 JNI DLL。 DLL 可能需要一些 JVM 外部符号。但是如果你需要的话,你可以用假人来伪造它们。
如果 DLL 是从 Java 为您加载的,那就更简单了:您可以放心地调用 DLL 的任何导出函数。
如果导出的 JNI 方法调用不使用 JNIEnv 参数(如您的 Add()
示例),您只需传递 nullptr 即可满足调用约定.
不过,这不会让您传递 jstring 或 jarray 等参数。无论如何,好的做法是将 JNI 的层与实际逻辑分开,后者将参数从 Java 转换为本机。
但如果您无法控制 DLL,则可以尝试完全伪造 JNI。请参阅jni.h并以适合您的方式实现必要的功能。
对于第 1 点,我认为使用一些重构创建一个简单的替代方案是个好主意。
与其将算法逻辑放入 JNI 调用本身,不如将逻辑移至单独的 c++ 函数并从两个用例中调用该函数。
即:
// MyJNIWrapper.cpp
#include "MyMathFunctions.h"
JNIEXPORT jint JNICALL Java_SomeNamespace_Add(JNIEnv* _Env, jobject _Object, jint a, jint b)
{
return (jint)add((int)a, (int)b);
}
// MyMathFunctions.h
int add(int a, int b)
{
return a + b;
}
// MyCppProgram.cpp
#include "MyMathFunctions.h"
int main()
{
int c = add(a, b)
}
对于数字 2,您可以使用标准 C 样式转换在 jint 和 int 之间进行转换:
int a = 10;
jint b = (jint) a;
int c = (int) b
至于数字 3:
如果您从 JNI 中调用该函数,您将使用描述的一对函数 here:
JNIEXPORT void JNICALLJava_MyJavaClass_printName(JNIEnv *env, jobject obj, jstring name)
{
const char *str= (*env)->GetStringUTFChars(env,name,0);
printf(“%s”, str);
//need to release this string when done with it in order to
//avoid memory leak
(*env)->ReleaseStringUTFChars(env, name, str);
}
要将上述 C 字符串转换为 std::string,您可以执行以下操作:
std::string cpp_string = str;
如果您不使用 JNI 调用该函数,您似乎需要尝试进行自己的转换。我会看看您是否可以使用现有的 VM 实现,弄清楚他们是如何做到的并模仿它。
例如,您可以尝试使用 Android VM 并将这些作为起点:
https://android.googlesource.com/platform/dalvik/+/donut-release/vm/Jni.c#2230
https://android.googlesource.com/platform/dalvik.git/+/android-4.3_r3/vm/UtfString.cpp#284
情况: 我有一个实现 JNI 的 dll,我想从 Cpp 应用程序调用其中的方法。
当前状态:
按照我的理解,一个实现了JNI的dll其实和JAVA没有任何关系,例如:
在Test.java,我写了
public native int Add(int a,int b);
并通过 Cpp In TestDll.Cpp 实现
JNIEXPORT jint JNICALL Java_SomeNamespace_Add(JNIEnv* _Env, jobject _Object, jint a, jint b)
{
return a+b;
}
我认为这样的程序与 JVM 无关,jint 结构似乎已在 jni.h 中完全定义。
所以,我想知道是否可以直接调用 Java_SomeNamespace_Add
而无需从 Cpp 应用程序创建 VM,如果可能的话,:
- 参数列表中的`JNIEnv*`和`jobject`应该是什么?
- 如何将 `jint` 变量转换为标准的 `int` 变量?
- 如何在不使用 _Env->FindClass("Ljava/lang/String;") 和以下代码的情况下将 `jstring` 变量转换为标准 `string` 变量?
一般来说,有一种原因会阻止您在没有 Java 的情况下加载 JNI DLL。 DLL 可能需要一些 JVM 外部符号。但是如果你需要的话,你可以用假人来伪造它们。
如果 DLL 是从 Java 为您加载的,那就更简单了:您可以放心地调用 DLL 的任何导出函数。
如果导出的 JNI 方法调用不使用 JNIEnv 参数(如您的 Add()
示例),您只需传递 nullptr 即可满足调用约定.
不过,这不会让您传递 jstring 或 jarray 等参数。无论如何,好的做法是将 JNI 的层与实际逻辑分开,后者将参数从 Java 转换为本机。
但如果您无法控制 DLL,则可以尝试完全伪造 JNI。请参阅jni.h并以适合您的方式实现必要的功能。
对于第 1 点,我认为使用一些重构创建一个简单的替代方案是个好主意。
与其将算法逻辑放入 JNI 调用本身,不如将逻辑移至单独的 c++ 函数并从两个用例中调用该函数。
即:
// MyJNIWrapper.cpp
#include "MyMathFunctions.h"
JNIEXPORT jint JNICALL Java_SomeNamespace_Add(JNIEnv* _Env, jobject _Object, jint a, jint b)
{
return (jint)add((int)a, (int)b);
}
// MyMathFunctions.h
int add(int a, int b)
{
return a + b;
}
// MyCppProgram.cpp
#include "MyMathFunctions.h"
int main()
{
int c = add(a, b)
}
对于数字 2,您可以使用标准 C 样式转换在 jint 和 int 之间进行转换:
int a = 10;
jint b = (jint) a;
int c = (int) b
至于数字 3:
如果您从 JNI 中调用该函数,您将使用描述的一对函数 here:
JNIEXPORT void JNICALLJava_MyJavaClass_printName(JNIEnv *env, jobject obj, jstring name)
{
const char *str= (*env)->GetStringUTFChars(env,name,0);
printf(“%s”, str);
//need to release this string when done with it in order to
//avoid memory leak
(*env)->ReleaseStringUTFChars(env, name, str);
}
要将上述 C 字符串转换为 std::string,您可以执行以下操作:
std::string cpp_string = str;
如果您不使用 JNI 调用该函数,您似乎需要尝试进行自己的转换。我会看看您是否可以使用现有的 VM 实现,弄清楚他们是如何做到的并模仿它。
例如,您可以尝试使用 Android VM 并将这些作为起点: https://android.googlesource.com/platform/dalvik/+/donut-release/vm/Jni.c#2230 https://android.googlesource.com/platform/dalvik.git/+/android-4.3_r3/vm/UtfString.cpp#284