Отображение функций delphi/pascal dll в дескрипторе и строке jna
Я пытаюсь вызвать функцию в DLL Delphi с использованием 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
Я не мастер сборки, так что поправьте меня, где я не прав. Я думаю, что это перемещение адреса (аргумента функции) из местоположения ebp-8 в регистр edx. ebp-8 указывает на значение 0, поэтому edx равен 0. он перемещает eax по адресу, указанному edx. Это не должно перемещать что-либо в 0, так что все ломается?
Почему мои аргументы неправильно передаются в функцию? Я получаю aHandle из той же DLL из предыдущего вызова и устанавливаю aBuf как WString aBuf = new WString ("placeholderstring"); Я ожидаю, что aBuf будет заполнен реальным текстом после возврата функции.
Это все работает на Windows 7 с Java 7 64bit. 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));
}
2 ответа
Если это реальное объявление функции DLL, то проблема может заключаться в соглашении о вызовах. Соглашение о вызовах по умолчанию в Delphi: register
, который хранит первые два аргумента в EAX и EDX, но соглашение о вызовах C по умолчанию cdecl
, который хранит их в стеке. Измените объявление Delphi на это:
function myFuncGetName(aHandle: THandle; var aBuf: PWideChar): Integer; stdcall;
(The export
директива на самом деле больше ничего не делает (я думаю, что в Delphi 2), так что вы можете удалить ее. Это было включено в exports
пункт, который вы должны найти в другом месте в источнике DLL.)
Сторона Java тоже не права. Второй параметр в коде Delphi является ссылкой на PWideChar
, Не вижу WStringByReference
введите JNA, но это то, что вам нужно. Но я не могу дать совет, как это сделать самостоятельно.
Вам нужно будет использовать соглашение о вызовах stdcall, и строковый параметр объявлен неправильно (я думаю). Ключевое слово export больше не используется и может быть опущено. Вы называете свои экспорты ключевым словом export, где-то еще в коде вашей библиотеки.
Ваша функция Delphi должна быть такой.
function myFuncGetName(aHandle: THandle; aBuf: pwideChar): integer; stdcall;
Я не уверен насчет PointerByReference. Если это эквивалентно void**, почему вы отображаете его в THandle?