C++非静态回调和 JNA

发布于 2024-10-20 10:49:36 字数 3336 浏览 2 评论 0原文

我正在尝试将 Java 中的 C++ API 与 JNA 一起使用。此 API 使用回调来处理会话事件。

我找到的关于如何向 JNA 注册回调的唯一资源是 this,它处理 C 回调,我真的不知道如何将其扩展到 C++ 非静态回调。

编辑:我刚刚找到此资源,我认为“重新访问回调”一章可能会有所帮助。

回调的所有函数指针都存储在以下sp_session_callbacks结构中:

/**
 * Session callbacks
 *
 * Registered when you create a session.
 * If some callbacks should not be of interest, set them to NULL.
 */
typedef struct sp_session_callbacks {
    void (__stdcall *logged_in)(sp_session *session, sp_error error);
    void (__stdcall *logged_out)(sp_session *session);
    void (__stdcall *connection_error)(sp_session *session, sp_error error);
    void (__stdcall *message_to_user)(sp_session *session, const char *message);
    // Other callbacks function pointers
} sp_session_callbacks;

我创建的用于描述的Java类该结构如下:

public class sp_session_callbacks extends Structure{
    public Function logged_in;
    public Function logged_out;
    public Function connection_error;
    public Function message_to_user;
}

您认为在这种情况下用 com.sun.jna.Function 对象表示函数指针有意义吗?

每个会话都由一个 sp_session object,它是一个 C++ 不透明结构。当我初始化它时,我确实有一个 sp_session_callbacks 对象的句柄。

以下是我的主类中的代码片段:

JLibspotify lib = (JLibspotify)Native.loadLibrary("libspotify", JLibspotify.class);

sp_session_config cfg = new sp_session_config();
/* Some cfg config here */
sp_session_callbacks sessCallbacks = new sp_session_callbacks(); // Handle on my sp_session_callbacks object
cfg.callbacks = sessCallbacks;

PointerByReference sessionPbr = new PointerByReference();
int errorId = lib.sessionCreate(cfg, sessionPbr);

sp_session session = new sp_session(sessionPbr.getValue()); // handle on my sp_session object

我应该如何注册这些回调函数,以便在触发它们时在 Java 端实际执行某些操作?

谢谢!

编辑

使用回调而不是函数的新代码:

public class sp_session_callbacks extends Structure{
    public LoggedIn logged_in;
    /* Other callbacks... */
}



public interface LoggedIn extends StdCallCallback {
    public void logged_in(sp_session session, int error);
}

主类:

JLibspotify lib = (JLibspotify)Native.loadLibrary("libspotify", JLibspotify.class);

sp_session_config cfg = new sp_session_config();
/* Some cfg config here */
sp_session_callbacks sessCallbacks = new sp_session_callbacks(); // Handle on my sp_session_callbacks object
LoggedIn loggedInCallback = new LoggedIn(){
    public void logged_in(sp_session session, int error){
        System.out.println("It works");
    }
};
sessCallbacks.logged_in = loggedInCallback;
/* Setting all the other callbacks to null */

cfg.callbacks = sessCallbacks;

PointerByReference sessionPbr = new PointerByReference();
int errorId = lib.sessionCreate(cfg, sessionPbr);

sp_session session = new sp_session(sessionPbr.getValue()); // handle on my sp_session object

当 cfg.logged_in 未设置为 null 而是设置为 LoggedIn 实例时,sessionCreate() 调用会引发 JRE 致命错误 (EXCEPTION_ACCES_VIOLATION 0x0000005)。奇怪的是,logged_in 和 connection-error 两个回调具有相同的签名,并且当设置 cfg.connection_error 时,它不会抛出任何内容。

I am trying to use a C++ API in Java with JNA. This API uses callbacks to handle sessions events.

The only resource I found on how to register callbacks with JNA is this, and it deals with C callbacks, and I don't really know how it can be extended to C++ non-static callbacks.

EDIT: I just found this resource, I think the "Revisiting Callbacks" chapter might help.

All the function pointers for the callbacks are stored in the following sp_session_callbacks structure:

/**
 * Session callbacks
 *
 * Registered when you create a session.
 * If some callbacks should not be of interest, set them to NULL.
 */
typedef struct sp_session_callbacks {
    void (__stdcall *logged_in)(sp_session *session, sp_error error);
    void (__stdcall *logged_out)(sp_session *session);
    void (__stdcall *connection_error)(sp_session *session, sp_error error);
    void (__stdcall *message_to_user)(sp_session *session, const char *message);
    // Other callbacks function pointers
} sp_session_callbacks;

The Java class I created to described this structure is the following:

public class sp_session_callbacks extends Structure{
    public Function logged_in;
    public Function logged_out;
    public Function connection_error;
    public Function message_to_user;
}

Does it make sense to represent the function pointers by com.sun.jna.Function objects in this case in your opinion?

Each session is represented by a sp_session object, which is a C++ opaque struct. I do have a handle on the sp_session_callbacks object when I initialize it though.

Here is a code snippet from my main class:

JLibspotify lib = (JLibspotify)Native.loadLibrary("libspotify", JLibspotify.class);

sp_session_config cfg = new sp_session_config();
/* Some cfg config here */
sp_session_callbacks sessCallbacks = new sp_session_callbacks(); // Handle on my sp_session_callbacks object
cfg.callbacks = sessCallbacks;

PointerByReference sessionPbr = new PointerByReference();
int errorId = lib.sessionCreate(cfg, sessionPbr);

sp_session session = new sp_session(sessionPbr.getValue()); // handle on my sp_session object

How should I register those callbacks function to actually do something on the Java side when they are triggered?

Thank you!

EDIT

New code using Callback instead of Function:

public class sp_session_callbacks extends Structure{
    public LoggedIn logged_in;
    /* Other callbacks... */
}



public interface LoggedIn extends StdCallCallback {
    public void logged_in(sp_session session, int error);
}

Main class:

JLibspotify lib = (JLibspotify)Native.loadLibrary("libspotify", JLibspotify.class);

sp_session_config cfg = new sp_session_config();
/* Some cfg config here */
sp_session_callbacks sessCallbacks = new sp_session_callbacks(); // Handle on my sp_session_callbacks object
LoggedIn loggedInCallback = new LoggedIn(){
    public void logged_in(sp_session session, int error){
        System.out.println("It works");
    }
};
sessCallbacks.logged_in = loggedInCallback;
/* Setting all the other callbacks to null */

cfg.callbacks = sessCallbacks;

PointerByReference sessionPbr = new PointerByReference();
int errorId = lib.sessionCreate(cfg, sessionPbr);

sp_session session = new sp_session(sessionPbr.getValue()); // handle on my sp_session object

The sessionCreate() call is throwing a JRE fatal error (EXCEPTION_ACCES_VIOLATION 0x0000005) when cfg.logged_in is not set to null but to an instance of LoggedIn. The weird thing is that the 2 callbacks logged_in and connection-error have the same signature, and when cfg.connection_error is set, it doesn't throw anything.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

爱的十字路口 2024-10-27 10:49:36

从 javadoc 函数代表一个本机方法,如果你想调用一个 java 方法,你必须创建一个 每个函数指针的回调

如果您只使用 java 回调而不使用本机函数,则可以将 Function 替换为 Callback。 (根据所使用的调用约定,您可能想使用 StdCallLibrary.StdCallCallback 代替)

public class sp_session_callbacks extends Structure{
    public StdCallCallback logged_in;
    public StdCallCallback logged_out;
    public StdCallCallback connection_error;
    public StdCallCallback message_to_user;
}

sp_session_callbacks calls = new sp_session_callbacks();
calls.logged_out = new StdCallCallback(){

    public void someName(sp_session sp){...}
}

From the javadoc Function represents a native method, if you want to call a java method you have to create a Callback for each function pointer.

If you only use java callbacks and no native Functions you can just replace Function with Callback. (Depending on the calling convention used you might want to use StdCallLibrary.StdCallCallback instead)

public class sp_session_callbacks extends Structure{
    public StdCallCallback logged_in;
    public StdCallCallback logged_out;
    public StdCallCallback connection_error;
    public StdCallCallback message_to_user;
}

sp_session_callbacks calls = new sp_session_callbacks();
calls.logged_out = new StdCallCallback(){

    public void someName(sp_session sp){...}
}
机场等船 2024-10-27 10:49:36

基本上,为了将任何类型的回调连接到对象的成员函数中,它必须传递目标函数和对象的实例以满足第一个不可见参数。这里的问题是 JNA 只接受特定格式的函数。因此,您必须尽可能解决该问题。遗憾的是,在 C++ 中,这可能会导致使用临时全局变量,但只要您专注于将控制权转移回对象,就可以保持良好的 OO 设计。

它与“C vs C++”无关。您只需要了解成员函数调用需要什么以及它基本上编译成什么。

myObject.memberFunction(); // This is what the programmer sees.
memberFunction(&myObject); // This is what the compiler sees.

成员函数是对仅将对象作为第一个参数的函数的奇特描述。它只是在实际参数列表中不可见。

void MyClass::memberFunction() // This is the declaration the programmer sees.
void memberFunction(MyClass* this) // This is what the compiler sees.

从那时起,C++ 添加了特殊的语义,使其能够轻松地以面向对象的方式工作。

简而言之,您实际上永远无法直接连接到对象的成员函数,除非 JNA 本身添加了这样做的机制。

Basically, in order to wire a callback of any kind into a member function of an object, it would have to pass the target function and an instance of the object to satisfy that first invisible parameter. The issue here is that JNA only accepts a particular format of function. So, you have to work around the issue where possible. Sadly, in C++, this can result in the use of temporary global variables, but as long as you focus on transferring control back over to an object, you can maintain good OO design.

It has nothing to do with a "C vs C++" thing. You just need to understand what a member function call entails and basically what it compiles down to.

myObject.memberFunction(); // This is what the programmer sees.
memberFunction(&myObject); // This is what the compiler sees.

A member function is a fancy description of a function that simply takes the object as a first parameter. It's just invisible in the actual parameter list.

void MyClass::memberFunction() // This is the declaration the programmer sees.
void memberFunction(MyClass* this) // This is what the compiler sees.

From there, C++ adds special semantics to make it easy to work in an object-oriented fashion.

In short, you will virtually never be able to wire directly into an object's member function until the JNA itself adds mechanisms to do so.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文