WinCE build fix.
[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 // if we don't have a running event loop, we shouldn't wait for the
231 // messages as we never remove them from the message queue and so we enter
232 // an infinite loop as MsgWaitForMultipleObjects() keeps returning
233 // WAIT_OBJECT_0 + 1
234 if ( !wxEventLoop::GetActive() )
235 return DoSimpleWaitForThread(hThread);
236
237 const DWORD wakeMask =
238 QS_ALLINPUT // return as soon as there are any events
239 #if !defined(__WXWINCE__)
240 | QS_ALLPOSTMESSAGE
241 #endif
242 ;
243
244 return ::MsgWaitForMultipleObjects
245 (
246 1, // number of objects to wait for
247 (HANDLE *)&hThread, // the objects
248 false, // wait for any objects, not all
249 INFINITE, // no timeout
250 wakeMask
251 );
252 }
253
254 wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const
255 {
256 OSVERSIONINFO info;
257 wxZeroMemory(info);
258
259 // on Windows, the toolkit version is the same of the OS version
260 // as Windows integrates the OS kernel with the GUI toolkit.
261 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
262 if ( ::GetVersionEx(&info) )
263 {
264 if ( majVer )
265 *majVer = info.dwMajorVersion;
266 if ( minVer )
267 *minVer = info.dwMinorVersion;
268 }
269
270 #if defined(__WXHANDHELD__) || defined(__WXWINCE__)
271 return wxPORT_WINCE;
272 #else
273 return wxPORT_MSW;
274 #endif
275 }
276
277 // ===========================================================================
278 // wxApp implementation
279 // ===========================================================================
280
281 int wxApp::m_nCmdShow = SW_SHOWNORMAL;
282
283 // ---------------------------------------------------------------------------
284 // wxWin macros
285 // ---------------------------------------------------------------------------
286
287 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
288
289 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
290 EVT_IDLE(wxApp::OnIdle)
291 EVT_END_SESSION(wxApp::OnEndSession)
292 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
293 END_EVENT_TABLE()
294
295 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
296 // fails
297 class wxCallBaseCleanup
298 {
299 public:
300 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
301 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
302
303 void Dismiss() { m_app = NULL; }
304
305 private:
306 wxApp *m_app;
307 };
308
309 //// Initialize
310 bool wxApp::Initialize(int& argc, wxChar **argv)
311 {
312 if ( !wxAppBase::Initialize(argc, argv) )
313 return false;
314
315 // ensure that base cleanup is done if we return too early
316 wxCallBaseCleanup callBaseCleanup(this);
317
318 #ifdef __WXWINCE__
319 wxString tmp = GetAppName();
320 tmp += wxT("ClassName");
321 wxCanvasClassName = wxStrdup( tmp.c_str() );
322 tmp += wxT("NR");
323 wxCanvasClassNameNR = wxStrdup( tmp.c_str() );
324 HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL );
325 if (hWnd)
326 {
327 SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) );
328 return false;
329 }
330 #endif
331
332 #if !defined(__WXMICROWIN__)
333 InitCommonControls();
334 #endif // !defined(__WXMICROWIN__)
335
336 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
337 SHInitExtraControls();
338 #endif
339
340 #ifndef __WXWINCE__
341 // Don't show a message box if a function such as SHGetFileInfo
342 // fails to find a device.
343 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
344 #endif
345
346 wxOleInitialize();
347
348 RegisterWindowClasses();
349
350 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
351
352 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
353 wxSetKeyboardHook(true);
354 #endif
355
356 callBaseCleanup.Dismiss();
357
358 return true;
359 }
360
361 // ---------------------------------------------------------------------------
362 // RegisterWindowClasses
363 // ---------------------------------------------------------------------------
364
365 // TODO we should only register classes really used by the app. For this it
366 // would be enough to just delay the class registration until an attempt
367 // to create a window of this class is made.
368 bool wxApp::RegisterWindowClasses()
369 {
370 WNDCLASS wndclass;
371 wxZeroMemory(wndclass);
372
373 // for each class we register one with CS_(V|H)REDRAW style and one
374 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
375 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
376 static const long styleNoRedraw = CS_DBLCLKS;
377
378 // the fields which are common to all classes
379 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
380 wndclass.hInstance = wxhInstance;
381 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
382
383 // register the class for all normal windows
384 wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
385 wndclass.lpszClassName = wxCanvasClassName;
386 wndclass.style = styleNormal;
387
388 if ( !RegisterClass(&wndclass) )
389 {
390 wxLogLastError(wxT("RegisterClass(frame)"));
391 }
392
393 // "no redraw" frame
394 wndclass.lpszClassName = wxCanvasClassNameNR;
395 wndclass.style = styleNoRedraw;
396
397 if ( !RegisterClass(&wndclass) )
398 {
399 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
400 }
401
402 // Register the MDI frame window class.
403 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
404 wndclass.lpszClassName = wxMDIFrameClassName;
405 wndclass.style = styleNormal;
406
407 if ( !RegisterClass(&wndclass) )
408 {
409 wxLogLastError(wxT("RegisterClass(MDI parent)"));
410 }
411
412 // "no redraw" MDI frame
413 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
414 wndclass.style = styleNoRedraw;
415
416 if ( !RegisterClass(&wndclass) )
417 {
418 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
419 }
420
421 // Register the MDI child frame window class.
422 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
423 wndclass.lpszClassName = wxMDIChildFrameClassName;
424 wndclass.style = styleNormal;
425
426 if ( !RegisterClass(&wndclass) )
427 {
428 wxLogLastError(wxT("RegisterClass(MDI child)"));
429 }
430
431 // "no redraw" MDI child frame
432 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
433 wndclass.style = styleNoRedraw;
434
435 if ( !RegisterClass(&wndclass) )
436 {
437 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
438 }
439
440 return true;
441 }
442
443 // ---------------------------------------------------------------------------
444 // UnregisterWindowClasses
445 // ---------------------------------------------------------------------------
446
447 bool wxApp::UnregisterWindowClasses()
448 {
449 bool retval = true;
450
451 #ifndef __WXMICROWIN__
452 // MDI frame window class.
453 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
454 {
455 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
456
457 retval = false;
458 }
459
460 // "no redraw" MDI frame
461 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
462 {
463 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
464
465 retval = false;
466 }
467
468 // MDI child frame window class.
469 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
470 {
471 wxLogLastError(wxT("UnregisterClass(MDI child)"));
472
473 retval = false;
474 }
475
476 // "no redraw" MDI child frame
477 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
478 {
479 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
480
481 retval = false;
482 }
483
484 // canvas class name
485 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
486 {
487 wxLogLastError(wxT("UnregisterClass(canvas)"));
488
489 retval = false;
490 }
491
492 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
493 {
494 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
495
496 retval = false;
497 }
498 #endif // __WXMICROWIN__
499
500 return retval;
501 }
502
503 void wxApp::CleanUp()
504 {
505 // all objects pending for deletion must be deleted first, otherwise we
506 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
507 // call wouldn't succeed as long as any windows still exist), so call the
508 // base class method first and only then do our clean up
509 wxAppBase::CleanUp();
510
511 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
512 wxSetKeyboardHook(false);
513 #endif
514
515 wxOleUninitialize();
516
517 // for an EXE the classes are unregistered when it terminates but DLL may
518 // be loaded several times (load/unload/load) into the same process in
519 // which case the registration will fail after the first time if we don't
520 // unregister the classes now
521 UnregisterWindowClasses();
522
523 delete wxWinHandleHash;
524 wxWinHandleHash = NULL;
525
526 #ifdef __WXWINCE__
527 free( wxCanvasClassName );
528 free( wxCanvasClassNameNR );
529 #endif
530 }
531
532 // ----------------------------------------------------------------------------
533 // wxApp ctor/dtor
534 // ----------------------------------------------------------------------------
535
536 wxApp::wxApp()
537 {
538 m_printMode = wxPRINT_WINDOWS;
539 }
540
541 wxApp::~wxApp()
542 {
543 }
544
545 // ----------------------------------------------------------------------------
546 // wxApp idle handling
547 // ----------------------------------------------------------------------------
548
549 void wxApp::OnIdle(wxIdleEvent& event)
550 {
551 wxAppBase::OnIdle(event);
552
553 #if wxUSE_DC_CACHEING
554 // automated DC cache management: clear the cached DCs and bitmap
555 // if it's likely that the app has finished with them, that is, we
556 // get an idle event and we're not dragging anything.
557 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
558 wxDC::ClearCache();
559 #endif // wxUSE_DC_CACHEING
560 }
561
562 void wxApp::WakeUpIdle()
563 {
564 // Send the top window a dummy message so idle handler processing will
565 // start up again. Doing it this way ensures that the idle handler
566 // wakes up in the right thread (see also wxWakeUpMainThread() which does
567 // the same for the main app thread only)
568 wxWindow *topWindow = wxTheApp->GetTopWindow();
569 if ( topWindow )
570 {
571 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
572 {
573 // should never happen
574 wxLogLastError(wxT("PostMessage(WM_NULL)"));
575 }
576 }
577 }
578
579 // ----------------------------------------------------------------------------
580 // other wxApp event hanlders
581 // ----------------------------------------------------------------------------
582
583 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
584 {
585 if (GetTopWindow())
586 GetTopWindow()->Close(true);
587 }
588
589 // Default behaviour: close the application with prompts. The
590 // user can veto the close, and therefore the end session.
591 void wxApp::OnQueryEndSession(wxCloseEvent& event)
592 {
593 if (GetTopWindow())
594 {
595 if (!GetTopWindow()->Close(!event.CanVeto()))
596 event.Veto(true);
597 }
598 }
599
600 // ----------------------------------------------------------------------------
601 // miscellaneous
602 // ----------------------------------------------------------------------------
603
604 /* static */
605 int wxApp::GetComCtl32Version()
606 {
607 #if defined(__WXMICROWIN__) || defined(__WXWINCE__)
608 return 0;
609 #else
610 // cache the result
611 //
612 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
613 // but as its value should be the same both times it doesn't matter
614 static int s_verComCtl32 = -1;
615
616 if ( s_verComCtl32 == -1 )
617 {
618 // initally assume no comctl32.dll at all
619 s_verComCtl32 = 0;
620
621 // we're prepared to handle the errors
622 wxLogNull noLog;
623
624 #if wxUSE_DYNLIB_CLASS
625 // do we have it?
626 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
627
628 // if so, then we can check for the version
629 if ( dllComCtl32.IsLoaded() )
630 {
631 // now check if the function is available during run-time
632 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
633 if ( pfnDllGetVersion )
634 {
635 DLLVERSIONINFO dvi;
636 dvi.cbSize = sizeof(dvi);
637
638 HRESULT hr = (*pfnDllGetVersion)(&dvi);
639 if ( FAILED(hr) )
640 {
641 wxLogApiError(_T("DllGetVersion"), hr);
642 }
643 else
644 {
645 // this is incompatible with _WIN32_IE values, but
646 // compatible with the other values returned by
647 // GetComCtl32Version()
648 s_verComCtl32 = 100*dvi.dwMajorVersion +
649 dvi.dwMinorVersion;
650 }
651 }
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 #endif
683 }
684
685 return s_verComCtl32;
686 #endif // Microwin/!Microwin
687 }
688
689 // Yield to incoming messages
690
691 bool wxApp::Yield(bool onlyIfNeeded)
692 {
693 // MT-FIXME
694 static bool s_inYield = false;
695
696 #if wxUSE_LOG
697 // disable log flushing from here because a call to wxYield() shouldn't
698 // normally result in message boxes popping up &c
699 wxLog::Suspend();
700 #endif // wxUSE_LOG
701
702 if ( s_inYield )
703 {
704 if ( !onlyIfNeeded )
705 {
706 wxFAIL_MSG( wxT("wxYield called recursively" ) );
707 }
708
709 return false;
710 }
711
712 s_inYield = true;
713
714 // we don't want to process WM_QUIT from here - it should be processed in
715 // the main event loop in order to stop it
716 MSG msg;
717 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
718 msg.message != WM_QUIT )
719 {
720 #if wxUSE_THREADS
721 wxMutexGuiLeaveOrEnter();
722 #endif // wxUSE_THREADS
723
724 if ( !wxTheApp->Dispatch() )
725 break;
726 }
727
728 // if there are pending events, we must process them.
729 ProcessPendingEvents();
730
731 #if wxUSE_LOG
732 // let the logs be flashed again
733 wxLog::Resume();
734 #endif // wxUSE_LOG
735
736 s_inYield = false;
737
738 return true;
739 }
740
741 #if wxUSE_EXCEPTIONS
742
743 // ----------------------------------------------------------------------------
744 // exception handling
745 // ----------------------------------------------------------------------------
746
747 bool wxApp::OnExceptionInMainLoop()
748 {
749 // ask the user about what to do: use the Win32 API function here as it
750 // could be dangerous to use any wxWidgets code in this state
751 switch (
752 ::MessageBox
753 (
754 NULL,
755 _T("An unhandled exception occurred. Press \"Abort\" to \
756 terminate the program,\r\n\
757 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
758 _T("Unhandled exception"),
759 MB_ABORTRETRYIGNORE |
760 MB_ICONERROR|
761 MB_TASKMODAL
762 )
763 )
764 {
765 case IDABORT:
766 throw;
767
768 default:
769 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
770 // fall through
771
772 case IDRETRY:
773 return false;
774
775 case IDIGNORE:
776 return true;
777 }
778 }
779
780 #endif // wxUSE_EXCEPTIONS
781
782 // ----------------------------------------------------------------------------
783 // deprecated event loop functions
784 // ----------------------------------------------------------------------------
785
786 #if WXWIN_COMPATIBILITY_2_4
787
788 void wxApp::DoMessage(WXMSG *pMsg)
789 {
790 wxEventLoop *evtLoop = wxEventLoop::GetActive();
791 if ( evtLoop )
792 evtLoop->ProcessMessage(pMsg);
793 }
794
795 bool wxApp::DoMessage()
796 {
797 wxEventLoop *evtLoop = wxEventLoop::GetActive();
798 return evtLoop ? evtLoop->Dispatch() : false;
799 }
800
801 bool wxApp::ProcessMessage(WXMSG* pMsg)
802 {
803 wxEventLoop *evtLoop = wxEventLoop::GetActive();
804 return evtLoop && evtLoop->PreProcessMessage(pMsg);
805 }
806
807 #endif // WXWIN_COMPATIBILITY_2_4