我正在尝试使用JNA在delphi dll中调用函数。功能定义是:
function myFuncGetName (aHandle : THandle; var aBuf : pwideChar ): integer; export;
我的jna映射看起来像这样:
int myFuncGetName(PointerByReference aHandle, WString aBuf);
返回值应为0表示成功,-1表示失败,我总是得-1。
我启动了WinDbg并附加到进程,它在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
我不是集会,所以在我错了的地方纠正我。 我认为它将地址(函数参数)从位置ebp-8移动到edx寄存器。 ebp-8指向值0,因此edx为0。 它将eax移动到edx指向的地址。 它不应该将任何东西移动到0所以它都会破坏?
为什么我的参数没有正确传递给函数? 我从之前的调用中得到了来自同一个DLL的aHandle,我将aBuf设置为 WString aBuf = new WString(“placeholderstring”); 我希望在函数返回后,aBuf会被填充真实文本。
这都是在带有java 7 64bit的Windows 7上运行的。 DLL是32位DLL。
更新和解决方案:
感谢大卫和罗布的评论。我已经将delphi定义更改为使用stdcall声明。现在调用该函数返回0它应该。要检索pwideChar的值,我执行了以下操作:
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));
}
答案 0 :(得分:4)
如果这是DLL函数的真实声明,则问题可能是调用约定。 Delphi中的默认调用约定是register
,它将前两个参数存储在EAX和EDX中,但默认的C调用约定是cdecl
,它将它们存储在堆栈中。将Delphi声明更改为:
function myFuncGetName(aHandle: THandle; var aBuf: PWideChar): Integer; stdcall;
(export
指令实际上不再执行任何操作(我认为是Delphi 2),所以你可以删除它。它被exports
子句所包含,你应该找到它DLL源代码中的其他地方。)
Java方面也是错误的。 Delphi代码中的第二个参数是{em>引用到PWideChar
。我在JNA中看不到WStringByReference
类型,但这就是你需要的。但是,我无法就如何自己实施它提出任何建议。
答案 1 :(得分:1)
你需要使用stdcall调用约定,并且字符串参数声明不正确(我认为)。不再使用export关键字,可以省略。您可以使用exports关键字在库代码中的其他位置命名导出。
您的Delphi功能应该是这样的。
function myFuncGetName(aHandle: THandle; aBuf: pwideChar): integer; stdcall;
我不确定PointerByReference。如果这相当于void **,为什么要将它映射到THandle?