Как назначить ссылку на процедуру (переданную как параметр) в поле записи в Delphi?

Когда я передаю ссылку на процедуру в качестве 9X_delphi параметра и хочу присвоить ее другой переменной 9X_delphi ссылки на процедуру (TMyRec.proc), может 9X_object-pascal быть, она хочет вызвать процедуру и присвоить 9X_delphi результат... результатом будет GPF. Как 9X_delphi я могу назначить параметр, переданный proc 9X_delphi ref, другому proc ref?

Пример: он просто 9X_delphi играет с заданием. Нет никаких реальных 9X_delphi задач, назначенных как 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

2
0
1
Общее количество ответов: 1

Ответ #1

Ответ на вопрос: Как назначить ссылку на процедуру (переданную как параметр) в поле записи в Delphi?

Компилятор не должен пытаться вызывать процедуру, поскольку 9X_object-pascal ей не передается входной параметр.

Я подозреваю, что 9X_delphi реальная проблема заключается в том, что вы используете 9X_object-pascal GetMem(), поскольку она не инициализирует поля записи 9X_delphi нулями. Итак, вы пытаетесь присвоить pMR^.proc, когда 9X_delphi оно содержит неопределенное значение, которое, скорее 9X_delphi всего, не nil. А так как TMyProc под капотом является 9X_delphi типом интерфейса с подсчетом ссылок, компилятор 9X_object-pascal пытается Release() "старый" интерфейс и 9X_object-pascal падает.

pMR^.proc должно быть nil, прежде чем вы его 9X_delphi назначите. Попробуйте вместо этого использовать 9X_object-pascal AllocMem(), так как это приведет к обнулению выделенной 9X_object-pascal памяти. Или лучше используйте вместо этого 9X_delphi New().

Кроме того, при использовании GetMem() или AllocMem() вам 9X_object-pascal необходимо вручную завершить запись перед 9X_object-pascal освобождением памяти, чтобы счетчик ссылок 9X_delphi 'proc' правильно уменьшался для освобождения 9X_delphi анонимной процедуры. Вам не нужно беспокоиться 9X_delphi об этом с New(), так как Dispose() завершит запись для 9X_delphi вас.

Попробуйте это:

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;

Или:

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;

11
0