2
votes

I'm trying to call a function in a delphi dll using JNA. the function definition is:

function myFuncGetName (aHandle : THandle; var aBuf : pwideChar ): integer; export;

my jna mapping looks like this:

int myFuncGetName(PointerByReference aHandle, WString aBuf);

the return value should be 0 for success and -1 for fail and I'm always getting -1.

I have started up WinDbg and attached to the process and it breaks at myFuncGetName.

057cb384 eb11            jmp     myDLL!myFuncGetName+0x87 (057cb397)
057cb386 b8dcb37c05      mov     eax,offset myDLL!myFuncGetName+0xcc (057cb3dc)
057cb38b 8b55f8          mov     edx,dword ptr [ebp-8]
057cb38e 8902            mov     dword ptr [edx],eax  ds:002b:00000000=???????? <-- ### breaks here ###
057cb390 c745f4ffffffff  mov     dword ptr [ebp-0Ch],0FFFFFFFFh

I'm not an assembly wiz so correct me where I'm wrong. I think its moving an address (function argument) from location ebp-8 to the edx register. ebp-8 points to value 0 so edx is 0. it moves eax to address pointed by edx. Its not supposed to move anything to 0 so it all breaks?

Why aren't my arguments correctly passed to the function? I get aHandle from the same DLL from a previous call and I set up aBuf as WString aBuf = new WString("placeholderstring"); I expect aBuf to be filled with real text after the function returns.

This is all running on Windows 7 with java 7 64bit. The DLL is a 32bit DLL.

UPDATE AND SOLUTION:

Thank you David and Rob for your comments. I have changed the delphi definition to use the stdcall declaration. Calling the function now returns 0 which it should. To retrieve the value of the pwideChar I did the following:

int charcount= "placeholder".length();
PointerByReference aBuf = new PointerByReference(new Memory(charcount*4));
int returnvalue = myFuncGetName(aHandle, aBuf);
if(returnvalue == 0) {
    System.out.println(aBuf.getValue().getString(0, true));
}
2
If that's really the machine code, then only the first line is relevant. It jumps past the four subsequent lines to address 057cb397. Please show more.Rob Kennedy
you're right, didn't see that, there must be something happening to jump that statement as well or the entry point is below it? because the debugger breaks on the second to last line. I just edited it again to make it clearer where the debugger breaks.Alex

2 Answers

4
votes

If that's the real declaration of the DLL function, then the problem could be the calling convention. The default calling convention in Delphi is register, which stores the first two arguments in EAX and EDX, but the default C calling convention is cdecl, which stores them on the stack. Change the Delphi declaration to this:

function myFuncGetName(aHandle: THandle; var aBuf: PWideChar): Integer; stdcall;

(The export directive doesn't really do anything anymore (as of Delphi 2, I think), so you can remove it. It's been subsumed by the exports clause, which you should find elsewhere in the DLL source.)

The Java side is also wrong. The second parameter in the Delphi code is a reference to a PWideChar. I see no WStringByReference type in JNA, but that's what you'll need. I can't offer any advice on how to implement it yourself, though.

1
votes

You'll need to use stdcall calling convention, and the string parameter is declared incorrectly (I think). The export keyword is no longer used and can be omitted. You name your exports with the exports keyword, somewhere else in your library code.

Your Delphi function should be like this.

function myFuncGetName(aHandle: THandle; aBuf: pwideChar): integer; stdcall;

I'm not sure about PointerByReference. If that is equivalent to void**, why are you mapping it to THandle?