I noticed that you have the constructor of TMyThread start the thread immediately:
My guess is that if you end the program before the 3 second sleep is over, then OnTerminate will be unassigned and never called, so Killed will never become True.
So, since you are assigning an event handler for the OnTerminate event you should create the thread in a suspended state, assign the handler and then start the thread yourself:
procedure TForm1.FormCreate(Sender: TObject);
begin
Killed := false;
t := TMyThread.Create;
t.OnTerminate:=@tTerminate;
t.Start;
end;
EDIT: Benny was faster. :-)
EDIT2: Why did the app hang? Was it because t.Terminate was called but not assigned? If the thread is finished, WaitFor returns at once. You could make a test:
procedure TForm1.FormDestroy(Sender: TObject);
begin
if not Killed then begin
if assigned(t.OnTerminate) then
t.Terminate
else
Application.MessageBox('Gee, I was not assigned!','');
t.WaitFor;
Application.MessageBox('I was alive. Bye ...','');
end;