从C ++调用DLL实现的JNI

时间:2018-08-08 02:25:00

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

情况: 我有一个实现JNI的dll,我想从Cpp应用程序中调用其中的方法。

当前状态: 根据我的理解,实现JNI的dll实际上与JAVA无关,例如: 在Test.java中,我写了
public native int Add(int a,int b);
并在TestDll.Cpp中用Cpp实现
JNIEXPORT jint JNICALL Java_SomeNamespace_Add(JNIEnv* _Env, jobject _Object, jint a, jint b) { return a+b; }
我认为这样的程序与JVM无关, jint 结构似乎已在jni.h中完全定义。
因此,我想知道是否可以在不通过Cpp应用程序创建VM的情况下直接调用Java_SomeNamespace_Add,如果可以的话,

  1. 参数列表中的“ JNIEnv *”和“ jobject”应该是什么?
  2. 如何将“ jint”变量转换为标准的“ int”变量?
  3. 如何在不使用_Env-> FindClass(“ Ljava / lang / String;”)`和以下一系列代码的情况下将jstring变量转换为标准的string变量?

2 个答案:

答案 0 :(得分:1)

通常来说,有一个原因可以阻止您在没有Java的情况下加载JNI DLL。 DLL可能需要一些JVM外部符号。但是,如果需要,您可以用假人伪造它们。

如果为您从Java加载了DLL,则更加简单:您可以轻松地调用DLL的任何导出函数。

如果导出的JNI方法调用未使用JNIEnv参数(例如在var click = 0; $('#element_0_0').on('click', function(event) { if(click == 0){ $('#element_0_1').removeClass('animated fadeInDown infinite'); setTimeout(function() { $('#element_0_1').addClass('animated fadeInDown'); }, 10); click = 1; }else{ $('#element_0_1').addClass('animated fadeInDown'); setTimeout(function() { $('#element_0_1').removeClass('animated fadeInDown infinite') }, 10); click = 0; } }); 的示例中),则只需传递 nullptr 即可满足调用约定。

但这不会让您传递诸如 jstring jarray 之类的参数。无论如何,好的做法是将JNI的层与实际的逻辑分开,这需要将参数从Java转换为本机。

但是,如果您无法控制DLL,则可以尝试完全伪造JNI。请参见 jni.h 并以适合您的方式实现必要的功能。

答案 1 :(得分:1)

对于数字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