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
103 wxChar
*wxCanvasClassName
;
104 wxChar
*wxCanvasClassNameNR
;
106 const wxChar
*wxCanvasClassName
= wxT("wxWindowClass");
107 const wxChar
*wxCanvasClassNameNR
= wxT("wxWindowClassNR");
109 const wxChar
*wxMDIFrameClassName
= wxT("wxMDIFrameClass");
110 const wxChar
*wxMDIFrameClassNameNoRedraw
= wxT("wxMDIFrameClassNR");
111 const wxChar
*wxMDIChildFrameClassName
= wxT("wxMDIChildFrameClass");
112 const wxChar
*wxMDIChildFrameClassNameNoRedraw
= wxT("wxMDIChildFrameClassNR");
114 HBRUSH wxDisableButtonBrush
= (HBRUSH
) 0;
116 // ----------------------------------------------------------------------------
118 // ----------------------------------------------------------------------------
120 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
122 // ===========================================================================
123 // wxGUIAppTraits implementation
124 // ===========================================================================
126 // private class which we use to pass parameters from BeforeChildWaitLoop() to
127 // AfterChildWaitLoop()
128 struct ChildWaitLoopData
130 ChildWaitLoopData(wxWindowDisabler
*wd_
, wxWindow
*winActive_
)
133 winActive
= winActive_
;
136 wxWindowDisabler
*wd
;
140 void *wxGUIAppTraits::BeforeChildWaitLoop()
143 We use a dirty hack here to disable all application windows (which we
144 must do because otherwise the calls to wxYield() could lead to some very
145 unexpected reentrancies in the users code) but to avoid losing
146 focus/activation entirely when the child process terminates which would
147 happen if we simply disabled everything using wxWindowDisabler. Indeed,
148 remember that Windows will never activate a disabled window and when the
149 last childs window is closed and Windows looks for a window to activate
150 all our windows are still disabled. There is no way to enable them in
151 time because we don't know when the childs windows are going to be
152 closed, so the solution we use here is to keep one special tiny frame
153 enabled all the time. Then when the child terminates it will get
154 activated and when we close it below -- after reenabling all the other
155 windows! -- the previously active window becomes activated again and
160 // first disable all existing windows
161 wxWindowDisabler
*wd
= new wxWindowDisabler
;
163 // then create an "invisible" frame: it has minimal size, is positioned
164 // (hopefully) outside the screen and doesn't appear on the taskbar
165 wxWindow
*winActive
= new wxFrame
167 wxTheApp
->GetTopWindow(),
170 wxPoint(32600, 32600),
172 wxDEFAULT_FRAME_STYLE
| wxFRAME_NO_TASKBAR
176 return new ChildWaitLoopData(wd
, winActive
);
179 void wxGUIAppTraits::AlwaysYield()
184 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
)
188 const ChildWaitLoopData
* const data
= (ChildWaitLoopData
*)dataOrig
;
192 // finally delete the dummy frame and, as wd has been already destroyed and
193 // the other windows reenabled, the activation is going to return to the
194 // window which had had it before
195 data
->winActive
->Destroy();
198 bool wxGUIAppTraits::DoMessageFromThreadWait()
200 // we should return false only if the app should exit, i.e. only if
201 // Dispatch() determines that the main event loop should terminate
202 return !wxTheApp
|| wxTheApp
->Dispatch();
205 wxToolkitInfo
& wxGUIAppTraits::GetToolkitInfo()
207 static wxToolkitInfo info
;
208 wxToolkitInfo
& baseInfo
= wxAppTraits::GetToolkitInfo();
209 info
.versionMajor
= baseInfo
.versionMajor
;
210 info
.versionMinor
= baseInfo
.versionMinor
;
211 info
.os
= baseInfo
.os
;
212 info
.shortName
= _T("msw");
213 info
.name
= _T("wxMSW");
214 #ifdef __WXUNIVERSAL__
215 info
.shortName
<< _T("univ");
216 info
.name
<< _T("/wxUniversal");
221 // ===========================================================================
222 // wxApp implementation
223 // ===========================================================================
225 int wxApp::m_nCmdShow
= SW_SHOWNORMAL
;
227 // ---------------------------------------------------------------------------
229 // ---------------------------------------------------------------------------
231 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
233 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
234 EVT_IDLE(wxApp::OnIdle
)
235 EVT_END_SESSION(wxApp::OnEndSession
)
236 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
239 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
241 class wxCallBaseCleanup
244 wxCallBaseCleanup(wxApp
*app
) : m_app(app
) { }
245 ~wxCallBaseCleanup() { if ( m_app
) m_app
->wxAppBase::CleanUp(); }
247 void Dismiss() { m_app
= NULL
; }
254 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
256 if ( !wxAppBase::Initialize(argc
, argv
) )
259 // ensure that base cleanup is done if we return too early
260 wxCallBaseCleanup
callBaseCleanup(this);
263 wxString tmp
= GetAppName();
264 tmp
+= wxT("ClassName");
265 wxCanvasClassName
= wxStrdup( tmp
.c_str() );
267 wxCanvasClassNameNR
= wxStrdup( tmp
.c_str() );
268 HWND hWnd
= FindWindow( wxCanvasClassNameNR
, NULL
);
271 SetForegroundWindow( (HWND
)(((DWORD
)hWnd
)|0x01) );
276 // the first thing to do is to check if we're trying to run an Unicode
277 // program under Win9x w/o MSLU emulation layer - if so, abort right now
278 // as it has no chance to work
279 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
280 if ( wxGetOsVersion() != wxWINDOWS_NT
&& wxGetOsVersion() != wxWINDOWS_CE
)
282 // note that we can use MessageBoxW() as it's implemented even under
283 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
284 // used by wxLocale are not
288 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
289 _T("wxWindows Fatal Error"),
295 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
297 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
298 InitCommonControls();
301 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
304 // we need to initialize OLE library
306 if ( FAILED(::CoInitializeEx(NULL
, COINIT_MULTITHREADED
)) )
307 wxLogError(_("Cannot initialize OLE"));
309 if ( FAILED(::OleInitialize(NULL
)) )
310 wxLogError(_("Cannot initialize OLE"));
317 if (!Ctl3dRegister(wxhInstance
))
318 wxLogError(wxT("Cannot register CTL3D"));
320 Ctl3dAutoSubclass(wxhInstance
);
321 #endif // wxUSE_CTL3D
323 RegisterWindowClasses();
325 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
326 // Create the brush for disabling bitmap buttons
329 lb
.lbStyle
= BS_PATTERN
;
331 lb
.lbHatch
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") );
334 wxDisableButtonBrush
= ::CreateBrushIndirect( & lb
);
335 ::DeleteObject( (HGDIOBJ
)lb
.lbHatch
);
337 //else: wxWindows resources are probably not linked in
344 wxWinHandleHash
= new wxWinHashTable(wxKEY_INTEGER
, 100);
346 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
347 wxSetKeyboardHook(TRUE
);
350 callBaseCleanup
.Dismiss();
355 // ---------------------------------------------------------------------------
356 // RegisterWindowClasses
357 // ---------------------------------------------------------------------------
359 // TODO we should only register classes really used by the app. For this it
360 // would be enough to just delay the class registration until an attempt
361 // to create a window of this class is made.
362 bool wxApp::RegisterWindowClasses()
365 wxZeroMemory(wndclass
);
367 // for each class we register one with CS_(V|H)REDRAW style and one
368 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
369 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
370 static const long styleNoRedraw
= CS_DBLCLKS
;
372 // the fields which are common to all classes
373 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
374 wndclass
.hInstance
= wxhInstance
;
375 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
377 // Register the frame window class.
378 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1);
379 wndclass
.lpszClassName
= wxCanvasClassName
;
380 wndclass
.style
= styleNormal
;
382 if ( !RegisterClass(&wndclass
) )
384 wxLogLastError(wxT("RegisterClass(frame)"));
388 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
389 wndclass
.style
= styleNoRedraw
;
391 if ( !RegisterClass(&wndclass
) )
393 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
396 // Register the MDI frame window class.
397 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
398 wndclass
.lpszClassName
= wxMDIFrameClassName
;
399 wndclass
.style
= styleNormal
;
401 if ( !RegisterClass(&wndclass
) )
403 wxLogLastError(wxT("RegisterClass(MDI parent)"));
406 // "no redraw" MDI frame
407 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
408 wndclass
.style
= styleNoRedraw
;
410 if ( !RegisterClass(&wndclass
) )
412 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
415 // Register the MDI child frame window class.
416 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
417 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
418 wndclass
.style
= styleNormal
;
420 if ( !RegisterClass(&wndclass
) )
422 wxLogLastError(wxT("RegisterClass(MDI child)"));
425 // "no redraw" MDI child frame
426 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
427 wndclass
.style
= styleNoRedraw
;
429 if ( !RegisterClass(&wndclass
) )
431 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
437 // ---------------------------------------------------------------------------
438 // UnregisterWindowClasses
439 // ---------------------------------------------------------------------------
441 bool wxApp::UnregisterWindowClasses()
445 #ifndef __WXMICROWIN__
446 // MDI frame window class.
447 if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) )
449 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
454 // "no redraw" MDI frame
455 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) )
457 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
462 // MDI child frame window class.
463 if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) )
465 wxLogLastError(wxT("UnregisterClass(MDI child)"));
470 // "no redraw" MDI child frame
471 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) )
473 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
479 if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) )
481 wxLogLastError(wxT("UnregisterClass(canvas)"));
486 if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) )
488 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
492 #endif // __WXMICROWIN__
497 void wxApp::CleanUp()
499 // all objects pending for deletion must be deleted first, otherwise we
500 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
501 // call wouldn't succeed as long as any windows still exist), so call the
502 // base class method first and only then do our clean up
503 wxAppBase::CleanUp();
505 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
506 wxSetKeyboardHook(FALSE
);
513 if ( wxDisableButtonBrush
)
514 ::DeleteObject( wxDisableButtonBrush
);
524 // for an EXE the classes are unregistered when it terminates but DLL may
525 // be loaded several times (load/unload/load) into the same process in
526 // which case the registration will fail after the first time if we don't
527 // unregister the classes now
528 UnregisterWindowClasses();
531 Ctl3dUnregister(wxhInstance
);
534 delete wxWinHandleHash
;
535 wxWinHandleHash
= NULL
;
538 free( wxCanvasClassName
);
539 free( wxCanvasClassNameNR
);
543 // ----------------------------------------------------------------------------
545 // ----------------------------------------------------------------------------
549 m_printMode
= wxPRINT_WINDOWS
;
554 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
555 // don't come from main(), so we have to free them
559 // m_argv elements were allocated by wxStrdup()
563 // but m_argv itself -- using new[]
567 // ----------------------------------------------------------------------------
568 // wxApp idle handling
569 // ----------------------------------------------------------------------------
571 void wxApp::OnIdle(wxIdleEvent
& event
)
573 wxAppBase::OnIdle(event
);
575 #if wxUSE_DC_CACHEING
576 // automated DC cache management: clear the cached DCs and bitmap
577 // if it's likely that the app has finished with them, that is, we
578 // get an idle event and we're not dragging anything.
579 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
581 #endif // wxUSE_DC_CACHEING
584 void wxApp::WakeUpIdle()
586 // Send the top window a dummy message so idle handler processing will
587 // start up again. Doing it this way ensures that the idle handler
588 // wakes up in the right thread (see also wxWakeUpMainThread() which does
589 // the same for the main app thread only)
590 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
593 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
595 // should never happen
596 wxLogLastError(wxT("PostMessage(WM_NULL)"));
601 // ----------------------------------------------------------------------------
602 // other wxApp event hanlders
603 // ----------------------------------------------------------------------------
605 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
608 GetTopWindow()->Close(TRUE
);
611 // Default behaviour: close the application with prompts. The
612 // user can veto the close, and therefore the end session.
613 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
617 if (!GetTopWindow()->Close(!event
.CanVeto()))
622 // ----------------------------------------------------------------------------
624 // ----------------------------------------------------------------------------
627 int wxApp::GetComCtl32Version()
629 //FIX ME FOR DIGITALMARS!!
630 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__)
635 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
636 // but as its value should be the same both times it doesn't matter
637 static int s_verComCtl32
= -1;
639 if ( s_verComCtl32
== -1 )
641 // initally assume no comctl32.dll at all
644 // we're prepared to handle the errors
648 wxDynamicLibrary
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
);
650 // if so, then we can check for the version
651 if ( dllComCtl32
.IsLoaded() )
653 #ifdef DLLVER_PLATFORM_WINDOWS
654 // try to use DllGetVersion() if available in _headers_
655 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32
);
656 if ( pfnDllGetVersion
)
659 dvi
.cbSize
= sizeof(dvi
);
661 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
664 wxLogApiError(_T("DllGetVersion"), hr
);
668 // this is incompatible with _WIN32_IE values, but
669 // compatible with the other values returned by
670 // GetComCtl32Version()
671 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
677 // if DllGetVersion() is unavailable either during compile or
678 // run-time, try to guess the version otherwise
679 if ( !s_verComCtl32
)
681 // InitCommonControlsEx is unique to 4.70 and later
682 void *pfn
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx"));
685 // not found, must be 4.00
690 // many symbols appeared in comctl32 4.71, could use any of
691 // them except may be DllInstall()
692 pfn
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB"));
695 // not found, must be 4.70
700 // found, must be 4.71 or later
708 return s_verComCtl32
;
709 #endif // Microwin/!Microwin
712 // Yield to incoming messages
714 bool wxApp::Yield(bool onlyIfNeeded
)
717 static bool s_inYield
= FALSE
;
720 // disable log flushing from here because a call to wxYield() shouldn't
721 // normally result in message boxes popping up &c
729 wxFAIL_MSG( wxT("wxYield called recursively" ) );
737 // we don't want to process WM_QUIT from here - it should be processed in
738 // the main event loop in order to stop it
740 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
741 msg
.message
!= WM_QUIT
)
744 wxMutexGuiLeaveOrEnter();
745 #endif // wxUSE_THREADS
747 if ( !wxTheApp
->Dispatch() )
751 // if there are pending events, we must process them.
752 ProcessPendingEvents();
755 // let the logs be flashed again
766 // ----------------------------------------------------------------------------
767 // exception handling
768 // ----------------------------------------------------------------------------
770 bool wxApp::OnExceptionInMainLoop()
772 // ask the user about what to do: use the Win32 API function here as it
773 // could be dangerous to use any wxWindows code in this state
778 _T("An unhandled exception occurred. Press \"Abort\" to \
779 terminate the program,\r\n\
780 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
781 _T("Unhandled exception"),
782 MB_ABORTRETRYIGNORE
|
792 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
803 #endif // wxUSE_EXCEPTIONS