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

Posted

技术标签:

【中文标题】如何将c/c++回调函数转换为delphi【英文标题】:How to convert c/c++ callback functon to delphi 【发布时间】:2017-12-13 21:29:39 【问题描述】:
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,但回调对我来说是新的。 我的定义正确吗?

【问题讨论】:

哪种语言,C 或 C++?它们是不同的语言。例如,C++ 有运算符和函数重载,这可能会导致名称混乱。 C 函数看起来像 cdecl 【参考方案1】:

您的 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

【讨论】:

那么我更喜欢哪一个,它的用法如何?对不起,我很困惑。非常感谢。 @ErkanK 你喜欢哪一个取决于你。使用适合您情况的任何一种。 我昨天尝试了你的定义,但我仍然无法解决我的问题。首先,我尝试了第二个定义。我总是在开始时在 myPaymentResultCallback 函数中收到“访问冲突”错误。所以它没有解决我的问题。但我喜欢这个定义。:) 第一个定义是总是用调试器说我“需要变量”。那么在这种情况下我的错是什么 对不起。对不起。这是我的错。您的第二个解决方案对我来说是正确的。问题是“cdecl”。在我的示例中,我忘记将它用于 myPaymentResultCallback 函数。再次感谢您

以上是关于如何将c/c++回调函数转换为delphi的主要内容,如果未能解决你的问题,请参考以下文章

是否有可能在Delphi中对一个回调函数进行类型转换?

Delphi回调函数及其使用

请大家解释一下Delphi的回调函数

如何使用 C++ lambda 将成员函数指针转换为普通函数指针以用作回调

C#/C++ 回调作为 NULL 传递

C#/C++ 回调类(非函数)互操作 - 如何?