无法释放调用者组件

Can't Free caller component

我试图在单击某个组件时将其释放。所以,我写了我能想到的最简单的代码来实现这个:一个释放它的发送者的过程。但是在 Delphi 7 上(在 Delphi XE 10 上试过并且没有错误)它有时会随机抛出访问冲突或抽象错误。复制它的最简单方法是插入 30 个按钮,并使用下面的代码分配一个 onclick 过程,然后单击它们。

我已经尝试了下面的两个代码,都在 onclick 上:

procedure FreeMe(Sender: TObject);
begin
    TButton(Sender).Free;
end;

procedure FreeMe(Sender: TObject);
begin
    (Sender as TButton).Free;
end;

您需要将释放延迟到按钮的 OnClick 事件处理程序完全退出之后。重要的是,释放发生在被释放的对象处于空闲状态而不是在处理任何东西的过程中。

一种方法是使用 PostMessage(),例如:

var
  MyReleaseWnd: HWND;

procedure TMyMainForm.FormCreate(Sender: TObject);
begin
  MyReleaseWnd := AllocateHWnd(MyReleaseWndProc);
end;

procedure TMyMainForm.FormDestroy(Sender: TObject);
begin
   DeallocateHWnd(MyReleaseWnd);
end;

procedure TMyMainForm.MyReleaseWndProc(var Message: TMessage);
begin
  if Message.Msg = CM_RELEASE then
    TObject(Msg.LParam).Free
  else
    Message.Result := DefWindowProc(MyReleaseWnd, Message.Msg, Message.WParam, Message.LParam);
end;

procedure DelayFreeMe(Sender: TObject);
begin
  PostMessage(MyReleaseWnd, CM_RELEASE, 0, LPARAM(Sender));
end;

或者,在 10.2 Tokyo 及更高版本中,您可以使用 TThread.ForceQueue() 代替:

procedure DelayFreeMe(Sender: TObject);
begin
  TThread.ForceQueue(nil, Sender.Free);
end;

无论哪种方式,您都可以这样做:

procedure TSomeForm.ButtonClick(Sender: TObject);
begin
  DelayFreeMe(Sender);
end;