JNI Hello World Ошибка неудовлетворенной связи - PullRequest
11 голосов
/ 31 августа 2009

Это моя первая попытка JNI. Моя конечная цель - запустить все задачи, выполняемые в данный момент на компьютере, но мне нужно запустить даже простой пример. Я продолжаю получать эту ошибку, когда я пытаюсь выполнить свою основную программу. Я предоставил мою простую основную программу на Java, сгенерированный файл заголовка и ошибку.

Я не знаю, от чего может зависеть эта DLL. Первоначально он ссылался на DLL, которую я выследил и поместил в 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. длл

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" 

Ответы [ 5 ]

9 голосов
/ 09 сентября 2009

Ошибка неудовлетворенной связи может означать, что многие вещи пошли не так. Я бы использовал

System.loadLibrary("HelloWorld");

Вместо

System.load();

Как предложил TwentyMiles.

Кроме того, при вызове вашей программы вам нужно (при условии, что ваша DLL находится в том же каталоге, что и ваши файлы классов:

java -Djava.library.path =. HelloWorld

Вот простая демонстрация, которую я сделал, которая вызывает функцию Win32 API (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

Код C 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 C ++ 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. длл

Затем запустите код:

java -Djava.library.path =. CallApi

3 голосов
/ 01 сентября 2009

Я не претендую на то, чтобы понять ситуацию достаточно, чтобы объяснить ее, однако некоторые пользователи сообщали об ошибке при использовании флага компилятора "-MD".

Для получения дополнительной информации см. Собственный интерфейс Java (JNI) - невозможно использовать VS2005 с Java? , в котором обсуждается эта проблема и предлагаются возможные обходные пути, а подумайте о техническом блоге для альтернатив.

1 голос
/ 22 января 2011

Я только что удалил опцию -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
1 голос
/ 01 сентября 2009

Я считаю, что вы должны использовать

System.loadLibrary("HelloWorld");

вместо System.load. LoadLibrary проверит ваш системный путь (не путь библиотеки Java), поэтому убедитесь, что HelloWorld.dll находится в каталоге, где он может быть найден. Также обратите внимание, что для этого не требуется полный путь, и вам не нужно добавлять расширение dll в конец.

0 голосов
/ 11 июня 2019

Если вы измените расположение (пакет) объявления своей нативной функции со стороны 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).

Обратите внимание, что вы можете изменить эти подписи вручную, но я не буду рекомендовать

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...