Search code examples
javajna

java.lang.UnsatisfiedLinkError: The specified procedure could not be found


I'm trying to develop a JNA wrapper of a C++ DLL.

I do not have access to the code of the DLL. I checked the DLL using depends.exe and I saw that there is no decorator around the C++ methods. And it seems that extern "C" is also set in the C++ *.h file I retrieved.

But I have the following error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'compute': The specified procedure could not be found.

at 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) at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:562) at com.sun.jna.Library$Handler.invoke(Library.java:243) at com.sun.proxy.$Proxy0.compute(Unknown Source) at com.JNA.main(JNA.java:171)

See my cpp *.h file:

#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

See below my JNA wrapper:

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

Thus in my test class I set:

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

Thus I have the feeling that the raised exception does not come from my implementation but from the DLL. But I do not have any clue to explain why regarding my assertions at the beginning of my post.

  1. Could there be another reason except decorator and extern declaration issue?

  2. How could I check that extern declaration has been set from the DLL inspection with depends.exe?

@dbwiddis Thanx for your reply but :

  1. const his* const input means that input is a constant pointer on a constant his structure. This means that the pointer is a readonly parameter on a readonlyvalue.

  2. I set outputPointer as an array because I was not sure about the way to use it. Indeed I need it as an input parameter for another method. For c++ I have something like :

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

Thus I have in my jna Wrapper :

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

In my test class I have :

Pointer[] outputPointer = null;

int resultCompute = compute(input_ref, outputPointer);

int manage(outputPointer[0]);

Anyway I tried also with your recommandation as follow : Thus I have in my jna Wrapper :

public int compute(his input, PointerByReference outputPointer);

public int manage(Pointer inputPointer);

In my test class I have :

PointerByReference outputPointer = null;

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

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

But I still have the same issue. As reminder whatever the method defined in the c++ dll I have the same raised exception. I really feel that the issue does not come from my jna implementation. Also important detail, in my test class I perform a upload of the 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);

The sysout above displays the name of the current method which is called i.e I have method names = compute displayed. Debugging the code, I noticed that their was an issue on the method name. But as the sysout displays the name of the method I declared in my jna wrapper, it is not helpful. I 've just performed a quick test with a fake method which is not defined in the c++ dll and I have the same error : the procedure is not found. Thus I really think that there is an issue with that dll but I don't know how to find it out...


Solution

  • Finally, I had to add in my java Test main class which calls my wrapper the following line to solve my issue : System.setProperty("jna.library.path", "C:\myWrapper\src\main\resources"); where C:\myWrapper\src\main\resources is the folder in which my dll file is stored.

    But It does not explained why I did not need to set this line for other dll stored in the same folder as I declared also jna.library.path in my environment variables as well.