C ++ нестатические обратные вызовы и JNA - PullRequest
4 голосов
/ 04 марта 2011

Я пытаюсь использовать C ++ API в Java с 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. По вашему мнению, функциональные объекты в этом случае?

Каждый сеанс представлен объектом sp_session, который является непрозрачной структурой 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, когда они запускаются?

Спасибо!

EDIT

Новый код с использованием функции обратного вызова вместо функции:

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

Вызов sessionCreate () вызывает фатальную ошибку JRE (EXCEPTION_ACCES_VIOLATION 0x0000005), когда для cfg.logged_in задано не нулевое значение, а экземпляр LoggedIn. Странно то, что 2 обратных вызова logged_in и connection-error имеют одинаковую сигнатуру, и когда установлен cfg.connection_error, он ничего не выдает.

Ответы [ 2 ]

2 голосов
/ 04 марта 2011

Из функции javadoc представляет собственный метод, если вы хотите вызвать метод java, вы должны создать Callback для каждого указателя функции.

Если вы используете только обратные вызовы Java и никаких собственных функций, вы можете просто заменить функцию обратным вызовом. (В зависимости от используемого соглашения о вызовах вы можете использовать вместо него 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){...}
}
0 голосов
/ 05 марта 2011

По сути, для того, чтобы связать обратный вызов любого вида с функцией-членом объекта, ему необходимо передать целевой функции и экземпляр объекта, чтобы удовлетворить этот первый невидимый параметр.Проблема здесь в том, что JNA принимает только определенный формат функции.Таким образом, вы должны обойти проблему, где это возможно.К сожалению, в C ++ это может привести к использованию временных глобальных переменных, но если вы сосредоточены на передаче управления обратно объекту, вы можете поддерживать хороший дизайн ОО.

Это не имеет ничего общего свещь "C против 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 не добавит механизмы для этого.

...