function mapping delphi/pascal dll in jna handle a

2019-08-02 20:01发布

问题:

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

回答1:

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.



回答2:

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?