java.lang.UnsatisfiedLinkError: La procédure spécifiée est introuvable

Nov 16 2020

J'essaye de développer un wrapper JNA d'une DLL C ++.

Je n'ai pas accès au code de la DLL. J'ai vérifié la DLL à l'aide de depend.exe et j'ai vu qu'il n'y avait pas de décorateur autour des méthodes C ++. Et il semble que ce extern "C"soit également défini dans le fichier C ++ * .h que j'ai récupéré.

Mais j'ai l'erreur suivante:

Exception dans le thread "main" java.lang.UnsatisfiedLinkError: Erreur lors de la recherche de la fonction 'compute': La procédure spécifiée est introuvable.

à com.sun.jna.Function. (Function.java:252) à com.sun.jna.NativeLibrary.getFunction (NativeLibrary.java:600) à com.sun.jna.NativeLibrary.getFunction (NativeLibrary.java:576) à com.sun.jna.NativeLibrary.getFunction (NativeLibrary.java:562) à com.sun.jna.Library$Handler.invoke(Library.java:243) at com.sun.proxy.$Proxy0.compute (source inconnue) sur com.JNA.main (JNA.java:171)

Voir mon fichier cpp * .h:

#ifdef __cplusplus

extern "C" {

#endif

typedef struct s_mine
{
    e_color           color;    //e_color is enum type made of int values
    his               data;        
    int               str;        
    unsigned int      wild;         
    unsigned int      hello;        
    float             rice; 
} mine;

typedef struct s_his
{
    unsigned char * data; 
    unsigned int    size;
} his;

// compute function which raised the exception

int compute(const his* const input, void ** outputPointer);

// treat function raised also the same exception

int treat(const mine* inputParameter, mine* outputParameter);

#ifdef __cplusplus

}

#endif

Voir ci-dessous mon wrapper JNA:

public interface MyInterface extends Library {

    @FieldOrder({"data", "size"})
    public static class his extends Structure {
        public static class ByReference extends his implements Structure.ByReference {}
        public static class ByValue extends rt_buffer implements Structure.ByValue {}
        public Pointer data;
        public int size;
    }

    @FieldOrder({"color","data","str","wild","hello","rice"})
    public class mine extends Structure {
        public static class ByReference extends mine implements Structure.ByReference {}
        public int color; 
        public his data;
        public int str; 
        public int wild; 
        public int hello; 
        public float rice;
    }

    public int compute(his input, Pointer[] outputPointer);

    public int treat(mine inputParameter, mine outputParameter);
}

Ainsi, dans ma classe de test, j'ai défini:

// COMPUTE

MyInterface.his.ByReference input_ref = new MyInterface.his.ByReference();

ByteBuffer init_buffer;

// init_buffer is initialized with some not null values

Pointer init_p = Native.getDirectBufferPointer(init_buffer);

input_ref.data = init_p;

input_ref.size = init_buffer.capacity();

Pointer[] outputPointer = null;

int resultCompute = compute(input_ref, outputPointer);

// TREAT

MyInterface.mine.ByReference inputParameter_ref = new MyInterface.mine.ByReference();

MyInterface.his.ByValue buffer = new MyInterface.his.ByValue();

// initialize buffer with an input buffer value different from null value

// Set other fields of inputParameter_ref with none null values

inputParameter_ref.data = buffer;

MyInterface.mine.ByReference outputParameter_ref = null;

int resultTreat = treat(inputParameter_ref, outputParameter_ref);

J'ai donc le sentiment que l'exception levée ne vient pas de mon implémentation mais de la DLL. Mais je n'ai aucune idée pour expliquer pourquoi concernant mes affirmations au début de mon message.

  1. Pourrait-il y avoir une autre raison à part le problème du décorateur et de la déclaration externe?

  2. Comment puis-je vérifier que la déclaration externe a été définie à partir de l'inspection DLL avec depend.exe?

@dbwiddis Merci pour votre réponse mais:

  1. const son entrée * const signifie que l'entrée est un pointeur constant sur une constante de sa structure. Cela signifie que le pointeur est un paramètre en lecture seule sur une valeur en lecture seule.

  2. J'ai défini outputPointer comme un tableau car je n'étais pas sûr de la façon de l'utiliser. En effet, j'en ai besoin comme paramètre d'entrée pour une autre méthode. Pour c ++, j'ai quelque chose comme:

int compute(const his* const input, void ** outputPointer); // **outputPointer is an output of compute method

int manage(void * inputPointer); // As *outputPointer becomes an input of manage method

Ainsi j'ai dans mon jna Wrapper:

public int compute(his input, Pointer[] outputPointer); public int manage(Pointer inputPointer);

Dans ma classe de test, j'ai:

Pointer[] outputPointer = null;

int resultCompute = compute(input_ref, outputPointer);

int manage(outputPointer[0]);

Quoi qu'il en soit j'ai essayé aussi avec votre recommandation comme suit: Ainsi j'ai dans mon jna Wrapper:

public int compute(his input, PointerByReference outputPointer);

public int manage(Pointer inputPointer);

Dans ma classe de test, j'ai:

PointerByReference outputPointer = null;

int resultCompute = myInterface.compute(input_ref, outputPointer);

int myInterface.manage(outputPointer.getValue());

Mais j'ai toujours le même problème. Pour rappel quelle que soit la méthode définie dans la dll c ++, j'ai la même exception levée. J'ai vraiment l'impression que le problème ne vient pas de mon implémentation jna. Détail également important, dans ma classe de test, j'effectue un téléchargement de la dll:

Map options = new HashMap();

options.put(Library.OPTION_FUNCTION_MAPPER, new StdCallFunctionMapper() {
public String getFunctionName(NativeLibrary library, Method method) {
System.out.println("method names = "+method.getName());
return super.getFunctionName(library, method);
}
});

MyInterface myInterface = (MyInterface) Native.load("dllName",MyInterface.class,options);

Le sysout ci-dessus affiche le nom de la méthode actuelle qui est appelée c'est-à-dire que j'ai method names = computeaffiché. En déboguant le code, j'ai remarqué qu'il y avait un problème sur le nom de la méthode. Mais comme le sysout affiche le nom de la méthode que j'ai déclarée dans mon wrapper jna, ce n'est pas utile. Je viens de faire un test rapide avec une fausse méthode qui n'est pas définie dans la dll c ++ et j'ai la même erreur: la procédure n'est pas trouvée. Donc je pense vraiment qu'il y a un problème avec cette dll mais je ne sais pas comment le trouver ...

Réponses

cknelle Nov 21 2020 at 23:12

Enfin, j'ai dû ajouter dans ma classe principale java Test qui appelle mon wrapper la ligne suivante pour résoudre mon problème: System.setProperty ("jna.library.path", "C: \ myWrapper \ src \ main \ resources"); où C: \ myWrapper \ src \ main \ resources est le dossier dans lequel mon fichier dll est stocké.

Mais cela n'explique pas pourquoi je n'avais pas besoin de définir cette ligne pour d'autres dll stockées dans le même dossier que j'ai déclaré également jna.library.path dans mes variables d'environnement.