Search code examples
delphivcltthread

Why does a MessageBox not block the Application on a synchronized thread?


As far as I understand and know the method of the TThread Class, if you synchronize your code, it actually get's executed in the main Application Thread (just like a timer/buttonclick/etc.) I've been playing around and noticed that a MessageBox DOES NOT block the main application, however sleep does just as expected. Why is that?

type
  TTestThread = class(TThread)
  private
    procedure SynchThread;
  protected
    procedure Execute; override;
  public
    constructor Create(CreateSuspended: Boolean);
  end;

procedure TTestThread.SynchThread;
begin
 MessageBoxA (0, 'Hello', 'Test', 0);
end;

procedure TTestThread.Execute;
begin
 Synchronize (SynchThread)
end;

constructor TTestThread.Create(CreateSuspended: Boolean);
begin
  inherited;
  FreeOnTerminate := True;
end;

procedure StartThread;
var
 TestThread : TTestThread;
begin
 TestThread := TTestThread.Create (FALSE);
end;

Solution

  • There are two parts to this answer.

    Part 1 is nicely explained in If MessageBox()/related are synchronous, why doesn't my message loop freeze?. The MessageBox function is not blocking, it merely creates a dialog box with its own message loop.

    Part 2 is explained in the MessageBox documentation.

    hWnd: A handle to the owner window of the message box to be created. If this parameter is NULL, the message box has no owner window.

    When you display a modal dialog, Windows disables its owner, but if you pass 0 for the first parameter, there is no owner and nothing to disable. Therefore, your program will continue to process messages (and react to them) while the message box is displayed.

    To change this behaviour, pass form's handle as a first parameter. For example:

    procedure TTestThread.SynchThread;
    begin
      MessageBoxA (Form1.Handle, 'Hello', 'Test', 0);
    end;