我的C程序使用定期调用的回调函数.我希望能够在Java或C#程序中处理回调函数.我应该如何编写.i文件来实现这一目标?
C回调看起来如此:
static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata)
Run Code Online (Sandbox Code Playgroud)
Fle*_*exo 24
如果你有机会通过回调传递一些数据,你可以这样做,但你需要编写一些JNI粘合剂.我汇总了一个完整的示例,说明如何将C样式回调映射到Java接口.
您需要做的第一件事就是确定一个适合Java端的接口.我假设在C中我们有回调,如:
typedef void (*callback_t)(int arg, void *userdata);
Run Code Online (Sandbox Code Playgroud)
我决定用Java表示:
public interface Callback {
public void handle(int value);
}
Run Code Online (Sandbox Code Playgroud)
(的损失void *userdata在Java端是不是因为我们可以存储在该州的一个现实问题Object,实现Callback平凡).
然后,我编写了以下头文件(它不应该只是一个标题,但它保持简单)来执行包装:
typedef void (*callback_t)(int arg, void *data);
static void *data = NULL;
static callback_t active = NULL;
static void set(callback_t cb, void *userdata) {
active = cb;
data = userdata;
}
static void dispatch(int val) {
active(val, data);
}
Run Code Online (Sandbox Code Playgroud)
我能够使用以下界面成功包装此C:
%module test
%{
#include <assert.h>
#include "test.h"
// 1:
struct callback_data {
JNIEnv *env;
jobject obj;
};
// 2:
void java_callback(int arg, void *ptr) {
struct callback_data *data = ptr;
const jclass callbackInterfaceClass = (*data->env)->FindClass(data->env, "Callback");
assert(callbackInterfaceClass);
const jmethodID meth = (*data->env)->GetMethodID(data->env, callbackInterfaceClass, "handle", "(I)V");
assert(meth);
(*data->env)->CallVoidMethod(data->env, data->obj, meth, (jint)arg);
}
%}
// 3:
%typemap(jstype) callback_t cb "Callback";
%typemap(jtype) callback_t cb "Callback";
%typemap(jni) callback_t cb "jobject";
%typemap(javain) callback_t cb "$javainput";
// 4:
%typemap(in,numinputs=1) (callback_t cb, void *userdata) {
struct callback_data *data = malloc(sizeof *data);
data->env = jenv;
data->obj = JCALL1(NewGlobalRef, jenv, $input);
JCALL1(DeleteLocalRef, jenv, $input);
$1 = java_callback;
$2 = data;
}
%include "test.h"
Run Code Online (Sandbox Code Playgroud)
界面有很多部分:
struct用于存储调用Java接口所需的信息.callback_t.它接受struct我们刚刚定义的用户数据,然后使用一些标准JNI调用Java接口.Callback对象作为实际直接传递给C实现jobject.void*在Java端并设置callback数据并填充相应的实际函数参数,以使用我们刚刚编写的函数将调用发送回Java.它需要对Java对象进行全局引用,以防止它随后被垃圾回收.我写了一个小Java类来测试它:
public class run implements Callback {
public void handle(int val) {
System.out.println("Java callback - " + val);
}
public static void main(String argv[]) {
run r = new run();
System.loadLibrary("test");
test.set(r);
test.dispatch(666);
}
}
Run Code Online (Sandbox Code Playgroud)
这是你希望的工作.
有些要点需要注意:
set多次调用它将泄漏全局引用.您需要提供一种方法来取消设置回调,防止多次设置,或者使用弱引用.JNIEnv比我在这里更聪明.%constant但这些类型映射将阻止您的包装函数接受此类输入.可能你会想要提供重载来解决这个问题.在这个问题上有一些更好的建议.
我相信C#的解决方案会有些类似,使用不同的类型映射名称和您在C中编写的回调函数的不同实现.
| 归档时间: |
|
| 查看次数: |
4117 次 |
| 最近记录: |