2012-06-04 93 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

對不起,我的回答對您無用 –