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