java.lang.UnsatisfiedLinkError : 지정된 프로 시저를 찾을 수 없습니다.

Nov 16 2020

C ++ DLL의 JNA 래퍼를 개발하려고합니다.

DLL 코드에 액세스 할 수 없습니다. Depends.exe를 사용하여 DLL을 확인했는데 C ++ 메서드 주변에 데코레이터가 없다는 것을 알았습니다. 그리고 extern "C"내가 검색 한 C ++ * .h 파일에도 설정되어있는 것 같습니다 .

하지만 다음과 같은 오류가 있습니다.

스레드 "main"에서 예외 java.lang.UnsatisfiedLinkError : 'compute'함수 검색 오류 : 지정된 프로 시저를 찾을 수 없습니다.

com.sun.jna.Function. (Function.java:252) at com.sun.jna.NativeLibrary.getFunction (NativeLibrary.java:600) at 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.$com.JNA.main (JNA.java:171)의 Proxy0.compute (알 수없는 소스)

내 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

내 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);
}

따라서 내 테스트 클래스에서 다음을 설정했습니다.

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

따라서 발생한 예외는 내 구현에서 비롯된 것이 아니라 DLL에서 비롯된 것 같습니다. 그러나 게시물 시작 부분에서 내 주장과 관련하여 이유를 설명 할 단서가 없습니다.

  1. 데코레이터와 외부 선언 문제 외에 다른 이유가 있을까요?

  2. Depends.exe를 사용하여 DLL 검사에서 extern 선언이 설정되었는지 어떻게 확인할 수 있습니까?

답장에 대한 @dbwiddis Thanx 그러나 :

  1. const his * const 입력은 입력이 his 구조 상수에 대한 상수 포인터임을 의미합니다. 이것은 포인터가 readonlyvalue에 대한 readonly 매개 변수임을 의미합니다.

  2. 사용 방법을 잘 모르기 때문에 outputPointer를 배열로 설정했습니다. 실제로 다른 메서드의 입력 매개 변수로 필요합니다. C ++의 경우 다음과 같습니다.

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

따라서 내 jna 래퍼에 있습니다.

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

내 테스트 클래스에는 다음이 있습니다.

Pointer[] outputPointer = null;

int resultCompute = compute(input_ref, outputPointer);

int manage(outputPointer[0]);

어쨌든 다음과 같이 귀하의 추천으로 시도했습니다. 따라서 내 jna 래퍼에 있습니다.

public int compute(his input, PointerByReference outputPointer);

public int manage(Pointer inputPointer);

내 테스트 클래스에는 다음이 있습니다.

PointerByReference outputPointer = null;

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

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

하지만 여전히 같은 문제가 있습니다. C ++ dll에 정의 된 방법이 무엇이든간에 동일한 예외가 발생했습니다. 나는 문제가 내 jna 구현에서 나온 것이 아니라고 생각합니다. 또한 중요한 세부 사항은 테스트 클래스에서 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);

위의 sysout은 내가 method names = compute표시 한 현재 메소드의 이름을 표시합니다. 코드를 디버깅하면서 메소드 이름에 문제가 있음을 알았습니다. 그러나 sysout은 jna 래퍼에서 선언 한 메서드의 이름을 표시하므로 도움이되지 않습니다. 방금 C ++ dll에 정의되지 않은 가짜 방법으로 빠른 테스트를 수행했으며 동일한 오류가 발생했습니다. 절차를 찾을 수 없습니다. 따라서 나는 정말로 그 dll에 문제가 있다고 생각하지만 그것을 찾는 방법을 모르겠습니다 ...

답변

cknelle Nov 21 2020 at 23:12

마지막으로 내 문제를 해결하기 위해 내 래퍼를 호출하는 Java Test 기본 클래스에 다음 줄을 추가해야했습니다. System.setProperty ( "jna.library.path", "C : \ myWrapper \ src \ main \ resources"); 여기서 C : \ myWrapper \ src \ main \ resources는 내 dll 파일이 저장된 폴더입니다.

그러나 환경 변수에서도 jna.library.path를 선언 한 것과 동일한 폴더에 저장된 다른 dll에 대해이 줄을 설정할 필요가없는 이유는 설명하지 않습니다.