如何将c / c ++回调函数转换为delphi

时间:2017-12-13 21:29:40

标签: c++ c delphi dll callback

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);

我将以上定义转换为:

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;

我知道C / C ++ dll函数转换为Delphi,但回调对我来说是新的。 我的定义是否正确?

1 个答案:

答案 0 :(得分:3)

您的Delphi翻译中存在一些错误。试试这个:

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;

与您的代码最重要的区别是TPaymentResultCallback未声明为of object。您不能将Delphi样式的方法指针用作C样式的函数指针,这意味着您不能使用非静态类方法进行DLL回调,至少在此示例中。

但是有一个简单的解决方法 - 将所需的方法指针存储在全局变量中,然后使用私有回调函数来调用它,例如:

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;

毋庸置疑,如果您需要同时调用ARPaymentItemCredit()的多个类,这将无效。因此,每次都需要DLL调用不同的方法。

IF DLL提供了一种将用户定义的值与回调相关联的方法(并且您的示例似乎没有该选项,除非为此目的有单独的DLL函数),变得更容易您可以简单地将(指针)实际方法指针作为该用户定义的值传递,然后您的私有回调函数可以直接调用它。不需要全局变量,使其可以重复并行运行多个事件。但这是一个很大的 IF