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