不兼容的类型:方法指针和常规过程

4

我很困扰因为我不太明白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中使用指针,所以可能是一个愚蠢的问题,但请帮助我。

3个回答

6

TCustomizedTenderPlugin.CBMICRRead是一个实例方法。这意味着在调用它之前必须有一个实例。

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

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

TMICRCallback = function: Integer of object; stdcall;
of object 表示此类型与实例方法兼容。 类型为 TMICRCallback(在本答案中定义)的变量包含函数指针和实例指针。有时也称为双指针函数类型。
在继续之前,建议您仔细阅读文档
我注意到您正在为这些函数指针使用 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);

经过查看相关问题中的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, ....);

当我使用对象时,问题得到了解决,但也许你最后写的那个东西是我们内存问题的根源。 - Rafael Miguel Caceres Choto
也许吧。我的答案后半部分有点含糊不清,可能无法很好地适应你的实际系统设计。我猜你在做什么。你是在与外部代码进行互操作吗? - David Heffernan
好的,我已经更新了一些代码,与其他问题中的C++代码相匹配。 - David Heffernan
我尝试使用该函数来读取IBM4610打印机的支票。该函数接收CBMICREAD函数。 - Rafael Miguel Caceres Choto

0

显然,CBMICRRead被定义为一个对象方法(即TCustomizedTenderPlugin的一个方法),因此不是一个“独立”的函数。因此,您需要执行以下操作:

type
  TMICRCallback   = function: Integer of object; stdcall;

1
那么我想我们会有一个 https://dev59.com/pmnWa4cB1Zd3GeqPzlpb 的副本。 :) - Sertac Akyuz
如果我没看错的话,函数声明是从一个DLL中获取的。 - Uwe Raabe
@Uwe:嗯,现在我想起来了,调用约定和命名肯定表明了这一点。 - Andreas Rejbrand

0
如果DLL中的函数声明不是像您写的对象方法,您可以通过将该函数声明为全局函数而不是对象的方法,或者将其声明为对象的静态类函数来解决此问题。
class function CBMICRRead: Integer; static; stdcall;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接