首页 文章

调用dll从C实现了JNI

提问于
浏览
1

情况:我有一个实现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`变量?

2 回答

  • 1

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

    如果DLL是从Java加载的,那就更容易了:你可以毫无顾虑地简单地调用DLL的任何导出函数 .

    如果导出的JNI方法调用不使用JNIEnv参数(如 Add() 的示例中所示),则可以简单地传递 nullptr 以满足调用约定 .

    但是,这不会让您传递 jstringjarray 之类的参数 . 无论如何,良好的做法是将JNI层和实际逻辑层分开,这些逻辑将从Java转换为本机的参数 .

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

  • 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

相关问题