在C函数中注册Java函数作为回调函数

7

我正在尝试通过使用SWIG 1.3在Java中实现一些C代码。现在,我需要将一些现有的C代码重建为Java代码,并向C方法提供指向Java函数的函数指针。

C代码:

net.c:
void register_message_handler( context_t *ctx, message_handler_t handler) {
context->msg_handler = (void (*)( void *, coap_queue_t *, void *)) handler;
}

client.c:

void message_handler(context_t  *ctx, queue_t *node, void *data) {
...
}

int main(int argc, char **argv) {
// setup ctx
register_message_handler( ctx, message_handler );
}

我在Java中已经拥有的是:

public static void message_handler(def.SWIGTYPE_p_context_t ctx, def.SWIGTYPE_p_queue_t node, String data ) {}

现在,这应该像上面的C代码一样以相同的方式注册为回调函数,但是现在在Java中:

net.register_message_handler(ctx, message_handler);

我发现的是http://www.swig.org/Doc1.3/SWIGDocumentation.html#SWIG_nn30,其中包括本章末尾的未定义引用: “现在,关于函数指针支持的最后说明。虽然 SWIG 通常不允许在目标语言中编写回调函数,但可以通过使用 typemaps 和其他高级 SWIG 功能来实现。这将在后面的章节中介绍。” 这是指什么?
我也找到了一个 C++ 的解决方案,但有没有办法将其适应于 C?Swig c++ w/ Java loses type on polymorphic callback functions
谢谢你的帮助。

1
我在这个相同的问题上写了一个相当详细的答案,网址是:https://dev59.com/pmfWa4cB1Zd3GeqPlugU - Flexo
1个回答

11

我也记得在SWIG手册中对此引用感到困惑。

如果没有奇怪的功能,您可以按照以下方式执行:

  • 需要机制将传入的C回调分派到Java中。为此,您需要要调用的对象的对象ID和处理程序的方法ID。在C注册助手中,为这些创建全局引用并缓存它们以供回调使用。

  • 您还需要任何要作为参数传递给java回调的内容的类ID和构造函数方法ID。您还希望缓存这些的全局引用。

  • 在回调的C部分中,查找您的方法ID,构造参数并调用Java。

  • 回调进入的线程需要附加到Java VM(使用JNI函数AttachCurrentThread())。您从中获取JNIEnv指针。此指针仅在调用AttachCurrentThread()的线程的上下文中有效!这意味着,如果您有在多个线程上发生的回调,则需要将JNIEnv*缓存在本地存储中。

  • 确保在从JNI函数返回后检查返回值

  • 在任何回调进入Java之后,请务必检查ExceptionOccurred()。不这样做会让您以难以调试的方式陷入麻烦。

  • 我发现使用Eclipse和Visual Studio相对容易调试:从Eclipse启动主Java程序,将Visual Studio调试器附加到该进程。您可以在任一侧设置断点。


你能分享一个示例项目给社区吗? - Duna
抱歉,我已经十年左右没有写过Java了。 - Jan Schiefer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接