1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  21     #pragma implementation "app.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  27 #if defined(__BORLANDC__) 
  35     #include "wx/gdicmn.h" 
  38     #include "wx/cursor.h" 
  40     #include "wx/palette.h" 
  42     #include "wx/dialog.h" 
  43     #include "wx/msgdlg.h" 
  45     #include "wx/dynarray.h" 
  46     #include "wx/wxchar.h" 
  51 #include "wx/apptrait.h" 
  52 #include "wx/filename.h" 
  53 #include "wx/module.h" 
  54 #include "wx/dynlib.h" 
  56 #include "wx/msw/private.h" 
  59     #include "wx/thread.h" 
  61     // define the array of MSG strutures 
  62     WX_DECLARE_OBJARRAY(MSG
, wxMsgArray
); 
  64     #include "wx/arrimpl.cpp" 
  66     WX_DEFINE_OBJARRAY(wxMsgArray
); 
  67 #endif // wxUSE_THREADS 
  70     #include "wx/tooltip.h" 
  71 #endif // wxUSE_TOOLTIPS 
  73 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some 
  74 // compilers don't support it (missing headers, libs, ...) 
  75 #if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__) 
  79 #endif // broken compilers 
  88 #if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__WXMICROWIN__)) && !defined(__CYGWIN10__)) 
  92 // ---------------------------------------------------------------------------- 
  93 // conditional compilation 
  94 // ---------------------------------------------------------------------------- 
  96 // The macro _WIN32_IE is defined by commctrl.h (unless it had already been 
  97 // defined before) and shows us what common control features are available 
  98 // during the compile time (it doesn't mean that they will be available during 
  99 // the run-time, use GetComCtl32Version() to test for them!). The possible 
 102 // 0x0200     for comctl32.dll 4.00 shipped with Win95/NT 4.0 
 103 // 0x0300                      4.70              IE 3.x 
 104 // 0x0400                      4.71              IE 4.0 
 105 // 0x0401                      4.72              IE 4.01 and Win98 
 106 // 0x0500                      5.80              IE 5.x 
 107 // 0x0500                      5.81              Win2k/ME 
 111     // use maximal set of features by default, we check for them during 
 113     #define _WIN32_IE 0x0600 
 116 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \ 
 117     !defined(__CYGWIN__) && !defined(__WXWINCE__) && \ 
 118     (!defined(_MSC_VER) || (_MSC_VER > 1100)) 
 122 // --------------------------------------------------------------------------- 
 124 // --------------------------------------------------------------------------- 
 126 extern wxList WXDLLEXPORT wxPendingDelete
; 
 128 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 129 extern void wxSetKeyboardHook(bool doIt
); 
 134 // NB: all "NoRedraw" classes must have the same names as the "normal" classes 
 135 //     with NR suffix - wxWindow::MSWCreate() supposes this 
 136 const wxChar 
*wxCanvasClassName        
= wxT("wxWindowClass"); 
 137 const wxChar 
*wxCanvasClassNameNR      
= wxT("wxWindowClassNR"); 
 138 const wxChar 
*wxMDIFrameClassName      
= wxT("wxMDIFrameClass"); 
 139 const wxChar 
*wxMDIFrameClassNameNoRedraw 
= wxT("wxMDIFrameClassNR"); 
 140 const wxChar 
*wxMDIChildFrameClassName 
= wxT("wxMDIChildFrameClass"); 
 141 const wxChar 
*wxMDIChildFrameClassNameNoRedraw 
= wxT("wxMDIChildFrameClassNR"); 
 143 HBRUSH wxDisableButtonBrush 
= (HBRUSH
) 0; 
 145 // ---------------------------------------------------------------------------- 
 147 // ---------------------------------------------------------------------------- 
 149 LRESULT WXDLLEXPORT APIENTRY 
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
); 
 151 // =========================================================================== 
 152 // wxGUIAppTraits implementation 
 153 // =========================================================================== 
 155 // private class which we use to pass parameters from BeforeChildWaitLoop() to 
 156 // AfterChildWaitLoop() 
 157 struct ChildWaitLoopData
 
 159     ChildWaitLoopData(wxWindowDisabler 
*wd_
, wxWindow 
*winActive_
) 
 162         winActive 
= winActive_
; 
 165     wxWindowDisabler 
*wd
; 
 169 void *wxGUIAppTraits::BeforeChildWaitLoop() 
 172        We use a dirty hack here to disable all application windows (which we 
 173        must do because otherwise the calls to wxYield() could lead to some very 
 174        unexpected reentrancies in the users code) but to avoid losing 
 175        focus/activation entirely when the child process terminates which would 
 176        happen if we simply disabled everything using wxWindowDisabler. Indeed, 
 177        remember that Windows will never activate a disabled window and when the 
 178        last childs window is closed and Windows looks for a window to activate 
 179        all our windows are still disabled. There is no way to enable them in 
 180        time because we don't know when the childs windows are going to be 
 181        closed, so the solution we use here is to keep one special tiny frame 
 182        enabled all the time. Then when the child terminates it will get 
 183        activated and when we close it below -- after reenabling all the other 
 184        windows! -- the previously active window becomes activated again and 
 189     // first disable all existing windows 
 190     wxWindowDisabler 
*wd 
= new wxWindowDisabler
; 
 192     // then create an "invisible" frame: it has minimal size, is positioned 
 193     // (hopefully) outside the screen and doesn't appear on the taskbar 
 194     wxWindow 
*winActive 
= new wxFrame
 
 196                         wxTheApp
->GetTopWindow(), 
 199                         wxPoint(32600, 32600), 
 201                         wxDEFAULT_FRAME_STYLE 
| wxFRAME_NO_TASKBAR
 
 205     return new ChildWaitLoopData(wd
, winActive
); 
 208 void wxGUIAppTraits::AlwaysYield() 
 213 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
) 
 217     const ChildWaitLoopData 
* const data 
= (ChildWaitLoopData 
*)dataOrig
; 
 221     // finally delete the dummy frame and, as wd has been already destroyed and 
 222     // the other windows reenabled, the activation is going to return to the 
 223     // window which had had it before 
 224     data
->winActive
->Destroy(); 
 227 bool wxGUIAppTraits::DoMessageFromThreadWait() 
 229     return !wxTheApp 
|| wxTheApp
->DoMessage(); 
 232 wxToolkitInfo
& wxGUIAppTraits::GetToolkitInfo() 
 234     static wxToolkitInfo info
;     
 235     wxToolkitInfo
& baseInfo 
= wxAppTraits::GetToolkitInfo(); 
 236     info
.versionMajor 
= baseInfo
.versionMajor
; 
 237     info
.versionMinor 
= baseInfo
.versionMinor
; 
 238     info
.os 
= baseInfo
.os
; 
 239     info
.shortName 
= _T("msw"); 
 240     info
.name 
= _T("wxMSW"); 
 241 #ifdef __WXUNIVERSAL__ 
 242     info
.shortName 
<< _T("univ"); 
 243     info
.name 
<< _T("/wxUniversal"); 
 248 // =========================================================================== 
 249 // wxApp implementation 
 250 // =========================================================================== 
 252 int wxApp::m_nCmdShow 
= SW_SHOWNORMAL
; 
 254 // --------------------------------------------------------------------------- 
 256 // --------------------------------------------------------------------------- 
 258 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
) 
 260 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
 261     EVT_IDLE(wxApp::OnIdle
) 
 262     EVT_END_SESSION(wxApp::OnEndSession
) 
 263     EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
) 
 266 // class to ensure that wxAppBase::CleanUp() is called if our Initialize() 
 268 class wxCallBaseCleanup
 
 271     wxCallBaseCleanup(wxApp 
*app
) : m_app(app
) { } 
 272     ~wxCallBaseCleanup() { if ( m_app 
) m_app
->wxAppBase::CleanUp(); } 
 274     void Dismiss() { m_app 
= NULL
; } 
 281 bool wxApp::Initialize(int& argc
, wxChar 
**argv
) 
 283     if ( !wxAppBase::Initialize(argc
, argv
) ) 
 286     // ensure that base cleanup is done if we return too early 
 287     wxCallBaseCleanup 
callBaseCleanup(this); 
 289     // the first thing to do is to check if we're trying to run an Unicode 
 290     // program under Win9x w/o MSLU emulation layer - if so, abort right now 
 291     // as it has no chance to work 
 292 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU 
 293     if ( wxGetOsVersion() != wxWINDOWS_NT 
&& wxGetOsVersion() != wxWINDOWS_CE 
) 
 295         // note that we can use MessageBoxW() as it's implemented even under 
 296         // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs 
 297         // used by wxLocale are not 
 301          _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."), 
 302          _T("wxWindows Fatal Error"), 
 308 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU 
 310 #if defined(__WIN95__) && !defined(__WXMICROWIN__) 
 311     InitCommonControls(); 
 314 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP 
 317     // for OLE, enlarge message queue to be as large as possible 
 319     while (!SetMessageQueue(iMsg
) && (iMsg 
-= 8)) 
 324     // we need to initialize OLE library 
 326     if ( FAILED(::CoInitializeEx(NULL
, COINIT_MULTITHREADED
)) ) 
 327         wxLogError(_("Cannot initialize OLE")); 
 329     if ( FAILED(::OleInitialize(NULL
)) ) 
 330         wxLogError(_("Cannot initialize OLE")); 
 337     if (!Ctl3dRegister(wxhInstance
)) 
 338         wxLogError(wxT("Cannot register CTL3D")); 
 340     Ctl3dAutoSubclass(wxhInstance
); 
 341 #endif // wxUSE_CTL3D 
 343     RegisterWindowClasses(); 
 345 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 346     // Create the brush for disabling bitmap buttons 
 349     lb
.lbStyle 
= BS_PATTERN
; 
 351     lb
.lbHatch 
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") ); 
 354         wxDisableButtonBrush 
= ::CreateBrushIndirect( & lb 
); 
 355         ::DeleteObject( (HGDIOBJ
)lb
.lbHatch 
); 
 357     //else: wxWindows resources are probably not linked in 
 364     wxWinHandleHash 
= new wxWinHashTable(wxKEY_INTEGER
, 100); 
 366     // This is to foil optimizations in Visual C++ that throw out dummy.obj. 
 367     // PLEASE DO NOT ALTER THIS. 
 368 #if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL) 
 369     extern char wxDummyChar
; 
 370     if (wxDummyChar
) wxDummyChar
++; 
 373 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 374     wxSetKeyboardHook(TRUE
); 
 377     callBaseCleanup
.Dismiss(); 
 382 // --------------------------------------------------------------------------- 
 383 // RegisterWindowClasses 
 384 // --------------------------------------------------------------------------- 
 386 // TODO we should only register classes really used by the app. For this it 
 387 //      would be enough to just delay the class registration until an attempt 
 388 //      to create a window of this class is made. 
 389 bool wxApp::RegisterWindowClasses() 
 392     wxZeroMemory(wndclass
); 
 394     // for each class we register one with CS_(V|H)REDRAW style and one 
 395     // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag 
 396     static const long styleNormal 
= CS_HREDRAW 
| CS_VREDRAW 
| CS_DBLCLKS
; 
 397     static const long styleNoRedraw 
= CS_DBLCLKS
; 
 399     // the fields which are common to all classes 
 400     wndclass
.lpfnWndProc   
= (WNDPROC
)wxWndProc
; 
 401     wndclass
.hInstance     
= wxhInstance
; 
 402     wndclass
.hCursor       
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
); 
 404     // Register the frame window class. 
 405     wndclass
.hbrBackground 
= (HBRUSH
)(COLOR_APPWORKSPACE 
+ 1); 
 406     wndclass
.lpszClassName 
= wxCanvasClassName
; 
 407     wndclass
.style         
= styleNormal
; 
 409     if ( !RegisterClass(&wndclass
) ) 
 411         wxLogLastError(wxT("RegisterClass(frame)")); 
 415     wndclass
.lpszClassName 
= wxCanvasClassNameNR
; 
 416     wndclass
.style         
= styleNoRedraw
; 
 418     if ( !RegisterClass(&wndclass
) ) 
 420         wxLogLastError(wxT("RegisterClass(no redraw frame)")); 
 423     // Register the MDI frame window class. 
 424     wndclass
.hbrBackground 
= (HBRUSH
)NULL
; // paint MDI frame ourselves 
 425     wndclass
.lpszClassName 
= wxMDIFrameClassName
; 
 426     wndclass
.style         
= styleNormal
; 
 428     if ( !RegisterClass(&wndclass
) ) 
 430         wxLogLastError(wxT("RegisterClass(MDI parent)")); 
 433     // "no redraw" MDI frame 
 434     wndclass
.lpszClassName 
= wxMDIFrameClassNameNoRedraw
; 
 435     wndclass
.style         
= styleNoRedraw
; 
 437     if ( !RegisterClass(&wndclass
) ) 
 439         wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)")); 
 442     // Register the MDI child frame window class. 
 443     wndclass
.hbrBackground 
= (HBRUSH
)(COLOR_WINDOW 
+ 1); 
 444     wndclass
.lpszClassName 
= wxMDIChildFrameClassName
; 
 445     wndclass
.style         
= styleNormal
; 
 447     if ( !RegisterClass(&wndclass
) ) 
 449         wxLogLastError(wxT("RegisterClass(MDI child)")); 
 452     // "no redraw" MDI child frame 
 453     wndclass
.lpszClassName 
= wxMDIChildFrameClassNameNoRedraw
; 
 454     wndclass
.style         
= styleNoRedraw
; 
 456     if ( !RegisterClass(&wndclass
) ) 
 458         wxLogLastError(wxT("RegisterClass(no redraw MDI child)")); 
 464 // --------------------------------------------------------------------------- 
 465 // UnregisterWindowClasses 
 466 // --------------------------------------------------------------------------- 
 468 bool wxApp::UnregisterWindowClasses() 
 472 #ifndef __WXMICROWIN__ 
 473     // MDI frame window class. 
 474     if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) ) 
 476         wxLogLastError(wxT("UnregisterClass(MDI parent)")); 
 481     // "no redraw" MDI frame 
 482     if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) ) 
 484         wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)")); 
 489     // MDI child frame window class. 
 490     if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) ) 
 492         wxLogLastError(wxT("UnregisterClass(MDI child)")); 
 497     // "no redraw" MDI child frame 
 498     if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) ) 
 500         wxLogLastError(wxT("UnregisterClass(no redraw MDI child)")); 
 506     if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) ) 
 508         wxLogLastError(wxT("UnregisterClass(canvas)")); 
 513     if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) ) 
 515         wxLogLastError(wxT("UnregisterClass(no redraw canvas)")); 
 519 #endif // __WXMICROWIN__ 
 524 void wxApp::CleanUp() 
 526 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 527     wxSetKeyboardHook(FALSE
); 
 534     if ( wxDisableButtonBrush 
) 
 535         ::DeleteObject( wxDisableButtonBrush 
); 
 545     // for an EXE the classes are unregistered when it terminates but DLL may 
 546     // be loaded several times (load/unload/load) into the same process in 
 547     // which case the registration will fail after the first time if we don't 
 548     // unregister the classes now 
 549     UnregisterWindowClasses(); 
 552     Ctl3dUnregister(wxhInstance
); 
 555     delete wxWinHandleHash
; 
 556     wxWinHandleHash 
= NULL
; 
 558     wxAppBase::CleanUp(); 
 561 // ---------------------------------------------------------------------------- 
 563 // ---------------------------------------------------------------------------- 
 567     m_printMode 
= wxPRINT_WINDOWS
; 
 572     // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they 
 573     // don't come from main(), so we have to free them 
 577         // m_argv elements were allocated by wxStrdup() 
 581     // but m_argv itself -- using new[] 
 585 bool wxApp::Initialized() 
 592 #else // Assume initialized if DLL (no way of telling) 
 598  * Get and process a message, returning FALSE if WM_QUIT 
 599  * received (and also set the flag telling the app to exit the main loop) 
 602 bool wxApp::DoMessage() 
 604     BOOL rc 
= ::GetMessage(&s_currentMsg
, (HWND
) NULL
, 0, 0); 
 614         // should never happen, but let's test for it nevertheless 
 615         wxLogLastError(wxT("GetMessage")); 
 620         wxASSERT_MSG( wxThread::IsMain(), 
 621                       wxT("only the main thread can process Windows messages") ); 
 623         static bool s_hadGuiLock 
= TRUE
; 
 624         static wxMsgArray s_aSavedMessages
; 
 626         // if a secondary thread owns is doing GUI calls, save all messages for 
 627         // later processing - we can't process them right now because it will 
 628         // lead to recursive library calls (and we're not reentrant) 
 629         if ( !wxGuiOwnedByMainThread() ) 
 631             s_hadGuiLock 
= FALSE
; 
 633             // leave out WM_COMMAND messages: too dangerous, sometimes 
 634             // the message will be processed twice 
 635             if ( !wxIsWaitingForThread() || 
 636                     s_currentMsg
.message 
!= WM_COMMAND 
) 
 638                 s_aSavedMessages
.Add(s_currentMsg
); 
 645             // have we just regained the GUI lock? if so, post all of the saved 
 648             // FIXME of course, it's not _exactly_ the same as processing the 
 649             //       messages normally - expect some things to break... 
 654                 size_t count 
= s_aSavedMessages
.GetCount(); 
 655                 for ( size_t n 
= 0; n 
< count
; n
++ ) 
 657                     MSG
& msg 
= s_aSavedMessages
[n
]; 
 659                     DoMessage((WXMSG 
*)&msg
); 
 662                 s_aSavedMessages
.Empty(); 
 665 #endif // wxUSE_THREADS 
 667         // Process the message 
 668         DoMessage((WXMSG 
*)&s_currentMsg
); 
 674 void wxApp::DoMessage(WXMSG 
*pMsg
) 
 676     if ( !ProcessMessage(pMsg
) ) 
 678         ::TranslateMessage((MSG 
*)pMsg
); 
 679         ::DispatchMessage((MSG 
*)pMsg
); 
 684  * Keep trying to process messages until WM_QUIT 
 687  * If there are messages to be processed, they will all be 
 688  * processed and OnIdle will not be called. 
 689  * When there are no more messages, OnIdle is called. 
 690  * If OnIdle requests more time, 
 691  * it will be repeatedly called so long as there are no pending messages. 
 692  * A 'feature' of this is that once OnIdle has decided that no more processing 
 693  * is required, then it won't get processing time until further messages 
 694  * are processed (it'll sit in DoMessage). 
 697 int wxApp::MainLoop() 
 701     while ( m_keepGoing 
) 
 704         wxMutexGuiLeaveOrEnter(); 
 705 #endif // wxUSE_THREADS 
 707         while ( !Pending() && ProcessIdle() ) 
 710         // a message came or no more idle processing to do 
 714     return s_currentMsg
.wParam
; 
 717 void wxApp::ExitMainLoop() 
 719     // this will set m_keepGoing to FALSE a bit later 
 720     ::PostQuitMessage(0); 
 723 bool wxApp::Pending() 
 725     return ::PeekMessage(&s_currentMsg
, 0, 0, 0, PM_NOREMOVE
) != 0; 
 728 void wxApp::Dispatch() 
 734  * Give all windows a chance to preprocess 
 735  * the message. Some may have accelerator tables, or have 
 739 bool wxApp::ProcessMessage(WXMSG 
*wxmsg
) 
 741     MSG 
*msg 
= (MSG 
*)wxmsg
; 
 742     HWND hwnd 
= msg
->hwnd
; 
 743     wxWindow 
*wndThis 
= wxGetWindowFromHWND((WXHWND
)hwnd
); 
 745     // this may happen if the event occured in a standard modeless dialog (the 
 746     // only example of which I know of is the find/replace dialog) - then call 
 747     // IsDialogMessage() to make TAB navigation in it work 
 750         // we need to find the dialog containing this control as 
 751         // IsDialogMessage() just eats all the messages (i.e. returns TRUE for 
 752         // them) if we call it for the control itself 
 753         while ( hwnd 
&& ::GetWindowLong(hwnd
, GWL_STYLE
) & WS_CHILD 
) 
 755             hwnd 
= ::GetParent(hwnd
); 
 758         return hwnd 
&& ::IsDialogMessage(hwnd
, msg
) != 0; 
 762     // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to 
 763     // popup the tooltip bubbles 
 764     if ( (msg
->message 
== WM_MOUSEMOVE
) ) 
 766         wxToolTip 
*tt 
= wndThis
->GetToolTip(); 
 769             tt
->RelayEvent(wxmsg
); 
 772 #endif // wxUSE_TOOLTIPS 
 774     // allow the window to prevent certain messages from being 
 775     // translated/processed (this is currently used by wxTextCtrl to always 
 776     // grab Ctrl-C/V/X, even if they are also accelerators in some parent) 
 777     if ( !wndThis
->MSWShouldPreProcessMessage(wxmsg
) ) 
 782     // try translations first: the accelerators override everything 
 785     for ( wnd 
= wndThis
; wnd
; wnd 
= wnd
->GetParent() ) 
 787         if ( wnd
->MSWTranslateMessage(wxmsg
)) 
 790         // stop at first top level window, i.e. don't try to process the key 
 791         // strokes originating in a dialog using the accelerators of the parent 
 792         // frame - this doesn't make much sense 
 793         if ( wnd
->IsTopLevel() ) 
 797     // now try the other hooks (kbd navigation is handled here): we start from 
 798     // wndThis->GetParent() because wndThis->MSWProcessMessage() was already 
 800     for ( wnd 
= wndThis
->GetParent(); wnd
; wnd 
= wnd
->GetParent() ) 
 802         if ( wnd
->MSWProcessMessage(wxmsg
) ) 
 806     // no special preprocessing for this message, dispatch it normally 
 810 // this is a temporary hack and will be replaced by using wxEventLoop in the 
 813 // it is needed to allow other event loops (currently only one: the modal 
 814 // dialog one) to reset the OnIdle() semaphore because otherwise OnIdle() 
 815 // wouldn't do anything while a modal dialog shown from OnIdle() call is shown. 
 816 bool wxIsInOnIdleFlag 
= FALSE
; 
 818 void wxApp::OnIdle(wxIdleEvent
& event
) 
 820     // Avoid recursion (via ProcessEvent default case) 
 821     if ( wxIsInOnIdleFlag 
) 
 824     wxIsInOnIdleFlag 
= TRUE
; 
 826     wxAppBase::OnIdle(event
); 
 828 #if wxUSE_DC_CACHEING 
 829     // automated DC cache management: clear the cached DCs and bitmap 
 830     // if it's likely that the app has finished with them, that is, we 
 831     // get an idle event and we're not dragging anything. 
 832     if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
)) 
 834 #endif // wxUSE_DC_CACHEING 
 836     wxIsInOnIdleFlag 
= FALSE
; 
 839 void wxApp::WakeUpIdle() 
 841     // Send the top window a dummy message so idle handler processing will 
 842     // start up again.  Doing it this way ensures that the idle handler 
 843     // wakes up in the right thread (see also wxWakeUpMainThread() which does 
 844     // the same for the main app thread only) 
 845     wxWindow 
*topWindow 
= wxTheApp
->GetTopWindow(); 
 848         if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) ) 
 850             // should never happen 
 851             wxLogLastError(wxT("PostMessage(WM_NULL)")); 
 856 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
)) 
 859         GetTopWindow()->Close(TRUE
); 
 862 // Default behaviour: close the application with prompts. The 
 863 // user can veto the close, and therefore the end session. 
 864 void wxApp::OnQueryEndSession(wxCloseEvent
& event
) 
 868         if (!GetTopWindow()->Close(!event
.CanVeto())) 
 874 int wxApp::GetComCtl32Version() 
 876 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) 
 881     // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice, 
 882     //     but as its value should be the same both times it doesn't matter 
 883     static int s_verComCtl32 
= -1; 
 885     if ( s_verComCtl32 
== -1 ) 
 887         // initally assume no comctl32.dll at all 
 890         // we're prepared to handle the errors 
 894         wxDynamicLibrary 
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
); 
 896         // if so, then we can check for the version 
 897         if ( dllComCtl32
.IsLoaded() ) 
 899             // try to use DllGetVersion() if available in _headers_ 
 900             wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32 
); 
 901             if ( pfnDllGetVersion 
) 
 904                 dvi
.cbSize 
= sizeof(dvi
); 
 906                 HRESULT hr 
= (*pfnDllGetVersion
)(&dvi
); 
 909                     wxLogApiError(_T("DllGetVersion"), hr
); 
 913                     // this is incompatible with _WIN32_IE values, but 
 914                     // compatible with the other values returned by 
 915                     // GetComCtl32Version() 
 916                     s_verComCtl32 
= 100*dvi
.dwMajorVersion 
+ 
 921             // if DllGetVersion() is unavailable either during compile or 
 922             // run-time, try to guess the version otherwise 
 923             if ( !s_verComCtl32 
) 
 925                 // InitCommonControlsEx is unique to 4.70 and later 
 926                 void *pfn 
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx")); 
 929                     // not found, must be 4.00 
 934                     // many symbols appeared in comctl32 4.71, could use any of 
 935                     // them except may be DllInstall() 
 936                     pfn 
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB")); 
 939                         // not found, must be 4.70 
 944                         // found, must be 4.71 or later 
 952     return s_verComCtl32
; 
 953 #endif // Microwin/!Microwin 
 956 // Yield to incoming messages 
 958 bool wxApp::Yield(bool onlyIfNeeded
) 
 961     static bool s_inYield 
= FALSE
; 
 964     // disable log flushing from here because a call to wxYield() shouldn't 
 965     // normally result in message boxes popping up &c 
 973             wxFAIL_MSG( wxT("wxYield called recursively" ) ); 
 981     // we don't want to process WM_QUIT from here - it should be processed in 
 982     // the main event loop in order to stop it 
 984     while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) && 
 985             msg
.message 
!= WM_QUIT 
) 
 988         wxMutexGuiLeaveOrEnter(); 
 989 #endif // wxUSE_THREADS 
 991         if ( !wxTheApp
->DoMessage() ) 
 995     // if there are pending events, we must process them. 
 996     ProcessPendingEvents(); 
 999     // let the logs be flashed again