Andrei
Andrei

Reputation: 8924

timed MessageBox in console application

I use MessageBox function in Win32 console application.
Application does not not use MFC, not even event loop.
I need to make a wrapper, MessageBoxTimed(), that exits
(and dialog box disappears) after N seconds, if user did not press any button.

Is there more or less simple way to do this ?

Upvotes: 0

Views: 1230

Answers (4)

Remy Lebeau
Remy Lebeau

Reputation: 598194

There is an undocumented MessageBoxTimeout() API in user32.dll that has existed since like XP. MessageBox() uses this API internally with an infinite timeout.

int MessageBoxA(
  [in, optional] HWND   hWnd,
  [in, optional] LPCSTR lpText,
  [in, optional] LPCSTR lpCaption,
  [in]           UINT   uType
  [in]           WORD wLanguageId,
  [in]           DWORD dwMilliseconds
);

int MessageBoxW(
  [in, optional] HWND   hWnd,
  [in, optional] LPCWSTR lpText,
  [in, optional] LPCWSTR lpCaption,
  [in]           UINT   uType
  [in]           WORD wLanguageId,
  [in]           DWORD dwMilliseconds
);

Upvotes: 0

David Heffernan
David Heffernan

Reputation: 613531

Don't do this. Modal dialogs should be closed by user intervention. Deviating from this pattern is just confusing and non-standard. If you want a message windows that closes itself, then use a balloon window.

Upvotes: 1

Jerry Coffin
Jerry Coffin

Reputation: 490673

If you need to dismiss it automatically, I'd avoid using MessageBox at all. Instead, I'd just put together a dialog that closes itself after the specified period of time. If memory serves, you can do this pretty easily by setting a time when you display the pseudo-message box dialog. When the time goes off or the user clicks "ok" (or "close", etc.) you close the window and cancel the timer.

Upvotes: 0

Chad
Chad

Reputation: 19052

This will not be trivial. Since the MessageBox() function itself is modal, you will likely need to start another thread that waits for the predefined number of seconds, and is interrupt-able if the message box is dismissed manually.

If the timer expires, use the FindWindow() API to find the handle of the message box and then simulate a click of the OK button, or perhaps more appropriately a keypress of the ESC button.

EDIT: Actually, not too bad. This isn't fully tested, may need some additional cleanup, but is enough to get you started.

  #include <Windows.h>

  class TimedMB
  {
  public:
     TimedMB() : timeout_(0), caption_(0)
     {
        interrupt_ = CreateEvent(NULL, FALSE, FALSE, NULL);
     }

     ~TimedMB()
     {
        CloseHandle(interrupt_);
     }

     static DWORD WINAPI timer(LPVOID param)
     {
        TimedMB* mb = reinterpret_cast<TimedMB*>(param);

        if(WAIT_TIMEOUT == WaitForSingleObject(mb->interrupt_, mb->timeout_))
        {
           HWND message_box = FindWindow(NULL, mb->caption_);

           if(::IsWindow(message_box))
           {
              PostMessage(message_box, WM_COMMAND, IDCANCEL, 0);
           }
        }

        return 0;
     }

     void DisplayMessageBox(const char* msg, const char* caption, DWORD timeout)
     {
        timeout_ = timeout;
        caption_ = caption;

        CreateThread(NULL, 0, &TimedMB::timer, this, 0, NULL);
        ::MessageBox(NULL, msg, caption, MB_OKCANCEL);
        ::SetEvent(interrupt_);
     }

  private:
     HANDLE      interrupt_;
     DWORD       timeout_;
     const char* caption_;
  };

  int main()
  {
     TimedMB mb;
     mb.DisplayMessageBox("Hello There!", "My Message Box", 5000);
  }

Upvotes: 2

Related Questions