Использование JNI

Взаимодействие кодов JAVA и С/С++ может осуществляться двумя способами: С/С++-код получает управление непосредственно из JAVA-программы путем вызова собственного (NATIVE) метода; С/С++-код динамически загружает JVM с помощью INVOCATION API.

Сентябрь 21, 2008 — Рубрика: C++
Метки: , ,

Правила формирования имени С/С++-функции

Имя С/С++-функции формируется путем последовательного соединения следующих компонентов:
префикс JAVA_;
полное квалифицированное имя класса;
символ подчеркивания (”_”);
имя метода;
для перегружаемых (OVERLOADED) методов - два символа подчеркивания (”_ _”) с последующей сигнатурой метода.

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

Для соответствия лексиграфическим правилам С/С++ и использования UNICODE-кодировки, применяются дополнительные правила преобразования, представленные в табл. 2.

Таблица 2Исходный символ Результирующая последовательность
“_” _1
“;” _2
“[" _3
символ UNICODE с кодом ХХХХ _0ХХХХ

Ниже приведен пример JAVA-класса с собственными методами:
PACKAGE TESTPACKAGE;
ABSTRACT CLASS TEST {
PUBLIC NATIVE VOID M1(STRING[] SA, OBJECT O, INT[][] IA2);
PUBLIC NATIVE FLOAT[] M1(DOUBLE D, TEST T);
PUBLIC NATIVE TEST M3(INT I);
}

и соответствующие им имена С/С++-функций:

JNIEXPORT VOID JNICALL JAVA_TESTPACKAGE_TEST_M1___3LJAVA_LANG_STRING_2LJAVA_LANG_OBJECT_2_3_3I
(JNIENV *, JOBJECT, JOBJECTARRAY, JOBJECT, JOBJECTARRAY);
JNIEXPORT JFLOATARRAY JNICALL JAVA_TESTPACKAGE_TEST_M1__LJAVA_LANG_DOUBLE_2LTESTPACKAGE_TEST_2
(JNIENV *, JOBJECT, JOBJECT, JOBJECT);
JNIEXPORT JOBJECT JNICALL JAVA_TESTPACKAGE_TEST_M3
(JNIENV *, JOBJECT, JINT);

Рассмотрим типы параметров, которые получает на входе С/С++-функция при ее вызове.

Май 1, 2008 — Рубрика: C++
Метки: ,

Создание заголовочного файла

Создание С/С++-кода необходимо начинать с создания заголовочного файла. Его можно написать вручную или воспользоваться утилитой JAVAH. Второй путь предпочтительней, так как допускает меньшее количество ошибок. При обращении к утилите JAVAH указывается имя класса и параметр -JNI. Без него JAVAH будет генерировать файл в формате JDK 1.0 NI. Имя класса представляет собой полное квалифицированное имя класса. Например:
JAVAH -JNI JAVA.LANG.RUNTIME

Перед использованием утилиты JAVAH соответствующий JAVA-класс должен быть скомпилирован в CLASS-файл. Утилита JAVAH анализирует CLASS-файл и строит заголовочный файл, в котором перечислены объявления С/С++-функций, представляющих реализации соответствующих собственных методов. В качестве имен создаваемых заголовочных файлов используются полные квалифицированные имена классов, которые описаны в указанном файле и содержат собственные методы. Например, если выполнить следующие команды:
JAVAC APP.JAVA
JAVAH -JNI SYSTEMSPECIFIC

то JAVAH сгенерирует следующий файл SYSTEMSPECIFIC.H:
/* DO NOT EDIT THIS FILE - IT IS MACHINE GENERATED */
#INCLUDE
/* HEADER FOR CLASS SYSTEMSPECIFIC */
#IFNDEF _INCLUDED_SYSTEMSPECIFIC
#DEFINE _INCLUDED_SYSTEMSPECIFIC
#IFDEF _ _CPLUSPLUS
EXTERN “C” {
#ENDIF
/*
* CLASS: SYSTEMSPECIFIC
* METHOD: DOSPECIFIC
* SIGNATURE: ()V
*/
JNIEXPORT VOID JNICALL JAVA_SYSTEMSPECIFIC_DOSPECIFIC(JNIENV *, JOBJECT);
#IFDEF _ _CPLUSPLUS
}
#ENDIF
#ENDIF

Как указывалось выше, данный файл можно создать вручную или с помощью утилиты JAVAH. В последнем случае не рекомендуется вносить в него какие-либо изменения, так как при последующем применении JAVAH к данному классу все внесенные изменения будут потеряны.

Директива препроцессора #INCLUDE включает файл JNI.H (из подкаталога INLCUDE основного каталога JAVA), в котором находятся все необходимые объявления типов и функций для реализации собственного метода.

Макросы JNIEXPORT и JNICALL необходимы только для платформы WIN32, где они раскрываются соответственно в __DECLSPEC(DLLEXPORT) и __STDCALL и позволяют более эффективно строить DLL. Платформа UNIX использует для этих целей обычные С-соглашения, поэтому указанные макросы раскрываются в пустые строки.

Как видно из примера, имя С/С++-функции значительно отличается от имени собственного JAVA-метода. Важным понятием при построении имени С/С++-функции и использовании JNI-функций является сигнатура метода (SIGNATURE или METHOD ARGUMENTS SIGNATURE).

Апрель 28, 2008 — Рубрика: C++
Метки: ,