2012-06-04 108 views
1

我想要调用一个函数在德尔福DLL使用JNA。函数的定义是:功能映射德尔福/帕斯卡DLL在JNA句柄和字符串

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 

我不是一个组装wiz所以我错了。 我认为它将地址(函数参数)从位置ebp-8移动到edx寄存器。 ebp-8指向值0,因此edx为0. 它将eax移至edx指向的地址。 它不应该将任何东西移动到0,所以它都打破了?

为什么我的参数不能正确传递给函数? 我从以前的调用中得到一个来自同一个DLL的句柄,并且我设置了一个aBuf作为 WString aBuf = new WString(“placeholderstring”); 我希望aBuf在函数返回后被真实文本填充。

这是所有在Java 7 64位Windows 7上运行。该DLL是一个32位的DLL。

更新及解决方法:

谢谢大卫和Rob您的意见。我已将delphi定义更改为使用stdcall声明。调用该函数现在返回它应该的值。要检索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

如果这真的是机器代码,那么只有第一行是相关的。它跳过了后面的四条线,以解决057cb397。请展示更多。 –

+0

你是对的,没有看到,有什么事情可以跳过这种说法,或者入口点在它下面?因为调试器在倒数第二行中断。我只是再次编辑它以使调试器中断的地方更清晰。 – Alex

回答

4

如果这是DLL函数的真正声明,那么问题可能是调用约定。 Delphi中的默认调用约定是register,它将前两个参数存储在EAX和EDX中,但默认的C调用约定是cdecl,它将它们存储在堆栈中。德尔福声明改成这样:

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

(该export指令并没有真正做什么了(德尔福2,我认为),那么你可以将其删除它被exports条款,纳入其中。你应该在DLL源文件的其他地方找到。)

Java方面也是错误的。Delphi代码中的第二个参数是参考PWideChar。我在JNA看到没有WStringByReference类型,但这就是你需要的。不过,我无法就自己如何实施提供任何建议。

+0

JNA中没有cdecl。最后一段的结论不一定是正确的。是的,Java方面可能是错误的,但德尔福方面也是如此。由于提问者很可能知道Java,我敢打赌它是后者。在这种情况下,签名将按照我答案中的参数2。 –

+1

@David,'Library'及其后代'StdCallLibrary'的存在似乎表明Java可以调用任何一种约定的函数。 Java代码在问题中提供的信息的上下文中是错误的,该信息指出DLL函数通过引用接收PWideChar。如果这个DLL是错误的,那是在为DLL的操作规定的规范的背景下,我们没有任何信息。我试图对待DLL是一个给定的,这是Java程序员的工作,以消耗它。坏惯例必须是固定的DLL端;该类型可能是固定的Java端。 –

1

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

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

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

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

+0

你是对的,PointerByReference是错误的。 int工作得很好。我在那里测试过,因为我测试了为什么事情没有起作用,并且它在Delphi中被声明为Cardinal,它是一个unsigned int,所以我认为它会在Java中导致问题。我认为我的处理在某些时候是不正确的。 – Alex

+0

对不起,我的回答对您无用 –