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