java.lang.UnsatisfiedLinkError: Nie można znaleźć określonej procedury

Nov 16 2020

Próbuję opracować opakowanie JNA biblioteki DLL C ++.

Nie mam dostępu do kodu biblioteki DLL. Sprawdziłem bibliotekę DLL za pomocą depend.exe i zauważyłem, że nie ma dekoratora wokół metod C ++. Wygląda na to, że extern "C"jest to również ustawione w pobranym pliku C ++ * .h.

Ale mam następujący błąd:

Wyjątek w wątku „main” java.lang.UnsatisfiedLinkError: Błąd podczas wyszukiwania funkcji „compute”: nie można znaleźć określonej procedury.

at com.sun.jna.Function. (Function.java:252) at com.sun.jna.NativeLibrary.getFunction (NativeLibrary.java:600) pod adresem com.sun.jna.NativeLibrary.getFunction (NativeLibrary.java:576) at com.sun.jna.NativeLibrary.getFunction (NativeLibrary.java:562) pod adresem com.sun.jna.Library$Handler.invoke(Library.java:243) at com.sun.proxy.$Proxy0.compute (Unknown Source) at com.JNA.main (JNA.java:171)

Zobacz mój plik 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

Zobacz poniżej moje opakowanie 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);
}

Tak więc w mojej klasie testowej ustawiłem:

// 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);

Dlatego mam wrażenie, że podniesiony wyjątek nie pochodzi z mojej implementacji, ale z biblioteki DLL. Ale nie mam pojęcia, dlaczego w odniesieniu do moich twierdzeń na początku mojego postu.

  1. Czy może istnieć inny powód niż problem z dekoratorem i zewnętrzną deklaracją?

  2. Jak mogę sprawdzić, czy deklaracja zewnętrzna została ustawiona na podstawie inspekcji DLL za pomocą depend.exe?

@dbwiddis Dzięki za odpowiedź, ale:

  1. const jego * wejście const oznacza, że ​​wejście jest stałym wskaźnikiem do stałej jego struktury. Oznacza to, że wskaźnik jest parametrem tylko do odczytu w wartości tylko do odczytu.

  2. Ustawiłem outputPointer jako tablicę, ponieważ nie byłem pewien, jak go użyć. Rzeczywiście potrzebuję go jako parametru wejściowego dla innej metody. Dla c ++ mam coś takiego:

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

Tak więc mam w moim jna Wrapper:

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

W mojej klasie testowej mam:

Pointer[] outputPointer = null;

int resultCompute = compute(input_ref, outputPointer);

int manage(outputPointer[0]);

W każdym razie próbowałem również z twoją rekomendacją w następujący sposób: Tak mam w moim jna Wrapper:

public int compute(his input, PointerByReference outputPointer);

public int manage(Pointer inputPointer);

W mojej klasie testowej mam:

PointerByReference outputPointer = null;

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

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

Ale wciąż mam ten sam problem. Jako przypomnienie, niezależnie od metody zdefiniowanej w dll c ++, mam ten sam podniesiony wyjątek. Naprawdę czuję, że problem nie wynika z mojej implementacji jna. Również ważne szczegóły, w mojej klasie testowej wykonuję ładowanie biblioteki 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);

Powyższy sysout wyświetla nazwę bieżącej metody, która jest wywoływana, tj method names = compute. Wyświetliłem. Debugując kod, zauważyłem, że był to problem z nazwą metody. Ale ponieważ sysout wyświetla nazwę metody, którą zadeklarowałem w moim opakowaniu jna, nie jest to pomocne. Właśnie wykonałem szybki test z fałszywą metodą, która nie jest zdefiniowana w bibliotece dll c ++ i mam ten sam błąd: procedura nie została znaleziona. Dlatego naprawdę myślę, że jest problem z tą biblioteką dll, ale nie wiem, jak się tego dowiedzieć ...

Odpowiedzi

cknelle Nov 21 2020 at 23:12

Na koniec musiałem dodać w mojej głównej klasie Java Test, która wywołuje moje opakowanie następującą linią, aby rozwiązać mój problem: System.setProperty ("jna.library.path", "C: \ myWrapper \ src \ main \ resources"); gdzie C: \ myWrapper \ src \ main \ resources to folder, w którym przechowywany jest mój plik dll.

Ale to nie wyjaśnia, dlaczego nie musiałem ustawiać tej linii dla innych bibliotek dll przechowywanych w tym samym folderze, ponieważ zadeklarowałem również jna.library.path w moich zmiennych środowiskowych.