英文:
SWIG (Java): How can I call a function with a void* out parameter?
问题
背景
我正在开发一款用于 Android 的实时通讯应用,使用了一个 C++ 代码库。我使用 SWIG 生成了一个 JNI 桥接,以便从 Java 中访问原生代码。为了跟踪活动通话,使用了一个 void*
作为句柄(指向包含有关正在通话信息的地址)。以下是示例函数头,展示了如何使用它:
void initiateCall(void** callHandleRef);
void closeCall(void* callHandle);
initiateCall
接受一个 void**
,分配一个结构体并将其地址(以 void*
形式)写入 callHandleRef
。它作为一个“出参”使用,你将其作为参数传递,并期望有内容被写入其中。当调用 closeCall
时,会传递原始指针,使得 C++ 库能够访问与特定通话相关联的数据。
问题描述
我希望能够从 Java 中调用 initiateCall
和 closeCall
,并使用 SWIG 生成 JNI 代码来实现。然而,SWIG 生成了类型 "SWIGTYPE_p_p_void" 和 "SWIGTYPE_p_void" 分别对应于这两个函数,我无法按照上述描述的方式使用它们。我应该如何设置我的 SWIG 接口文件,以使我能够实现这一点?
英文:
Background
I am developing a real-time communication app for Android using a C++ code library. I generate a JNI bridge using SWIG to access the native code from Java. In order to keep track of an active call, a void*
is used as a handle (which points to an adress containing information about the ongoing call). The following function headers are examples of how it is meant to be used:
void initiateCall(void** callHandleRef);
void closeCall(void* callHandle);
initateCall
takes a void**
, allocates a struct and writes its address (as a void*) to callHandleRef
. It works as an "out" parameter in that you pass it as an argument and expect something to be written to it. When closeCall
is called, the raw pointer is passed, allowing the C++ library to access the data associated with that specific call.
Problem description
I want to invoke initiateCall
and closeCall
from Java, using SWIG to generate the JNI code necessary to do so. However. SWIG generates types "SWIGTYPE_p_p_void" and "SWIGTYPE_p_void" respectively, and I am unable to use these in the way described above. How to I setup my SWIG interface file to allow me to do this?
答案1
得分: 1
Flexo对问题的评论对我很有帮助,可以在这里看到链接。这是我的解决方案,基本上是从他们的答案中复制粘贴的。
C++头文件(call.h):
typedef void* CALL_HANDLE;
int initiateCall(const char* name, CALL_HANDLE* handle);
int closeCall(CALL_HANDLE handle);
SWIG接口(call.i):
%module bridge
%include <cpointer.i>
%pointer_class(CALL_HANDLE, inst_ptr);
%javamethodmodifiers initiateCall "private";
%pragma(java) modulecode=%{
public static SWIGTYPE_p_void initiateCall(String name) {
inst_ptr ptr = new inst_ptr();
final int err = initiateCall(name, ptr.cast());
if (0 != err) {
// 抛出错误或类似操作
}
return ptr.value();
}
%}
%include "include/call.h";
extern int initiateCall(const char* name, CALL_HANDLE* handle);
extern int closeCall(CALL_HANDLE handle);
主要活动(MainActivity.kt):
class MainActivity : AppCompatActivity() {
private lateinit var callHandle: SWIGTYPE_p_void
fun call(name: String) {
callHandle = bridge.initiateCall(name)
}
fun hangup() {
bridge.closeCall(callHandle)
}
}
英文:
Flexo's comment on the question turned out to work for me, as seen here. This is my solution, more or less copy-pasted from their answer.
C++ header (call.h):
typedef void* CALL_HANDLE;
int initiateCall(const char* name, CALL_HANDLE* handle);
int closeCall(CALL_HANDLE handle);
SWIG interface (call.i):
%module bridge
%include <cpointer.i>
%pointer_class(CALL_HANDLE, inst_ptr);
%javamethodmodifiers initiateCall "private";
%pragma(java) modulecode=%{
public static SWIGTYPE_p_void initiateCall(String name) {
inst_ptr ptr = new inst_ptr();
final int err = initiateCall(name, ptr.cast());
if (0 != err) {
// Throw error or something like that
}
return ptr.value();
}
%}
%include "include/call.h"
extern int initiateCall(const char* name, CALL_HANDLE* handle);
extern int closeCall(CALL_HANDLE handle);
Main activity (MainActivity.kt):
class MainActivity : AppCompatActivity() {
private lateinit var callHandle: SWIGTYPE_p_void
fun call(name: String) {
callHandle = bridge.initiateCall(name)
}
fun hangup() {
bridge.closeCall(callHandle)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论