2012-07-10 3 views
3

J'essaie de créer un wrapper Java pour une DLL tierce. J'ai créé ma propre DLL qui agit comme un intermédiaire entre JNI et la DLL tierce. En java je charge bien cette DLL mais l'erreur java.lang.UnsatisfiedLinkError: sixense.Sixense.init()Z est renvoyée. Quelle pourrait être la cause de cette erreur et comment puis-je la déboguer correctement?java.lang.UnsatisfiedLinkError retourné lors de l'appel de la méthode native

Main.java:

package sixense_test; 

import sixense.ControllerData; 
import sixense.Sixense; 

public class Main { 

    public static ControllerData[] controllers = new ControllerData[4]; 
    public static boolean quit; 

    public static void main(String[] args) { 
     if(Sixense.init()) { 
      Sixense.setActiveBase(0); 
      Sixense.getAllNewestData(controllers); 
      System.out.println("X: " + controllers[0].pos[0] + "Y: " + controllers[0].pos[1] + "Z: " + controllers[0].pos[2]); 
     } 
    } 
} 

Sixense.java:

package sixense; 

public class Sixense { 
    public static native boolean init(); 
    public static native boolean exit(); 
    public static native int getMaxBases(); 
    public static native boolean setActiveBase(int base_num); 
    public static native boolean isBaseConnected(int base_num); 
    public static native int getMaxControllers(); 
    public static native int getNumActiveControllers(); 
    public static native boolean isControllerEnabled(int controller_id); 
    public static native boolean getAllNewestData(ControllerData[] all_data); 
    public static native boolean getAllData(int index_back, ControllerData[] all_data); 
    public static native boolean getNewestData(int controller_id, ControllerData data); 
    public static native boolean getData(int controller_id, int index_back, ControllerData all_data); 
    public static native int getHistorySize(); 
    public static native boolean setFilterEnabled(boolean on_or_off); 
    public static native boolean getFilterEnabled(); 
    public static native boolean setFilterParams(float near_range, float near_val, float far_range, float far_val); 
    public static native boolean getFilterParams(float[] params); 
    public static native boolean triggerVibration(int controller_id, int duration, int pattern_id); 
    public static native boolean autoEnableHemisphereTracking(int controller_id); 
    public static native boolean setHighPriorityBinding(boolean on_or_off); 
    public static native boolean getHighPriorityBinding(); 
    public static native boolean setBaseColor(int red, int green, int blue); 
    public static native boolean getColorBase(int[] colors); 
    static { 
     System.loadLibrary("Sixense_Java"); 
    } 
} 

Un extrait de sixense_Sixense.cpp:

#include <jni.h> 
#include <sixense.h> 
#include "sixense_Sixense.h" 

JNIEXPORT jboolean JNICALL Java_sixense_Sixense_init(JNIEnv *env, jclass obj) { 
    int i; 
    i = sixenseInit(); 
    return (i == -1) ? JNI_FALSE : JNI_TRUE; 
} 

Un extrait de sixense_Sixense.h:

/* DO NOT EDIT THIS FILE - it is machine generated */ 
#include <jni.h> 
/* Header for class sixense_Sixense */ 

#ifndef _Included_sixense_Sixense 
#define _Included_sixense_Sixense 
#ifdef __cplusplus 
extern "C" { 
#endif 
/* 
* Class:  sixense_Sixense 
* Method: init 
* Signature:()Z 
*/ 
JNIEXPORT jboolean JNICALL Java_sixense_Sixense_init 
    (JNIEnv *, jclass); 

sortie de dumpbin:

File Type: DLL 

    Section contains the following exports for Sixense_Java.dll 

    00000000 characteristics 
    4FFBC481 time date stamp Tue Jul 10 01:58:25 2012 
     0.00 version 
      1 ordinal base 
      23 number of functions 
      23 number of names 

    ordinal hint RVA  name 

      1 0 00001D10 [email protected] 
      2 1 000011A0 [email protected] 
      3 2 00001A40 [email protected] 
      4 3 000019A0 [email protected] 
      5 4 00001DC0 [email protected] 
      6 5 00001B30 [email protected] 
      7 6 00001BD0 [email protected] 
      8 7 00001C40 [email protected] 
      9 8 00001D60 [email protected] 
     10 9 00001B90 [email protected] 
     11 A 000011C0 [email protected] 
     12 B 00001210 [email protected] 
     13 C 00001AE0 [email protected] 
     14 D 00001220 [email protected] 
     15 E 00001180 [email protected] 
     16 F 000011F0 [email protected] 
     17 10 [email protected] 
     18 11 000011D0 [email protected] 
     19 12 00001D90 [email protected] 
     20 13 00001BA0 [email protected] 
     21 14 00001C00 [email protected] 
     22 15 00001D30 [email protected] 
     23 16 00001CE0 [email protected] 

    Summary 

     1000 .bss 
     1000 .data 
     1000 .edata 
     1000 .idata 
     1000 .rdata 
     1000 .reloc 
     2000 .text 
+1

Avez-vous le dossier avec les dll dans votre -Djava.library.path VM arg? –

+0

Que génère le rapport dumpbin/exports Sixense_Java.dll? – Petesh

+0

Les DLL sont dans un dossier qui fait partie de java.library.path et @Petesh Je viens d'ajouter la sortie de dumpbin. – yodal

Répondre

5

Lorsque vous appelez une fonction native en Java, le moteur d'exécution essaie d'utiliser:

  • fonction décorée de style stdcall: [email protected], où n est le nombre d'octets dans la liste des paramètres,
  • et Fonction non décorée de style cdecl: functionName.

Lors de la compilation avec MinGW, vous obtiendrez un mélange de ces deux: MinGW ajoutera la @n, mais ne sera pas placé le trait de soulignement: fun[email protected].

La façon de résoudre ce problème est de dire ld ne pas ajouter le suffixe, en utilisant le commutateur --kill-at (ou -Wl,--kill-at si vous l'appelez par GCC).

+0

Ceci devrait être la réponse acceptée. – Anton

+0

Pourriez-vous aller un peu plus en profondeur avec votre réponse? J'ai le même problème que OP, j'utilise un makefile pour appeler javah pour générer l'en-tête et g ++ pour générer le .o et .dll. J'utilise MinGW mais '@ n' n'est pas ajouté à un nom de fonction, pas plus qu'un caractère de soulignement, mais contrairement à l'OP, la simple modification des fichiers (je sais, ne devrait vraiment pas le faire) n'aide pas vraiment. – Troyseph

1
java.lang.UnsatisfiedLinkError: no Sixense_Java in java.library.path 

On dirait que Java ne peux pas trouver la bibliothèque, avez-vous le mettre au bon endroit?

Vous devrez peut-être changer le java.library.path, jetez un oeil à this.

Si vous souhaitez imprimer le contenu de l'utiliser:

System.out.println(System.getProperties().getProperty("java.library.path")); 

Cela peut imprimer beaucoup, vous pouvez split(";") et imprimer chaque entrée lui-même.

+0

Cette erreur a été sortie uniquement lorsque j'ai supprimé la bibliothèque pour tester si elle a envoyé un message d'erreur différent. – yodal

+0

Je viens de remarquer que Sixense_init demande deux paramètres, vous l'appelez sans eux cependant. Cela pourrait être la raison pour laquelle la fonction ne peut pas être trouvée. – Brainbot

+0

La façon dont JNI fonctionne est que chaque fonction native est envoyée JNIEnv et une référence à la classe qui a appelé la fonction ainsi que tous les paramètres supplémentaires. JNI prend soin d'envoyer JNIEnv et la référence de classe par ses propres moyens. – yodal

4

J'ai trouvé la réponse! Il semble que lorsque vous utilisez JNI dans Windows, il recherche une fonction commençant par _Java_ alors que dans toutes les autres plates-formes, il recherche Java_. Pourquoi c'est le cas et pas écrit dans la documentation je ne sais pas mais ça fait tout fonctionner parfaitement!

+0

Alors, comment l'avez-vous réparé exactement? Modifié les drapeaux de compilation dll? –

+0

Lorsque javah crée le fichier d'en-tête, chaque fonction s'appelle 'Java_package_Class_method'. La chose étrange est que quand compilé comme ceci, JNI ne peut pas trouver la bonne fonction pour la méthode native et crache des erreurs, mais si un soulignement a été ajouté avant 'Java' alors JNI serait capable de trouver la fonction. Sur une note de côté, j'ai depuis essayé de compiler avec VC++ 2010 (j'utilisais MinGW auparavant) et les underscores étaient un problème lors de la compilation. Allez comprendre. – yodal

+2

Le trait de soulignement principal est une décoration de nom stdcall connue pour MSVC. Ce n'est pas un problème tant que vous compilez et utilisez contre le même et un seul JDK (jni.h est une clé). D'un autre côté, MinGW n'a pas cette décoration et ne l'attend pas. Vous avez peut-être mélangé les deux environnements ou les conventions d'appel. Wild devinez. Mais pirater votre en-tête créé n'est pas une solution. Le commentaire "NE PAS MODIFIER CE FICHIER" a vraiment une raison. –

Questions connexes