【问题标题】:"Incompatible types: method pointer and regular procedure"“不兼容的类型:方法指针和常规过程”
【发布时间】:2012-10-09 16:06:09
【问题描述】:

我有一个大问题,因为我不明白指针在 delphi 中是如何工作的

首先,我从 dll 中获取函数声明。

功能:

type
  TMICRCallback   = function: Integer; stdcall;

然后我在我的代码中声明一个函数。

function CBMICRRead : Integer;stdcall;

函数真的很简单(这是一个例子)

function TCustomizedTenderPlugin.CBMICRRead : Integer; stdcall;
var
  SUCCESS:integer;
begin
   SUCCESS:=1;
   Result:= SUCCESS;
end;

我声明一个这样的变量

Respuesta : TMICRCallback;

当我尝试将此变量分配给我的函数时,问题发生了:(

Respuesta      := CBMICRRead;

这是我第一次在 delphi 中使用指针,所以也许这是一个愚蠢的问题,但请帮助我

【问题讨论】:

    标签: delphi function pointers compiler-errors


    【解决方案1】:

    TCustomizedTenderPlugin.CBMICRRead 是一个实例方法。这意味着为了调用它,您必须有一个实例来调用它。

    另一方面,TMICRCallback 是一个函数指针。它兼容普通函数而不是实例方法。

    它们根本不兼容。为了使TCustomizedTenderPlugin.CBMICRReadTMICRCallback 兼容,您需要将其定义为:

    TMICRCallback = function: Integer of object; stdcall;
    

    of object 表示该类型与实例方法兼容。 TMICRCallback 类型的变量(如本答案中所定义)同时包含函数指针和实例指针。它有时被称为双指针函数类型。

    在继续之前,我建议您仔细阅读documentation


    我注意到您正在为这些函数指针使用stdcall 调用约定。这通常表明您正在尝试与外部模块进行互操作。这不是实例方法可靠的东西。我的意思是你不能用 Delphi 以外的语言实现 of object 实例方法。如果此代码注定要在互操作设置中使用,那么您应该避免使用of object

    对于互操作设置,您通常会将实例指针作为单独的参数包含在内。在这种情况下,Delphi 声明将如下所示:

    type
      TMICRCallback = function(Data: Pointer): Integer; stdcall;
    

    然后你会实现这样的功能

    type
      TPlugin = class
        function CBMICRRead: Integer;
      end;
    
    .....
    
    function PluginCBMICRReadCallback(Data: Instance): Integer; stdcall;
    begin
      Result := TPlugin(Data).CBMICRRead;
    end;
    
    function TPlugin.CBMICRRead: Integer;
    begin
      Result := ....
    end;
    

    最后,传递回调的外部模块中的函数需要同时传递PluginCBMICRReadCallbackTPlugin 实例的实例指针。也许有点像这样:

    procedure RegisterCallback(Callback: TMICRCallback; Data: Pointer); stdcall;
    

    你会这样称呼它:

    var
      Plugin: TPlugin;
    ....
    Plugin := ...;//get this instance from somewhere
    RegisterCallback(PluginCBMICRReadCallback, Plugin);
    

    看了related question的C++代码,界面的C++端看起来是这样的:

    int WINAPI BiMICRSetReadBackFunction(int    nHandle, 
                                         int    (CALLBACK *pMicrCB)(void),
                                         LPBYTE pReadBuffSize,   
                                         LPBYTE readCharBuff,    
                                         LPBYTE pStatus,         
                                         LPBYTE pDetail); 
    

    这个回调甚至不承认数据指针,所以你根本不能使用实例方法。你是如何为多个实例实现回调的,这超出了我的理解!无论如何,你可以像这样在 Delphi 中声明这个函数:

    type
      TMICRCallback = function: Integer; stdcall;
    
    function BiMICRSetReadBackFunction(
      nHandle: Integer;
      MicrCB: TMICRCallback;
      pReadBuffSize: PByte;
      readCharBuff: PByte;
      pStatus: PByte;
      pDetail: PByte
    ): Integer; stdcall; external dllname;
    

    要调用它,你需要这个:

    function MICRCallback: Integer; stdcall;//not the method of a class
    begin
      Result := ....
    end;
    .....
    retval := BiMICRSetReadBackFunction(..., MICRCallback, ....);
    

    【讨论】:

    • 当我使用对象时,问题解决了,但也许你写的最后一件事是我们遇到内存问题的原因。
    • 也许吧。我的回答的后半部分有些含糊,可能无法很好地转化为您的实际系统设计。我猜你在做什么。您是否在与外部代码进行互操作?
    • 好的,我已经更新了一些与另一个问题的 C++ 代码相匹配的代码。
    • 我尝试使用此功能读取打印机 ibm4610 的支票。函数打印机接收CBMICREAD函数。
    【解决方案2】:

    显然CBMICRRead 被定义为对象方法(即TCustomizedTenderPlugin 的方法),因此不是“独立”函数。正因为如此,你需要这样做

    type
      TMICRCallback   = function: Integer of object; stdcall;
    

    【讨论】:

    • 然后我们将复制stackoverflow.com/questions/12791258/… 我想。 :)
    • 如果我没看错的话,函数声明是从 DLL 中获取的。
    • @Uwe:好吧,现在我想起来了,调用约定和命名肯定表明了这一点。
    【解决方案3】:

    如果 DLL 中的函数声明不是您编写的对象方法,您可以通过将该函数声明为全局函数而不是对象的方法来解决此问题,或者您可以将其声明为静态类对象的功能。

    class function CBMICRRead: Integer; static; stdcall;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-26
      • 1970-01-01
      • 1970-01-01
      • 2014-03-19
      • 1970-01-01
      相关资源
      最近更新 更多