1 ///////////////////////////////////////////////////////////////////////////// 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // =========================================================================== 
  14 // =========================================================================== 
  16 // --------------------------------------------------------------------------- 
  18 // --------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  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/tooltip.h" 
  60 #endif // wxUSE_TOOLTIPS 
  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__) 
  68 #endif // broken compilers 
  77 #include "wx/msw/wrapcctl.h" 
  81 #include "wx/msw/wince/missing.h" 
  84 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \ 
  85     !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \ 
  86     (!defined(_MSC_VER) || (_MSC_VER > 1100)) 
  90 // --------------------------------------------------------------------------- 
  92 // --------------------------------------------------------------------------- 
  94 extern wxList WXDLLEXPORT wxPendingDelete
; 
  96 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
  97 extern void wxSetKeyboardHook(bool doIt
); 
 100 // NB: all "NoRedraw" classes must have the same names as the "normal" classes 
 101 //     with NR suffix - wxWindow::MSWCreate() supposes this 
 103 WXDLLIMPEXP_CORE       wxChar 
*wxCanvasClassName
; 
 104 WXDLLIMPEXP_CORE       wxChar 
*wxCanvasClassNameNR
; 
 106 WXDLLIMPEXP_CORE 
const wxChar 
*wxCanvasClassName        
= wxT("wxWindowClass"); 
 107 WXDLLIMPEXP_CORE 
const wxChar 
*wxCanvasClassNameNR      
= wxT("wxWindowClassNR"); 
 109 WXDLLIMPEXP_CORE 
const wxChar 
*wxMDIFrameClassName      
= wxT("wxMDIFrameClass"); 
 110 WXDLLIMPEXP_CORE 
const wxChar 
*wxMDIFrameClassNameNoRedraw 
= wxT("wxMDIFrameClassNR"); 
 111 WXDLLIMPEXP_CORE 
const wxChar 
*wxMDIChildFrameClassName 
= wxT("wxMDIChildFrameClass"); 
 112 WXDLLIMPEXP_CORE 
const wxChar 
*wxMDIChildFrameClassNameNoRedraw 
= wxT("wxMDIChildFrameClassNR"); 
 114 // ---------------------------------------------------------------------------- 
 116 // ---------------------------------------------------------------------------- 
 118 LRESULT WXDLLEXPORT APIENTRY 
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
); 
 120 // =========================================================================== 
 121 // wxGUIAppTraits implementation 
 122 // =========================================================================== 
 124 // private class which we use to pass parameters from BeforeChildWaitLoop() to 
 125 // AfterChildWaitLoop() 
 126 struct ChildWaitLoopData
 
 128     ChildWaitLoopData(wxWindowDisabler 
*wd_
, wxWindow 
*winActive_
) 
 131         winActive 
= winActive_
; 
 134     wxWindowDisabler 
*wd
; 
 138 void *wxGUIAppTraits::BeforeChildWaitLoop() 
 141        We use a dirty hack here to disable all application windows (which we 
 142        must do because otherwise the calls to wxYield() could lead to some very 
 143        unexpected reentrancies in the users code) but to avoid losing 
 144        focus/activation entirely when the child process terminates which would 
 145        happen if we simply disabled everything using wxWindowDisabler. Indeed, 
 146        remember that Windows will never activate a disabled window and when the 
 147        last childs window is closed and Windows looks for a window to activate 
 148        all our windows are still disabled. There is no way to enable them in 
 149        time because we don't know when the childs windows are going to be 
 150        closed, so the solution we use here is to keep one special tiny frame 
 151        enabled all the time. Then when the child terminates it will get 
 152        activated and when we close it below -- after reenabling all the other 
 153        windows! -- the previously active window becomes activated again and 
 158     // first disable all existing windows 
 159     wxWindowDisabler 
*wd 
= new wxWindowDisabler
; 
 161     // then create an "invisible" frame: it has minimal size, is positioned 
 162     // (hopefully) outside the screen and doesn't appear on the taskbar 
 163     wxWindow 
*winActive 
= new wxFrame
 
 165                         wxTheApp
->GetTopWindow(), 
 168                         wxPoint(32600, 32600), 
 170                         wxDEFAULT_FRAME_STYLE 
| wxFRAME_NO_TASKBAR
 
 174     return new ChildWaitLoopData(wd
, winActive
); 
 177 void wxGUIAppTraits::AlwaysYield() 
 182 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
) 
 186     ChildWaitLoopData 
* const data 
= (ChildWaitLoopData 
*)dataOrig
; 
 190     // finally delete the dummy frame and, as wd has been already destroyed and 
 191     // the other windows reenabled, the activation is going to return to the 
 192     // window which had had it before 
 193     data
->winActive
->Destroy(); 
 195     // also delete the temporary data object itself 
 199 bool wxGUIAppTraits::DoMessageFromThreadWait() 
 201     // we should return false only if the app should exit, i.e. only if 
 202     // Dispatch() determines that the main event loop should terminate 
 203     return !wxTheApp 
|| wxTheApp
->Dispatch(); 
 206 wxToolkitInfo
& wxGUIAppTraits::GetToolkitInfo() 
 208     static wxToolkitInfo info
; 
 209     wxToolkitInfo
& baseInfo 
= wxAppTraits::GetToolkitInfo(); 
 210     info
.versionMajor 
= baseInfo
.versionMajor
; 
 211     info
.versionMinor 
= baseInfo
.versionMinor
; 
 212     info
.os 
= baseInfo
.os
; 
 213     info
.shortName 
= _T("msw"); 
 214     info
.name 
= _T("wxMSW"); 
 215 #ifdef __WXUNIVERSAL__ 
 216     info
.shortName 
<< _T("univ"); 
 217     info
.name 
<< _T("/wxUniversal"); 
 222 // =========================================================================== 
 223 // wxApp implementation 
 224 // =========================================================================== 
 226 int wxApp::m_nCmdShow 
= SW_SHOWNORMAL
; 
 228 // --------------------------------------------------------------------------- 
 230 // --------------------------------------------------------------------------- 
 232 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
) 
 234 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
 235     EVT_IDLE(wxApp::OnIdle
) 
 236     EVT_END_SESSION(wxApp::OnEndSession
) 
 237     EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
) 
 240 // class to ensure that wxAppBase::CleanUp() is called if our Initialize() 
 242 class wxCallBaseCleanup
 
 245     wxCallBaseCleanup(wxApp 
*app
) : m_app(app
) { } 
 246     ~wxCallBaseCleanup() { if ( m_app 
) m_app
->wxAppBase::CleanUp(); } 
 248     void Dismiss() { m_app 
= NULL
; } 
 255 bool wxApp::Initialize(int& argc
, wxChar 
**argv
) 
 257     if ( !wxAppBase::Initialize(argc
, argv
) ) 
 260     // ensure that base cleanup is done if we return too early 
 261     wxCallBaseCleanup 
callBaseCleanup(this); 
 264     wxString tmp 
= GetAppName(); 
 265     tmp 
+= wxT("ClassName"); 
 266     wxCanvasClassName 
= wxStrdup( tmp
.c_str() ); 
 268     wxCanvasClassNameNR 
= wxStrdup( tmp
.c_str() ); 
 269     HWND hWnd 
= FindWindow( wxCanvasClassNameNR
, NULL 
); 
 272         SetForegroundWindow( (HWND
)(((DWORD
)hWnd
)|0x01) ); 
 277     // the first thing to do is to check if we're trying to run an Unicode 
 278     // program under Win9x w/o MSLU emulation layer - if so, abort right now 
 279     // as it has no chance to work 
 280 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU 
 281     if ( wxGetOsVersion() != wxWINDOWS_NT 
&& wxGetOsVersion() != wxWINDOWS_CE 
) 
 283         // note that we can use MessageBoxW() as it's implemented even under 
 284         // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs 
 285         // used by wxLocale are not 
 289          _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."), 
 290          _T("wxWidgets Fatal Error"), 
 296 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU 
 298 #if defined(__WIN95__) && !defined(__WXMICROWIN__) 
 299     InitCommonControls(); 
 302 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP 
 305     // we need to initialize OLE library 
 307     if ( FAILED(::CoInitializeEx(NULL
, COINIT_MULTITHREADED
)) ) 
 308         wxLogError(_("Cannot initialize OLE")); 
 310     if ( FAILED(::OleInitialize(NULL
)) ) 
 311         wxLogError(_("Cannot initialize OLE")); 
 318     if (!Ctl3dRegister(wxhInstance
)) 
 319         wxLogError(wxT("Cannot register CTL3D")); 
 321     Ctl3dAutoSubclass(wxhInstance
); 
 322 #endif // wxUSE_CTL3D 
 324     RegisterWindowClasses(); 
 330     wxWinHandleHash 
= new wxWinHashTable(wxKEY_INTEGER
, 100); 
 332 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 333     wxSetKeyboardHook(true); 
 336     callBaseCleanup
.Dismiss(); 
 341 // --------------------------------------------------------------------------- 
 342 // RegisterWindowClasses 
 343 // --------------------------------------------------------------------------- 
 345 // TODO we should only register classes really used by the app. For this it 
 346 //      would be enough to just delay the class registration until an attempt 
 347 //      to create a window of this class is made. 
 348 bool wxApp::RegisterWindowClasses() 
 351     wxZeroMemory(wndclass
); 
 353     // for each class we register one with CS_(V|H)REDRAW style and one 
 354     // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag 
 355     static const long styleNormal 
= CS_HREDRAW 
| CS_VREDRAW 
| CS_DBLCLKS
; 
 356     static const long styleNoRedraw 
= CS_DBLCLKS
; 
 358     // the fields which are common to all classes 
 359     wndclass
.lpfnWndProc   
= (WNDPROC
)wxWndProc
; 
 360     wndclass
.hInstance     
= wxhInstance
; 
 361     wndclass
.hCursor       
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
); 
 363     // register the class for all normal windows 
 364     wndclass
.hbrBackground 
= (HBRUSH
)(COLOR_BTNFACE 
+ 1); 
 365     wndclass
.lpszClassName 
= wxCanvasClassName
; 
 366     wndclass
.style         
= styleNormal
; 
 368     if ( !RegisterClass(&wndclass
) ) 
 370         wxLogLastError(wxT("RegisterClass(frame)")); 
 374     wndclass
.lpszClassName 
= wxCanvasClassNameNR
; 
 375     wndclass
.style         
= styleNoRedraw
; 
 377     if ( !RegisterClass(&wndclass
) ) 
 379         wxLogLastError(wxT("RegisterClass(no redraw frame)")); 
 382     // Register the MDI frame window class. 
 383     wndclass
.hbrBackground 
= (HBRUSH
)NULL
; // paint MDI frame ourselves 
 384     wndclass
.lpszClassName 
= wxMDIFrameClassName
; 
 385     wndclass
.style         
= styleNormal
; 
 387     if ( !RegisterClass(&wndclass
) ) 
 389         wxLogLastError(wxT("RegisterClass(MDI parent)")); 
 392     // "no redraw" MDI frame 
 393     wndclass
.lpszClassName 
= wxMDIFrameClassNameNoRedraw
; 
 394     wndclass
.style         
= styleNoRedraw
; 
 396     if ( !RegisterClass(&wndclass
) ) 
 398         wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)")); 
 401     // Register the MDI child frame window class. 
 402     wndclass
.hbrBackground 
= (HBRUSH
)(COLOR_WINDOW 
+ 1); 
 403     wndclass
.lpszClassName 
= wxMDIChildFrameClassName
; 
 404     wndclass
.style         
= styleNormal
; 
 406     if ( !RegisterClass(&wndclass
) ) 
 408         wxLogLastError(wxT("RegisterClass(MDI child)")); 
 411     // "no redraw" MDI child frame 
 412     wndclass
.lpszClassName 
= wxMDIChildFrameClassNameNoRedraw
; 
 413     wndclass
.style         
= styleNoRedraw
; 
 415     if ( !RegisterClass(&wndclass
) ) 
 417         wxLogLastError(wxT("RegisterClass(no redraw MDI child)")); 
 423 // --------------------------------------------------------------------------- 
 424 // UnregisterWindowClasses 
 425 // --------------------------------------------------------------------------- 
 427 bool wxApp::UnregisterWindowClasses() 
 431 #ifndef __WXMICROWIN__ 
 432     // MDI frame window class. 
 433     if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) ) 
 435         wxLogLastError(wxT("UnregisterClass(MDI parent)")); 
 440     // "no redraw" MDI frame 
 441     if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) ) 
 443         wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)")); 
 448     // MDI child frame window class. 
 449     if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) ) 
 451         wxLogLastError(wxT("UnregisterClass(MDI child)")); 
 456     // "no redraw" MDI child frame 
 457     if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) ) 
 459         wxLogLastError(wxT("UnregisterClass(no redraw MDI child)")); 
 465     if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) ) 
 467         wxLogLastError(wxT("UnregisterClass(canvas)")); 
 472     if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) ) 
 474         wxLogLastError(wxT("UnregisterClass(no redraw canvas)")); 
 478 #endif // __WXMICROWIN__ 
 483 void wxApp::CleanUp() 
 485     // all objects pending for deletion must be deleted first, otherwise we 
 486     // would crash when they use wxWinHandleHash (and UnregisterWindowClasses() 
 487     // call wouldn't succeed as long as any windows still exist), so call the 
 488     // base class method first and only then do our clean up 
 489     wxAppBase::CleanUp(); 
 491 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 492     wxSetKeyboardHook(false); 
 507     // for an EXE the classes are unregistered when it terminates but DLL may 
 508     // be loaded several times (load/unload/load) into the same process in 
 509     // which case the registration will fail after the first time if we don't 
 510     // unregister the classes now 
 511     UnregisterWindowClasses(); 
 514     Ctl3dUnregister(wxhInstance
); 
 517     delete wxWinHandleHash
; 
 518     wxWinHandleHash 
= NULL
; 
 521     free( wxCanvasClassName 
); 
 522     free( wxCanvasClassNameNR 
); 
 526 // ---------------------------------------------------------------------------- 
 528 // ---------------------------------------------------------------------------- 
 532     m_printMode 
= wxPRINT_WINDOWS
; 
 537     // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they 
 538     // don't come from main(), so we have to free them 
 542         // m_argv elements were allocated by wxStrdup() 
 546     // but m_argv itself -- using new[] 
 550 // ---------------------------------------------------------------------------- 
 551 // wxApp idle handling 
 552 // ---------------------------------------------------------------------------- 
 554 void wxApp::OnIdle(wxIdleEvent
& event
) 
 556     wxAppBase::OnIdle(event
); 
 558 #if wxUSE_DC_CACHEING 
 559     // automated DC cache management: clear the cached DCs and bitmap 
 560     // if it's likely that the app has finished with them, that is, we 
 561     // get an idle event and we're not dragging anything. 
 562     if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
)) 
 564 #endif // wxUSE_DC_CACHEING 
 567 void wxApp::WakeUpIdle() 
 569     // Send the top window a dummy message so idle handler processing will 
 570     // start up again.  Doing it this way ensures that the idle handler 
 571     // wakes up in the right thread (see also wxWakeUpMainThread() which does 
 572     // the same for the main app thread only) 
 573     wxWindow 
*topWindow 
= wxTheApp
->GetTopWindow(); 
 576         if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) ) 
 578             // should never happen 
 579             wxLogLastError(wxT("PostMessage(WM_NULL)")); 
 584 // ---------------------------------------------------------------------------- 
 585 // other wxApp event hanlders 
 586 // ---------------------------------------------------------------------------- 
 588 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
)) 
 591         GetTopWindow()->Close(true); 
 594 // Default behaviour: close the application with prompts. The 
 595 // user can veto the close, and therefore the end session. 
 596 void wxApp::OnQueryEndSession(wxCloseEvent
& event
) 
 600         if (!GetTopWindow()->Close(!event
.CanVeto())) 
 605 // ---------------------------------------------------------------------------- 
 607 // ---------------------------------------------------------------------------- 
 610 int wxApp::GetComCtl32Version() 
 612 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) 
 617     // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice, 
 618     //     but as its value should be the same both times it doesn't matter 
 619     static int s_verComCtl32 
= -1; 
 621     if ( s_verComCtl32 
== -1 ) 
 623         // initally assume no comctl32.dll at all 
 626         // we're prepared to handle the errors 
 630         wxDynamicLibrary 
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
); 
 632         // if so, then we can check for the version 
 633         if ( dllComCtl32
.IsLoaded() ) 
 635 #ifdef DLLVER_PLATFORM_WINDOWS 
 636             // try to use DllGetVersion() if available in _headers_ 
 637             wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32 
); 
 638             if ( pfnDllGetVersion 
) 
 641                 dvi
.cbSize 
= sizeof(dvi
); 
 643                 HRESULT hr 
= (*pfnDllGetVersion
)(&dvi
); 
 646                     wxLogApiError(_T("DllGetVersion"), hr
); 
 650                     // this is incompatible with _WIN32_IE values, but 
 651                     // compatible with the other values returned by 
 652                     // GetComCtl32Version() 
 653                     s_verComCtl32 
= 100*dvi
.dwMajorVersion 
+ 
 659             // if DllGetVersion() is unavailable either during compile or 
 660             // run-time, try to guess the version otherwise 
 661             if ( !s_verComCtl32 
) 
 663                 // InitCommonControlsEx is unique to 4.70 and later 
 664                 void *pfn 
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx")); 
 667                     // not found, must be 4.00 
 672                     // many symbols appeared in comctl32 4.71, could use any of 
 673                     // them except may be DllInstall() 
 674                     pfn 
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB")); 
 677                         // not found, must be 4.70 
 682                         // found, must be 4.71 or later 
 690     return s_verComCtl32
; 
 691 #endif // Microwin/!Microwin 
 694 // Yield to incoming messages 
 696 bool wxApp::Yield(bool onlyIfNeeded
) 
 699     static bool s_inYield 
= false; 
 702     // disable log flushing from here because a call to wxYield() shouldn't 
 703     // normally result in message boxes popping up &c 
 711             wxFAIL_MSG( wxT("wxYield called recursively" ) ); 
 719     // we don't want to process WM_QUIT from here - it should be processed in 
 720     // the main event loop in order to stop it 
 722     while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) && 
 723             msg
.message 
!= WM_QUIT 
) 
 726         wxMutexGuiLeaveOrEnter(); 
 727 #endif // wxUSE_THREADS 
 729         if ( !wxTheApp
->Dispatch() ) 
 733     // if there are pending events, we must process them. 
 734     ProcessPendingEvents(); 
 737     // let the logs be flashed again 
 748 // ---------------------------------------------------------------------------- 
 749 // exception handling 
 750 // ---------------------------------------------------------------------------- 
 752 bool wxApp::OnExceptionInMainLoop() 
 754     // ask the user about what to do: use the Win32 API function here as it 
 755     // could be dangerous to use any wxWidgets code in this state 
 760                 _T("An unhandled exception occurred. Press \"Abort\" to \ 
 761 terminate the program,\r\n\ 
 762 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."), 
 763                 _T("Unhandled exception"), 
 764                 MB_ABORTRETRYIGNORE 
| 
 774             wxFAIL_MSG( _T("unexpected MessageBox() return code") ); 
 785 #endif // wxUSE_EXCEPTIONS 
 787 // ---------------------------------------------------------------------------- 
 788 // deprecated event loop functions 
 789 // ---------------------------------------------------------------------------- 
 791 #if WXWIN_COMPATIBILITY_2_4 
 793 #include "wx/evtloop.h" 
 795 void wxApp::DoMessage(WXMSG 
*pMsg
) 
 797     wxEventLoop 
*evtLoop 
= wxEventLoop::GetActive(); 
 799         evtLoop
->ProcessMessage(pMsg
); 
 802 bool wxApp::DoMessage() 
 804     wxEventLoop 
*evtLoop 
= wxEventLoop::GetActive(); 
 805     return evtLoop 
? evtLoop
->Dispatch() : false; 
 808 bool wxApp::ProcessMessage(WXMSG
* pMsg
) 
 810     wxEventLoop 
*evtLoop 
= wxEventLoop::GetActive(); 
 811     return evtLoop 
&& evtLoop
->PreProcessMessage(pMsg
); 
 814 #endif // WXWIN_COMPATIBILITY_2_4