I'm creating a DLL in Delphi and the method is like this:
function teste3 : PWideString; stdcall;
var
_string : string;
begin
_string := 'teste';
Result := PWideString(_string);
end;
Then i'm trying to call this method using JNA lib in JAVA. The code that call the method in JAVA is like this:
System.out.println(TDLL.getInstance().teste3());
But when the return of the call is only the char t
the rest of the text is not comming.
How can I convert the String
to PWideString
without losing all the chars?
Obs: I tried returning PWideChar too but the result is the same.
Delphi's PWideString
type is a pointer to a WideString
. If you return such a pointer to Java, Java won't know what to do with it. You would need to return a raw PAnsiChar
or PWideChar
instead (prefer the latter, since Java strings are Unicode), but then you have an issue to deal with - memory management.
If you return a pointer to a statically allocated string, or at least a dynamically allocated string that outlives the function, you can return a pointer to the character data directly:
Delphi:
const
_string : WideString = 'teste'; // or UnicodeString in D2009+
function teste3 : PWideChar; stdcall;
begin
Result := PWideChar(_string);
end;
Or:
var
_string : WideString; // or UnicodeString
function teste3 : PWideChar; stdcall;
begin
_string = 'teste'
Result := PWideChar(_string);
end;
Java:
public class TDLL extends Library {
TDLL INSTANCE = (TDLL) Native.loadLibrary("myjnalib.dll", TDLL.class);
public static TDLL getInstance() {
return INSTANCE;
}
WString teste3();
}
System.out.println(TDLL.getInstance().teste3().toString());
However, if you need to dynamically allocate the string, you have to free that memory inside the same DLL or else it will be leaked. Java can't free the memory for you, since it doesn't know how the memory was allocated.
To get around that, you should redesign the DLL function to accept a memory buffer as input, and then you can use JNA's Memory
class on the Java side. Have the DLL fill the memory buffer, and then Java can call the Memory.getString()
method to read the output data into a native Java string
:
Delphi:
function teste3(buffer: PByte; bufsize: Integer) : Integer; stdcall;
var
_string : WideString; // or UnicodeString
MaxChars: Integer;
begin
_string := 'teste';
MaxChars := (bufsize div sizeof(WideChar)) - 1;
StrLCopy(PWideChar(buffer), PWideChar(_string), MaxChars);
Result := Min(Length(_string), MaxChars);
end;
Java:
public class TDLL extends Library {
TDLL INSTANCE = (TDLL) Native.loadLibrary("myjnalib.dll", TDLL.class);
public static TDLL getInstance() {
return INSTANCE;
}
int teste3(Memory buf, int bufsize);
}
Memory buf = new Memory(10);
TDLL.getInstance().teste3(buf, buf.size());
System.out.println(buf.getString(0, true));
That being said, you might consider switching to JNI instead (see Programming JNI with Delphi), because then the DLL can use Java's own memory manager to dynamically allocate and return an actual Java string
object, and then Java can free it normally as needed:
Delphi:
function Java_TDLL_test3(env: PJNIEnv; obj: JObject): JString; stdcall;
var
_string : WideString; // or UnicodeString
begin
_string := 'teste';
Result := env^.NewString(env, PJChar(PWideChar(_string)), Length(_string));
end;
Java:
public class TDLL {
static {
System.loadLibrary("myjnalib");
}
public native string test3();
}
System.out.println(new TDLL().teste3());