Ошибка JNI Hello World Неудовлетворительная ссылка
Это моя первая попытка JNI. Моя конечная цель - получить все задачи, выполняемые в настоящее время на машине, но для этого нужно просто выполнить простой пример. Я продолжаю получать эту ошибку, когда пытаюсь выполнить свою основную программу. Я предоставил мою простую основную программу Java, сгенерированный файл заголовка и ошибку.
Я не знаю, от чего зависит эта DLL. Первоначально он ссылался на DLL I, отслеженный и помещенный в system32 (msvcr90.dll).
Вот команда, которую я использовал для компиляции C-кода, который создал файлы DLL, OBJ, LIB, EXP и манифеста.
cl -I "C:\Program Files\Java\jdk1.6.0\include" -I "C:\Program Files\Java\jdk1.6.0\include\win32" -MD -LD HelloWorld.c -FeHelloWorld. DLL
class HelloWorld {
private native void print();
public static void main(String[] args) {
new HelloWorld().print();
}
static {
System.load("C:\\temp\\HelloWorld.dll");
}
}
#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World!\n");
return;
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: print
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_print
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
java.lang.UnsatisfiedLinkError: C:\temp\HelloWorld.dll: A dynamic link library (DLL) initialization routine failed
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(Unknown Source)
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.load0(Unknown Source)
at java.lang.System.load(Unknown Source)
at HelloWorld.<clinit>(HelloWorld.java:7)
Exception in thread "main"
Ответы
Ответ 1
Ошибка неудовлетворенной ссылки может означать, что многие вещи пошло не так. Я бы использовал
System.loadLibrary("HelloWorld");
Вместо
System.load();
Как предположил TwentyMiles.
Кроме того, при вызове вашей программы вам необходимо (если ваша DLL находится в том же каталоге, что и ваши файлы классов:
java -Djava.library.path =. HelloWorld
Вот простая демонстрация, которую я сделал, которая вызывает функцию API Win32 (MessageBox)
Класс Java
class CallApi{
private native String showMessageBox(String msg);
private native double getRandomDouble();
static{
try{
System.loadLibrary("CallApi");
System.out.println("Loaded CallApi");
}catch(UnsatisfiedLinkError e){
//nothing to do
System.out.println("Couldn't load CallApi");
System.out.println(e.getMessage());
}
}
public static void main(String args[]){
CallApi api = new CallApi();
double randomNumber = api.getRandomDouble();
String retval = api.showMessageBox("Hello from Java!\n"+
"The native random number: "+randomNumber);
System.out.println("The native string: "+retval);
}
}
Сгенерированный файл заголовка
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class CallApi */
#ifndef _Included_CallApi
#define _Included_CallApi
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: CallApi
* Method: showMessageBox
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_CallApi_showMessageBox
(JNIEnv *, jobject, jstring);
/*
* Class: CallApi
* Method: getRandomDouble
* Signature: ()D
*/
JNIEXPORT jdouble JNICALL Java_CallApi_getRandomDouble
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Код DLL
#include "CallApi.h"
#include <windows.h>
#include <stdlib.h>
#include <time.h>
#pragma comment(lib,"user32.lib")
JNIEXPORT jstring JNICALL Java_CallApi_showMessageBox
(JNIEnv *env, jobject thisObject, jstring js)
{
//first convert jstring to const char for use in MessageBox
const jbyte* argvv = (*env)->GetStringUTFChars(env, js, NULL);
char* argv =(char *) argvv;
//Call MessageBoxA
MessageBox(NULL, argv, "Called from Java!", MB_ICONEXCLAMATION | MB_OK);
return js;
}
JNIEXPORT jdouble JNICALL Java_CallApi_getRandomDouble
(JNIEnv *env, jobject thisObject)
{
double num1;
srand((unsigned)(time(0)));
num1 = ((double)rand()/(double)RAND_MAX);
return num1;
}
Инструкции по компиляции
Я компилирую с Visual С++ express 2008 cl, удаляя флаг -ML, поскольку он вызывает исключение, когда код Java пытается вызвать собственный код:
cl/I "c:\Program Files\Java\jdk1.6.0_10\include" /I "c:\Program Files\Java\jdk1.6.0_10\include\win32" -LD CallApi.c -FeCallApi. DLL
Затем, чтобы запустить код:
java -Djava.library.path =. CallApi
Ответ 2
Я не утверждаю, что понимаю ситуацию достаточно, чтобы объяснить ее, однако некоторые пользователи сообщили об ошибке при использовании флага компилятора "-MD".
Для получения дополнительной информации см. Java Native Interface (JNI) - Невозможно использовать VS2005 с Java?, который обсуждает эту проблему и предлагает возможные обходы и подумайте о техническом блоге для альтернатив.
Ответ 3
Я считаю, что вы должны использовать
System.loadLibrary("HelloWorld");
вместо System.load. LoadLibrary проверит ваш системный путь (а не путь библиотеки Java), поэтому убедитесь, что HelloWorld.dll находится в каталоге, в котором он может найти. Также обратите внимание, что для этого не требуется полный путь, и вам не нужно добавлять расширение dll в конец.
Ответ 4
Я только что удалил параметр -MD и скомпилировал его, как charm
cl -I"C:\Program Files\Java\jdk1.6.0_21\include" -I"C:\Program Files\Java\jdk1.6.0_21\include\win32" -LD HelloWorld.c -FeHelloWorld.dll
Ответ 5
Если вы измените расположение (пакет) объявления своей нативной функции со стороны java без обновления h файла и сигнатуру метода на стороне c++, он не будет преобразован в метод и выдаст неудовлетворенный..
package x;
public class A {
private native void print();
...
}
переехал в:
package x.y;
public class A {
private native void print();
...
}
Это потребует регенерации H файла (что-то вроде Java_x_y_A_print).
Обратите внимание, что вы можете изменить эти подписи вручную, но я не буду рекомендовать