ErkanK
ErkanK

Reputation: 95

How to convert c/c++ callback functon to delphi

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

Answers (1)

Remy Lebeau
Remy Lebeau

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

Related Questions