I'm using a C++ DLL via JNA. I want to call the following method in Java, which writes into szVisor information that I want to read.
long FAR PASCAL DLL_GetLocalPortTS(char* szEquip,char* szVisor){
...
}
The Java interface implementation is the following:
public interface IE2E extends Library {
// Instancia de la dll, carga la librería
IE2E INSTANCE = (IE2E) Native.loadLibrary("e2e", IE2E.class);
...
int GetLocalPortTS(String equip, String[] equipInfo);
}
And the method call:
String equip = "equipID";
String equipInfo = "";
String[] rEquipInfo = {equipInfo};
IE2E sdll = IE2E.INSTANCE;
int ret = sdll.GetLocalPortTS(equip, rEquipInfo);
This execution nets me a fatal error in the JRE, but if I put both arguments as either String or String[] it doesn't. However, if I use both Strings it doesnt overwrite equipInfo and I don't get the info which I want; if I use both as arrays, the method doesn't get the equip value and doesn't operate.
Any insight on this will be welcome.
The problem is that the C code wants to write into szVisor
, right? I guess it does something like this:
long GetLocalPortTS(char* szEquip,char* szVisor){
strcpy(szVisor, "I am C code result :)");
return 0;
}
If you pass in a String from the Java side, then the memory is owned by the JVM, so writing to it causes a crash. What you need is a Memory object, which is a wrapped malloc'd bit of memory that the C code can safely write to.
Your new JNA interface would be as follows. I've commented out the old version so you can compare:
public interface IE2E extends Library {
IE2E INSTANCE = (IE2E) Native.loadLibrary("e2e", IE2E.class);
//int GetLocalPortTS(String equip, String[] equipInfo);
int GetLocalPortTS(String equip, Memory equipInfo);
}
And the code to call it would be as follows, the 256 is a placeholder. Make sure you allocate enough to write the string to:
String equip = "equipID";
String equipInfo = "";
//String[] rEquipInfo = {equipInfo};
Memory rEquipInfo = new Memory(256);
IE2E sdll = IE2E.INSTANCE;
int ret = sdll.GetLocalPortTS(equip, rEquipInfo);
To use the result as a String, you'd do this:
rEquipInfo.getString(0);
As the documentation says, the Memory's finalize()
method automatically calls free on the malloc'd memory so there's no need to worry about memory leaks.