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" 
  79 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \ 
  80     !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \ 
  81     (!defined(_MSC_VER) || (_MSC_VER > 1100)) 
  85 // --------------------------------------------------------------------------- 
  87 // --------------------------------------------------------------------------- 
  89 extern wxList WXDLLEXPORT wxPendingDelete
; 
  91 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
  92 extern void wxSetKeyboardHook(bool doIt
); 
  95 // NB: all "NoRedraw" classes must have the same names as the "normal" classes 
  96 //     with NR suffix - wxWindow::MSWCreate() supposes this 
  97 const wxChar 
*wxCanvasClassName        
= wxT("wxWindowClass"); 
  98 const wxChar 
*wxCanvasClassNameNR      
= wxT("wxWindowClassNR"); 
  99 const wxChar 
*wxMDIFrameClassName      
= wxT("wxMDIFrameClass"); 
 100 const wxChar 
*wxMDIFrameClassNameNoRedraw 
= wxT("wxMDIFrameClassNR"); 
 101 const wxChar 
*wxMDIChildFrameClassName 
= wxT("wxMDIChildFrameClass"); 
 102 const wxChar 
*wxMDIChildFrameClassNameNoRedraw 
= wxT("wxMDIChildFrameClassNR"); 
 104 HBRUSH wxDisableButtonBrush 
= (HBRUSH
) 0; 
 106 // ---------------------------------------------------------------------------- 
 108 // ---------------------------------------------------------------------------- 
 110 LRESULT WXDLLEXPORT APIENTRY 
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
); 
 112 // =========================================================================== 
 113 // wxGUIAppTraits implementation 
 114 // =========================================================================== 
 116 // private class which we use to pass parameters from BeforeChildWaitLoop() to 
 117 // AfterChildWaitLoop() 
 118 struct ChildWaitLoopData
 
 120     ChildWaitLoopData(wxWindowDisabler 
*wd_
, wxWindow 
*winActive_
) 
 123         winActive 
= winActive_
; 
 126     wxWindowDisabler 
*wd
; 
 130 void *wxGUIAppTraits::BeforeChildWaitLoop() 
 133        We use a dirty hack here to disable all application windows (which we 
 134        must do because otherwise the calls to wxYield() could lead to some very 
 135        unexpected reentrancies in the users code) but to avoid losing 
 136        focus/activation entirely when the child process terminates which would 
 137        happen if we simply disabled everything using wxWindowDisabler. Indeed, 
 138        remember that Windows will never activate a disabled window and when the 
 139        last childs window is closed and Windows looks for a window to activate 
 140        all our windows are still disabled. There is no way to enable them in 
 141        time because we don't know when the childs windows are going to be 
 142        closed, so the solution we use here is to keep one special tiny frame 
 143        enabled all the time. Then when the child terminates it will get 
 144        activated and when we close it below -- after reenabling all the other 
 145        windows! -- the previously active window becomes activated again and 
 150     // first disable all existing windows 
 151     wxWindowDisabler 
*wd 
= new wxWindowDisabler
; 
 153     // then create an "invisible" frame: it has minimal size, is positioned 
 154     // (hopefully) outside the screen and doesn't appear on the taskbar 
 155     wxWindow 
*winActive 
= new wxFrame
 
 157                         wxTheApp
->GetTopWindow(), 
 160                         wxPoint(32600, 32600), 
 162                         wxDEFAULT_FRAME_STYLE 
| wxFRAME_NO_TASKBAR
 
 166     return new ChildWaitLoopData(wd
, winActive
); 
 169 void wxGUIAppTraits::AlwaysYield() 
 174 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
) 
 178     const ChildWaitLoopData 
* const data 
= (ChildWaitLoopData 
*)dataOrig
; 
 182     // finally delete the dummy frame and, as wd has been already destroyed and 
 183     // the other windows reenabled, the activation is going to return to the 
 184     // window which had had it before 
 185     data
->winActive
->Destroy(); 
 188 bool wxGUIAppTraits::DoMessageFromThreadWait() 
 190     // we should return false only if the app should exit, i.e. only if 
 191     // Dispatch() determines that the main event loop should terminate 
 192     return !wxTheApp 
|| wxTheApp
->Dispatch(); 
 195 wxToolkitInfo
& wxGUIAppTraits::GetToolkitInfo() 
 197     static wxToolkitInfo info
; 
 198     wxToolkitInfo
& baseInfo 
= wxAppTraits::GetToolkitInfo(); 
 199     info
.versionMajor 
= baseInfo
.versionMajor
; 
 200     info
.versionMinor 
= baseInfo
.versionMinor
; 
 201     info
.os 
= baseInfo
.os
; 
 202     info
.shortName 
= _T("msw"); 
 203     info
.name 
= _T("wxMSW"); 
 204 #ifdef __WXUNIVERSAL__ 
 205     info
.shortName 
<< _T("univ"); 
 206     info
.name 
<< _T("/wxUniversal"); 
 211 // =========================================================================== 
 212 // wxApp implementation 
 213 // =========================================================================== 
 215 int wxApp::m_nCmdShow 
= SW_SHOWNORMAL
; 
 217 // --------------------------------------------------------------------------- 
 219 // --------------------------------------------------------------------------- 
 221 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
) 
 223 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
) 
 224     EVT_IDLE(wxApp::OnIdle
) 
 225     EVT_END_SESSION(wxApp::OnEndSession
) 
 226     EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
) 
 229 // class to ensure that wxAppBase::CleanUp() is called if our Initialize() 
 231 class wxCallBaseCleanup
 
 234     wxCallBaseCleanup(wxApp 
*app
) : m_app(app
) { } 
 235     ~wxCallBaseCleanup() { if ( m_app 
) m_app
->wxAppBase::CleanUp(); } 
 237     void Dismiss() { m_app 
= NULL
; } 
 244 bool wxApp::Initialize(int& argc
, wxChar 
**argv
) 
 246     if ( !wxAppBase::Initialize(argc
, argv
) ) 
 249     // ensure that base cleanup is done if we return too early 
 250     wxCallBaseCleanup 
callBaseCleanup(this); 
 252     // the first thing to do is to check if we're trying to run an Unicode 
 253     // program under Win9x w/o MSLU emulation layer - if so, abort right now 
 254     // as it has no chance to work 
 255 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU 
 256     if ( wxGetOsVersion() != wxWINDOWS_NT 
&& wxGetOsVersion() != wxWINDOWS_CE 
) 
 258         // note that we can use MessageBoxW() as it's implemented even under 
 259         // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs 
 260         // used by wxLocale are not 
 264          _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."), 
 265          _T("wxWindows Fatal Error"), 
 271 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU 
 273 #if defined(__WIN95__) && !defined(__WXMICROWIN__) 
 274     InitCommonControls(); 
 277 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP 
 280     // we need to initialize OLE library 
 282     if ( FAILED(::CoInitializeEx(NULL
, COINIT_MULTITHREADED
)) ) 
 283         wxLogError(_("Cannot initialize OLE")); 
 285     if ( FAILED(::OleInitialize(NULL
)) ) 
 286         wxLogError(_("Cannot initialize OLE")); 
 293     if (!Ctl3dRegister(wxhInstance
)) 
 294         wxLogError(wxT("Cannot register CTL3D")); 
 296     Ctl3dAutoSubclass(wxhInstance
); 
 297 #endif // wxUSE_CTL3D 
 299     RegisterWindowClasses(); 
 301 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 302     // Create the brush for disabling bitmap buttons 
 305     lb
.lbStyle 
= BS_PATTERN
; 
 307     lb
.lbHatch 
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") ); 
 310         wxDisableButtonBrush 
= ::CreateBrushIndirect( & lb 
); 
 311         ::DeleteObject( (HGDIOBJ
)lb
.lbHatch 
); 
 313     //else: wxWindows resources are probably not linked in 
 320     wxWinHandleHash 
= new wxWinHashTable(wxKEY_INTEGER
, 100); 
 322 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 323     wxSetKeyboardHook(TRUE
); 
 326     callBaseCleanup
.Dismiss(); 
 331 // --------------------------------------------------------------------------- 
 332 // RegisterWindowClasses 
 333 // --------------------------------------------------------------------------- 
 335 // TODO we should only register classes really used by the app. For this it 
 336 //      would be enough to just delay the class registration until an attempt 
 337 //      to create a window of this class is made. 
 338 bool wxApp::RegisterWindowClasses() 
 341     wxZeroMemory(wndclass
); 
 343     // for each class we register one with CS_(V|H)REDRAW style and one 
 344     // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag 
 345     static const long styleNormal 
= CS_HREDRAW 
| CS_VREDRAW 
| CS_DBLCLKS
; 
 346     static const long styleNoRedraw 
= CS_DBLCLKS
; 
 348     // the fields which are common to all classes 
 349     wndclass
.lpfnWndProc   
= (WNDPROC
)wxWndProc
; 
 350     wndclass
.hInstance     
= wxhInstance
; 
 351     wndclass
.hCursor       
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
); 
 353     // Register the frame window class. 
 354     wndclass
.hbrBackground 
= (HBRUSH
)(COLOR_APPWORKSPACE 
+ 1); 
 355     wndclass
.lpszClassName 
= wxCanvasClassName
; 
 356     wndclass
.style         
= styleNormal
; 
 358     if ( !RegisterClass(&wndclass
) ) 
 360         wxLogLastError(wxT("RegisterClass(frame)")); 
 364     wndclass
.lpszClassName 
= wxCanvasClassNameNR
; 
 365     wndclass
.style         
= styleNoRedraw
; 
 367     if ( !RegisterClass(&wndclass
) ) 
 369         wxLogLastError(wxT("RegisterClass(no redraw frame)")); 
 372     // Register the MDI frame window class. 
 373     wndclass
.hbrBackground 
= (HBRUSH
)NULL
; // paint MDI frame ourselves 
 374     wndclass
.lpszClassName 
= wxMDIFrameClassName
; 
 375     wndclass
.style         
= styleNormal
; 
 377     if ( !RegisterClass(&wndclass
) ) 
 379         wxLogLastError(wxT("RegisterClass(MDI parent)")); 
 382     // "no redraw" MDI frame 
 383     wndclass
.lpszClassName 
= wxMDIFrameClassNameNoRedraw
; 
 384     wndclass
.style         
= styleNoRedraw
; 
 386     if ( !RegisterClass(&wndclass
) ) 
 388         wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)")); 
 391     // Register the MDI child frame window class. 
 392     wndclass
.hbrBackground 
= (HBRUSH
)(COLOR_WINDOW 
+ 1); 
 393     wndclass
.lpszClassName 
= wxMDIChildFrameClassName
; 
 394     wndclass
.style         
= styleNormal
; 
 396     if ( !RegisterClass(&wndclass
) ) 
 398         wxLogLastError(wxT("RegisterClass(MDI child)")); 
 401     // "no redraw" MDI child frame 
 402     wndclass
.lpszClassName 
= wxMDIChildFrameClassNameNoRedraw
; 
 403     wndclass
.style         
= styleNoRedraw
; 
 405     if ( !RegisterClass(&wndclass
) ) 
 407         wxLogLastError(wxT("RegisterClass(no redraw MDI child)")); 
 413 // --------------------------------------------------------------------------- 
 414 // UnregisterWindowClasses 
 415 // --------------------------------------------------------------------------- 
 417 bool wxApp::UnregisterWindowClasses() 
 421 #ifndef __WXMICROWIN__ 
 422     // MDI frame window class. 
 423     if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) ) 
 425         wxLogLastError(wxT("UnregisterClass(MDI parent)")); 
 430     // "no redraw" MDI frame 
 431     if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) ) 
 433         wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)")); 
 438     // MDI child frame window class. 
 439     if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) ) 
 441         wxLogLastError(wxT("UnregisterClass(MDI child)")); 
 446     // "no redraw" MDI child frame 
 447     if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) ) 
 449         wxLogLastError(wxT("UnregisterClass(no redraw MDI child)")); 
 455     if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) ) 
 457         wxLogLastError(wxT("UnregisterClass(canvas)")); 
 462     if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) ) 
 464         wxLogLastError(wxT("UnregisterClass(no redraw canvas)")); 
 468 #endif // __WXMICROWIN__ 
 473 void wxApp::CleanUp() 
 475     // all objects pending for deletion must be deleted first, otherwise we 
 476     // would crash when they use wxWinHandleHash (and UnregisterWindowClasses() 
 477     // call wouldn't succeed as long as any windows still exist), so call the 
 478     // base class method first and only then do our clean up 
 479     wxAppBase::CleanUp(); 
 481 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) 
 482     wxSetKeyboardHook(FALSE
); 
 489     if ( wxDisableButtonBrush 
) 
 490         ::DeleteObject( wxDisableButtonBrush 
); 
 500     // for an EXE the classes are unregistered when it terminates but DLL may 
 501     // be loaded several times (load/unload/load) into the same process in 
 502     // which case the registration will fail after the first time if we don't 
 503     // unregister the classes now 
 504     UnregisterWindowClasses(); 
 507     Ctl3dUnregister(wxhInstance
); 
 510     delete wxWinHandleHash
; 
 511     wxWinHandleHash 
= NULL
; 
 514 // ---------------------------------------------------------------------------- 
 516 // ---------------------------------------------------------------------------- 
 520     m_printMode 
= wxPRINT_WINDOWS
; 
 525     // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they 
 526     // don't come from main(), so we have to free them 
 530         // m_argv elements were allocated by wxStrdup() 
 534     // but m_argv itself -- using new[] 
 538 void wxApp::OnIdle(wxIdleEvent
& event
) 
 540     wxAppBase::OnIdle(event
); 
 542 #if wxUSE_DC_CACHEING 
 543     // automated DC cache management: clear the cached DCs and bitmap 
 544     // if it's likely that the app has finished with them, that is, we 
 545     // get an idle event and we're not dragging anything. 
 546     if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
)) 
 548 #endif // wxUSE_DC_CACHEING 
 551 void wxApp::WakeUpIdle() 
 553     // Send the top window a dummy message so idle handler processing will 
 554     // start up again.  Doing it this way ensures that the idle handler 
 555     // wakes up in the right thread (see also wxWakeUpMainThread() which does 
 556     // the same for the main app thread only) 
 557     wxWindow 
*topWindow 
= wxTheApp
->GetTopWindow(); 
 560         if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) ) 
 562             // should never happen 
 563             wxLogLastError(wxT("PostMessage(WM_NULL)")); 
 568 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
)) 
 571         GetTopWindow()->Close(TRUE
); 
 574 // Default behaviour: close the application with prompts. The 
 575 // user can veto the close, and therefore the end session. 
 576 void wxApp::OnQueryEndSession(wxCloseEvent
& event
) 
 580         if (!GetTopWindow()->Close(!event
.CanVeto())) 
 586 int wxApp::GetComCtl32Version() 
 588 //FIX ME FOR DIGITALMARS!! 
 589 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__) 
 594     // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice, 
 595     //     but as its value should be the same both times it doesn't matter 
 596     static int s_verComCtl32 
= -1; 
 598     if ( s_verComCtl32 
== -1 ) 
 600         // initally assume no comctl32.dll at all 
 603         // we're prepared to handle the errors 
 607         wxDynamicLibrary 
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
); 
 609         // if so, then we can check for the version 
 610         if ( dllComCtl32
.IsLoaded() ) 
 612 #ifdef DLLVER_PLATFORM_WINDOWS 
 613             // try to use DllGetVersion() if available in _headers_ 
 614             wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32 
); 
 615             if ( pfnDllGetVersion 
) 
 618                 dvi
.cbSize 
= sizeof(dvi
); 
 620                 HRESULT hr 
= (*pfnDllGetVersion
)(&dvi
); 
 623                     wxLogApiError(_T("DllGetVersion"), hr
); 
 627                     // this is incompatible with _WIN32_IE values, but 
 628                     // compatible with the other values returned by 
 629                     // GetComCtl32Version() 
 630                     s_verComCtl32 
= 100*dvi
.dwMajorVersion 
+ 
 636             // if DllGetVersion() is unavailable either during compile or 
 637             // run-time, try to guess the version otherwise 
 638             if ( !s_verComCtl32 
) 
 640                 // InitCommonControlsEx is unique to 4.70 and later 
 641                 void *pfn 
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx")); 
 644                     // not found, must be 4.00 
 649                     // many symbols appeared in comctl32 4.71, could use any of 
 650                     // them except may be DllInstall() 
 651                     pfn 
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB")); 
 654                         // not found, must be 4.70 
 659                         // found, must be 4.71 or later 
 667     return s_verComCtl32
; 
 668 #endif // Microwin/!Microwin 
 671 // Yield to incoming messages 
 673 bool wxApp::Yield(bool onlyIfNeeded
) 
 676     static bool s_inYield 
= FALSE
; 
 679     // disable log flushing from here because a call to wxYield() shouldn't 
 680     // normally result in message boxes popping up &c 
 688             wxFAIL_MSG( wxT("wxYield called recursively" ) ); 
 696     // we don't want to process WM_QUIT from here - it should be processed in 
 697     // the main event loop in order to stop it 
 699     while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) && 
 700             msg
.message 
!= WM_QUIT 
) 
 703         wxMutexGuiLeaveOrEnter(); 
 704 #endif // wxUSE_THREADS 
 706         if ( !wxTheApp
->Dispatch() ) 
 710     // if there are pending events, we must process them. 
 711     ProcessPendingEvents(); 
 714     // let the logs be flashed again