4
votes

I have a big problem because i dont understand how the pointers really work in delphi

First I take a function declaration from a dll.

FUNCTION:

type
  TMICRCallback   = function: Integer; stdcall;

Then I declare a Function in my code.

function CBMICRRead : Integer;stdcall;

The Function its really simple (This is an example)

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

I declare a varible like this

Respuesta : TMICRCallback;

when i try to assign this variable to my function the problem happens :(

Respuesta      := CBMICRRead;

This is my first time using pointers in delphi so maybe its a dumb question but please help me

3

3 Answers

6
votes

TCustomizedTenderPlugin.CBMICRRead is an instance method. Which means that in order to call it you must have an instance on which to invoke it.

On the other hand, TMICRCallback is a function pointer. It is compatible with plain functions rather than instance methods.

They are simply not compatible. In order for TCustomizedTenderPlugin.CBMICRRead to be compatible with TMICRCallback you need to define it as:

TMICRCallback = function: Integer of object; stdcall;

The of object indicates that this type is compatible with instance methods. A variable of type TMICRCallback (as defined in this answer) holds both a function pointer and an instance pointer. It is sometimes referred to as a two pointer function type.

Before you proceed I recommend that you read carefully the documentation.


I note that you are using stdcall calling convention for these function pointers. This usually indicates that you are attempting interop with external modules. That's not something that is reliable with instance methods. What I mean by this is that you cannot implement an of object instance method in a language other than Delphi. If this code is destined for use in an interop setting then you should refrain from using of object.

For an interop setting you would normally include the instance pointer as a separate parameter. In which case the Delphi declaration would look like this:

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

You would then implement such a function like this

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;

Finally, the function in the external module that is passed the callback would need to be passed both PluginCBMICRReadCallback and the instance pointer for the TPlugin instance. Perhaps a little like this:

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

which you would call like this:

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

Having looked at the C++ code at the related question it seems that the C++ side of the interface looks like this:

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

This callback doesn't even admit a data pointer so you cannot use an instance method at all. Quite how you are meant to implement callbacks for multiple instances is beyond me! Anyway, you can declare this function in Delphi like this:

type
  TMICRCallback = function: Integer; stdcall;

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

To call it you'll need this:

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

Clearly CBMICRRead is defined as an object method (namely, a method of TCustomizedTenderPlugin), and so is not a 'stand-alone' function. Because of this, you need to do

type
  TMICRCallback   = function: Integer of object; stdcall;
0
votes

If the declaration of the function in the DLL is not an object method as you wrote, you can solve this either by declaring that function as a global function instead of a method of an object or you can declare it as a static class function of the object.

class function CBMICRRead: Integer; static; stdcall;