Search code examples
delphidelphi-2007

Can I assign the method of an extended record to an event in Delphi?


Given the following record type:

type
  TMyRecord = record
  private
    procedure SomeMethod(_Sender: TObject);
  end;

should it be possible to assign this method as the event handler?

var
  MyRecord: TMyRecord;
begin
  Button1.OnClick := MyRecord.SomeMethod;
end;

In Delphi 2007 I get an internal compiler error C1264 after the assignment.

I am not sure whether the internal structure of a Record's method fulfill the requirements for being assigned to an event pointer.

EDIT: As David Heffernan pointed out, this is a compiler bug in Delhpi 2007. I ended up using the following workaround:

type
  TMyRecord = record
  private
    procedure SomeMethod(_Sender: TObject);
    function GenerateNotifyEvent(_CodePtr: pointer): TNotifyEvent;
  end;

function TMyRecord.GenerateNotifyEvent(_CodePtr: pointer): TNotifyEvent;
var
  Method: TMethod;
begin
  Method.Data := @Self;
  Method.Code := _CodePtr;
  Result := TNotifyEvent(Method);
end;

var
  MyRecord: TMyRecord;
begin
  Button1.OnClick := MyRecord.GenerateNotifyEvent(@TMyRecord.SomeMethod);
end;

Not as nice as a simple assignment, but good enough. I just wish I could simply update to a newer version of Delphi where that bug has been fixed.


Solution

  • Yes, you should be able to do this. You can assign the following type of methods:

    • Instance methods of classes.
    • Class methods of classes.
    • Instance methods of records.
    • Instance methods of objects, that is the deprecated types introduced with the object keyword.

    Since this is an internal compiler error, this would appear to be a compiler bug in Delphi 2007. Certainly your code will compile in later versions of Delphi.

    QC#59807 seems to be very similar to your issue. According to that bug report it was resolved in build 11.0.2902.10471. Then again, perhaps it is this one: QC#60621 which is reported as being resolved in build 12.0.0.15784.

    If you cannot upgrade to a compiler that does not have the fault, then do this:

    var
      Method: TMethod;
    ....
    Method.Code := @TMyRecord.SomeMethod;
    Method.Data := @MyRecord;
    Button1.OnClick := TNotifyEvent(Method);