1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/msw/app.cpp 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  23 #if defined(__BORLANDC__) 
  28     #include "wx/msw/wrapcctl.h" 
  29     #include "wx/dynarray.h" 
  33     #include "wx/gdicmn.h" 
  36     #include "wx/cursor.h" 
  38     #include "wx/palette.h" 
  40     #include "wx/dialog.h" 
  41     #include "wx/msgdlg.h" 
  45     #include "wx/module.h" 
  48 #include "wx/apptrait.h" 
  49 #include "wx/filename.h" 
  50 #include "wx/dynlib.h" 
  51 #include "wx/evtloop.h" 
  52 #include "wx/thread.h" 
  54 #include "wx/msw/private.h" 
  55 #include "wx/msw/dc.h" 
  56 #include "wx/msw/ole/oleutils.h" 
  57 #include "wx/msw/private/timer.h" 
  60     #include "wx/tooltip.h" 
  61 #endif // wxUSE_TOOLTIPS 
  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__) 
  69 #endif // broken compilers 
  71 #if defined(__POCKETPC__) || defined(__SMARTPHONE__) 
  83 #include "wx/msw/missing.h" 
  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 
  89 // NB: DLLVER_PLATFORM_WINDOWS will be defined if shlwapi.h had been somehow 
  91 #ifndef DLLVER_PLATFORM_WINDOWS 
  92     // hopefully we don't need to change packing as DWORDs should be already 
  97         DWORD dwMajorVersion
;                   // Major version 
  98         DWORD dwMinorVersion
;                   // Minor version 
  99         DWORD dwBuildNumber
;                    // Build number 
 100         DWORD dwPlatformID
;                     // DLLVER_PLATFORM_* 
 103     typedef HRESULT (CALLBACK
* DLLGETVERSIONPROC
)(DLLVERSIONINFO 
*); 
 104 #endif // defined(DLLVERSIONINFO) 
 107 // --------------------------------------------------------------------------- 
 109 // --------------------------------------------------------------------------- 
 111 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 112 extern void wxSetKeyboardHook(bool doIt
); 
 115 // NB: all "NoRedraw" classes must have the same names as the "normal" classes 
 116 //     with NR suffix - wxWindow::MSWCreate() supposes this 
 118 WXDLLIMPEXP_CORE       wxChar 
*wxCanvasClassName
; 
 119 WXDLLIMPEXP_CORE       wxChar 
*wxCanvasClassNameNR
; 
 121 WXDLLIMPEXP_CORE 
const wxChar 
*wxCanvasClassName 
= NULL
; 
 122 WXDLLIMPEXP_CORE 
const wxChar 
*wxCanvasClassNameNR 
= NULL
; 
 124 WXDLLIMPEXP_CORE 
const wxChar 
*wxMDIFrameClassName 
= NULL
; 
 125 WXDLLIMPEXP_CORE 
const wxChar 
*wxMDIFrameClassNameNoRedraw 
= NULL
; 
 126 WXDLLIMPEXP_CORE 
const wxChar 
*wxMDIChildFrameClassName 
= NULL
; 
 127 WXDLLIMPEXP_CORE 
const wxChar 
*wxMDIChildFrameClassNameNoRedraw 
= NULL
; 
 129 // ---------------------------------------------------------------------------- 
 131 // ---------------------------------------------------------------------------- 
 133 LRESULT WXDLLEXPORT APIENTRY 
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
); 
 135 // =========================================================================== 
 136 // wxGUIAppTraits implementation 
 137 // =========================================================================== 
 139 // private class which we use to pass parameters from BeforeChildWaitLoop() to 
 140 // AfterChildWaitLoop() 
 141 struct ChildWaitLoopData
 
 143     ChildWaitLoopData(wxWindowDisabler 
*wd_
, wxWindow 
*winActive_
) 
 146         winActive 
= winActive_
; 
 149     wxWindowDisabler 
*wd
; 
 153 void *wxGUIAppTraits::BeforeChildWaitLoop() 
 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 
 173     // first disable all existing windows 
 174     wxWindowDisabler 
*wd 
= new wxWindowDisabler
; 
 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
 
 180                         wxTheApp
->GetTopWindow(), 
 183                         wxPoint(32600, 32600), 
 185                         wxDEFAULT_FRAME_STYLE 
| wxFRAME_NO_TASKBAR
 
 189     return new ChildWaitLoopData(wd
, winActive
); 
 192 void wxGUIAppTraits::AlwaysYield() 
 197 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
) 
 201     ChildWaitLoopData 
* const data 
= (ChildWaitLoopData 
*)dataOrig
; 
 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(); 
 210     // also delete the temporary data object itself 
 214 bool wxGUIAppTraits::DoMessageFromThreadWait() 
 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     wxEventLoopBase 
* const evtLoop 
= wxEventLoop::GetActive(); 
 219     if ( !evtLoop 
|| !evtLoop
->Pending() ) 
 221         // no events means no quit event 
 225     return evtLoop
->Dispatch(); 
 228 DWORD 
wxGUIAppTraits::WaitForThread(WXHANDLE hThread
) 
 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 
 234     if ( !wxEventLoop::GetActive() ) 
 235         return DoSimpleWaitForThread(hThread
); 
 237     return ::MsgWaitForMultipleObjects
 
 239                1,                   // number of objects to wait for 
 240                (HANDLE 
*)&hThread
,  // the objects 
 241                false,               // wait for any objects, not all 
 242                INFINITE
,            // no timeout 
 243                QS_ALLINPUT 
|        // return as soon as there are any events 
 248 wxPortId 
wxGUIAppTraits::GetToolkitVersion(int *majVer
, int *minVer
) const 
 253     // on Windows, the toolkit version is the same of the OS version 
 254     // as Windows integrates the OS kernel with the GUI toolkit. 
 255     info
.dwOSVersionInfoSize 
= sizeof(OSVERSIONINFO
); 
 256     if ( ::GetVersionEx(&info
) ) 
 259             *majVer 
= info
.dwMajorVersion
; 
 261             *minVer 
= info
.dwMinorVersion
; 
 264 #if defined(__WXHANDHELD__) || defined(__WXWINCE__) 
 273 wxTimerImpl 
*wxGUIAppTraits::CreateTimerImpl(wxTimer 
*timer
) 
 275     return new wxMSWTimerImpl(timer
); 
 278 #endif // wxUSE_TIMER 
 280 wxEventLoopBase
* wxGUIAppTraits::CreateEventLoop() 
 282     return new wxEventLoop
; 
 285 // =========================================================================== 
 286 // wxApp implementation 
 287 // =========================================================================== 
 289 int wxApp::m_nCmdShow 
= SW_SHOWNORMAL
; 
 291 // --------------------------------------------------------------------------- 
 293 // --------------------------------------------------------------------------- 
 295 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
) 
 297 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
 298     EVT_IDLE(wxApp::OnIdle
) 
 299     EVT_END_SESSION(wxApp::OnEndSession
) 
 300     EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
) 
 303 // class to ensure that wxAppBase::CleanUp() is called if our Initialize() 
 305 class wxCallBaseCleanup
 
 308     wxCallBaseCleanup(wxApp 
*app
) : m_app(app
) { } 
 309     ~wxCallBaseCleanup() { if ( m_app 
) m_app
->wxAppBase::CleanUp(); } 
 311     void Dismiss() { m_app 
= NULL
; } 
 318 bool wxApp::Initialize(int& argc
, wxChar 
**argv
) 
 320     if ( !wxAppBase::Initialize(argc
, argv
) ) 
 323     // ensure that base cleanup is done if we return too early 
 324     wxCallBaseCleanup 
callBaseCleanup(this); 
 327     wxString tmp 
= GetAppName(); 
 328     tmp 
+= wxT("ClassName"); 
 329     wxCanvasClassName 
= wxStrdup( tmp
.wc_str() ); 
 331     wxCanvasClassNameNR 
= wxStrdup( tmp
.wc_str() ); 
 332     HWND hWnd 
= FindWindow( wxCanvasClassNameNR
, NULL 
); 
 335         SetForegroundWindow( (HWND
)(((DWORD
)hWnd
)|0x01) ); 
 340 #if !defined(__WXMICROWIN__) 
 341     InitCommonControls(); 
 342 #endif // !defined(__WXMICROWIN__) 
 344 #if defined(__SMARTPHONE__) || defined(__POCKETPC__) 
 345     SHInitExtraControls(); 
 349     // Don't show a message box if a function such as SHGetFileInfo 
 350     // fails to find a device. 
 351     SetErrorMode(SEM_FAILCRITICALERRORS
|SEM_NOOPENFILEERRORBOX
); 
 356     RegisterWindowClasses(); 
 358 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 359     wxSetKeyboardHook(true); 
 362     callBaseCleanup
.Dismiss(); 
 367 // --------------------------------------------------------------------------- 
 368 // RegisterWindowClasses 
 369 // --------------------------------------------------------------------------- 
 371 // This function registers the given class name and stores a pointer to a 
 372 // heap-allocated copy of it at the specified location, it must be deleted 
 374 static void RegisterAndStoreClassName(const wxString
& uniqueClassName
, 
 375                                       const wxChar 
**className
, 
 376                                       WNDCLASS 
*lpWndClass
) 
 378     const size_t length 
= uniqueClassName
.length() + 1; // for trailing NUL 
 379     wxChar 
*newChars 
= new wxChar
[length
]; 
 380     wxStrncpy(newChars
, uniqueClassName
, length
); 
 381     *className 
= newChars
; 
 382     lpWndClass
->lpszClassName 
= *className
; 
 384     if ( !::RegisterClass(lpWndClass
) ) 
 386         wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"), newChars
)); 
 390 // This function registers the class defined by the provided WNDCLASS struct 
 391 // contents using a unique name constructed from the specified base name and 
 392 // and a suffix unique to this library instance. It also stores the generated 
 393 // unique names for normal and "no redraw" versions of the class in the 
 394 // provided variables, caller must delete their contents later. 
 395 static void RegisterClassWithUniqueNames(const wxString
& baseName
, 
 396                                          const wxChar 
**className
, 
 397                                          const wxChar 
**classNameNR
, 
 398                                          WNDCLASS 
*lpWndClass
) 
 400     // for each class we register one with CS_(V|H)REDRAW style and one 
 401     // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag 
 402     static const long styleNormal 
= CS_HREDRAW 
| CS_VREDRAW 
| CS_DBLCLKS
; 
 403     static const long styleNoRedraw 
= CS_DBLCLKS
; 
 405     const wxString 
uniqueSuffix(wxString::Format(wxT("@%p"), className
)); 
 407     wxString 
uniqueClassName(baseName 
+ uniqueSuffix
); 
 408     lpWndClass
->style 
= styleNormal
; 
 409     RegisterAndStoreClassName(uniqueClassName
, className
, lpWndClass
); 
 411     // NB: remember that code elsewhere supposes that no redraw class names 
 412     //     use the same names as normal classes with "NR" suffix so we must put 
 413     //     "NR" at the end instead of using more natural baseName+"NR"+suffix 
 414     wxString 
uniqueClassNameNR(uniqueClassName 
+ wxT("NR")); 
 415     lpWndClass
->style 
= styleNoRedraw
; 
 416     RegisterAndStoreClassName(uniqueClassNameNR
, classNameNR
, lpWndClass
); 
 419 // TODO we should only register classes really used by the app. For this it 
 420 //      would be enough to just delay the class registration until an attempt 
 421 //      to create a window of this class is made. 
 422 bool wxApp::RegisterWindowClasses() 
 425     wxZeroMemory(wndclass
); 
 427     // the fields which are common to all classes 
 428     wndclass
.lpfnWndProc   
= (WNDPROC
)wxWndProc
; 
 429     wndclass
.hInstance     
= wxhInstance
; 
 430     wndclass
.hCursor       
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
); 
 432     // register the class for all normal windows and "no redraw" frames 
 433     wndclass
.hbrBackground 
= (HBRUSH
)(COLOR_BTNFACE 
+ 1); 
 434     RegisterClassWithUniqueNames(wxT("wxWindowClass"), 
 436                                  &wxCanvasClassNameNR
, 
 439     // Register the MDI frame window class and "no redraw" MDI frame 
 440     wndclass
.hbrBackground 
= (HBRUSH
)NULL
; // paint MDI frame ourselves 
 441     RegisterClassWithUniqueNames(wxT("wxMDIFrameClass"), 
 442                                  &wxMDIFrameClassName
, 
 443                                  &wxMDIFrameClassNameNoRedraw
, 
 446     // Register the MDI child frame window class and "no redraw" MDI child frame 
 447     wndclass
.hbrBackground 
= (HBRUSH
)(COLOR_WINDOW 
+ 1); 
 448     RegisterClassWithUniqueNames(wxT("wxMDIChildFrameClass"), 
 449                                  &wxMDIChildFrameClassName
, 
 450                                  &wxMDIChildFrameClassNameNoRedraw
, 
 456 // --------------------------------------------------------------------------- 
 457 // UnregisterWindowClasses 
 458 // --------------------------------------------------------------------------- 
 460 // This function unregisters the class with the given name and frees memory 
 461 // allocated for it by RegisterAndStoreClassName(). 
 462 static bool UnregisterAndFreeClassName(const wxChar 
**ppClassName
) 
 466     if ( !::UnregisterClass(*ppClassName
, wxhInstance
) ) 
 469                 wxString::Format(wxT("UnregisterClass(%s)"), *ppClassName
)); 
 474     delete [] *ppClassName
; 
 480 bool wxApp::UnregisterWindowClasses() 
 484 #ifndef __WXMICROWIN__ 
 485     if ( !UnregisterAndFreeClassName(&wxMDIFrameClassName
) ) 
 488     if ( !UnregisterAndFreeClassName(&wxMDIFrameClassNameNoRedraw
) ) 
 491     if ( !UnregisterAndFreeClassName(&wxMDIChildFrameClassName
) ) 
 494     if ( !UnregisterAndFreeClassName(&wxMDIChildFrameClassNameNoRedraw
) ) 
 497     if ( !UnregisterAndFreeClassName(&wxCanvasClassName
) ) 
 500     if ( !UnregisterAndFreeClassName(&wxCanvasClassNameNR
) ) 
 502 #endif // __WXMICROWIN__ 
 507 void wxApp::CleanUp() 
 509     // all objects pending for deletion must be deleted first, otherwise 
 510     // UnregisterWindowClasses() call wouldn't succeed (because windows 
 511     // using the classes being unregistered still exist), so call the base 
 512     // class method first and only then do our clean up 
 513     wxAppBase::CleanUp(); 
 515 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 516     wxSetKeyboardHook(false); 
 521     // for an EXE the classes are unregistered when it terminates but DLL may 
 522     // be loaded several times (load/unload/load) into the same process in 
 523     // which case the registration will fail after the first time if we don't 
 524     // unregister the classes now 
 525     UnregisterWindowClasses(); 
 528     free( wxCanvasClassName 
); 
 529     free( wxCanvasClassNameNR 
); 
 533 // ---------------------------------------------------------------------------- 
 535 // ---------------------------------------------------------------------------- 
 539     m_printMode 
= wxPRINT_WINDOWS
; 
 546 // ---------------------------------------------------------------------------- 
 547 // wxApp idle handling 
 548 // ---------------------------------------------------------------------------- 
 550 void wxApp::OnIdle(wxIdleEvent
& WXUNUSED(event
)) 
 552 #if wxUSE_DC_CACHEING 
 553     // automated DC cache management: clear the cached DCs and bitmap 
 554     // if it's likely that the app has finished with them, that is, we 
 555     // get an idle event and we're not dragging anything. 
 556     if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
)) 
 557         wxMSWDCImpl::ClearCache(); 
 558 #endif // wxUSE_DC_CACHEING 
 561 void wxApp::WakeUpIdle() 
 563     // Send the top window a dummy message so idle handler processing will 
 564     // start up again.  Doing it this way ensures that the idle handler 
 565     // wakes up in the right thread (see also wxWakeUpMainThread() which does 
 566     // the same for the main app thread only) 
 567     wxWindow 
* const topWindow 
= wxTheApp
->GetTopWindow(); 
 570         HWND hwndTop 
= GetHwndOf(topWindow
); 
 572         // Do not post WM_NULL if there's already a pending WM_NULL to avoid 
 573         // overflowing the message queue. 
 575         // Notice that due to a limitation of PeekMessage() API (which handles 
 576         // 0,0 range specially), we have to check the range from 0-1 instead. 
 577         // This still makes it possible to overflow the queue with WM_NULLs by 
 578         // interspersing the calles to WakeUpIdle() with windows creation but 
 579         // it should be rather hard to do it accidentally. 
 581         if ( !::PeekMessage(&msg
, hwndTop
, 0, 1, PM_NOREMOVE
) || 
 582               ::PeekMessage(&msg
, hwndTop
, 1, 1, PM_NOREMOVE
) ) 
 584             if ( !::PostMessage(hwndTop
, WM_NULL
, 0, 0) ) 
 586                 // should never happen 
 587                 wxLogLastError(wxT("PostMessage(WM_NULL)")); 
 593 // ---------------------------------------------------------------------------- 
 594 // other wxApp event hanlders 
 595 // ---------------------------------------------------------------------------- 
 597 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
)) 
 599     // Windows will terminate the process soon after we return from 
 600     // WM_ENDSESSION handler or when we delete our last window, so make sure we 
 601     // at least execute our cleanup code before 
 603     // prevent the window from being destroyed when the corresponding wxTLW is 
 604     // destroyed: this will result in a leak of a HWND, of course, but who 
 605     // cares when the process is being killed anyhow 
 606     if ( !wxTopLevelWindows
.empty() ) 
 607         wxTopLevelWindows
[0]->SetHWND(0); 
 609     const int rc 
= OnExit(); 
 613     // calling exit() instead of ExitProcess() or not doing anything at all and 
 614     // being killed by Windows has the advantage of executing the dtors of 
 619 // Default behaviour: close the application with prompts. The 
 620 // user can veto the close, and therefore the end session. 
 621 void wxApp::OnQueryEndSession(wxCloseEvent
& event
) 
 625         if (!GetTopWindow()->Close(!event
.CanVeto())) 
 630 // ---------------------------------------------------------------------------- 
 631 // system DLL versions 
 632 // ---------------------------------------------------------------------------- 
 634 // these functions have trivial inline implementations for CE 
 637 #if wxUSE_DYNLIB_CLASS 
 642 // helper function: retrieve the DLL version by using DllGetVersion(), returns 
 643 // 0 if the DLL doesn't export such function 
 644 int CallDllGetVersion(wxDynamicLibrary
& dll
) 
 646     // now check if the function is available during run-time 
 647     wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dll 
); 
 648     if ( !pfnDllGetVersion 
) 
 652     dvi
.cbSize 
= sizeof(dvi
); 
 654     HRESULT hr 
= (*pfnDllGetVersion
)(&dvi
); 
 657         wxLogApiError(_T("DllGetVersion"), hr
); 
 662     return 100*dvi
.dwMajorVersion 
+ dvi
.dwMinorVersion
; 
 665 } // anonymous namespace 
 668 int wxApp::GetComCtl32Version() 
 672     // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice, 
 673     //     but as its value should be the same both times it doesn't matter 
 674     static int s_verComCtl32 
= -1; 
 676     if ( s_verComCtl32 
== -1 ) 
 678         // we're prepared to handle the errors 
 681         // the DLL should really be available 
 682         wxDynamicLibrary 
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
); 
 683         if ( !dllComCtl32
.IsLoaded() ) 
 689         // try DllGetVersion() for recent DLLs 
 690         s_verComCtl32 
= CallDllGetVersion(dllComCtl32
); 
 692         // if DllGetVersion() is unavailable either during compile or 
 693         // run-time, try to guess the version otherwise 
 694         if ( !s_verComCtl32 
) 
 696             // InitCommonControlsEx is unique to 4.70 and later 
 697             void *pfn 
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx")); 
 700                 // not found, must be 4.00 
 705                 // many symbols appeared in comctl32 4.71, could use any of 
 706                 // them except may be DllInstall() 
 707                 pfn 
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB")); 
 710                     // not found, must be 4.70 
 715                     // found, must be 4.71 or later 
 722     return s_verComCtl32
; 
 726 int wxApp::GetShell32Version() 
 728     static int s_verShell32 
= -1; 
 729     if ( s_verShell32 
== -1 ) 
 731         // we're prepared to handle the errors 
 734         wxDynamicLibrary 
dllShell32(_T("shell32.dll"), wxDL_VERBATIM
); 
 735         if ( dllShell32
.IsLoaded() ) 
 737             s_verShell32 
= CallDllGetVersion(dllShell32
); 
 741                 // there doesn't seem to be any way to distinguish between 4.00 
 742                 // and 4.70 (starting from 4.71 we have DllGetVersion()) so 
 743                 // just assume it is 4.0 
 747         else // failed load the DLL? 
 756 #else // !wxUSE_DYNLIB_CLASS 
 759 int wxApp::GetComCtl32Version() 
 765 int wxApp::GetShell32Version() 
 770 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS 
 772 #endif // !__WXWINCE__ 
 774 // ---------------------------------------------------------------------------- 
 775 // Yield to incoming messages 
 776 // ---------------------------------------------------------------------------- 
 778 bool wxApp::Yield(bool onlyIfNeeded
) 
 781     static bool s_inYield 
= false; 
 784     // disable log flushing from here because a call to wxYield() shouldn't 
 785     // normally result in message boxes popping up &c 
 793             wxFAIL_MSG( wxT("wxYield called recursively" ) ); 
 801     // we don't want to process WM_QUIT from here - it should be processed in 
 802     // the main event loop in order to stop it 
 803     wxEventLoopGuarantor dummyLoopIfNeeded
; 
 805     while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) && 
 806             msg
.message 
!= WM_QUIT 
) 
 809         wxMutexGuiLeaveOrEnter(); 
 810 #endif // wxUSE_THREADS 
 812         if ( !wxTheApp
->Dispatch() ) 
 816     // if there are pending events, we must process them. 
 817     ProcessPendingEvents(); 
 820     // let the logs be flashed again 
 831 // ---------------------------------------------------------------------------- 
 832 // exception handling 
 833 // ---------------------------------------------------------------------------- 
 835 bool wxApp::OnExceptionInMainLoop() 
 837     // ask the user about what to do: use the Win32 API function here as it 
 838     // could be dangerous to use any wxWidgets code in this state 
 843                 _T("An unhandled exception occurred. Press \"Abort\" to \ 
 844 terminate the program,\r\n\ 
 845 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."), 
 846                 _T("Unhandled exception"), 
 847                 MB_ABORTRETRYIGNORE 
| 
 857             wxFAIL_MSG( _T("unexpected MessageBox() return code") ); 
 868 #endif // wxUSE_EXCEPTIONS