1
votes

Here is my simple code which compiles well, but raise Access Violation. It enters MD procedure and debugger displays some X and Y value, but after exiting procedure AV happens. Hope someone can help.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Controls, Forms,  ExtCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

    {$R *.dfm}

procedure MD(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  form1.caption:= inttostr(x)+ ' '+ inttostr(y);
end;

procedure TForm1.FormCreate(Sender: TObject);

function MakeMethod(data, code: pointer): TMethod;
begin
  result.Data:= data;
  result.Code:= code;
end;

begin
  panel1.OnMouseDown:= TMouseEvent(MakeMethod(nil, @MD));
end;

end.

Thanks

2
Are you surprised by the AV? - You passing Nil to MakeMethod. - MartynA
Same happens if I put pointer to some array of bytes. - Djole
@MartynA, your comments are completely misleading, MD never references data pointer, the actual reason of failure is parameter mismatch. - Free Consulting
If you don't want to make MD a method of TForm1 you could try the technique I described here: stackoverflow.com/questions/11083336/…. - Uli Gerhardt
@Uli Gerhardt - Yes, I was aware of that solution and it works OK. However solution with class procedures raises compile problems with Lazarus (it is my prime interest) which I didn't understand. However this should be for some other thread. - Djole

2 Answers

5
votes

MD signature should include additional hidden parameter; it solves AV issue.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;


type
  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure MD(Instance, Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  form1.caption:= inttostr(x)+ ' '+ inttostr(y);
end;

procedure TForm1.FormCreate(Sender: TObject);

function MakeMethod(data, code: pointer): TMethod;
begin
  result.Data:= data;
  result.Code:= code;
end;

begin
  panel1.OnMouseDown:= TMouseEvent(MakeMethod(nil, @MD));
end;

end.
1
votes

Try making MD a member of your form class. Edit your example the following way: In the class definition:

type
TForm1 = class(TForm)
  Panel1: TPanel;
  procedure FormCreate(Sender: TObject);
  procedure MD(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
end;

Later in your code make sure to enter the owner of the MD method like so:

procedure TForm1.MD(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

Finally, when assigning this eventhandler to your component, all you have to do is:

panel1.OnMouseDown:= MD;

I don't know what your intention was, but that is how you take care of eventhandlers at run time.