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.
Could there be another reason except decorator and extern declaration issue?
How could I check that extern declaration has been set from the DLL inspection with depends.exe?
@dbwiddis Thanx for your reply but :
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.
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...
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.