Reputation: 95
typedef void (*onPaymentResultCallback) (int result);
DLL_EXPORT int AR_payment_item_credit(const char *terminal_no, const char *description, double amount, enum currency_id cid, int receiptid,
onPaymentResultCallback cb);
I convert above definetions like this:
TonPaymentResultCallback = procedure(result:LongInt) of object;
function AR_payment_item_credit(HInst:THandle; const TerminalNo:PAnsiChar; const Description:PAnsiChar; Amount:Double; CurrencyId:LongInt;
RecepitID:LongInt; onPaymentResultCallback:tonPaymentResultCallback):LongInt;
var
MyFunct: function (const TerminalNo:PAnsiChar; const Description:PAnsiChar; Amount:Double; CurrencyId:LongInt;
RecepitID:LongInt; onPaymentResultCallback:tonPaymentResultCallback): LongInt; cdecl;
begin
Result := 0;
MyFunct:=GetProcAddress(HInst,'AR_payment_item_credit');
if Assigned(MyFunct) then
Result := MyFunct(TerminalNo, Description, Amount, CurrencyId, RecepitID,onPaymentResultCallback);
end;
I know C/C++ dll function converting to Delphi, but callback is new for me. Are my definitions correct?
Upvotes: 2
Views: 673
Reputation: 595339
Your Delphi translation has some errors in it. Try this instead:
type
TPaymentResultCallback = procedure(AResult: Integer); cdecl;
function ARPaymentItemCredit(HInst: THandle; const TerminalNo: PAnsiChar;
const Description: PAnsiChar; Amount: Double; CurrencyID: Integer;
ReceiptID: Integer; onPaymentResult: TPaymentResultCallback): Integer;
var
MyFunct: function(const TerminalNo: PAnsiChar; const Description: PAnsiChar;
Amount: Double; CurrencyID: Integer; ReceiptID: Integer;
onPaymentResult: TPaymentResultCallback): Integer; cdecl;
begin
@MyFunct := GetProcAddress(HInst, 'AR_payment_item_credit');
if Assigned(MyFunct) then
Result := MyFunct(TerminalNo, Description, Amount, CurrencyID, ReceiptID, onPaymentResult)
else
Result := 0;
end;
The most important difference from your code is TPaymentResultCallback
is not declared as of object
. You can't use a Delphi-style method pointer as a C-style function pointer, which means you can't use a non-static class method for your DLL callback, at least in this example.
There is a simple workaround, though - store the desired method pointer in a global variable, and then use a private callback function to invoke it, eg:
type
TPaymentResultEvent = procedure(AResult: Integer) of object;
var
gOnPaymentResult: TPaymentResultEvent;
procedure myPaymentResultCallback(AResult: Integer); cdecl;
begin
if Assigned(gOnPaymentResult) then
gOnPaymentResult(AResult);
end;
function ARPaymentItemCredit(HInst: THandle; const TerminalNo: PAnsiChar;
const Description: PAnsiChar; Amount: Double; CurrencyID: Integer;
ReceiptID: Integer; onPaymentResult: TPaymentResultEvent): Integer;
type
TPaymentResultCallback = procedure(AResult: Integer); cdecl;
var
MyFunct: function(const TerminalNo: PAnsiChar; const Description: PAnsiChar;
Amount: Double; CurrencyID: Integer; ReceiptID: Integer;
onPaymentResult: TPaymentResultCallback): Integer; cdecl;
begin
@MyFunct := GetProcAddress(HInst, 'AR_payment_item_credit');
if Assigned(MyFunct) then
begin
gOnPaymentResult := onPaymentResult;
Result := MyFunct(TerminalNo, Description, Amount, CurrencyID, ReceiptID, @myPaymentResultCallback)
end
else
Result := 0;
end;
Needless to say, this won't work if you need to have multiple classes calling ARPaymentItemCredit()
at the same time, thus requiring the DLL to call different methods each time.
IF the DLL provides a way to associate a user-defined value with the callback (and your example appears to not have that option, unless there is a separate DLL function for that purpose), things get easier. You can simply pass (a pointer to) the actual method pointer as that user-defined value, and then your private callback function can invoke it directly. No global variable is needed, making it re-entrant for multiple events to run in parallel. But that is a big IF.
Upvotes: 3