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