2

Using Delphi 7 here. When I take the address of a procedure (with the purpose of sending this method address to an external C++ DLL as a callback) the Delphi 7 compiler reports Variable required. Why? How do you take the address of a method with or without a parameter list?

Here's my simplified code which shows the compiler error.

// ...

type
  PTProcedureCallback = ^TProcedureCallback;
  TProcedureCallback = procedure() of object;

  // ...

  TTestCallback = class
    constructor Create();
    procedure MyCallback();
  end;

    //...

implementation
  constructor TTestCallback.Create();
  var
    pCallback: PTProcedureCallback;
  begin
    // Constructor
    inherited;

    // Test callback
    pCallback := @MyCallback;   // <- [Error] Variable required
  end;

  procedure TTestCallback.MyCallback();
  begin
    // Do something
  end;
end;
AlainD
  • 5,413
  • 6
  • 45
  • 99
  • 3
    You can't pass a method pointer (a method of a class) to a C++ DLL, because it has an implicit `Self` reference passed along with it that the C++ DLL doesn't understand. The `procedure of object` indicates that it will have that `Self` reference. (Not the answer to the problem here, but it will save you time in the future trying to figure out why it doesn't work anyway once you figure this out.) – Ken White Jun 26 '19 at 17:34

1 Answers1

3

You don't need PTProcedureCallback at all, as TProcedureCallback is already a pointer type.

constructor TTestCallback.Create();
var
  pCallback: TProcedureCallback;
begin
  // Constructor
  inherited;
  // Test callback
  pCallback := MyCallback;
end;

That being said, you can't use a procedure of object as a C/C++ callback, unless the C/C++ code was written in C++Builder specifically, and is actually expecting a procedure of object via the __closure compiler extension. If not, you will not be able to use a non-static class method as the callback. However, if the callback allows you to pass in a user-defined value, you can use that to pass in your object's Self pointer so your callback can access its non-static members.

Also, your TProcedureCallback is using Delphi's default register calling convention (__fastcall in C++Builder), which does not exist in non-C++Builder compilers. Only cdecl and stdcall are portable calling conventions.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks Remy. I'm busy working through that at the moment. If I just change the code as you suggest, though, I still get the same `Variable required` error. I'm actually trying to answer this question: https://stackoverflow.com/questions/56707554 in which another question has been marked as a duplicate. I can get the C++ DLL calling my method when I specify no parameters, but when I try an integer parameter, the parameter becomes garbled. The C++ DLL is being built in Visual Studio and I've tried both `__cdecl` and `__stdcall` calling conventions. – AlainD Jun 26 '19 at 17:56
  • Then try simply `pCallback := MyCallback;` instead (drop the `@`). – Remy Lebeau Jun 26 '19 at 21:56
  • Looks like my problem was as you stated in the 2nd paragraph: I'm trying to provide a `non-static` class method as a C/C++ callback. When I made the methods static (changing `procedure TTestCallback.MyCallback` to `procedure MyCallback`) it starting working. So much to learn...thanks Remy! – AlainD Jun 27 '19 at 10:00