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
71 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
83 #include "wx/msw/wrapcctl.h"
87 #include "wx/msw/wince/missing.h"
90 // For DLLVER_PLATFORM_WINDOWS
91 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
92 !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \
93 (!defined(_MSC_VER) || (_MSC_VER > 1100))
97 // ---------------------------------------------------------------------------
99 // ---------------------------------------------------------------------------
101 extern wxList WXDLLEXPORT wxPendingDelete
;
103 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
104 extern void wxSetKeyboardHook(bool doIt
);
107 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
108 // with NR suffix - wxWindow::MSWCreate() supposes this
110 WXDLLIMPEXP_CORE wxChar
*wxCanvasClassName
;
111 WXDLLIMPEXP_CORE wxChar
*wxCanvasClassNameNR
;
113 WXDLLIMPEXP_CORE
const wxChar
*wxCanvasClassName
= wxT("wxWindowClass");
114 WXDLLIMPEXP_CORE
const wxChar
*wxCanvasClassNameNR
= wxT("wxWindowClassNR");
116 WXDLLIMPEXP_CORE
const wxChar
*wxMDIFrameClassName
= wxT("wxMDIFrameClass");
117 WXDLLIMPEXP_CORE
const wxChar
*wxMDIFrameClassNameNoRedraw
= wxT("wxMDIFrameClassNR");
118 WXDLLIMPEXP_CORE
const wxChar
*wxMDIChildFrameClassName
= wxT("wxMDIChildFrameClass");
119 WXDLLIMPEXP_CORE
const wxChar
*wxMDIChildFrameClassNameNoRedraw
= wxT("wxMDIChildFrameClassNR");
121 // ----------------------------------------------------------------------------
123 // ----------------------------------------------------------------------------
125 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
127 // ===========================================================================
128 // wxGUIAppTraits implementation
129 // ===========================================================================
131 // private class which we use to pass parameters from BeforeChildWaitLoop() to
132 // AfterChildWaitLoop()
133 struct ChildWaitLoopData
135 ChildWaitLoopData(wxWindowDisabler
*wd_
, wxWindow
*winActive_
)
138 winActive
= winActive_
;
141 wxWindowDisabler
*wd
;
145 void *wxGUIAppTraits::BeforeChildWaitLoop()
148 We use a dirty hack here to disable all application windows (which we
149 must do because otherwise the calls to wxYield() could lead to some very
150 unexpected reentrancies in the users code) but to avoid losing
151 focus/activation entirely when the child process terminates which would
152 happen if we simply disabled everything using wxWindowDisabler. Indeed,
153 remember that Windows will never activate a disabled window and when the
154 last childs window is closed and Windows looks for a window to activate
155 all our windows are still disabled. There is no way to enable them in
156 time because we don't know when the childs windows are going to be
157 closed, so the solution we use here is to keep one special tiny frame
158 enabled all the time. Then when the child terminates it will get
159 activated and when we close it below -- after reenabling all the other
160 windows! -- the previously active window becomes activated again and
165 // first disable all existing windows
166 wxWindowDisabler
*wd
= new wxWindowDisabler
;
168 // then create an "invisible" frame: it has minimal size, is positioned
169 // (hopefully) outside the screen and doesn't appear on the taskbar
170 wxWindow
*winActive
= new wxFrame
172 wxTheApp
->GetTopWindow(),
175 wxPoint(32600, 32600),
177 wxDEFAULT_FRAME_STYLE
| wxFRAME_NO_TASKBAR
181 return new ChildWaitLoopData(wd
, winActive
);
184 void wxGUIAppTraits::AlwaysYield()
189 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
)
193 ChildWaitLoopData
* const data
= (ChildWaitLoopData
*)dataOrig
;
197 // finally delete the dummy frame and, as wd has been already destroyed and
198 // the other windows reenabled, the activation is going to return to the
199 // window which had had it before
200 data
->winActive
->Destroy();
202 // also delete the temporary data object itself
206 bool wxGUIAppTraits::DoMessageFromThreadWait()
208 // we should return false only if the app should exit, i.e. only if
209 // Dispatch() determines that the main event loop should terminate
210 return !wxTheApp
|| wxTheApp
->Dispatch();
213 wxToolkitInfo
& wxGUIAppTraits::GetToolkitInfo()
215 static wxToolkitInfo info
;
216 wxToolkitInfo
& baseInfo
= wxAppTraits::GetToolkitInfo();
217 info
.versionMajor
= baseInfo
.versionMajor
;
218 info
.versionMinor
= baseInfo
.versionMinor
;
219 info
.os
= baseInfo
.os
;
220 info
.shortName
= _T("msw");
221 info
.name
= _T("wxMSW");
222 #ifdef __WXUNIVERSAL__
223 info
.shortName
<< _T("univ");
224 info
.name
<< _T("/wxUniversal");
229 // ===========================================================================
230 // wxApp implementation
231 // ===========================================================================
233 int wxApp::m_nCmdShow
= SW_SHOWNORMAL
;
235 // ---------------------------------------------------------------------------
237 // ---------------------------------------------------------------------------
239 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
241 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
242 EVT_IDLE(wxApp::OnIdle
)
243 EVT_END_SESSION(wxApp::OnEndSession
)
244 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
247 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
249 class wxCallBaseCleanup
252 wxCallBaseCleanup(wxApp
*app
) : m_app(app
) { }
253 ~wxCallBaseCleanup() { if ( m_app
) m_app
->wxAppBase::CleanUp(); }
255 void Dismiss() { m_app
= NULL
; }
262 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
264 if ( !wxAppBase::Initialize(argc
, argv
) )
267 // ensure that base cleanup is done if we return too early
268 wxCallBaseCleanup
callBaseCleanup(this);
271 wxString tmp
= GetAppName();
272 tmp
+= wxT("ClassName");
273 wxCanvasClassName
= wxStrdup( tmp
.c_str() );
275 wxCanvasClassNameNR
= wxStrdup( tmp
.c_str() );
276 HWND hWnd
= FindWindow( wxCanvasClassNameNR
, NULL
);
279 SetForegroundWindow( (HWND
)(((DWORD
)hWnd
)|0x01) );
284 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
285 InitCommonControls();
288 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
289 SHInitExtraControls();
294 RegisterWindowClasses();
300 wxWinHandleHash
= new wxWinHashTable(wxKEY_INTEGER
, 100);
302 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
303 wxSetKeyboardHook(true);
306 callBaseCleanup
.Dismiss();
311 // ---------------------------------------------------------------------------
312 // RegisterWindowClasses
313 // ---------------------------------------------------------------------------
315 // TODO we should only register classes really used by the app. For this it
316 // would be enough to just delay the class registration until an attempt
317 // to create a window of this class is made.
318 bool wxApp::RegisterWindowClasses()
321 wxZeroMemory(wndclass
);
323 // for each class we register one with CS_(V|H)REDRAW style and one
324 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
325 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
326 static const long styleNoRedraw
= CS_DBLCLKS
;
328 // the fields which are common to all classes
329 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
330 wndclass
.hInstance
= wxhInstance
;
331 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
333 // register the class for all normal windows
334 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
335 wndclass
.lpszClassName
= wxCanvasClassName
;
336 wndclass
.style
= styleNormal
;
338 if ( !RegisterClass(&wndclass
) )
340 wxLogLastError(wxT("RegisterClass(frame)"));
344 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
345 wndclass
.style
= styleNoRedraw
;
347 if ( !RegisterClass(&wndclass
) )
349 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
352 // Register the MDI frame window class.
353 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
354 wndclass
.lpszClassName
= wxMDIFrameClassName
;
355 wndclass
.style
= styleNormal
;
357 if ( !RegisterClass(&wndclass
) )
359 wxLogLastError(wxT("RegisterClass(MDI parent)"));
362 // "no redraw" MDI frame
363 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
364 wndclass
.style
= styleNoRedraw
;
366 if ( !RegisterClass(&wndclass
) )
368 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
371 // Register the MDI child frame window class.
372 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
373 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
374 wndclass
.style
= styleNormal
;
376 if ( !RegisterClass(&wndclass
) )
378 wxLogLastError(wxT("RegisterClass(MDI child)"));
381 // "no redraw" MDI child frame
382 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
383 wndclass
.style
= styleNoRedraw
;
385 if ( !RegisterClass(&wndclass
) )
387 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
393 // ---------------------------------------------------------------------------
394 // UnregisterWindowClasses
395 // ---------------------------------------------------------------------------
397 bool wxApp::UnregisterWindowClasses()
401 #ifndef __WXMICROWIN__
402 // MDI frame window class.
403 if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) )
405 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
410 // "no redraw" MDI frame
411 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) )
413 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
418 // MDI child frame window class.
419 if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) )
421 wxLogLastError(wxT("UnregisterClass(MDI child)"));
426 // "no redraw" MDI child frame
427 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) )
429 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
435 if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) )
437 wxLogLastError(wxT("UnregisterClass(canvas)"));
442 if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) )
444 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
448 #endif // __WXMICROWIN__
453 void wxApp::CleanUp()
455 // all objects pending for deletion must be deleted first, otherwise we
456 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
457 // call wouldn't succeed as long as any windows still exist), so call the
458 // base class method first and only then do our clean up
459 wxAppBase::CleanUp();
461 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
462 wxSetKeyboardHook(false);
471 // for an EXE the classes are unregistered when it terminates but DLL may
472 // be loaded several times (load/unload/load) into the same process in
473 // which case the registration will fail after the first time if we don't
474 // unregister the classes now
475 UnregisterWindowClasses();
477 delete wxWinHandleHash
;
478 wxWinHandleHash
= NULL
;
481 free( wxCanvasClassName
);
482 free( wxCanvasClassNameNR
);
486 // ----------------------------------------------------------------------------
488 // ----------------------------------------------------------------------------
492 m_printMode
= wxPRINT_WINDOWS
;
497 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
498 // don't come from main(), so we have to free them
502 // m_argv elements were allocated by wxStrdup()
506 // but m_argv itself -- using new[]
510 // ----------------------------------------------------------------------------
511 // wxApp idle handling
512 // ----------------------------------------------------------------------------
514 void wxApp::OnIdle(wxIdleEvent
& event
)
516 wxAppBase::OnIdle(event
);
518 #if wxUSE_DC_CACHEING
519 // automated DC cache management: clear the cached DCs and bitmap
520 // if it's likely that the app has finished with them, that is, we
521 // get an idle event and we're not dragging anything.
522 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
524 #endif // wxUSE_DC_CACHEING
527 void wxApp::WakeUpIdle()
529 // Send the top window a dummy message so idle handler processing will
530 // start up again. Doing it this way ensures that the idle handler
531 // wakes up in the right thread (see also wxWakeUpMainThread() which does
532 // the same for the main app thread only)
533 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
536 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
538 // should never happen
539 wxLogLastError(wxT("PostMessage(WM_NULL)"));
544 // ----------------------------------------------------------------------------
545 // other wxApp event hanlders
546 // ----------------------------------------------------------------------------
548 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
551 GetTopWindow()->Close(true);
554 // Default behaviour: close the application with prompts. The
555 // user can veto the close, and therefore the end session.
556 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
560 if (!GetTopWindow()->Close(!event
.CanVeto()))
565 // ----------------------------------------------------------------------------
567 // ----------------------------------------------------------------------------
570 int wxApp::GetComCtl32Version()
572 #if defined(__WXMICROWIN__) || defined(__WXWINCE__)
577 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
578 // but as its value should be the same both times it doesn't matter
579 static int s_verComCtl32
= -1;
581 if ( s_verComCtl32
== -1 )
583 // initally assume no comctl32.dll at all
586 // we're prepared to handle the errors
590 wxDynamicLibrary
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
);
592 // if so, then we can check for the version
593 if ( dllComCtl32
.IsLoaded() )
595 #ifndef DLLVER_PLATFORM_WINDOWS
596 typedef struct _DllVersionInfo
599 DWORD dwMajorVersion
; // Major version
600 DWORD dwMinorVersion
; // Minor version
601 DWORD dwBuildNumber
; // Build number
602 DWORD dwPlatformID
; // DLLVER_PLATFORM_*
604 typedef HRESULT (CALLBACK
* DLLGETVERSIONPROC
)(DLLVERSIONINFO
*);
606 // try to use DllGetVersion() if available in _headers_
607 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32
);
608 if ( pfnDllGetVersion
)
611 dvi
.cbSize
= sizeof(dvi
);
613 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
616 wxLogApiError(_T("DllGetVersion"), hr
);
620 // this is incompatible with _WIN32_IE values, but
621 // compatible with the other values returned by
622 // GetComCtl32Version()
623 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
628 // if DllGetVersion() is unavailable either during compile or
629 // run-time, try to guess the version otherwise
630 if ( !s_verComCtl32
)
632 // InitCommonControlsEx is unique to 4.70 and later
633 void *pfn
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx"));
636 // not found, must be 4.00
641 // many symbols appeared in comctl32 4.71, could use any of
642 // them except may be DllInstall()
643 pfn
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB"));
646 // not found, must be 4.70
651 // found, must be 4.71 or later
659 return s_verComCtl32
;
660 #endif // Microwin/!Microwin
663 // Yield to incoming messages
665 bool wxApp::Yield(bool onlyIfNeeded
)
668 static bool s_inYield
= false;
671 // disable log flushing from here because a call to wxYield() shouldn't
672 // normally result in message boxes popping up &c
680 wxFAIL_MSG( wxT("wxYield called recursively" ) );
688 // we don't want to process WM_QUIT from here - it should be processed in
689 // the main event loop in order to stop it
691 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
692 msg
.message
!= WM_QUIT
)
695 wxMutexGuiLeaveOrEnter();
696 #endif // wxUSE_THREADS
698 if ( !wxTheApp
->Dispatch() )
702 // if there are pending events, we must process them.
703 ProcessPendingEvents();
706 // let the logs be flashed again
717 // ----------------------------------------------------------------------------
718 // exception handling
719 // ----------------------------------------------------------------------------
721 bool wxApp::OnExceptionInMainLoop()
723 // ask the user about what to do: use the Win32 API function here as it
724 // could be dangerous to use any wxWidgets code in this state
729 _T("An unhandled exception occurred. Press \"Abort\" to \
730 terminate the program,\r\n\
731 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
732 _T("Unhandled exception"),
733 MB_ABORTRETRYIGNORE
|
743 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
754 #endif // wxUSE_EXCEPTIONS
756 // ----------------------------------------------------------------------------
757 // deprecated event loop functions
758 // ----------------------------------------------------------------------------
760 #if WXWIN_COMPATIBILITY_2_4
762 #include "wx/evtloop.h"
764 void wxApp::DoMessage(WXMSG
*pMsg
)
766 wxEventLoop
*evtLoop
= wxEventLoop::GetActive();
768 evtLoop
->ProcessMessage(pMsg
);
771 bool wxApp::DoMessage()
773 wxEventLoop
*evtLoop
= wxEventLoop::GetActive();
774 return evtLoop
? evtLoop
->Dispatch() : false;
777 bool wxApp::ProcessMessage(WXMSG
* pMsg
)
779 wxEventLoop
*evtLoop
= wxEventLoop::GetActive();
780 return evtLoop
&& evtLoop
->PreProcessMessage(pMsg
);
783 #endif // WXWIN_COMPATIBILITY_2_4