JNI 回调传递给 C

Posted

技术标签:

【中文标题】JNI 回调传递给 C【英文标题】:JNI callback passed to C 【发布时间】:2015-05-16 17:27:00 【问题描述】:

我有一个 java 回调函数,我想将其传递给 C++ 包装器,该包装器又将其传递给 C/C++ 函数。

我该怎么做?

我想包装器必须创建某种类型的 C++ lambda 函数或类似的东西来解析参数。

编辑:

这是 C 中的回调签名。我将在 java 中实现这些。 (至少其中一些)

typedef struct ASIOCallbacks

    void (*bufferSwitch) (long doubleBufferIndex, ASIOBool 
    void (*sampleRateDidChange) (ASiosampleRate sRate);
    long (*asioMessage) (long selector, long value, void* message, double* opt);
    ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess);
 ASIOCallbacks;

顺便说一句:ASIOTime *params 永远不会被使用。 我在 C 函数中设置回调。这是路径...

Java 将回调传递给 C++ 包装器。 C++ 包装器将它们传递给 C 函数以设置回调。

【问题讨论】:

要回调的函数是java函数,你是从C/c++调用的?或者你在java中有一个本地函数,调用C/C++函数/包装器? 我从 C/C++ 调用回调。 好的,你能发布回调的java签名吗(即静态与否、返回类型、带类型的参数、名称、类名)? 该类将被称为“回调”。它们将是非静态的。回调将通过 java 类从 java 传递到 C++。 【参考方案1】:

我想你已经在你的 C++ 代码的某个地方调用了 JVM 和 JNI 环境来托管你的 java 函数:

JavaVM *jvm;                // Pointer to the JVM (Java Virtual Machine)
JNIEnv *env;                // Pointer to native interface
...                         // initialisation of these

我们来看第一个例子:

您的 java 函数将类似于:

public class Callback 
    public static void bufferSwitch (long index, ASIOBool b);  

我猜你已经用 Java 实现了类似 ASIOBool 类型的东西。如果没有,您将不得不这样做。

现在您可以编写 C++ 包装器

class Callback  
public: 
    static void bufferSwitch (long index, ASIOBool b);
    ...
;
void Callback::bufferSwitch (long index, ASIOBool b) 
    jclass cls = env->FindClass("Callback"); // loads the Java class
    if (cls==nullptr) 
        throw exception("Java class not found"); 
    jmethodID mid = env->GetStaticMethodID(cls, "bufferSwitch","(JLASIOBool;)V"); 
    if (mid==nullptr)
        throw exception("Java method with appropriate signature not found");
    // primitive types can be passed by value
    // but for the other we must build an object
    jclass cls2 = env->FindClass("ASIOBool"); // loads the Java class
    if (cls2==nullptr) 
        throw exception("Java class not found"); 
    jmethodID ctor = env->GetMethodID(cls2, "<init>", "()V");
    if (ctor==nullptr) 
        throw exception("Java class constructor not found"); 
    jobject jb = env->NewObject(cls2, ctor);

    // ... to do:  you have to initialize the Java ASIOBool object with the C++ ASIOBool components
    // so if it's only a bool, better use the fundamental java type Boolean
    // to avoid building a java object from C++

    env->CallStaticVoidMethod(cls2, mid, (jlong)index, jb);  // FINALLY WE CAN CALL !
    env->DeleteLocalRef(jb);   // tell the java garbage collector that we no longer use the tmp object


请注意,对于用作参数的每个 Java 对象(也不是基本类型),您都必须提供签名。 fundamental types are coded 作为一个字母。其他类型/类以 L 开头,后跟完整的类名和半列。对于出现在包中的类,您必须指定全名(例如:“Ljava/lang/String;”对于 java 字符串)。

要了解更多信息:C++ JNI tutorial 和 C JNI tutorial。

【讨论】:

您应该添加有关从 JavaVM 初始化 JNIEnv 并附加当前线程的明确详细信息,参见 this code。 我相信任何 JNI 函数的第一个参数都是 JNIEnv。并感谢你们的帮助。 @CalebMerchant JNI函数的第一个参数是env,在C接口中。如果在 cpp 代码中使用,JNI 函数采用 OO 约定:env 是主要对象,您使用 env->function 调用该函数

以上是关于JNI 回调传递给 C的主要内容,如果未能解决你的问题,请参考以下文章

从本机 c 代码 (JNI) 为 Java 中的回调函数传递多个参数

将参数从 C/C++ JNI 传递到 Java 并获取修改后的值

如何在android的jni线程中实现回调

将 Go 函数作为回调传递给 C

[C#将回调传递给按钮

Twisted-将结果传递给多个回调