регистрация функции Java в качестве обратного вызова в функции C - PullRequest
6 голосов
/ 30 ноября 2010

Я пытаюсь реализовать C-код на Java с помощью SWIG 1.3. Сейчас я необходимо перестроить некоторые существующие C в код Java и предоставить функцию указатель на функцию Java для метода C.

Код 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 не обычно позволяют функциям обратного вызова быть написанными на целевом языке, это может быть достигнуто с использованием типографских карт и других расширенных функций SWIG. Это описано в следующей главе. " Куда это относится?

Я также нашел решение для C ++, но есть ли способ адаптировать его к C? Swig c ++ с Java теряет тип в полиморфных функциях обратного вызова морфические-обратные вызовы функция

Спасибо за вашу помощь.

1 Ответ

10 голосов
/ 02 декабря 2010

Я помню, как почесал голову над этим справочником в руководстве SWIG.

Вы можете сделать это без эзотерических функций следующим образом:

  • Вам необходим механизм для отправки входящего обратного вызова C в Java.Для этого вам понадобится идентификатор объекта вызываемого объекта и идентификатор метода вашего обработчика.В вашем помощнике по регистрации в C создайте глобальные ссылки для них и кэшируйте их для использования обратным вызовом.

  • Вам также понадобится идентификатор класса и идентификатор метода конструктора для всего, что вы хотите передатьобратный вызов Java в качестве параметра.Вы также хотите кэшировать глобальные ссылки на них.

  • В части обратного вызова на языке C найдите свои идентификаторы методов, создайте аргументы и вызовите в Java.

  • Поток, в который входит обратный вызов, должен быть подключен к Java VM (с помощью функции JNI AttachCurrentThread ()).Вот откуда вы получаете указатель JNIEnv.Этот указатель действителен только в контексте потока, из которого вы вызвали AttachCurrentThread ()!Это означает, что если у вас есть обратные вызовы, поступающие в несколько потоков, вам необходимо кэшировать JNIEnv * в локальном хранилище потоков.

  • Убедитесь, что вы проверяете возвращаемые значения после возврата из функций JNI

  • Обязательно проверяйте ExceptionOccurred () после любого и всех обратных вызовов в Java.Если вы этого не сделаете, то у вас возникнут проблемы с трудными способами отладки.

  • Я нашел это относительно простым для отладки в Eclipse и Visual Studio следующим образом: Запустите основную Java-программу из Eclipse, присоедините VisualStudio Debugger для этого процесса.Вы можете установить точки останова с любой стороны.

...