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