I have a 3rd party Delphi DLL which I am calling from C++. Unfortunately, I have no access to the Pascal DLL code, and am not a Pascal programmer.
There is no lib file, so I'm using GetProcAddress to call many DLL functions, successfully passing parameters by value, address and reference. I also register a callback function which gets called when expected.
My problem is that in the callback function, one of the two parameters cannot be evaluated (address 0x000001).
Here are the Pascal DLL function declarations
type
HANDLE = Pointer; /// handle
(** This function Registers the callback function OnACLNeeded
*)
function RegisterCallback(
h: HANDLE;
OnACLNeeded: MyCallbackFunc;
UserData: DWORD): Integer; stdcall;
This is the pascal version of the calling application, the callback function. Both parameters are passed by reference (var).
function TSNAPICongigF.OnACLNeeded(var keySettings, numOfKeys: Byte): Integer; stdcall;
begin
keySettings:=$0F;
numOfKeys:=1;
Result:=0;
end;
This is my C++ version of the callback function
int __stdcall OnACLNeeded(byte& keySettings, byte& numOfKeys)
{
keySettings = 0x0F;
numOfKeys = 1;
return 1;
}
This is my C++ calling code
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);
}
When running in the debugger, I reach the breakpoint on the first line of the callback function keySettings = 0x0F;
I find that numOfKeys
is valid, but keySettings
has an address of 0x00000001 and cannot be assigned to.
The application will crash with an AccessViolation if I continue.
int __stdcall OnACLNeeded(byte& keySettings, byte& numOfKeys)
{
keySettings = 0x0F;
I've tried declaring as __cdecl to no effect.
I've tried declaring the byte params as byte*, and I get the same invalid parameter.
I'm using Visual Studio 2010 running on Win7 64-bit, but compiling as Win32.
These are my compile and link commands
/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
Any suggestions very gratefully received. Thank you.
------ edit -----
I added the struct
struct Bodge {
void* code;
void* instance;
};
Bodge bodge;
bodge.code = OnACLNeeded;
bodge.instance = (void*)0x99; // just to test
My callback becomes
Integer __stdcall OnACLNeeded(void* instance, Byte& keySettings, Byte& numOfKeys);
And my function call to register the callback becomes
typedef Integer (__stdcall *FnRegisterCallback)(
HANDLE,
Bodge,
DWORD);
and is called like this
ret = (*pfnRegisterCallback)(
h,
bodge,
(DWORD)1);
This call produces an error
The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
which may also indicate a corrupt stack, I think.
BUT if I ignore the error and continue, I get into the callback function body, and BOTH parameters are now valid!
So success of a kind, but also, the void* instance
param has a value of zero, not the 0x99 that I set.
I feel we are getting there though!
----- edit -----
This is the function call to register the callback, from the original Pascal calling code.
* @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));
Note the "self" reference. What would be the C++ equivalent? (I'm not using classes)