Here's how to call a Message Box with a timeout, the message box closes itself after the timeout period was reached.

The trick is to call an undocumented MessageBoxTimeout API located in user32.dll.

The function returns an integer value of either a MB_TIMEDOUT value (indicating the timeout period was reached and the Message Box auto closed), or a value representing the button the user clicked.

Notice that the return value is always 1, when a message box with only an OK button (MB_OK Flag) is used. //interface declaration
const
MB_TIMEDOUT = 32000;
function MessageBoxTimeOut(hWnd: HWND; lpText: PChar; lpCaption: PChar; uType: UINT; wLanguageId: WORD; dwMilliseconds: DWORD): Integer; stdcall; external user32 name 'MessageBoxTimeoutA';
function MessageBoxTimeOutA(hWnd: HWND; lpText: PChar; lpCaption: PChar; uType: UINT; wLanguageId: WORD; dwMilliseconds: DWORD): Integer; stdcall; external user32 name 'MessageBoxTimeoutA';
function MessageBoxTimeOutW(hWnd: HWND; lpText: PWideChar; lpCaption: PWideChar; uType: UINT; wLanguageId: WORD; dwMilliseconds: DWORD): Integer; stdcall; external user32 name 'MessageBoxTimeoutW';

//implementation (Button1's OnClick event handler on Form1)
procedure TForm1.Button1Click(Sender: TObject);
var
iRet: Integer;
iFlags: Integer;
begin
iFlags := MB_OK or MB_SETFOREGROUND or MB_SYSTEMMODAL or MB_ICONINFORMATION;
MessageBoxTimeout(Application.Handle, ''Test a timeout of 2 seconds. ', 'MessageBoxTimeout Test', iFlags, 0, 2000) ;
iFlags := MB_YESNO or MB_SETFOREGROUND or MB_SYSTEMMODAL or MB_ICONINFORMATION;
iRet := MessageBoxTimeout(Application.Handle, 'Test a timeout of 5 seconds.', 'MessageBoxTimeout Test', iFlags, 0, 5000) ;
case iRet of
IDYES:
ShowMessage('Yes');
IDNO:
ShowMessage('No');
MB_TIMEDOUT:
ShowMessage('TimedOut');
end;
end;