Code for single instance and bring-to-top under CE.
[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("wxWindows 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
328 LOGBRUSH lb;
329 lb.lbStyle = BS_PATTERN;
330 lb.lbColor = 0;
331 lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
332 if ( lb.lbHatch )
333 {
334 wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
335 ::DeleteObject( (HGDIOBJ)lb.lbHatch );
336 }
337 //else: wxWindows resources are probably not linked in
338 #endif
339
340 #if wxUSE_PENWINDOWS
341 wxRegisterPenWin();
342 #endif
343
344 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
345
346 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
347 wxSetKeyboardHook(TRUE);
348 #endif
349
350 callBaseCleanup.Dismiss();
351
352 return true;
353 }
354
355 // ---------------------------------------------------------------------------
356 // RegisterWindowClasses
357 // ---------------------------------------------------------------------------
358
359 // TODO we should only register classes really used by the app. For this it
360 // would be enough to just delay the class registration until an attempt
361 // to create a window of this class is made.
362 bool wxApp::RegisterWindowClasses()
363 {
364 WNDCLASS wndclass;
365 wxZeroMemory(wndclass);
366
367 // for each class we register one with CS_(V|H)REDRAW style and one
368 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
369 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
370 static const long styleNoRedraw = CS_DBLCLKS;
371
372 // the fields which are common to all classes
373 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
374 wndclass.hInstance = wxhInstance;
375 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
376
377 // Register the frame window class.
378 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
379 wndclass.lpszClassName = wxCanvasClassName;
380 wndclass.style = styleNormal;
381
382 if ( !RegisterClass(&wndclass) )
383 {
384 wxLogLastError(wxT("RegisterClass(frame)"));
385 }
386
387 // "no redraw" frame
388 wndclass.lpszClassName = wxCanvasClassNameNR;
389 wndclass.style = styleNoRedraw;
390
391 if ( !RegisterClass(&wndclass) )
392 {
393 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
394 }
395
396 // Register the MDI frame window class.
397 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
398 wndclass.lpszClassName = wxMDIFrameClassName;
399 wndclass.style = styleNormal;
400
401 if ( !RegisterClass(&wndclass) )
402 {
403 wxLogLastError(wxT("RegisterClass(MDI parent)"));
404 }
405
406 // "no redraw" MDI frame
407 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
408 wndclass.style = styleNoRedraw;
409
410 if ( !RegisterClass(&wndclass) )
411 {
412 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
413 }
414
415 // Register the MDI child frame window class.
416 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
417 wndclass.lpszClassName = wxMDIChildFrameClassName;
418 wndclass.style = styleNormal;
419
420 if ( !RegisterClass(&wndclass) )
421 {
422 wxLogLastError(wxT("RegisterClass(MDI child)"));
423 }
424
425 // "no redraw" MDI child frame
426 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
427 wndclass.style = styleNoRedraw;
428
429 if ( !RegisterClass(&wndclass) )
430 {
431 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
432 }
433
434 return TRUE;
435 }
436
437 // ---------------------------------------------------------------------------
438 // UnregisterWindowClasses
439 // ---------------------------------------------------------------------------
440
441 bool wxApp::UnregisterWindowClasses()
442 {
443 bool retval = TRUE;
444
445 #ifndef __WXMICROWIN__
446 // MDI frame window class.
447 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
448 {
449 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
450
451 retval = FALSE;
452 }
453
454 // "no redraw" MDI frame
455 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
456 {
457 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
458
459 retval = FALSE;
460 }
461
462 // MDI child frame window class.
463 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
464 {
465 wxLogLastError(wxT("UnregisterClass(MDI child)"));
466
467 retval = FALSE;
468 }
469
470 // "no redraw" MDI child frame
471 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
472 {
473 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
474
475 retval = FALSE;
476 }
477
478 // canvas class name
479 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
480 {
481 wxLogLastError(wxT("UnregisterClass(canvas)"));
482
483 retval = FALSE;
484 }
485
486 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
487 {
488 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
489
490 retval = FALSE;
491 }
492 #endif // __WXMICROWIN__
493
494 return retval;
495 }
496
497 void wxApp::CleanUp()
498 {
499 // all objects pending for deletion must be deleted first, otherwise we
500 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
501 // call wouldn't succeed as long as any windows still exist), so call the
502 // base class method first and only then do our clean up
503 wxAppBase::CleanUp();
504
505 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
506 wxSetKeyboardHook(FALSE);
507 #endif
508
509 #if wxUSE_PENWINDOWS
510 wxCleanUpPenWin();
511 #endif
512
513 if ( wxDisableButtonBrush )
514 ::DeleteObject( wxDisableButtonBrush );
515
516 #if wxUSE_OLE
517 #ifdef __WXWINCE__
518 ::CoUninitialize();
519 #else
520 ::OleUninitialize();
521 #endif
522 #endif
523
524 // for an EXE the classes are unregistered when it terminates but DLL may
525 // be loaded several times (load/unload/load) into the same process in
526 // which case the registration will fail after the first time if we don't
527 // unregister the classes now
528 UnregisterWindowClasses();
529
530 #if wxUSE_CTL3D
531 Ctl3dUnregister(wxhInstance);
532 #endif
533
534 delete wxWinHandleHash;
535 wxWinHandleHash = NULL;
536
537 #ifdef __WXWINCE__
538 free( wxCanvasClassName );
539 free( wxCanvasClassNameNR );
540 #endif
541 }
542
543 // ----------------------------------------------------------------------------
544 // wxApp ctor/dtor
545 // ----------------------------------------------------------------------------
546
547 wxApp::wxApp()
548 {
549 m_printMode = wxPRINT_WINDOWS;
550 }
551
552 wxApp::~wxApp()
553 {
554 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
555 // don't come from main(), so we have to free them
556
557 while ( argc )
558 {
559 // m_argv elements were allocated by wxStrdup()
560 free(argv[--argc]);
561 }
562
563 // but m_argv itself -- using new[]
564 delete [] argv;
565 }
566
567 // ----------------------------------------------------------------------------
568 // wxApp idle handling
569 // ----------------------------------------------------------------------------
570
571 void wxApp::OnIdle(wxIdleEvent& event)
572 {
573 wxAppBase::OnIdle(event);
574
575 #if wxUSE_DC_CACHEING
576 // automated DC cache management: clear the cached DCs and bitmap
577 // if it's likely that the app has finished with them, that is, we
578 // get an idle event and we're not dragging anything.
579 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
580 wxDC::ClearCache();
581 #endif // wxUSE_DC_CACHEING
582 }
583
584 void wxApp::WakeUpIdle()
585 {
586 // Send the top window a dummy message so idle handler processing will
587 // start up again. Doing it this way ensures that the idle handler
588 // wakes up in the right thread (see also wxWakeUpMainThread() which does
589 // the same for the main app thread only)
590 wxWindow *topWindow = wxTheApp->GetTopWindow();
591 if ( topWindow )
592 {
593 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
594 {
595 // should never happen
596 wxLogLastError(wxT("PostMessage(WM_NULL)"));
597 }
598 }
599 }
600
601 // ----------------------------------------------------------------------------
602 // other wxApp event hanlders
603 // ----------------------------------------------------------------------------
604
605 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
606 {
607 if (GetTopWindow())
608 GetTopWindow()->Close(TRUE);
609 }
610
611 // Default behaviour: close the application with prompts. The
612 // user can veto the close, and therefore the end session.
613 void wxApp::OnQueryEndSession(wxCloseEvent& event)
614 {
615 if (GetTopWindow())
616 {
617 if (!GetTopWindow()->Close(!event.CanVeto()))
618 event.Veto(TRUE);
619 }
620 }
621
622 // ----------------------------------------------------------------------------
623 // miscellaneous
624 // ----------------------------------------------------------------------------
625
626 /* static */
627 int wxApp::GetComCtl32Version()
628 {
629 //FIX ME FOR DIGITALMARS!!
630 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__)
631 return 0;
632 #else
633 // cache the result
634 //
635 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
636 // but as its value should be the same both times it doesn't matter
637 static int s_verComCtl32 = -1;
638
639 if ( s_verComCtl32 == -1 )
640 {
641 // initally assume no comctl32.dll at all
642 s_verComCtl32 = 0;
643
644 // we're prepared to handle the errors
645 wxLogNull noLog;
646
647 // do we have it?
648 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
649
650 // if so, then we can check for the version
651 if ( dllComCtl32.IsLoaded() )
652 {
653 #ifdef DLLVER_PLATFORM_WINDOWS
654 // try to use DllGetVersion() if available in _headers_
655 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
656 if ( pfnDllGetVersion )
657 {
658 DLLVERSIONINFO dvi;
659 dvi.cbSize = sizeof(dvi);
660
661 HRESULT hr = (*pfnDllGetVersion)(&dvi);
662 if ( FAILED(hr) )
663 {
664 wxLogApiError(_T("DllGetVersion"), hr);
665 }
666 else
667 {
668 // this is incompatible with _WIN32_IE values, but
669 // compatible with the other values returned by
670 // GetComCtl32Version()
671 s_verComCtl32 = 100*dvi.dwMajorVersion +
672 dvi.dwMinorVersion;
673 }
674 }
675 #endif
676
677 // if DllGetVersion() is unavailable either during compile or
678 // run-time, try to guess the version otherwise
679 if ( !s_verComCtl32 )
680 {
681 // InitCommonControlsEx is unique to 4.70 and later
682 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
683 if ( !pfn )
684 {
685 // not found, must be 4.00
686 s_verComCtl32 = 400;
687 }
688 else // 4.70+
689 {
690 // many symbols appeared in comctl32 4.71, could use any of
691 // them except may be DllInstall()
692 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
693 if ( !pfn )
694 {
695 // not found, must be 4.70
696 s_verComCtl32 = 470;
697 }
698 else
699 {
700 // found, must be 4.71 or later
701 s_verComCtl32 = 471;
702 }
703 }
704 }
705 }
706 }
707
708 return s_verComCtl32;
709 #endif // Microwin/!Microwin
710 }
711
712 // Yield to incoming messages
713
714 bool wxApp::Yield(bool onlyIfNeeded)
715 {
716 // MT-FIXME
717 static bool s_inYield = FALSE;
718
719 #if wxUSE_LOG
720 // disable log flushing from here because a call to wxYield() shouldn't
721 // normally result in message boxes popping up &c
722 wxLog::Suspend();
723 #endif // wxUSE_LOG
724
725 if ( s_inYield )
726 {
727 if ( !onlyIfNeeded )
728 {
729 wxFAIL_MSG( wxT("wxYield called recursively" ) );
730 }
731
732 return FALSE;
733 }
734
735 s_inYield = TRUE;
736
737 // we don't want to process WM_QUIT from here - it should be processed in
738 // the main event loop in order to stop it
739 MSG msg;
740 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
741 msg.message != WM_QUIT )
742 {
743 #if wxUSE_THREADS
744 wxMutexGuiLeaveOrEnter();
745 #endif // wxUSE_THREADS
746
747 if ( !wxTheApp->Dispatch() )
748 break;
749 }
750
751 // if there are pending events, we must process them.
752 ProcessPendingEvents();
753
754 #if wxUSE_LOG
755 // let the logs be flashed again
756 wxLog::Resume();
757 #endif // wxUSE_LOG
758
759 s_inYield = FALSE;
760
761 return TRUE;
762 }
763
764 #if wxUSE_EXCEPTIONS
765
766 // ----------------------------------------------------------------------------
767 // exception handling
768 // ----------------------------------------------------------------------------
769
770 bool wxApp::OnExceptionInMainLoop()
771 {
772 // ask the user about what to do: use the Win32 API function here as it
773 // could be dangerous to use any wxWindows code in this state
774 switch (
775 ::MessageBox
776 (
777 NULL,
778 _T("An unhandled exception occurred. Press \"Abort\" to \
779 terminate the program,\r\n\
780 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
781 _T("Unhandled exception"),
782 MB_ABORTRETRYIGNORE |
783 MB_ICONERROR|
784 MB_TASKMODAL
785 )
786 )
787 {
788 case IDABORT:
789 throw;
790
791 default:
792 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
793 // fall through
794
795 case IDRETRY:
796 return false;
797
798 case IDIGNORE:
799 return true;
800 }
801 }
802
803 #endif // wxUSE_EXCEPTIONS