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