Can't Free caller component

时间:2019-05-31 11:25:09

标签: delphi delphi-7

I'm trying to free a component when i click it. So, i've written the simplest code i could imagine to achieve this: a procedure that frees it's sender. But on Delphi 7 (Tried on Delphi XE 10 and it worked with no errors) it sometimes throws an Access Violation or Abstract Error randomly. The easiest way to replicate this is to insert like 30 Buttons and assign an onclick procedure with the code below, then click them.

I've tried the two codes below, both on onclick:

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

or

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

1 个答案:

答案 0 :(得分:0)

您需要延迟释放,直到按钮的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及更高版本中,您可以改为使用TThread.ForceQueue()

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

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

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