implemented wxApp::OnExceptionInMainLoop()
[wxWidgets.git] / src / msw / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: app.cpp
3 // Purpose: wxApp
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "app.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #if defined(__BORLANDC__)
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #include "wx/app.h"
34 #include "wx/utils.h"
35 #include "wx/gdicmn.h"
36 #include "wx/pen.h"
37 #include "wx/brush.h"
38 #include "wx/cursor.h"
39 #include "wx/icon.h"
40 #include "wx/palette.h"
41 #include "wx/dc.h"
42 #include "wx/dialog.h"
43 #include "wx/msgdlg.h"
44 #include "wx/intl.h"
45 #include "wx/dynarray.h"
46 #include "wx/wxchar.h"
47 #include "wx/icon.h"
48 #include "wx/log.h"
49 #endif
50
51 #include "wx/apptrait.h"
52 #include "wx/filename.h"
53 #include "wx/module.h"
54 #include "wx/dynlib.h"
55
56 #include "wx/msw/private.h"
57
58 #if wxUSE_TOOLTIPS
59 #include "wx/tooltip.h"
60 #endif // wxUSE_TOOLTIPS
61
62 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
63 // compilers don't support it (missing headers, libs, ...)
64 #if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
65 #undef wxUSE_OLE
66
67 #define wxUSE_OLE 0
68 #endif // broken compilers
69
70 #if wxUSE_OLE
71 #include <ole2.h>
72 #endif
73
74 #include <string.h>
75 #include <ctype.h>
76
77 #include "wx/msw/wrapcctl.h"
78
79 // For MB_TASKMODAL
80 #ifdef __WXWINCE__
81 #include "wx/msw/wince/missing.h"
82 #endif
83
84 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
85 !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \
86 (!defined(_MSC_VER) || (_MSC_VER > 1100))
87 #include <shlwapi.h>
88 #endif
89
90 // ---------------------------------------------------------------------------
91 // global variables
92 // ---------------------------------------------------------------------------
93
94 extern wxList WXDLLEXPORT wxPendingDelete;
95
96 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
97 extern void wxSetKeyboardHook(bool doIt);
98 #endif
99
100 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
101 // with NR suffix - wxWindow::MSWCreate() supposes this
102 const wxChar *wxCanvasClassName = wxT("wxWindowClass");
103 const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
104 const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
105 const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
106 const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
107 const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
108
109 HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
110
111 // ----------------------------------------------------------------------------
112 // private functions
113 // ----------------------------------------------------------------------------
114
115 LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
116
117 // ===========================================================================
118 // wxGUIAppTraits implementation
119 // ===========================================================================
120
121 // private class which we use to pass parameters from BeforeChildWaitLoop() to
122 // AfterChildWaitLoop()
123 struct ChildWaitLoopData
124 {
125 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
126 {
127 wd = wd_;
128 winActive = winActive_;
129 }
130
131 wxWindowDisabler *wd;
132 wxWindow *winActive;
133 };
134
135 void *wxGUIAppTraits::BeforeChildWaitLoop()
136 {
137 /*
138 We use a dirty hack here to disable all application windows (which we
139 must do because otherwise the calls to wxYield() could lead to some very
140 unexpected reentrancies in the users code) but to avoid losing
141 focus/activation entirely when the child process terminates which would
142 happen if we simply disabled everything using wxWindowDisabler. Indeed,
143 remember that Windows will never activate a disabled window and when the
144 last childs window is closed and Windows looks for a window to activate
145 all our windows are still disabled. There is no way to enable them in
146 time because we don't know when the childs windows are going to be
147 closed, so the solution we use here is to keep one special tiny frame
148 enabled all the time. Then when the child terminates it will get
149 activated and when we close it below -- after reenabling all the other
150 windows! -- the previously active window becomes activated again and
151 everything is ok.
152 */
153 wxBeginBusyCursor();
154
155 // first disable all existing windows
156 wxWindowDisabler *wd = new wxWindowDisabler;
157
158 // then create an "invisible" frame: it has minimal size, is positioned
159 // (hopefully) outside the screen and doesn't appear on the taskbar
160 wxWindow *winActive = new wxFrame
161 (
162 wxTheApp->GetTopWindow(),
163 wxID_ANY,
164 wxEmptyString,
165 wxPoint(32600, 32600),
166 wxSize(1, 1),
167 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
168 );
169 winActive->Show();
170
171 return new ChildWaitLoopData(wd, winActive);
172 }
173
174 void wxGUIAppTraits::AlwaysYield()
175 {
176 wxYield();
177 }
178
179 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
180 {
181 wxEndBusyCursor();
182
183 const ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
184
185 delete data->wd;
186
187 // finally delete the dummy frame and, as wd has been already destroyed and
188 // the other windows reenabled, the activation is going to return to the
189 // window which had had it before
190 data->winActive->Destroy();
191 }
192
193 bool wxGUIAppTraits::DoMessageFromThreadWait()
194 {
195 // we should return false only if the app should exit, i.e. only if
196 // Dispatch() determines that the main event loop should terminate
197 return !wxTheApp || wxTheApp->Dispatch();
198 }
199
200 wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo()
201 {
202 static wxToolkitInfo info;
203 wxToolkitInfo& baseInfo = wxAppTraits::GetToolkitInfo();
204 info.versionMajor = baseInfo.versionMajor;
205 info.versionMinor = baseInfo.versionMinor;
206 info.os = baseInfo.os;
207 info.shortName = _T("msw");
208 info.name = _T("wxMSW");
209 #ifdef __WXUNIVERSAL__
210 info.shortName << _T("univ");
211 info.name << _T("/wxUniversal");
212 #endif
213 return info;
214 }
215
216 // ===========================================================================
217 // wxApp implementation
218 // ===========================================================================
219
220 int wxApp::m_nCmdShow = SW_SHOWNORMAL;
221
222 // ---------------------------------------------------------------------------
223 // wxWin macros
224 // ---------------------------------------------------------------------------
225
226 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
227
228 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
229 EVT_IDLE(wxApp::OnIdle)
230 EVT_END_SESSION(wxApp::OnEndSession)
231 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
232 END_EVENT_TABLE()
233
234 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
235 // fails
236 class wxCallBaseCleanup
237 {
238 public:
239 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
240 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
241
242 void Dismiss() { m_app = NULL; }
243
244 private:
245 wxApp *m_app;
246 };
247
248 //// Initialize
249 bool wxApp::Initialize(int& argc, wxChar **argv)
250 {
251 if ( !wxAppBase::Initialize(argc, argv) )
252 return false;
253
254 // ensure that base cleanup is done if we return too early
255 wxCallBaseCleanup callBaseCleanup(this);
256
257 // the first thing to do is to check if we're trying to run an Unicode
258 // program under Win9x w/o MSLU emulation layer - if so, abort right now
259 // as it has no chance to work
260 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
261 if ( wxGetOsVersion() != wxWINDOWS_NT && wxGetOsVersion() != wxWINDOWS_CE )
262 {
263 // note that we can use MessageBoxW() as it's implemented even under
264 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
265 // used by wxLocale are not
266 ::MessageBox
267 (
268 NULL,
269 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
270 _T("wxWindows Fatal Error"),
271 MB_ICONERROR | MB_OK
272 );
273
274 return FALSE;
275 }
276 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
277
278 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
279 InitCommonControls();
280 #endif // __WIN95__
281
282 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
283
284 #if wxUSE_OLE
285 // we need to initialize OLE library
286 #ifdef __WXWINCE__
287 if ( FAILED(::CoInitializeEx(NULL, COINIT_MULTITHREADED)) )
288 wxLogError(_("Cannot initialize OLE"));
289 #else
290 if ( FAILED(::OleInitialize(NULL)) )
291 wxLogError(_("Cannot initialize OLE"));
292 #endif
293 #endif
294
295 #endif // wxUSE_OLE
296
297 #if wxUSE_CTL3D
298 if (!Ctl3dRegister(wxhInstance))
299 wxLogError(wxT("Cannot register CTL3D"));
300
301 Ctl3dAutoSubclass(wxhInstance);
302 #endif // wxUSE_CTL3D
303
304 RegisterWindowClasses();
305
306 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
307 // Create the brush for disabling bitmap buttons
308
309 LOGBRUSH lb;
310 lb.lbStyle = BS_PATTERN;
311 lb.lbColor = 0;
312 lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
313 if ( lb.lbHatch )
314 {
315 wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
316 ::DeleteObject( (HGDIOBJ)lb.lbHatch );
317 }
318 //else: wxWindows resources are probably not linked in
319 #endif
320
321 #if wxUSE_PENWINDOWS
322 wxRegisterPenWin();
323 #endif
324
325 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
326
327 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
328 wxSetKeyboardHook(TRUE);
329 #endif
330
331 callBaseCleanup.Dismiss();
332
333 return true;
334 }
335
336 // ---------------------------------------------------------------------------
337 // RegisterWindowClasses
338 // ---------------------------------------------------------------------------
339
340 // TODO we should only register classes really used by the app. For this it
341 // would be enough to just delay the class registration until an attempt
342 // to create a window of this class is made.
343 bool wxApp::RegisterWindowClasses()
344 {
345 WNDCLASS wndclass;
346 wxZeroMemory(wndclass);
347
348 // for each class we register one with CS_(V|H)REDRAW style and one
349 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
350 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
351 static const long styleNoRedraw = CS_DBLCLKS;
352
353 // the fields which are common to all classes
354 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
355 wndclass.hInstance = wxhInstance;
356 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
357
358 // Register the frame window class.
359 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
360 wndclass.lpszClassName = wxCanvasClassName;
361 wndclass.style = styleNormal;
362
363 if ( !RegisterClass(&wndclass) )
364 {
365 wxLogLastError(wxT("RegisterClass(frame)"));
366 }
367
368 // "no redraw" frame
369 wndclass.lpszClassName = wxCanvasClassNameNR;
370 wndclass.style = styleNoRedraw;
371
372 if ( !RegisterClass(&wndclass) )
373 {
374 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
375 }
376
377 // Register the MDI frame window class.
378 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
379 wndclass.lpszClassName = wxMDIFrameClassName;
380 wndclass.style = styleNormal;
381
382 if ( !RegisterClass(&wndclass) )
383 {
384 wxLogLastError(wxT("RegisterClass(MDI parent)"));
385 }
386
387 // "no redraw" MDI frame
388 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
389 wndclass.style = styleNoRedraw;
390
391 if ( !RegisterClass(&wndclass) )
392 {
393 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
394 }
395
396 // Register the MDI child frame window class.
397 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
398 wndclass.lpszClassName = wxMDIChildFrameClassName;
399 wndclass.style = styleNormal;
400
401 if ( !RegisterClass(&wndclass) )
402 {
403 wxLogLastError(wxT("RegisterClass(MDI child)"));
404 }
405
406 // "no redraw" MDI child frame
407 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
408 wndclass.style = styleNoRedraw;
409
410 if ( !RegisterClass(&wndclass) )
411 {
412 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
413 }
414
415 return TRUE;
416 }
417
418 // ---------------------------------------------------------------------------
419 // UnregisterWindowClasses
420 // ---------------------------------------------------------------------------
421
422 bool wxApp::UnregisterWindowClasses()
423 {
424 bool retval = TRUE;
425
426 #ifndef __WXMICROWIN__
427 // MDI frame window class.
428 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
429 {
430 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
431
432 retval = FALSE;
433 }
434
435 // "no redraw" MDI frame
436 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
437 {
438 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
439
440 retval = FALSE;
441 }
442
443 // MDI child frame window class.
444 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
445 {
446 wxLogLastError(wxT("UnregisterClass(MDI child)"));
447
448 retval = FALSE;
449 }
450
451 // "no redraw" MDI child frame
452 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
453 {
454 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
455
456 retval = FALSE;
457 }
458
459 // canvas class name
460 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
461 {
462 wxLogLastError(wxT("UnregisterClass(canvas)"));
463
464 retval = FALSE;
465 }
466
467 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
468 {
469 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
470
471 retval = FALSE;
472 }
473 #endif // __WXMICROWIN__
474
475 return retval;
476 }
477
478 void wxApp::CleanUp()
479 {
480 // all objects pending for deletion must be deleted first, otherwise we
481 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
482 // call wouldn't succeed as long as any windows still exist), so call the
483 // base class method first and only then do our clean up
484 wxAppBase::CleanUp();
485
486 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
487 wxSetKeyboardHook(FALSE);
488 #endif
489
490 #if wxUSE_PENWINDOWS
491 wxCleanUpPenWin();
492 #endif
493
494 if ( wxDisableButtonBrush )
495 ::DeleteObject( wxDisableButtonBrush );
496
497 #if wxUSE_OLE
498 #ifdef __WXWINCE__
499 ::CoUninitialize();
500 #else
501 ::OleUninitialize();
502 #endif
503 #endif
504
505 // for an EXE the classes are unregistered when it terminates but DLL may
506 // be loaded several times (load/unload/load) into the same process in
507 // which case the registration will fail after the first time if we don't
508 // unregister the classes now
509 UnregisterWindowClasses();
510
511 #if wxUSE_CTL3D
512 Ctl3dUnregister(wxhInstance);
513 #endif
514
515 delete wxWinHandleHash;
516 wxWinHandleHash = NULL;
517 }
518
519 // ----------------------------------------------------------------------------
520 // wxApp ctor/dtor
521 // ----------------------------------------------------------------------------
522
523 wxApp::wxApp()
524 {
525 m_printMode = wxPRINT_WINDOWS;
526 }
527
528 wxApp::~wxApp()
529 {
530 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
531 // don't come from main(), so we have to free them
532
533 while ( argc )
534 {
535 // m_argv elements were allocated by wxStrdup()
536 free(argv[--argc]);
537 }
538
539 // but m_argv itself -- using new[]
540 delete [] argv;
541 }
542
543 // ----------------------------------------------------------------------------
544 // wxApp idle handling
545 // ----------------------------------------------------------------------------
546
547 void wxApp::OnIdle(wxIdleEvent& event)
548 {
549 wxAppBase::OnIdle(event);
550
551 #if wxUSE_DC_CACHEING
552 // automated DC cache management: clear the cached DCs and bitmap
553 // if it's likely that the app has finished with them, that is, we
554 // get an idle event and we're not dragging anything.
555 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
556 wxDC::ClearCache();
557 #endif // wxUSE_DC_CACHEING
558 }
559
560 void wxApp::WakeUpIdle()
561 {
562 // Send the top window a dummy message so idle handler processing will
563 // start up again. Doing it this way ensures that the idle handler
564 // wakes up in the right thread (see also wxWakeUpMainThread() which does
565 // the same for the main app thread only)
566 wxWindow *topWindow = wxTheApp->GetTopWindow();
567 if ( topWindow )
568 {
569 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
570 {
571 // should never happen
572 wxLogLastError(wxT("PostMessage(WM_NULL)"));
573 }
574 }
575 }
576
577 // ----------------------------------------------------------------------------
578 // other wxApp event hanlders
579 // ----------------------------------------------------------------------------
580
581 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
582 {
583 if (GetTopWindow())
584 GetTopWindow()->Close(TRUE);
585 }
586
587 // Default behaviour: close the application with prompts. The
588 // user can veto the close, and therefore the end session.
589 void wxApp::OnQueryEndSession(wxCloseEvent& event)
590 {
591 if (GetTopWindow())
592 {
593 if (!GetTopWindow()->Close(!event.CanVeto()))
594 event.Veto(TRUE);
595 }
596 }
597
598 // ----------------------------------------------------------------------------
599 // miscellaneous
600 // ----------------------------------------------------------------------------
601
602 /* static */
603 int wxApp::GetComCtl32Version()
604 {
605 //FIX ME FOR DIGITALMARS!!
606 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__)
607 return 0;
608 #else
609 // cache the result
610 //
611 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
612 // but as its value should be the same both times it doesn't matter
613 static int s_verComCtl32 = -1;
614
615 if ( s_verComCtl32 == -1 )
616 {
617 // initally assume no comctl32.dll at all
618 s_verComCtl32 = 0;
619
620 // we're prepared to handle the errors
621 wxLogNull noLog;
622
623 // do we have it?
624 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
625
626 // if so, then we can check for the version
627 if ( dllComCtl32.IsLoaded() )
628 {
629 #ifdef DLLVER_PLATFORM_WINDOWS
630 // try to use DllGetVersion() if available in _headers_
631 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
632 if ( pfnDllGetVersion )
633 {
634 DLLVERSIONINFO dvi;
635 dvi.cbSize = sizeof(dvi);
636
637 HRESULT hr = (*pfnDllGetVersion)(&dvi);
638 if ( FAILED(hr) )
639 {
640 wxLogApiError(_T("DllGetVersion"), hr);
641 }
642 else
643 {
644 // this is incompatible with _WIN32_IE values, but
645 // compatible with the other values returned by
646 // GetComCtl32Version()
647 s_verComCtl32 = 100*dvi.dwMajorVersion +
648 dvi.dwMinorVersion;
649 }
650 }
651 #endif
652
653 // if DllGetVersion() is unavailable either during compile or
654 // run-time, try to guess the version otherwise
655 if ( !s_verComCtl32 )
656 {
657 // InitCommonControlsEx is unique to 4.70 and later
658 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
659 if ( !pfn )
660 {
661 // not found, must be 4.00
662 s_verComCtl32 = 400;
663 }
664 else // 4.70+
665 {
666 // many symbols appeared in comctl32 4.71, could use any of
667 // them except may be DllInstall()
668 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
669 if ( !pfn )
670 {
671 // not found, must be 4.70
672 s_verComCtl32 = 470;
673 }
674 else
675 {
676 // found, must be 4.71 or later
677 s_verComCtl32 = 471;
678 }
679 }
680 }
681 }
682 }
683
684 return s_verComCtl32;
685 #endif // Microwin/!Microwin
686 }
687
688 // Yield to incoming messages
689
690 bool wxApp::Yield(bool onlyIfNeeded)
691 {
692 // MT-FIXME
693 static bool s_inYield = FALSE;
694
695 #if wxUSE_LOG
696 // disable log flushing from here because a call to wxYield() shouldn't
697 // normally result in message boxes popping up &c
698 wxLog::Suspend();
699 #endif // wxUSE_LOG
700
701 if ( s_inYield )
702 {
703 if ( !onlyIfNeeded )
704 {
705 wxFAIL_MSG( wxT("wxYield called recursively" ) );
706 }
707
708 return FALSE;
709 }
710
711 s_inYield = TRUE;
712
713 // we don't want to process WM_QUIT from here - it should be processed in
714 // the main event loop in order to stop it
715 MSG msg;
716 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
717 msg.message != WM_QUIT )
718 {
719 #if wxUSE_THREADS
720 wxMutexGuiLeaveOrEnter();
721 #endif // wxUSE_THREADS
722
723 if ( !wxTheApp->Dispatch() )
724 break;
725 }
726
727 // if there are pending events, we must process them.
728 ProcessPendingEvents();
729
730 #if wxUSE_LOG
731 // let the logs be flashed again
732 wxLog::Resume();
733 #endif // wxUSE_LOG
734
735 s_inYield = FALSE;
736
737 return TRUE;
738 }
739
740 #if wxUSE_EXCEPTIONS
741
742 // ----------------------------------------------------------------------------
743 // exception handling
744 // ----------------------------------------------------------------------------
745
746 bool wxApp::OnExceptionInMainLoop()
747 {
748 // ask the user about what to do: use the Win32 API function here as it
749 // could be dangerous to use any wxWindows code in this state
750 switch (
751 ::MessageBox
752 (
753 NULL,
754 _T("An unhandled exception occurred. Press \"Abort\" to \
755 terminate the program,\r\n\
756 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
757 _T("Unhandled exception"),
758 MB_ABORTRETRYIGNORE |
759 MB_ICONERROR|
760 MB_TASKMODAL
761 )
762 )
763 {
764 case IDABORT:
765 throw;
766
767 default:
768 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
769 // fall through
770
771 case IDRETRY:
772 return false;
773
774 case IDIGNORE:
775 return true;
776 }
777 }
778
779 #endif // wxUSE_EXCEPTIONS