Results 1 to 5 of 5

Thread: Passing method pointers to a function

  1. #1

    Passing method pointers to a function

    Good evening

    I have a small problem. Basically, I want to pass the method pointer for the function PaintProc into the Register... function. But Delphi won't let me. Here is my code:
    [pascal]type
    TMessageHandler = function(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT of object;

    TThing = class(TObject)
    protected
    function PaintProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;

    function RegisterMessageHandler(Msg: UINT; Handler: TMessageHandler): TMessageHandler;
    public
    constructor Create;
    end;

    ...

    constructor TThing.Create;
    begin
    RegisterMessageHandler(WM_PAINT, PaintProc); // this doesn't work
    RegisterMessageHandler(WM_PAINT, @PaintProc); // or this...
    end;[/pascal]
    [size=10px][ Join us in #pgd on irc.freenode.net ] [ Sign the Petition for a Software Patent Free Europe ][/size]

  2. #2

    Passing method pointers to a function

    The following works fine for me in Delphi 7:

    [pascal]unit Unit1;

    interface

    uses
    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls;

    type
    TMessageHandler = function(hWnd: HWND; Msg: UINT; wParam:
    WPARAM; lParam: LPARAM): LRESULT of object;

    TInfo = record
    Msg : UINT;
    CallMe: TMessageHandler;
    end;
    PInfo = ^TInfo;

    //------------------------------------------------------------------------------

    TThing = class(TObject)
    private
    FInfo: TList;
    protected
    function PaintProc(hWnd: HWND; Msg: UINT;
    wParam: WPARAM; lParam: LPARAM): LRESULT;
    function RegisterMessageHandler(Msg: UINT;
    Handler: TMessageHandler): TMessageHandler;

    procedure ClearInfo;

    procedure HandleSomeMessage(Msg: UINT);
    public
    constructor Create;
    destructor Destroy; override;
    end;

    //----------------------------------------------------------------------------

    TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    private
    FObject: TThing;
    public
    end;

    var
    Form1: TForm1;

    implementation

    {$R *.dfm}

    //------------------------------------------------------------------------------

    function TThing.PaintProc(hWnd: HWND; Msg: UINT;
    wParam: WPARAM; lParam: LPARAM): LRESULT;
    begin
    ShowMessage('In here');
    Result := 0;
    end;

    //------------------------------------------------------------------------------

    function TThing.RegisterMessageHandler(Msg: UINT; Handler: TMessageHandler):
    TMessageHandler;
    var
    NewInfo: PInfo;
    begin
    New(NewInfo);
    NewInfo.Msg := Msg;
    NewInfo.CallMe := Handler;
    FInfo.Add(NewInfo);

    Result := Handler;
    end;

    //------------------------------------------------------------------------------

    constructor TThing.Create;
    begin
    FInfo := TList.Create;
    RegisterMessageHandler(WM_PAINT, PaintProc);
    end;

    //------------------------------------------------------------------------------

    destructor TThing.Destroy;
    begin
    ClearInfo;
    FInfo.Free;
    end;

    //------------------------------------------------------------------------------

    procedure TThing.ClearInfo;
    var
    i: Integer;
    begin
    for i := 0 to FInfo.Count - 1 do
    Dispose(FInfo[i]);

    FInfo.Clear;
    end;

    //------------------------------------------------------------------------------

    procedure TThing.HandleSomeMessage(Msg: UINT);
    var
    i: Integer;
    ThisOne: PInfo;
    begin
    for i := 0 to FInfo.Count - 1 do
    begin
    ThisOne := FInfo[i];

    if ThisOne.Msg = Msg then
    begin
    if Assigned(ThisOne.CallMe) then
    ThisOne.CallMe(Application.Handle, ThisOne.Msg, 0, 0);
    end;
    end;
    end;

    //------------------------------------------------------------------------------

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    FObject := TThing.Create;
    end;

    //------------------------------------------------------------------------------

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
    FObject.Free;
    end;

    //------------------------------------------------------------------------------

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    FObject.HandleSomeMessage(WM_PAINT);
    end;

    //------------------------------------------------------------------------------

    end.[/pascal]
    "All paid jobs absorb and degrade the mind."
    <br />-- Aristotle

  3. #3

    Passing method pointers to a function

    Oh, and something for you to be careful of: pointers/functions "of object" are 8 bytes, not 4, so they can't be stored in a Pointer (not enough room!). Officially, they're of type "TMethod", having a Code and a Data pointer. The Code pointer points to the function and the Data pointer to the actual object instance IIRC. This is the reason I used the TInfo record rather than storing pointers directly -- the pointer to TInfo is 4 bytes as usual.
    "All paid jobs absorb and degrade the mind."
    <br />-- Aristotle

  4. #4

    Re: Passing method pointers to a function

    EDIT: BTW Alimonster, where did you get the rest of my code? :shock:

    Well, I've got it working now.

    In my actual code I was doing:
    [pascal]
    constructor TThing.Create;
    begin
    Self.RegisterMessageHandler(WM_PAINT, PaintProc); // this doesn't work
    end;[/pascal]
    Which gives a "Not enough actual parameters" error.

    But doing this works:
    [pascal]
    constructor TThing.Create;
    begin
    RegisterMessageHandler(WM_PAINT, PaintProc); // this does work
    end;[/pascal]

    I would have thought these would be exactly the same. :?
    [size=10px][ Join us in #pgd on irc.freenode.net ] [ Sign the Petition for a Software Patent Free Europe ][/size]

  5. #5

    Re: Passing method pointers to a function

    Quote Originally Posted by Useless Hacker
    EDIT: BTW Alimonster, where did you get the rest of my code? :shock:
    I have sinister, psychic powers... or I just wrote the most obvious test cradle for the given task, and it happens to look like yours. But I like the sinister psychic powers explanation.

    I would have thought these would be exactly the same. :?
    So would I, to be honest. Perhaps there's a subtle distinction that I can't think of yet. I've reproduced this behaviour ("self." being different) for this example with Delphi 5 Enterprise at work. I'll try Delphi 7 when I get home, if I remember.
    "All paid jobs absorb and degrade the mind."
    <br />-- Aristotle

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •