3f-lab: Маленький практикум по JNI
Как и обещал, публикую рецепт на случай, если кому-то из начинающих Java-разработчиков захочется задействовать часть кода, написанного на других языках (например, C). Эта технология называется JNI (Java Native Interface) и работает по следующему алгоритму.

1) В коде, который предполагается связывать с C-библиотеками, предусматривает т.н. native методы. У них нет тела (кода, заключенного в фигурные скобки). Все алгоритмы выполняются «в dll-ках», а методы просто декларируются
Обратите внимание на статический блок loadLibrary(«3f-win»). Он отвечает за загрузку библиотеки и без него работать ничего не будет. В каталоге, из которого запускается программа, должна лежать скомпилированная библиотека (например, 3f-win.dll), которую как раз и предстоит создать.
2) Компилируем Java-класс (привожу соответствующий фрагмент файла build.xml):
Как говорит в таких случаях Римский Папа — nihil novi.
3) Создаем т.н. заголовочный файл для программы на языке C:
После выполнения этого задания в каталоге include появится файл с длинным названием и расширением ".h". Из него и будем черпать названия методов и передаваемые аргументы для C-программы.
4) Пишем код на C в файле 3f-win.c:
Задача этого фрагмента — возвращать имя хоста, на котором запускается программа. Можно было бы сделать это и средствами самой Java, но, как ни удивительно, JNI (посредством WinAPI) дает более адекватное решение.
5) Компилируем C-программу. Вообще говоря, сделать это можно какой-нибудь простой командой типа
Но мы же истинные гики и программы для Windows пишем не выходя из Linux (посредством MinGW), так что вот:
Привожу этот фрагмент как есть, т.к. у меня класс для работы с WinAPI выполняет множество полезных функций: выводит список процессов, убивает некоторые из них, перезагружает компьютер и т.д.
В результате в чистом остатке имеем файл 3f-win.dll. Если дооснастить наш класс статическим методом
и запустить его в среде Windows (не забыв положить в текущий каталог полученную dll-ку)
на экране в консоли должно появиться имя хоста. Под Linux всё так же, только компилировать C-код проще.

1) В коде, который предполагается связывать с C-библиотеками, предусматривает т.н. native методы. У них нет тела (кода, заключенного в фигурные скобки). Все алгоритмы выполняются «в dll-ках», а методы просто декларируются
package com.michaelbelyakov1967.util;
public class Win32{
public static native String getHostName();
static{loadLibrary("3f-win");}
}Обратите внимание на статический блок loadLibrary(«3f-win»). Он отвечает за загрузку библиотеки и без него работать ничего не будет. В каталоге, из которого запускается программа, должна лежать скомпилированная библиотека (например, 3f-win.dll), которую как раз и предстоит создать.
2) Компилируем Java-класс (привожу соответствующий фрагмент файла build.xml):
<javac srcdir="." destdir="${classdir}">
<classpath>
<pathelement path="${classdir}"/>
</classpath>
</javac>Как говорит в таких случаях Римский Папа — nihil novi.
3) Создаем т.н. заголовочный файл для программы на языке C:
<javah destdir="include">
<class name="com.michaelbelyakov1967.util.Win32"/>
<classpath>
<pathelement path="${classdir}"/>
</classpath>
</javah>После выполнения этого задания в каталоге include появится файл с длинным названием и расширением ".h". Из него и будем черпать названия методов и передаваемые аргументы для C-программы.
4) Пишем код на C в файле 3f-win.c:
#include <windows.h>
#include "com_michaelbelyakov1967_util_Win32.h"
JNIEXPORT jstring JNICALL Java_com_michaelbelyakov1967_util_Win32_getHostName (JNIEnv *env, jclass cls) {
char *szHostName[255];
int n = 255;
gethostname(szHostName, n);
return (*env)->NewStringUTF(env, szHostName);
}Задача этого фрагмента — возвращать имя хоста, на котором запускается программа. Можно было бы сделать это и средствами самой Java, но, как ни удивительно, JNI (посредством WinAPI) дает более адекватное решение.
5) Компилируем C-программу. Вообще говоря, сделать это можно какой-нибудь простой командой типа
gcc -o 3f-win.dll 3f-win.cНо мы же истинные гики и программы для Windows пишем не выходя из Linux (посредством MinGW), так что вот:
<target name="cc">
<exec executable="${mingw}">
<arg value="-D_JNI_IMPLEMENTATION_"/>
<arg value="-Wl,--kill-at"/>
<arg value="-I/_bin/mingw/include/java"/>
<arg value="-I/_bin/mingw/include/java/win32"/>
<arg value="-Iinclude"/>
<arg value="-shared"/>
<arg value="-o"/>
<arg value="${classdir}/com/michaelbelyakov1967/resources/util/3f-win.dll"/>
<arg value="win32.c"/>
<arg value="-lnetapi32"/>
<arg value="-lpsapi"/>
<arg value="-lwsock32"/>
<arg value="-luser32"/>
</exec>
</target>Привожу этот фрагмент как есть, т.к. у меня класс для работы с WinAPI выполняет множество полезных функций: выводит список процессов, убивает некоторые из них, перезагружает компьютер и т.д.
В результате в чистом остатке имеем файл 3f-win.dll. Если дооснастить наш класс статическим методом
public static void main(String[] args){
System.out.println(getHostName());
}и запустить его в среде Windows (не забыв положить в текущий каталог полученную dll-ку)
java -cp /_classes com.michaelbelyakov1967.util.Win32на экране в консоли должно появиться имя хоста. Под Linux всё так же, только компилировать C-код проще.

Комментарии (5)
RSS свернуть / развернутьстолько времени уходит на беготню аж ппц
Sergei_T
yababay
столько всего интересного написали тут уже!
Gangsta
Очень полезная инфа !
Markony
Markony
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.