java.lang.UnsatisfiedLinkError: Nie można znaleźć określonej procedury
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.
Czy może istnieć inny powód niż problem z dekoratorem i zewnętrzną deklaracją?
Jak mogę sprawdzić, czy deklaracja zewnętrzna została ustawiona na podstawie inspekcji DLL za pomocą depend.exe?
@dbwiddis Dzięki za odpowiedź, ale:
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.
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
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.