我应该怎么写.i文件包在Java或C#回调 [英] How should I write the .i file to wrap callbacks in java or C#

查看:182
本文介绍了我应该怎么写.i文件包在Java或C#回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的C程序使用它周期性地称为回调函数。我希望能够处理在Java或C#程序的回调函数。我应该怎么写.i文件来实现这一目标?
的C回调看起来如此:

 静态无效on_incoming_call(pjsua_acc_id ACC_ID,pjsua_call_id CALL_ID,pjsip_rx_data * RDATA)


解决方案

您可以做到这一点,如果你有机会在回调各地传递一些数据,但你需要编写一些JNI胶水。我放在一起的你怎么可能C形式的回调映射到Java接口的完整例子。

您需要做的第一件事就是决定是在Java端相应的接口上。我用C假设我们已经回调,如:

无效的typedef(* callback_t)(INT ARG,无效*用户数据);

我决定重新present在Java中的:

公共接口回调{
  公共无效手柄(int值);
}

(即 void *的用户数据在Java端的损失是不是一个真正的问题,因为我们可以存储在对象状态实现回调平凡)。

我然后写了下面的头文件(它真的不应该只是一个头,但它让事情简单)行使包装:

无效的typedef(* callback_t)(INT ARG,无效*数据);静态无效*数据= NULL;
静态callback_t活跃= NULL;静态无效集(callback_t CB,无效*用户数据){
  激活= CB;
  数据=用户数据;
}静态无效讯(INT VAL){
  活性(VAL,数据);
}

我是能够成功地把这个包下与以下接口:

 %模块的测试%{
#包括LT&;&ASSERT.H GT;
#包括test.h// 1:
结构callback_data {
  JNIEnv的* ENV;
  jobject OBJ;
};// 2:
无效java_callback(INT ARG,无效* PTR){
  结构callback_data *数据= PTR;
  常量JCLASS callbackInterfaceClass =(*数据 - > ENV) - GT;的findClass(数据 - > ENV,回调);
  断言(callbackInterfaceClass);
  常量jmethodID甲基=(*数据 - > ENV) - >的GetMethodID(数据 - >包膜,callbackInterfaceClass,把手,(I)的V);
  断言(甲基);
  (*数据 - > ENV) - GT; CallVoidMethod(数据 - > ENV线,数据> OBJ,甲基,(jint)ARG);
}
%}// 3:
%类型映射(jstype)callback_t CB回调;
%类型映射(jtype的)callback_t CB回调;
%类型映射(JNI)callback_t CBjobject
%类型映射(javain)callback_t CB$ javainput
// 4:
%类型映射(中,numinputs = 1)(callback_t CB,无效*用户数据){
  结构callback_data *数据=的malloc(sizeof的*数据);
  数据 - > ENV = jenv;
  数据 - >的obj = JCALL1(NewGlobalRef,jenv,$输入);
  JCALL1(DeleteLocalRef,jenv,$输入);
  $ 1 = java_callback;
  $ 2 =数据;
}%包括test.h

该接口有相当多的部分是:


  1. A 结构来存储对Java接口的调用所需的信息。

  2. callback_t 的实现。它接受作为用户数据的结构我们刚刚定义,然后分派使用一些标准JNI的Java接口的调用。

  3. 这导致回调对象传递直奔C实现的一些typemaps一个真正的 jobject

  4. ,它隐藏类型映射的无效* 在Java端,并设置了一个回调数据,并在填写对于真正的功能对应的参数来使用我们刚刚写了调度呼叫回到Java功能。这需要一个全球性的参考Java对象prevent它被当作垃圾收集随后。

我写了一个小的Java类来测试它:

 公共类运行实现回调{
  公共无效手柄(INT VAL){
    的System.out.println(Java的回调 - + VAL);
  }  公共静态无效的主要(字符串的argv []){
    运行R =新的run();    的System.loadLibrary(测试);
    test.set(R);
    test.dispatch(666);
  }
}

该工作作为你的希望。

有几点需要注意:


  1. 如果你调用设置多次将泄漏的全球参考。你要么需要提供回调被取消设置的方式,prevent设置多次,或使用弱引用来代替。

  2. 如果您有你在身边多线程将需要更聪明的的JNIEnv 不是我一直在这里。

  3. 如果你想混回调Java和C实现的,那么你就需要在这个解决方案扩大了不少。可以公开用作与回调的C函数%不变但这些typemaps将prevent无法接受这样的输入您的包裹功能。也许你会想提供过载来解决这一点。

有在<一些好的建议href=\"http://stackoverflow.com/questions/4313004/registering-java-function-as-a-callback-in-c-function\">this问题。

我认为,C#中的解决办法是有几分相似,不同的类型映射名称和回调函数的不同实现在C写的。

My C program uses callback functions which are periodically called. I want to be able to handle the callback functions in a Java or C# program. How should I write the .i file to achieve this? The C callback looks so:

static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata)

解决方案

You can do this if you have a chance to pass some data around with the callback, but you'll need to write some JNI glue. I put together a complete example of how you might map C style callbacks onto a Java interface.

The first thing you need to do is decide on an interface that's appropriate on the Java side. I assumed in C we had callbacks like:

typedef void (*callback_t)(int arg, void *userdata);

I decided to represent that in Java as:

public interface Callback {
  public void handle(int value);
}

(The loss of the void *userdata on the Java side isn't a real problem since we can store state in the Object that implements Callback trivially).

I then wrote the following header file (it shouldn't really be just a header, but it keeps things simple) to exercise the wrapping:

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);
}

I was able to successfully wrap this C with the following interface:

%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"

The interface has quite a few parts to it:

  1. A struct to store the information needed to make a call to the Java interface.
  2. An implementation of the callback_t. It accepts as user data the struct we just defined and then dispatches a call to the Java interface using some standard JNI.
  3. Some typemaps that cause the Callback objects to be passed straight to the C implementation as a real jobject.
  4. A typemap that hides the void* on the Java side and sets up a callback data and fills in the corresponding arguments for the real function to use the function we just wrote for dispatching calls back to Java. It takes a global reference to the Java object to prevent it from being garbage collected subsequently.

I wrote a little Java class to test it with:

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);    
  }
}

which worked as you'd hope.

Some points to note:

  1. If you call set multiple times it will leak the global reference. You either need to supply a way for the callback to be unset, prevent setting multiple times, or use weak references instead.
  2. If you have multiple threads around you will need to be smarter with the JNIEnv than I've been here.
  3. If you wanted to mix Java and C implementations of callbacks then you'll need to expand on this solution quite a bit. You can expose C functions to be used as callbacks with %constant but these typemaps will prevent your wrapped functions from accepting such inputs. Probably you would want to supply overloads to work around that.

There's some more good advice in this question.

I believe that a solution for C# would be somewhat similar, with different typemap names and a differing implementation of the callback function you write in C.

这篇关于我应该怎么写.i文件包在Java或C#回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆