2

我正在尝试使用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));
}
4

2 回答 2

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 代码中的第二个参数是PWideChar. 我在 JNA 中没有看到任何WStringByReference类型,但这就是您需要的。不过,我无法就如何自己实施它提供任何建议。

于 2012-06-04T16:28:43.133 回答
1

您需要使用 stdcall 调用约定,并且字符串参数声明不正确(我认为)。export 关键字不再使用,可以省略。您可以在库代码的其他位置使用 exports 关键字命名您的导出。

你的 Delphi 函数应该是这样的。

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

我不确定PointerByReference。如果这相当于 void**,为什么要将它映射到 THandle?

于 2012-06-04T16:27:52.963 回答