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
102 const wxChar
*wxCanvasClassName
= wxT("wxWindowClass");
103 const wxChar
*wxCanvasClassNameNR
= wxT("wxWindowClassNR");
104 const wxChar
*wxMDIFrameClassName
= wxT("wxMDIFrameClass");
105 const wxChar
*wxMDIFrameClassNameNoRedraw
= wxT("wxMDIFrameClassNR");
106 const wxChar
*wxMDIChildFrameClassName
= wxT("wxMDIChildFrameClass");
107 const wxChar
*wxMDIChildFrameClassNameNoRedraw
= wxT("wxMDIChildFrameClassNR");
109 HBRUSH wxDisableButtonBrush
= (HBRUSH
) 0;
111 // ----------------------------------------------------------------------------
113 // ----------------------------------------------------------------------------
115 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
117 // ===========================================================================
118 // wxGUIAppTraits implementation
119 // ===========================================================================
121 // private class which we use to pass parameters from BeforeChildWaitLoop() to
122 // AfterChildWaitLoop()
123 struct ChildWaitLoopData
125 ChildWaitLoopData(wxWindowDisabler
*wd_
, wxWindow
*winActive_
)
128 winActive
= winActive_
;
131 wxWindowDisabler
*wd
;
135 void *wxGUIAppTraits::BeforeChildWaitLoop()
138 We use a dirty hack here to disable all application windows (which we
139 must do because otherwise the calls to wxYield() could lead to some very
140 unexpected reentrancies in the users code) but to avoid losing
141 focus/activation entirely when the child process terminates which would
142 happen if we simply disabled everything using wxWindowDisabler. Indeed,
143 remember that Windows will never activate a disabled window and when the
144 last childs window is closed and Windows looks for a window to activate
145 all our windows are still disabled. There is no way to enable them in
146 time because we don't know when the childs windows are going to be
147 closed, so the solution we use here is to keep one special tiny frame
148 enabled all the time. Then when the child terminates it will get
149 activated and when we close it below -- after reenabling all the other
150 windows! -- the previously active window becomes activated again and
155 // first disable all existing windows
156 wxWindowDisabler
*wd
= new wxWindowDisabler
;
158 // then create an "invisible" frame: it has minimal size, is positioned
159 // (hopefully) outside the screen and doesn't appear on the taskbar
160 wxWindow
*winActive
= new wxFrame
162 wxTheApp
->GetTopWindow(),
165 wxPoint(32600, 32600),
167 wxDEFAULT_FRAME_STYLE
| wxFRAME_NO_TASKBAR
171 return new ChildWaitLoopData(wd
, winActive
);
174 void wxGUIAppTraits::AlwaysYield()
179 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
)
183 const ChildWaitLoopData
* const data
= (ChildWaitLoopData
*)dataOrig
;
187 // finally delete the dummy frame and, as wd has been already destroyed and
188 // the other windows reenabled, the activation is going to return to the
189 // window which had had it before
190 data
->winActive
->Destroy();
193 bool wxGUIAppTraits::DoMessageFromThreadWait()
195 // we should return false only if the app should exit, i.e. only if
196 // Dispatch() determines that the main event loop should terminate
197 return !wxTheApp
|| wxTheApp
->Dispatch();
200 wxToolkitInfo
& wxGUIAppTraits::GetToolkitInfo()
202 static wxToolkitInfo info
;
203 wxToolkitInfo
& baseInfo
= wxAppTraits::GetToolkitInfo();
204 info
.versionMajor
= baseInfo
.versionMajor
;
205 info
.versionMinor
= baseInfo
.versionMinor
;
206 info
.os
= baseInfo
.os
;
207 info
.shortName
= _T("msw");
208 info
.name
= _T("wxMSW");
209 #ifdef __WXUNIVERSAL__
210 info
.shortName
<< _T("univ");
211 info
.name
<< _T("/wxUniversal");
216 // ===========================================================================
217 // wxApp implementation
218 // ===========================================================================
220 int wxApp::m_nCmdShow
= SW_SHOWNORMAL
;
222 // ---------------------------------------------------------------------------
224 // ---------------------------------------------------------------------------
226 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
228 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
229 EVT_IDLE(wxApp::OnIdle
)
230 EVT_END_SESSION(wxApp::OnEndSession
)
231 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
234 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
236 class wxCallBaseCleanup
239 wxCallBaseCleanup(wxApp
*app
) : m_app(app
) { }
240 ~wxCallBaseCleanup() { if ( m_app
) m_app
->wxAppBase::CleanUp(); }
242 void Dismiss() { m_app
= NULL
; }
249 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
251 if ( !wxAppBase::Initialize(argc
, argv
) )
254 // ensure that base cleanup is done if we return too early
255 wxCallBaseCleanup
callBaseCleanup(this);
257 // the first thing to do is to check if we're trying to run an Unicode
258 // program under Win9x w/o MSLU emulation layer - if so, abort right now
259 // as it has no chance to work
260 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
261 if ( wxGetOsVersion() != wxWINDOWS_NT
&& wxGetOsVersion() != wxWINDOWS_CE
)
263 // note that we can use MessageBoxW() as it's implemented even under
264 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
265 // used by wxLocale are not
269 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
270 _T("wxWindows Fatal Error"),
276 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
278 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
279 InitCommonControls();
282 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
285 // we need to initialize OLE library
287 if ( FAILED(::CoInitializeEx(NULL
, COINIT_MULTITHREADED
)) )
288 wxLogError(_("Cannot initialize OLE"));
290 if ( FAILED(::OleInitialize(NULL
)) )
291 wxLogError(_("Cannot initialize OLE"));
298 if (!Ctl3dRegister(wxhInstance
))
299 wxLogError(wxT("Cannot register CTL3D"));
301 Ctl3dAutoSubclass(wxhInstance
);
302 #endif // wxUSE_CTL3D
304 RegisterWindowClasses();
306 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
307 // Create the brush for disabling bitmap buttons
310 lb
.lbStyle
= BS_PATTERN
;
312 lb
.lbHatch
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") );
315 wxDisableButtonBrush
= ::CreateBrushIndirect( & lb
);
316 ::DeleteObject( (HGDIOBJ
)lb
.lbHatch
);
318 //else: wxWindows resources are probably not linked in
325 wxWinHandleHash
= new wxWinHashTable(wxKEY_INTEGER
, 100);
327 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
328 wxSetKeyboardHook(TRUE
);
331 callBaseCleanup
.Dismiss();
336 // ---------------------------------------------------------------------------
337 // RegisterWindowClasses
338 // ---------------------------------------------------------------------------
340 // TODO we should only register classes really used by the app. For this it
341 // would be enough to just delay the class registration until an attempt
342 // to create a window of this class is made.
343 bool wxApp::RegisterWindowClasses()
346 wxZeroMemory(wndclass
);
348 // for each class we register one with CS_(V|H)REDRAW style and one
349 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
350 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
351 static const long styleNoRedraw
= CS_DBLCLKS
;
353 // the fields which are common to all classes
354 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
355 wndclass
.hInstance
= wxhInstance
;
356 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
358 // Register the frame window class.
359 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1);
360 wndclass
.lpszClassName
= wxCanvasClassName
;
361 wndclass
.style
= styleNormal
;
363 if ( !RegisterClass(&wndclass
) )
365 wxLogLastError(wxT("RegisterClass(frame)"));
369 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
370 wndclass
.style
= styleNoRedraw
;
372 if ( !RegisterClass(&wndclass
) )
374 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
377 // Register the MDI frame window class.
378 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
379 wndclass
.lpszClassName
= wxMDIFrameClassName
;
380 wndclass
.style
= styleNormal
;
382 if ( !RegisterClass(&wndclass
) )
384 wxLogLastError(wxT("RegisterClass(MDI parent)"));
387 // "no redraw" MDI frame
388 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
389 wndclass
.style
= styleNoRedraw
;
391 if ( !RegisterClass(&wndclass
) )
393 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
396 // Register the MDI child frame window class.
397 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
398 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
399 wndclass
.style
= styleNormal
;
401 if ( !RegisterClass(&wndclass
) )
403 wxLogLastError(wxT("RegisterClass(MDI child)"));
406 // "no redraw" MDI child frame
407 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
408 wndclass
.style
= styleNoRedraw
;
410 if ( !RegisterClass(&wndclass
) )
412 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
418 // ---------------------------------------------------------------------------
419 // UnregisterWindowClasses
420 // ---------------------------------------------------------------------------
422 bool wxApp::UnregisterWindowClasses()
426 #ifndef __WXMICROWIN__
427 // MDI frame window class.
428 if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) )
430 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
435 // "no redraw" MDI frame
436 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) )
438 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
443 // MDI child frame window class.
444 if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) )
446 wxLogLastError(wxT("UnregisterClass(MDI child)"));
451 // "no redraw" MDI child frame
452 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) )
454 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
460 if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) )
462 wxLogLastError(wxT("UnregisterClass(canvas)"));
467 if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) )
469 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
473 #endif // __WXMICROWIN__
478 void wxApp::CleanUp()
480 // all objects pending for deletion must be deleted first, otherwise we
481 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
482 // call wouldn't succeed as long as any windows still exist), so call the
483 // base class method first and only then do our clean up
484 wxAppBase::CleanUp();
486 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
487 wxSetKeyboardHook(FALSE
);
494 if ( wxDisableButtonBrush
)
495 ::DeleteObject( wxDisableButtonBrush
);
505 // for an EXE the classes are unregistered when it terminates but DLL may
506 // be loaded several times (load/unload/load) into the same process in
507 // which case the registration will fail after the first time if we don't
508 // unregister the classes now
509 UnregisterWindowClasses();
512 Ctl3dUnregister(wxhInstance
);
515 delete wxWinHandleHash
;
516 wxWinHandleHash
= NULL
;
519 // ----------------------------------------------------------------------------
521 // ----------------------------------------------------------------------------
525 m_printMode
= wxPRINT_WINDOWS
;
530 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
531 // don't come from main(), so we have to free them
535 // m_argv elements were allocated by wxStrdup()
539 // but m_argv itself -- using new[]
543 // ----------------------------------------------------------------------------
544 // wxApp idle handling
545 // ----------------------------------------------------------------------------
547 void wxApp::OnIdle(wxIdleEvent
& event
)
549 wxAppBase::OnIdle(event
);
551 #if wxUSE_DC_CACHEING
552 // automated DC cache management: clear the cached DCs and bitmap
553 // if it's likely that the app has finished with them, that is, we
554 // get an idle event and we're not dragging anything.
555 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
557 #endif // wxUSE_DC_CACHEING
560 void wxApp::WakeUpIdle()
562 // Send the top window a dummy message so idle handler processing will
563 // start up again. Doing it this way ensures that the idle handler
564 // wakes up in the right thread (see also wxWakeUpMainThread() which does
565 // the same for the main app thread only)
566 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
569 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
571 // should never happen
572 wxLogLastError(wxT("PostMessage(WM_NULL)"));
577 // ----------------------------------------------------------------------------
578 // other wxApp event hanlders
579 // ----------------------------------------------------------------------------
581 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
584 GetTopWindow()->Close(TRUE
);
587 // Default behaviour: close the application with prompts. The
588 // user can veto the close, and therefore the end session.
589 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
593 if (!GetTopWindow()->Close(!event
.CanVeto()))
598 // ----------------------------------------------------------------------------
600 // ----------------------------------------------------------------------------
603 int wxApp::GetComCtl32Version()
605 //FIX ME FOR DIGITALMARS!!
606 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__)
611 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
612 // but as its value should be the same both times it doesn't matter
613 static int s_verComCtl32
= -1;
615 if ( s_verComCtl32
== -1 )
617 // initally assume no comctl32.dll at all
620 // we're prepared to handle the errors
624 wxDynamicLibrary
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
);
626 // if so, then we can check for the version
627 if ( dllComCtl32
.IsLoaded() )
629 #ifdef DLLVER_PLATFORM_WINDOWS
630 // try to use DllGetVersion() if available in _headers_
631 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32
);
632 if ( pfnDllGetVersion
)
635 dvi
.cbSize
= sizeof(dvi
);
637 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
640 wxLogApiError(_T("DllGetVersion"), hr
);
644 // this is incompatible with _WIN32_IE values, but
645 // compatible with the other values returned by
646 // GetComCtl32Version()
647 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
653 // if DllGetVersion() is unavailable either during compile or
654 // run-time, try to guess the version otherwise
655 if ( !s_verComCtl32
)
657 // InitCommonControlsEx is unique to 4.70 and later
658 void *pfn
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx"));
661 // not found, must be 4.00
666 // many symbols appeared in comctl32 4.71, could use any of
667 // them except may be DllInstall()
668 pfn
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB"));
671 // not found, must be 4.70
676 // found, must be 4.71 or later
684 return s_verComCtl32
;
685 #endif // Microwin/!Microwin
688 // Yield to incoming messages
690 bool wxApp::Yield(bool onlyIfNeeded
)
693 static bool s_inYield
= FALSE
;
696 // disable log flushing from here because a call to wxYield() shouldn't
697 // normally result in message boxes popping up &c
705 wxFAIL_MSG( wxT("wxYield called recursively" ) );
713 // we don't want to process WM_QUIT from here - it should be processed in
714 // the main event loop in order to stop it
716 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
717 msg
.message
!= WM_QUIT
)
720 wxMutexGuiLeaveOrEnter();
721 #endif // wxUSE_THREADS
723 if ( !wxTheApp
->Dispatch() )
727 // if there are pending events, we must process them.
728 ProcessPendingEvents();
731 // let the logs be flashed again
742 // ----------------------------------------------------------------------------
743 // exception handling
744 // ----------------------------------------------------------------------------
746 bool wxApp::OnExceptionInMainLoop()
748 // ask the user about what to do: use the Win32 API function here as it
749 // could be dangerous to use any wxWindows code in this state
754 _T("An unhandled exception occurred. Press \"Abort\" to \
755 terminate the program,\r\n\
756 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
757 _T("Unhandled exception"),
758 MB_ABORTRETRYIGNORE
|
768 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
779 #endif // wxUSE_EXCEPTIONS