I have a button. Its OnClick event calls a procedure which destroys the button, but then the "thread" wants to return to the OnClick event and I get an access violation.
I'm completely stumped!
You need to destroy the button after all its code is finished executing. The standard way to do this is by posting a user-defined message to the form and giving the form a message method that will interpret it. For example:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; const WM_KILLCONTROL = WM_USER + 1; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } procedure KillControl(var message: TMessage); message WM_KILLCONTROL; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject); begin PostMessage(self.Handle, WM_KILLCONTROL, 0, integer(Button1)) end; procedure TForm1.KillControl(var message: TMessage); var control: TControl; begin control := TObject(message.LParam) as TControl; assert(control.Owner = self); control.Free; end; end. This works because the message gets put into the Windows Message Queue and doesn't come out until everything before it (including the Click message that the button is currently responding to) is finished processing.
procedure TForm.Release has been doing since Delphi 1: PostMessage(Handle, CM_RELEASE, 0, 0); it works together with the procedure TForm.CMRelease which does Free, Knowing the difference between PostMessage and SendMessage is important: it is why it works. This question explains PostMessage in more detail: stackoverflow.com/questions/2551435/postmessage-tutorial