У меня есть сторонняя DLL-библиотека Delphi, которую я вызываю из C ++. К сожалению, у меня нет доступа к коду Pascal DLL, и я не программист на Pascal.
Нет файла lib, поэтому я использую GetProcAddress для вызова многих функций DLL, успешно передавая параметры по значению, адресу и ссылке. Я также регистрирую функцию обратного вызова, которая вызывается, когда ожидается.
Моя проблема в том, что в функции обратного вызова невозможно оценить один из двух параметров (адрес 0x000001).
Вот объявления функции Pascal DLL
type
HANDLE = Pointer; /// handle
(** This function Registers the callback function OnACLNeeded
*)
function RegisterCallback(
h: HANDLE;
OnACLNeeded: MyCallbackFunc;
UserData: DWORD): Integer; stdcall;
Это Паскаль версия вызывающего приложения, функция обратного вызова.
Оба параметра передаются по ссылке (var).
function TSNAPICongigF.OnACLNeeded(var keySettings, numOfKeys: Byte): Integer; stdcall;
begin
keySettings:=$0F;
numOfKeys:=1;
Result:=0;
end;
Это моя C ++ версия функции обратного вызова
int __stdcall OnACLNeeded(byte& keySettings, byte& numOfKeys)
{
keySettings = 0x0F;
numOfKeys = 1;
return 1;
}
Это мой код вызова C ++
int _tmain()
{
HMODULE hLib = LoadLibrary(PASCAL_DLL);
// DLL function pointer
typedef int (__stdcall *FnRegisterCallback)(HANDLE hKeyProvider,
int (__stdcall *)(byte&, byte&),
DWORD);
FnRegisterCallback pfnRegisterCallback =
(FnRegisterCallback)GetProcAddress(hLib, "RegisterCallback");
// register my callback function
int ret = (*pfnRegisteraCllback)(h, OnACLNeeded, (DWORD)1);
}
При работе в отладчике я достигаю точку останова в первой строке функции обратного вызова keySettings = 0x0F;
Я считаю, что numOfKeys
является действительным, но keySettings
имеет адрес 0x00000001 и не может быть назначен.
Приложение завершится с AccessViolation, если я продолжу.
int __stdcall OnACLNeeded(byte& keySettings, byte& numOfKeys)
{
keySettings = 0x0F;
Я пытался объявить __cdecl безрезультатно.
Я попытался объявить байтовые параметры как байты *, и я получил тот же недопустимый параметр.
Я использую Visual Studio 2010, работающую на 64-разрядной версии Win7, но компилирующую как Win32.
Это мои команды компиляции и компоновки
/ZI /nologo /W3 /WX- /Od /Oy- /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Debug\CallPascal.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /Gd /analyze- /errorReport:queue
/OUT:"...\Debug\CallPascal.exe" /INCREMENTAL /NOLOGO "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /MANIFEST /ManifestFile:"Debug\CallPascal.exe.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"...\Debug\CallPascal.pdb" /SUBSYSTEM:CONSOLE /PGD:"...y\Debug\CallPascal.pgd" /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE
Любые предложения с благодарностью приняты. Спасибо.
------ изменить -----
Я добавил структуру
struct Bodge {
void* code;
void* instance;
};
Bodge bodge;
bodge.code = OnACLNeeded;
bodge.instance = (void*)0x99; // just to test
Мой обратный вызов становится
Integer __stdcall OnACLNeeded(void* instance, Byte& keySettings, Byte& numOfKeys);
И мой вызов функции для регистрации обратного вызова становится
typedef Integer (__stdcall *FnRegisterCallback)(
HANDLE,
Bodge,
DWORD);
и называется так
ret = (*pfnRegisterCallback)(
h,
bodge,
(DWORD)1);
Этот вызов выдает ошибку
Значение ESP не было должным образом сохранено при вызове функции. Обычно это результат вызова функции, объявленной с одним соглашением о вызовах с указателем функции, объявленным с другим соглашением о вызовах.
, что также может указывать на поврежденный стек, я думаю.
НО, если я проигнорирую ошибку и продолжу, я попаду в тело функции обратного вызова, и ОБА параметры теперь действительны!
Так что успех такого рода, но также и параметр void* instance
имеет значение ноль, а не 0x99, который я установил.
Я чувствую, что мы туда добираемся!
----- редактировать -----
Это вызов функции для регистрации обратного вызова из исходного кода вызова Паскаля.
* @param hKeyProvider the key provider handle for Desfire card created previously with LASSeOKeyProvider_CreateHandle
* @param OnACLNeeded supplies a callback to be called for quering host application for the PICC master key settings
* @param UserData unsigned integer values specifiing any custom provided data to be returned when the callback is called
* @return 0 - on success; <>0 - denotes error code
RegisterCallback(hKeyProv,
@TSNAPICongigF.OnACLNeeded,
(Self));
Обратите внимание на ссылку на себя. Что будет эквивалентно С ++? (Я не пользуюсь классами)