When I pass a proc reference as parameter and want to assign it to another proc ref variable (TMyRec.proc), maybe it wants to call the proc and assign the result... the result is a GPF. How can I assign a parameter passed proc ref to another proc ref?
Example: it just plays around the assignment. There is no real tasks assigned as procs.
unit5.pas:
unit Unit5;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm5 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form5: TForm5;
implementation
{$R *.dfm}
type
TMyProc = reference to procedure ( i_ : integer );
PMyRec = ^TMyRec;
TMyRec = packed record
i : integer;
proc : TMyProc;
end;
procedure TForm5.Button1Click(Sender: TObject);
procedure createMyRec( i_ : integer; const proc_ : TMyProc );
var
pMR : PMyRec;
begin
getMem( pMR, sizeOf( TMyRec ) );
try
pMR^.i := i_;
pMR^.proc := proc_; // <--- GPF occures here
finally
FreeMem( pMR );
end;
end;
begin
createMyRec( 1, procedure ( i_ : integer ) begin end );
createMyRec( 2, procedure ( i_ : integer ) begin end );
end;
end.
unit5.dfm:
object Form5: TForm5
Left = 0
Top = 0
Caption = 'Form5'
ClientHeight = 441
ClientWidth = 624
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
TextHeight = 15
object Button1: TButton
Left = 200
Top = 176
Width = 75
Height = 25
Caption = 'Button1'
TabOrder = 0
OnClick = Button1Click
end
end
CodePudding user response:
The compiler shouldn't be trying to call the procedure, since there is no input parameter being passed to it.
I suspect the real problem is your use of GetMem()
, as it doesn't initialize the record's fields to zero. So, you are trying to assign to pMR^.proc
when it contains an indeterminate value that is likely not nil
. And since TMyProc
is a reference-counted interface type under the hood, the compiler tries to Release()
the "old" interface and crashes.
pMR^.proc
needs to be nil
before you assign to it. Try using AllocMem()
instead, as it will zero out the allocated memory. Or better, use New()
instead.
Also, when using either GetMem()
or AllocMem()
, you need to manually finalize the record before you free the memory, so that 'proc''s reference count is decremented correctly to release the anonymous procedure. You don't have to worry about that with New()
as Dispose()
will finalize the record for you.
Try this:
procedure createMyRec( i_ : integer; const proc_ : TMyProc );
var
pMR : PMyRec;
begin
pMR := PMyRec( AllocMem( SizeOf( TMyRec ) ) );
try
pMR^.i := i_;
pMR^.proc := proc_;
finally
Finalize( pMR^ );
FreeMem( pMR );
end;
end;
Or:
procedure createMyRec( i_ : integer; const proc_ : TMyProc );
var
pMR : PMyRec;
begin
New( pMR );
try
pMR^.i := i_;
pMR^.proc := proc_;
finally
Dispose( pMR );
end;
end;