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"
57 #include "wx/msw/ole/oleutils.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__) || defined(__SALFORDC__)
69 #endif // broken compilers
78 #include "wx/msw/wrapcctl.h"
82 #include "wx/msw/wince/missing.h"
85 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
86 !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \
87 (!defined(_MSC_VER) || (_MSC_VER > 1100))
91 // ---------------------------------------------------------------------------
93 // ---------------------------------------------------------------------------
95 extern wxList WXDLLEXPORT wxPendingDelete
;
97 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
98 extern void wxSetKeyboardHook(bool doIt
);
101 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
102 // with NR suffix - wxWindow::MSWCreate() supposes this
104 WXDLLIMPEXP_CORE wxChar
*wxCanvasClassName
;
105 WXDLLIMPEXP_CORE wxChar
*wxCanvasClassNameNR
;
107 WXDLLIMPEXP_CORE
const wxChar
*wxCanvasClassName
= wxT("wxWindowClass");
108 WXDLLIMPEXP_CORE
const wxChar
*wxCanvasClassNameNR
= wxT("wxWindowClassNR");
110 WXDLLIMPEXP_CORE
const wxChar
*wxMDIFrameClassName
= wxT("wxMDIFrameClass");
111 WXDLLIMPEXP_CORE
const wxChar
*wxMDIFrameClassNameNoRedraw
= wxT("wxMDIFrameClassNR");
112 WXDLLIMPEXP_CORE
const wxChar
*wxMDIChildFrameClassName
= wxT("wxMDIChildFrameClass");
113 WXDLLIMPEXP_CORE
const wxChar
*wxMDIChildFrameClassNameNoRedraw
= wxT("wxMDIChildFrameClassNR");
115 // ----------------------------------------------------------------------------
117 // ----------------------------------------------------------------------------
119 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
121 // ===========================================================================
122 // wxGUIAppTraits implementation
123 // ===========================================================================
125 // private class which we use to pass parameters from BeforeChildWaitLoop() to
126 // AfterChildWaitLoop()
127 struct ChildWaitLoopData
129 ChildWaitLoopData(wxWindowDisabler
*wd_
, wxWindow
*winActive_
)
132 winActive
= winActive_
;
135 wxWindowDisabler
*wd
;
139 void *wxGUIAppTraits::BeforeChildWaitLoop()
142 We use a dirty hack here to disable all application windows (which we
143 must do because otherwise the calls to wxYield() could lead to some very
144 unexpected reentrancies in the users code) but to avoid losing
145 focus/activation entirely when the child process terminates which would
146 happen if we simply disabled everything using wxWindowDisabler. Indeed,
147 remember that Windows will never activate a disabled window and when the
148 last childs window is closed and Windows looks for a window to activate
149 all our windows are still disabled. There is no way to enable them in
150 time because we don't know when the childs windows are going to be
151 closed, so the solution we use here is to keep one special tiny frame
152 enabled all the time. Then when the child terminates it will get
153 activated and when we close it below -- after reenabling all the other
154 windows! -- the previously active window becomes activated again and
159 // first disable all existing windows
160 wxWindowDisabler
*wd
= new wxWindowDisabler
;
162 // then create an "invisible" frame: it has minimal size, is positioned
163 // (hopefully) outside the screen and doesn't appear on the taskbar
164 wxWindow
*winActive
= new wxFrame
166 wxTheApp
->GetTopWindow(),
169 wxPoint(32600, 32600),
171 wxDEFAULT_FRAME_STYLE
| wxFRAME_NO_TASKBAR
175 return new ChildWaitLoopData(wd
, winActive
);
178 void wxGUIAppTraits::AlwaysYield()
183 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
)
187 ChildWaitLoopData
* const data
= (ChildWaitLoopData
*)dataOrig
;
191 // finally delete the dummy frame and, as wd has been already destroyed and
192 // the other windows reenabled, the activation is going to return to the
193 // window which had had it before
194 data
->winActive
->Destroy();
196 // also delete the temporary data object itself
200 bool wxGUIAppTraits::DoMessageFromThreadWait()
202 // we should return false only if the app should exit, i.e. only if
203 // Dispatch() determines that the main event loop should terminate
204 return !wxTheApp
|| wxTheApp
->Dispatch();
207 wxToolkitInfo
& wxGUIAppTraits::GetToolkitInfo()
209 static wxToolkitInfo info
;
210 wxToolkitInfo
& baseInfo
= wxAppTraits::GetToolkitInfo();
211 info
.versionMajor
= baseInfo
.versionMajor
;
212 info
.versionMinor
= baseInfo
.versionMinor
;
213 info
.os
= baseInfo
.os
;
214 info
.shortName
= _T("msw");
215 info
.name
= _T("wxMSW");
216 #ifdef __WXUNIVERSAL__
217 info
.shortName
<< _T("univ");
218 info
.name
<< _T("/wxUniversal");
223 // ===========================================================================
224 // wxApp implementation
225 // ===========================================================================
227 int wxApp::m_nCmdShow
= SW_SHOWNORMAL
;
229 // ---------------------------------------------------------------------------
231 // ---------------------------------------------------------------------------
233 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
235 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
236 EVT_IDLE(wxApp::OnIdle
)
237 EVT_END_SESSION(wxApp::OnEndSession
)
238 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
241 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
243 class wxCallBaseCleanup
246 wxCallBaseCleanup(wxApp
*app
) : m_app(app
) { }
247 ~wxCallBaseCleanup() { if ( m_app
) m_app
->wxAppBase::CleanUp(); }
249 void Dismiss() { m_app
= NULL
; }
256 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
258 if ( !wxAppBase::Initialize(argc
, argv
) )
261 // ensure that base cleanup is done if we return too early
262 wxCallBaseCleanup
callBaseCleanup(this);
265 wxString tmp
= GetAppName();
266 tmp
+= wxT("ClassName");
267 wxCanvasClassName
= wxStrdup( tmp
.c_str() );
269 wxCanvasClassNameNR
= wxStrdup( tmp
.c_str() );
270 HWND hWnd
= FindWindow( wxCanvasClassNameNR
, NULL
);
273 SetForegroundWindow( (HWND
)(((DWORD
)hWnd
)|0x01) );
278 // the first thing to do is to check if we're trying to run an Unicode
279 // program under Win9x w/o MSLU emulation layer - if so, abort right now
280 // as it has no chance to work
281 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
282 if ( wxGetOsVersion() != wxWINDOWS_NT
&& wxGetOsVersion() != wxWINDOWS_CE
)
284 // note that we can use MessageBoxW() as it's implemented even under
285 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
286 // used by wxLocale are not
290 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
291 _T("wxWidgets Fatal Error"),
297 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
299 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
300 InitCommonControls();
305 RegisterWindowClasses();
311 wxWinHandleHash
= new wxWinHashTable(wxKEY_INTEGER
, 100);
313 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
314 wxSetKeyboardHook(true);
317 callBaseCleanup
.Dismiss();
322 // ---------------------------------------------------------------------------
323 // RegisterWindowClasses
324 // ---------------------------------------------------------------------------
326 // TODO we should only register classes really used by the app. For this it
327 // would be enough to just delay the class registration until an attempt
328 // to create a window of this class is made.
329 bool wxApp::RegisterWindowClasses()
332 wxZeroMemory(wndclass
);
334 // for each class we register one with CS_(V|H)REDRAW style and one
335 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
336 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
337 static const long styleNoRedraw
= CS_DBLCLKS
;
339 // the fields which are common to all classes
340 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
341 wndclass
.hInstance
= wxhInstance
;
342 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
344 // register the class for all normal windows
345 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
346 wndclass
.lpszClassName
= wxCanvasClassName
;
347 wndclass
.style
= styleNormal
;
349 if ( !RegisterClass(&wndclass
) )
351 wxLogLastError(wxT("RegisterClass(frame)"));
355 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
356 wndclass
.style
= styleNoRedraw
;
358 if ( !RegisterClass(&wndclass
) )
360 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
363 // Register the MDI frame window class.
364 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
365 wndclass
.lpszClassName
= wxMDIFrameClassName
;
366 wndclass
.style
= styleNormal
;
368 if ( !RegisterClass(&wndclass
) )
370 wxLogLastError(wxT("RegisterClass(MDI parent)"));
373 // "no redraw" MDI frame
374 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
375 wndclass
.style
= styleNoRedraw
;
377 if ( !RegisterClass(&wndclass
) )
379 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
382 // Register the MDI child frame window class.
383 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
384 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
385 wndclass
.style
= styleNormal
;
387 if ( !RegisterClass(&wndclass
) )
389 wxLogLastError(wxT("RegisterClass(MDI child)"));
392 // "no redraw" MDI child frame
393 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
394 wndclass
.style
= styleNoRedraw
;
396 if ( !RegisterClass(&wndclass
) )
398 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
404 // ---------------------------------------------------------------------------
405 // UnregisterWindowClasses
406 // ---------------------------------------------------------------------------
408 bool wxApp::UnregisterWindowClasses()
412 #ifndef __WXMICROWIN__
413 // MDI frame window class.
414 if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) )
416 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
421 // "no redraw" MDI frame
422 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) )
424 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
429 // MDI child frame window class.
430 if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) )
432 wxLogLastError(wxT("UnregisterClass(MDI child)"));
437 // "no redraw" MDI child frame
438 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) )
440 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
446 if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) )
448 wxLogLastError(wxT("UnregisterClass(canvas)"));
453 if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) )
455 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
459 #endif // __WXMICROWIN__
464 void wxApp::CleanUp()
466 // all objects pending for deletion must be deleted first, otherwise we
467 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
468 // call wouldn't succeed as long as any windows still exist), so call the
469 // base class method first and only then do our clean up
470 wxAppBase::CleanUp();
472 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
473 wxSetKeyboardHook(false);
482 // for an EXE the classes are unregistered when it terminates but DLL may
483 // be loaded several times (load/unload/load) into the same process in
484 // which case the registration will fail after the first time if we don't
485 // unregister the classes now
486 UnregisterWindowClasses();
488 delete wxWinHandleHash
;
489 wxWinHandleHash
= NULL
;
492 free( wxCanvasClassName
);
493 free( wxCanvasClassNameNR
);
497 // ----------------------------------------------------------------------------
499 // ----------------------------------------------------------------------------
503 m_printMode
= wxPRINT_WINDOWS
;
508 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
509 // don't come from main(), so we have to free them
513 // m_argv elements were allocated by wxStrdup()
517 // but m_argv itself -- using new[]
521 // ----------------------------------------------------------------------------
522 // wxApp idle handling
523 // ----------------------------------------------------------------------------
525 void wxApp::OnIdle(wxIdleEvent
& event
)
527 wxAppBase::OnIdle(event
);
529 #if wxUSE_DC_CACHEING
530 // automated DC cache management: clear the cached DCs and bitmap
531 // if it's likely that the app has finished with them, that is, we
532 // get an idle event and we're not dragging anything.
533 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
535 #endif // wxUSE_DC_CACHEING
538 void wxApp::WakeUpIdle()
540 // Send the top window a dummy message so idle handler processing will
541 // start up again. Doing it this way ensures that the idle handler
542 // wakes up in the right thread (see also wxWakeUpMainThread() which does
543 // the same for the main app thread only)
544 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
547 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
549 // should never happen
550 wxLogLastError(wxT("PostMessage(WM_NULL)"));
555 // ----------------------------------------------------------------------------
556 // other wxApp event hanlders
557 // ----------------------------------------------------------------------------
559 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
562 GetTopWindow()->Close(true);
565 // Default behaviour: close the application with prompts. The
566 // user can veto the close, and therefore the end session.
567 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
571 if (!GetTopWindow()->Close(!event
.CanVeto()))
576 // ----------------------------------------------------------------------------
578 // ----------------------------------------------------------------------------
581 int wxApp::GetComCtl32Version()
583 #if defined(__WXMICROWIN__) || defined(__WXWINCE__)
588 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
589 // but as its value should be the same both times it doesn't matter
590 static int s_verComCtl32
= -1;
592 if ( s_verComCtl32
== -1 )
594 // initally assume no comctl32.dll at all
597 // we're prepared to handle the errors
601 wxDynamicLibrary
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
);
603 // if so, then we can check for the version
604 if ( dllComCtl32
.IsLoaded() )
606 #ifdef DLLVER_PLATFORM_WINDOWS
607 // try to use DllGetVersion() if available in _headers_
608 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32
);
609 if ( pfnDllGetVersion
)
612 dvi
.cbSize
= sizeof(dvi
);
614 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
617 wxLogApiError(_T("DllGetVersion"), hr
);
621 // this is incompatible with _WIN32_IE values, but
622 // compatible with the other values returned by
623 // GetComCtl32Version()
624 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
630 // if DllGetVersion() is unavailable either during compile or
631 // run-time, try to guess the version otherwise
632 if ( !s_verComCtl32
)
634 // InitCommonControlsEx is unique to 4.70 and later
635 void *pfn
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx"));
638 // not found, must be 4.00
643 // many symbols appeared in comctl32 4.71, could use any of
644 // them except may be DllInstall()
645 pfn
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB"));
648 // not found, must be 4.70
653 // found, must be 4.71 or later
661 return s_verComCtl32
;
662 #endif // Microwin/!Microwin
665 // Yield to incoming messages
667 bool wxApp::Yield(bool onlyIfNeeded
)
670 static bool s_inYield
= false;
673 // disable log flushing from here because a call to wxYield() shouldn't
674 // normally result in message boxes popping up &c
682 wxFAIL_MSG( wxT("wxYield called recursively" ) );
690 // we don't want to process WM_QUIT from here - it should be processed in
691 // the main event loop in order to stop it
693 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
694 msg
.message
!= WM_QUIT
)
697 wxMutexGuiLeaveOrEnter();
698 #endif // wxUSE_THREADS
700 if ( !wxTheApp
->Dispatch() )
704 // if there are pending events, we must process them.
705 ProcessPendingEvents();
708 // let the logs be flashed again
719 // ----------------------------------------------------------------------------
720 // exception handling
721 // ----------------------------------------------------------------------------
723 bool wxApp::OnExceptionInMainLoop()
725 // ask the user about what to do: use the Win32 API function here as it
726 // could be dangerous to use any wxWidgets code in this state
731 _T("An unhandled exception occurred. Press \"Abort\" to \
732 terminate the program,\r\n\
733 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
734 _T("Unhandled exception"),
735 MB_ABORTRETRYIGNORE
|
745 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
756 #endif // wxUSE_EXCEPTIONS
758 // ----------------------------------------------------------------------------
759 // deprecated event loop functions
760 // ----------------------------------------------------------------------------
762 #if WXWIN_COMPATIBILITY_2_4
764 #include "wx/evtloop.h"
766 void wxApp::DoMessage(WXMSG
*pMsg
)
768 wxEventLoop
*evtLoop
= wxEventLoop::GetActive();
770 evtLoop
->ProcessMessage(pMsg
);
773 bool wxApp::DoMessage()
775 wxEventLoop
*evtLoop
= wxEventLoop::GetActive();
776 return evtLoop
? evtLoop
->Dispatch() : false;
779 bool wxApp::ProcessMessage(WXMSG
* pMsg
)
781 wxEventLoop
*evtLoop
= wxEventLoop::GetActive();
782 return evtLoop
&& evtLoop
->PreProcessMessage(pMsg
);
785 #endif // WXWIN_COMPATIBILITY_2_4