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 // for OLE, enlarge message queue to be as large as possible
282 while (!SetMessageQueue(iMsg
) && (iMsg
-= 8))
287 // we need to initialize OLE library
289 if ( FAILED(::CoInitializeEx(NULL
, COINIT_MULTITHREADED
)) )
290 wxLogError(_("Cannot initialize OLE"));
292 if ( FAILED(::OleInitialize(NULL
)) )
293 wxLogError(_("Cannot initialize OLE"));
300 if (!Ctl3dRegister(wxhInstance
))
301 wxLogError(wxT("Cannot register CTL3D"));
303 Ctl3dAutoSubclass(wxhInstance
);
304 #endif // wxUSE_CTL3D
306 RegisterWindowClasses();
308 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
309 // Create the brush for disabling bitmap buttons
312 lb
.lbStyle
= BS_PATTERN
;
314 lb
.lbHatch
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") );
317 wxDisableButtonBrush
= ::CreateBrushIndirect( & lb
);
318 ::DeleteObject( (HGDIOBJ
)lb
.lbHatch
);
320 //else: wxWindows resources are probably not linked in
327 wxWinHandleHash
= new wxWinHashTable(wxKEY_INTEGER
, 100);
329 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
330 // PLEASE DO NOT ALTER THIS.
331 #if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
332 extern char wxDummyChar
;
333 if (wxDummyChar
) wxDummyChar
++;
336 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
337 wxSetKeyboardHook(TRUE
);
340 callBaseCleanup
.Dismiss();
345 // ---------------------------------------------------------------------------
346 // RegisterWindowClasses
347 // ---------------------------------------------------------------------------
349 // TODO we should only register classes really used by the app. For this it
350 // would be enough to just delay the class registration until an attempt
351 // to create a window of this class is made.
352 bool wxApp::RegisterWindowClasses()
355 wxZeroMemory(wndclass
);
357 // for each class we register one with CS_(V|H)REDRAW style and one
358 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
359 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
360 static const long styleNoRedraw
= CS_DBLCLKS
;
362 // the fields which are common to all classes
363 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
364 wndclass
.hInstance
= wxhInstance
;
365 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
367 // Register the frame window class.
368 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1);
369 wndclass
.lpszClassName
= wxCanvasClassName
;
370 wndclass
.style
= styleNormal
;
372 if ( !RegisterClass(&wndclass
) )
374 wxLogLastError(wxT("RegisterClass(frame)"));
378 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
379 wndclass
.style
= styleNoRedraw
;
381 if ( !RegisterClass(&wndclass
) )
383 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
386 // Register the MDI frame window class.
387 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
388 wndclass
.lpszClassName
= wxMDIFrameClassName
;
389 wndclass
.style
= styleNormal
;
391 if ( !RegisterClass(&wndclass
) )
393 wxLogLastError(wxT("RegisterClass(MDI parent)"));
396 // "no redraw" MDI frame
397 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
398 wndclass
.style
= styleNoRedraw
;
400 if ( !RegisterClass(&wndclass
) )
402 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
405 // Register the MDI child frame window class.
406 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
407 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
408 wndclass
.style
= styleNormal
;
410 if ( !RegisterClass(&wndclass
) )
412 wxLogLastError(wxT("RegisterClass(MDI child)"));
415 // "no redraw" MDI child frame
416 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
417 wndclass
.style
= styleNoRedraw
;
419 if ( !RegisterClass(&wndclass
) )
421 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
427 // ---------------------------------------------------------------------------
428 // UnregisterWindowClasses
429 // ---------------------------------------------------------------------------
431 bool wxApp::UnregisterWindowClasses()
435 #ifndef __WXMICROWIN__
436 // MDI frame window class.
437 if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) )
439 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
444 // "no redraw" MDI frame
445 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) )
447 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
452 // MDI child frame window class.
453 if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) )
455 wxLogLastError(wxT("UnregisterClass(MDI child)"));
460 // "no redraw" MDI child frame
461 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) )
463 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
469 if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) )
471 wxLogLastError(wxT("UnregisterClass(canvas)"));
476 if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) )
478 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
482 #endif // __WXMICROWIN__
487 void wxApp::CleanUp()
489 // all objects pending for deletion must be deleted first, otherwise we
490 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
491 // call wouldn't succeed as long as any windows still exist), so call the
492 // base class method first and only then do our clean up
493 wxAppBase::CleanUp();
495 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
496 wxSetKeyboardHook(FALSE
);
503 if ( wxDisableButtonBrush
)
504 ::DeleteObject( wxDisableButtonBrush
);
514 // for an EXE the classes are unregistered when it terminates but DLL may
515 // be loaded several times (load/unload/load) into the same process in
516 // which case the registration will fail after the first time if we don't
517 // unregister the classes now
518 UnregisterWindowClasses();
521 Ctl3dUnregister(wxhInstance
);
524 delete wxWinHandleHash
;
525 wxWinHandleHash
= NULL
;
528 // ----------------------------------------------------------------------------
530 // ----------------------------------------------------------------------------
534 m_printMode
= wxPRINT_WINDOWS
;
539 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
540 // don't come from main(), so we have to free them
544 // m_argv elements were allocated by wxStrdup()
548 // but m_argv itself -- using new[]
552 void wxApp::OnIdle(wxIdleEvent
& event
)
554 wxAppBase::OnIdle(event
);
556 #if wxUSE_DC_CACHEING
557 // automated DC cache management: clear the cached DCs and bitmap
558 // if it's likely that the app has finished with them, that is, we
559 // get an idle event and we're not dragging anything.
560 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
562 #endif // wxUSE_DC_CACHEING
565 void wxApp::WakeUpIdle()
567 // Send the top window a dummy message so idle handler processing will
568 // start up again. Doing it this way ensures that the idle handler
569 // wakes up in the right thread (see also wxWakeUpMainThread() which does
570 // the same for the main app thread only)
571 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
574 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
576 // should never happen
577 wxLogLastError(wxT("PostMessage(WM_NULL)"));
582 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
585 GetTopWindow()->Close(TRUE
);
588 // Default behaviour: close the application with prompts. The
589 // user can veto the close, and therefore the end session.
590 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
594 if (!GetTopWindow()->Close(!event
.CanVeto()))
600 int wxApp::GetComCtl32Version()
602 //FIX ME FOR DIGITALMARS!!
603 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__)
608 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
609 // but as its value should be the same both times it doesn't matter
610 static int s_verComCtl32
= -1;
612 if ( s_verComCtl32
== -1 )
614 // initally assume no comctl32.dll at all
617 // we're prepared to handle the errors
621 wxDynamicLibrary
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
);
623 // if so, then we can check for the version
624 if ( dllComCtl32
.IsLoaded() )
626 #ifdef DLLVER_PLATFORM_WINDOWS
627 // try to use DllGetVersion() if available in _headers_
628 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32
);
629 if ( pfnDllGetVersion
)
632 dvi
.cbSize
= sizeof(dvi
);
634 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
637 wxLogApiError(_T("DllGetVersion"), hr
);
641 // this is incompatible with _WIN32_IE values, but
642 // compatible with the other values returned by
643 // GetComCtl32Version()
644 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
650 // if DllGetVersion() is unavailable either during compile or
651 // run-time, try to guess the version otherwise
652 if ( !s_verComCtl32
)
654 // InitCommonControlsEx is unique to 4.70 and later
655 void *pfn
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx"));
658 // not found, must be 4.00
663 // many symbols appeared in comctl32 4.71, could use any of
664 // them except may be DllInstall()
665 pfn
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB"));
668 // not found, must be 4.70
673 // found, must be 4.71 or later
681 return s_verComCtl32
;
682 #endif // Microwin/!Microwin
685 // Yield to incoming messages
687 bool wxApp::Yield(bool onlyIfNeeded
)
690 static bool s_inYield
= FALSE
;
693 // disable log flushing from here because a call to wxYield() shouldn't
694 // normally result in message boxes popping up &c
702 wxFAIL_MSG( wxT("wxYield called recursively" ) );
710 // we don't want to process WM_QUIT from here - it should be processed in
711 // the main event loop in order to stop it
713 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
714 msg
.message
!= WM_QUIT
)
717 wxMutexGuiLeaveOrEnter();
718 #endif // wxUSE_THREADS
720 if ( !wxTheApp
->Dispatch() )
724 // if there are pending events, we must process them.
725 ProcessPendingEvents();
728 // let the logs be flashed again