1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/app.cpp
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
23 #if defined(__BORLANDC__)
28 #include "wx/msw/wrapcctl.h"
29 #include "wx/dynarray.h"
33 #include "wx/gdicmn.h"
36 #include "wx/cursor.h"
38 #include "wx/palette.h"
40 #include "wx/dialog.h"
41 #include "wx/msgdlg.h"
45 #include "wx/module.h"
48 #include "wx/apptrait.h"
49 #include "wx/filename.h"
50 #include "wx/dynlib.h"
51 #include "wx/evtloop.h"
52 #include "wx/thread.h"
53 #include "wx/scopeguard.h"
55 #include "wx/msw/private.h"
56 #include "wx/msw/dc.h"
57 #include "wx/msw/ole/oleutils.h"
58 #include "wx/msw/private/timer.h"
61 #include "wx/tooltip.h"
62 #endif // wxUSE_TOOLTIPS
64 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
65 // compilers don't support it (missing headers, libs, ...)
66 #if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__)
70 #endif // broken compilers
72 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
84 #include "wx/msw/missing.h"
86 // instead of including <shlwapi.h> which is not part of the core SDK and not
87 // shipped at all with other compilers, we always define the parts of it we
88 // need here ourselves
90 // NB: DLLVER_PLATFORM_WINDOWS will be defined if shlwapi.h had been somehow
92 #ifndef DLLVER_PLATFORM_WINDOWS
93 // hopefully we don't need to change packing as DWORDs should be already
98 DWORD dwMajorVersion
; // Major version
99 DWORD dwMinorVersion
; // Minor version
100 DWORD dwBuildNumber
; // Build number
101 DWORD dwPlatformID
; // DLLVER_PLATFORM_*
104 typedef HRESULT (CALLBACK
* DLLGETVERSIONPROC
)(DLLVERSIONINFO
*);
105 #endif // defined(DLLVERSIONINFO)
107 #ifndef ATTACH_PARENT_PROCESS
108 #define ATTACH_PARENT_PROCESS ((DWORD)-1)
111 // ---------------------------------------------------------------------------
113 // ---------------------------------------------------------------------------
115 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
116 extern void wxSetKeyboardHook(bool doIt
);
119 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
120 // with NR suffix - wxWindow::MSWCreate() supposes this
122 WXDLLIMPEXP_CORE wxChar
*wxCanvasClassName
;
123 WXDLLIMPEXP_CORE wxChar
*wxCanvasClassNameNR
;
125 WXDLLIMPEXP_CORE
const wxChar
*wxCanvasClassName
= NULL
;
126 WXDLLIMPEXP_CORE
const wxChar
*wxCanvasClassNameNR
= NULL
;
128 WXDLLIMPEXP_CORE
const wxChar
*wxMDIFrameClassName
= NULL
;
129 WXDLLIMPEXP_CORE
const wxChar
*wxMDIFrameClassNameNoRedraw
= NULL
;
130 WXDLLIMPEXP_CORE
const wxChar
*wxMDIChildFrameClassName
= NULL
;
131 WXDLLIMPEXP_CORE
const wxChar
*wxMDIChildFrameClassNameNoRedraw
= NULL
;
133 // ----------------------------------------------------------------------------
135 // ----------------------------------------------------------------------------
137 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
139 // ===========================================================================
140 // wxGUIAppTraits implementation
141 // ===========================================================================
143 // private class which we use to pass parameters from BeforeChildWaitLoop() to
144 // AfterChildWaitLoop()
145 struct ChildWaitLoopData
147 ChildWaitLoopData(wxWindowDisabler
*wd_
, wxWindow
*winActive_
)
150 winActive
= winActive_
;
153 wxWindowDisabler
*wd
;
157 void *wxGUIAppTraits::BeforeChildWaitLoop()
160 We use a dirty hack here to disable all application windows (which we
161 must do because otherwise the calls to wxYield() could lead to some very
162 unexpected reentrancies in the users code) but to avoid losing
163 focus/activation entirely when the child process terminates which would
164 happen if we simply disabled everything using wxWindowDisabler. Indeed,
165 remember that Windows will never activate a disabled window and when the
166 last childs window is closed and Windows looks for a window to activate
167 all our windows are still disabled. There is no way to enable them in
168 time because we don't know when the childs windows are going to be
169 closed, so the solution we use here is to keep one special tiny frame
170 enabled all the time. Then when the child terminates it will get
171 activated and when we close it below -- after reenabling all the other
172 windows! -- the previously active window becomes activated again and
177 // first disable all existing windows
178 wxWindowDisabler
*wd
= new wxWindowDisabler
;
180 // then create an "invisible" frame: it has minimal size, is positioned
181 // (hopefully) outside the screen and doesn't appear on the taskbar
182 wxWindow
*winActive
= new wxFrame
184 wxTheApp
->GetTopWindow(),
187 wxPoint(32600, 32600),
189 wxDEFAULT_FRAME_STYLE
| wxFRAME_NO_TASKBAR
193 return new ChildWaitLoopData(wd
, winActive
);
196 void wxGUIAppTraits::AlwaysYield()
201 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
)
205 ChildWaitLoopData
* const data
= (ChildWaitLoopData
*)dataOrig
;
209 // finally delete the dummy frame and, as wd has been already destroyed and
210 // the other windows reenabled, the activation is going to return to the
211 // window which had had it before
212 data
->winActive
->Destroy();
214 // also delete the temporary data object itself
218 bool wxGUIAppTraits::DoMessageFromThreadWait()
220 // we should return false only if the app should exit, i.e. only if
221 // Dispatch() determines that the main event loop should terminate
222 wxEventLoopBase
* const evtLoop
= wxEventLoop::GetActive();
223 if ( !evtLoop
|| !evtLoop
->Pending() )
225 // no events means no quit event
229 return evtLoop
->Dispatch();
232 DWORD
wxGUIAppTraits::WaitForThread(WXHANDLE hThread
)
234 // if we don't have a running event loop, we shouldn't wait for the
235 // messages as we never remove them from the message queue and so we enter
236 // an infinite loop as MsgWaitForMultipleObjects() keeps returning
238 if ( !wxEventLoop::GetActive() )
239 return DoSimpleWaitForThread(hThread
);
241 return ::MsgWaitForMultipleObjects
243 1, // number of objects to wait for
244 (HANDLE
*)&hThread
, // the objects
245 false, // wait for any objects, not all
246 INFINITE
, // no timeout
247 QS_ALLINPUT
| // return as soon as there are any events
252 wxPortId
wxGUIAppTraits::GetToolkitVersion(int *majVer
, int *minVer
) const
257 // on Windows, the toolkit version is the same of the OS version
258 // as Windows integrates the OS kernel with the GUI toolkit.
259 info
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
260 if ( ::GetVersionEx(&info
) )
263 *majVer
= info
.dwMajorVersion
;
265 *minVer
= info
.dwMinorVersion
;
268 #if defined(__WXHANDHELD__) || defined(__WXWINCE__)
277 wxTimerImpl
*wxGUIAppTraits::CreateTimerImpl(wxTimer
*timer
)
279 return new wxMSWTimerImpl(timer
);
282 #endif // wxUSE_TIMER
284 wxEventLoopBase
* wxGUIAppTraits::CreateEventLoop()
286 return new wxEventLoop
;
289 // ---------------------------------------------------------------------------
290 // Stuff for using console from the GUI applications
291 // ---------------------------------------------------------------------------
295 #include <wx/dynlib.h>
301 Helper class to manipulate console from a GUI app.
303 Notice that console output is available in the GUI app only if:
304 - AttachConsole() returns TRUE (which means it never works under pre-XP)
305 - we have a valid STD_ERROR_HANDLE
306 - command history hasn't been changed since our startup
308 To check if all these conditions are verified, you need to simple call
309 IsOkToUse(). It will check the first two conditions above the first time it
310 is called (and if this fails, the subsequent calls will return immediately)
311 and also recheck the last one every time it is called.
313 class wxConsoleStderr
316 // default ctor does nothing, call Init() before using this class
319 m_hStderr
= INVALID_HANDLE_VALUE
;
329 if ( m_hStderr
!= INVALID_HANDLE_VALUE
)
331 if ( !::FreeConsole() )
333 wxLogLastError(_T("FreeConsole"));
338 // return true if we were successfully initialized and there had been no
339 // console activity which would interfere with our output since then
340 bool IsOkToUse() const
344 wxConsoleStderr
* const self
= wx_const_cast(wxConsoleStderr
*, this);
345 self
->m_ok
= self
->DoInit();
347 // no need to call IsHistoryUnchanged() as we just initialized
352 return m_ok
&& IsHistoryUnchanged();
356 // output the provided text on the console, return true if ok
357 bool Write(const wxString
& text
);
360 // called by Init() once only to do the real initialization
363 // retrieve the command line history into the provided buffer and return
365 int GetCommandHistory(wxWxCharBuffer
& buf
) const;
367 // check if the console history has changed
368 bool IsHistoryUnchanged() const;
370 int m_ok
; // initially -1, set to true or false by Init()
372 wxDynamicLibrary m_dllKernel32
;
374 HANDLE m_hStderr
; // console handle, if it's valid we must call
375 // FreeConsole() (even if m_ok != 1)
377 wxWxCharBuffer m_history
; // command history on startup
378 int m_historyLen
; // length command history buffer
380 wxCharBuffer m_data
; // data between empty line and cursor position
381 int m_dataLen
; // length data buffer
382 int m_dataLine
; // line offset
384 typedef DWORD (WINAPI
*GetConsoleCommandHistory_t
)(LPTSTR sCommands
,
387 typedef DWORD (WINAPI
*GetConsoleCommandHistoryLength_t
)(LPCTSTR sExeName
);
389 GetConsoleCommandHistory_t m_pfnGetConsoleCommandHistory
;
390 GetConsoleCommandHistoryLength_t m_pfnGetConsoleCommandHistoryLength
;
392 DECLARE_NO_COPY_CLASS(wxConsoleStderr
)
395 bool wxConsoleStderr::DoInit()
397 HANDLE hStderr
= ::GetStdHandle(STD_ERROR_HANDLE
);
399 if ( hStderr
== INVALID_HANDLE_VALUE
|| !hStderr
)
402 if ( !m_dllKernel32
.Load(_T("kernel32.dll")) )
405 typedef BOOL (WINAPI
*AttachConsole_t
)(DWORD dwProcessId
);
406 AttachConsole_t
wxDL_INIT_FUNC(pfn
, AttachConsole
, m_dllKernel32
);
408 if ( !pfnAttachConsole
|| !pfnAttachConsole(ATTACH_PARENT_PROCESS
) )
411 // console attached, set m_hStderr now to ensure that we free it in the
415 wxDL_INIT_FUNC_AW(m_pfn
, GetConsoleCommandHistory
, m_dllKernel32
);
416 if ( !m_pfnGetConsoleCommandHistory
)
419 wxDL_INIT_FUNC_AW(m_pfn
, GetConsoleCommandHistoryLength
, m_dllKernel32
);
420 if ( !m_pfnGetConsoleCommandHistoryLength
)
423 // remember the current command history to be able to compare with it later
424 // in IsHistoryUnchanged()
425 m_historyLen
= GetCommandHistory(m_history
);
430 // now find the first blank line above the current position
431 CONSOLE_SCREEN_BUFFER_INFO csbi
;
433 if ( !::GetConsoleScreenBufferInfo(m_hStderr
, &csbi
) )
435 wxLogLastError(_T("GetConsoleScreenBufferInfo"));
441 pos
.Y
= csbi
.dwCursorPosition
.Y
+ 1;
443 // we decide that a line is empty if first 4 characters are spaces
449 if ( !::ReadConsoleOutputCharacterA(m_hStderr
, buf
, WXSIZEOF(buf
),
452 wxLogLastError(_T("ReadConsoleOutputCharacterA"));
455 } while ( wxStrncmp(" ", buf
, WXSIZEOF(buf
)) != 0 );
457 // calculate line offset and length of data
458 m_dataLine
= csbi
.dwCursorPosition
.Y
- pos
.Y
;
459 m_dataLen
= m_dataLine
*csbi
.dwMaximumWindowSize
.X
+ csbi
.dwCursorPosition
.X
;
463 m_data
.extend(m_dataLen
);
464 if ( !::ReadConsoleOutputCharacterA(m_hStderr
, m_data
.data(), m_dataLen
,
467 wxLogLastError(_T("ReadConsoleOutputCharacterA"));
475 int wxConsoleStderr::GetCommandHistory(wxWxCharBuffer
& buf
) const
477 // these functions are internal and may only be called by cmd.exe
478 static const wxChar
*CMD_EXE
= _T("cmd.exe");
480 const int len
= m_pfnGetConsoleCommandHistoryLength(CMD_EXE
);
485 int len2
= m_pfnGetConsoleCommandHistory(buf
.data(), len
, CMD_EXE
);
488 // there seems to be a bug in the GetConsoleCommandHistoryA(), it
489 // returns the length of Unicode string and not ANSI one
491 #endif // !wxUSE_UNICODE
495 wxFAIL_MSG( _T("failed getting history?") );
502 bool wxConsoleStderr::IsHistoryUnchanged() const
504 wxASSERT_MSG( m_ok
== 1, _T("shouldn't be called if not initialized") );
506 // get (possibly changed) command history
507 wxWxCharBuffer history
;
508 const int historyLen
= GetCommandHistory(history
);
510 // and compare it with the original one
511 return historyLen
== m_historyLen
&& history
&&
512 memcmp(m_history
, history
, historyLen
) == 0;
515 bool wxConsoleStderr::Write(const wxString
& text
)
517 wxASSERT_MSG( m_hStderr
!= INVALID_HANDLE_VALUE
,
518 _T("should only be called if Init() returned true") );
520 // get current position
521 CONSOLE_SCREEN_BUFFER_INFO csbi
;
522 if ( !::GetConsoleScreenBufferInfo(m_hStderr
, &csbi
) )
524 wxLogLastError(_T("GetConsoleScreenBufferInfo"));
528 // and calculate new position (where is empty line)
529 csbi
.dwCursorPosition
.X
= 0;
530 csbi
.dwCursorPosition
.Y
-= m_dataLine
;
532 if ( !::SetConsoleCursorPosition(m_hStderr
, csbi
.dwCursorPosition
) )
534 wxLogLastError(_T("SetConsoleCursorPosition"));
539 if ( !::FillConsoleOutputCharacter(m_hStderr
, _T(' '), m_dataLen
,
540 csbi
.dwCursorPosition
, &ret
) )
542 wxLogLastError(_T("FillConsoleOutputCharacter"));
546 if ( !::WriteConsole(m_hStderr
, text
.wx_str(), text
.length(), &ret
, NULL
) )
548 wxLogLastError(_T("WriteConsole"));
552 WriteConsoleA(m_hStderr
, m_data
, m_dataLen
, &ret
, 0);
557 wxConsoleStderr s_consoleStderr
;
559 } // anonymous namespace
561 bool wxGUIAppTraits::CanUseStderr()
563 return s_consoleStderr
.IsOkToUse();
566 bool wxGUIAppTraits::WriteToStderr(const wxString
& text
)
568 return s_consoleStderr
.IsOkToUse() && s_consoleStderr
.Write(text
);
571 #endif // !__WXWINCE__
573 // ===========================================================================
574 // wxApp implementation
575 // ===========================================================================
577 int wxApp::m_nCmdShow
= SW_SHOWNORMAL
;
579 // ---------------------------------------------------------------------------
581 // ---------------------------------------------------------------------------
583 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
585 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
586 EVT_IDLE(wxApp::OnIdle
)
587 EVT_END_SESSION(wxApp::OnEndSession
)
588 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
591 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
593 class wxCallBaseCleanup
596 wxCallBaseCleanup(wxApp
*app
) : m_app(app
) { }
597 ~wxCallBaseCleanup() { if ( m_app
) m_app
->wxAppBase::CleanUp(); }
599 void Dismiss() { m_app
= NULL
; }
606 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
608 if ( !wxAppBase::Initialize(argc
, argv
) )
611 // ensure that base cleanup is done if we return too early
612 wxCallBaseCleanup
callBaseCleanup(this);
615 wxString tmp
= GetAppName();
616 tmp
+= wxT("ClassName");
617 wxCanvasClassName
= wxStrdup( tmp
.wc_str() );
619 wxCanvasClassNameNR
= wxStrdup( tmp
.wc_str() );
620 HWND hWnd
= FindWindow( wxCanvasClassNameNR
, NULL
);
623 SetForegroundWindow( (HWND
)(((DWORD
)hWnd
)|0x01) );
628 #if !defined(__WXMICROWIN__)
629 InitCommonControls();
630 #endif // !defined(__WXMICROWIN__)
632 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
633 SHInitExtraControls();
637 // Don't show a message box if a function such as SHGetFileInfo
638 // fails to find a device.
639 SetErrorMode(SEM_FAILCRITICALERRORS
|SEM_NOOPENFILEERRORBOX
);
644 RegisterWindowClasses();
646 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
647 wxSetKeyboardHook(true);
650 callBaseCleanup
.Dismiss();
655 // ---------------------------------------------------------------------------
656 // RegisterWindowClasses
657 // ---------------------------------------------------------------------------
659 // This function registers the given class name and stores a pointer to a
660 // heap-allocated copy of it at the specified location, it must be deleted
662 static void RegisterAndStoreClassName(const wxString
& uniqueClassName
,
663 const wxChar
**className
,
664 WNDCLASS
*lpWndClass
)
666 const size_t length
= uniqueClassName
.length() + 1; // for trailing NUL
667 wxChar
*newChars
= new wxChar
[length
];
668 wxStrncpy(newChars
, uniqueClassName
, length
);
669 *className
= newChars
;
670 lpWndClass
->lpszClassName
= *className
;
672 if ( !::RegisterClass(lpWndClass
) )
674 wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"), newChars
));
678 // This function registers the class defined by the provided WNDCLASS struct
679 // contents using a unique name constructed from the specified base name and
680 // and a suffix unique to this library instance. It also stores the generated
681 // unique names for normal and "no redraw" versions of the class in the
682 // provided variables, caller must delete their contents later.
683 static void RegisterClassWithUniqueNames(const wxString
& baseName
,
684 const wxChar
**className
,
685 const wxChar
**classNameNR
,
686 WNDCLASS
*lpWndClass
)
688 // for each class we register one with CS_(V|H)REDRAW style and one
689 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
690 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
691 static const long styleNoRedraw
= CS_DBLCLKS
;
693 const wxString
uniqueSuffix(wxString::Format(wxT("@%p"), className
));
695 wxString
uniqueClassName(baseName
+ uniqueSuffix
);
696 lpWndClass
->style
= styleNormal
;
697 RegisterAndStoreClassName(uniqueClassName
, className
, lpWndClass
);
699 // NB: remember that code elsewhere supposes that no redraw class names
700 // use the same names as normal classes with "NR" suffix so we must put
701 // "NR" at the end instead of using more natural baseName+"NR"+suffix
702 wxString
uniqueClassNameNR(uniqueClassName
+ wxT("NR"));
703 lpWndClass
->style
= styleNoRedraw
;
704 RegisterAndStoreClassName(uniqueClassNameNR
, classNameNR
, lpWndClass
);
707 // TODO we should only register classes really used by the app. For this it
708 // would be enough to just delay the class registration until an attempt
709 // to create a window of this class is made.
710 bool wxApp::RegisterWindowClasses()
713 wxZeroMemory(wndclass
);
715 // the fields which are common to all classes
716 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
717 wndclass
.hInstance
= wxhInstance
;
718 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
720 // register the class for all normal windows and "no redraw" frames
721 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
722 RegisterClassWithUniqueNames(wxT("wxWindowClass"),
724 &wxCanvasClassNameNR
,
727 // Register the MDI frame window class and "no redraw" MDI frame
728 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
729 RegisterClassWithUniqueNames(wxT("wxMDIFrameClass"),
730 &wxMDIFrameClassName
,
731 &wxMDIFrameClassNameNoRedraw
,
734 // Register the MDI child frame window class and "no redraw" MDI child frame
735 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
736 RegisterClassWithUniqueNames(wxT("wxMDIChildFrameClass"),
737 &wxMDIChildFrameClassName
,
738 &wxMDIChildFrameClassNameNoRedraw
,
744 // ---------------------------------------------------------------------------
745 // UnregisterWindowClasses
746 // ---------------------------------------------------------------------------
748 // This function unregisters the class with the given name and frees memory
749 // allocated for it by RegisterAndStoreClassName().
750 static bool UnregisterAndFreeClassName(const wxChar
**ppClassName
)
754 if ( !::UnregisterClass(*ppClassName
, wxhInstance
) )
757 wxString::Format(wxT("UnregisterClass(%s)"), *ppClassName
));
762 delete [] (wxChar
*) *ppClassName
;
768 bool wxApp::UnregisterWindowClasses()
772 #ifndef __WXMICROWIN__
773 if ( !UnregisterAndFreeClassName(&wxMDIFrameClassName
) )
776 if ( !UnregisterAndFreeClassName(&wxMDIFrameClassNameNoRedraw
) )
779 if ( !UnregisterAndFreeClassName(&wxMDIChildFrameClassName
) )
782 if ( !UnregisterAndFreeClassName(&wxMDIChildFrameClassNameNoRedraw
) )
785 if ( !UnregisterAndFreeClassName(&wxCanvasClassName
) )
788 if ( !UnregisterAndFreeClassName(&wxCanvasClassNameNR
) )
790 #endif // __WXMICROWIN__
795 void wxApp::CleanUp()
797 // all objects pending for deletion must be deleted first, otherwise
798 // UnregisterWindowClasses() call wouldn't succeed (because windows
799 // using the classes being unregistered still exist), so call the base
800 // class method first and only then do our clean up
801 wxAppBase::CleanUp();
803 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
804 wxSetKeyboardHook(false);
809 // for an EXE the classes are unregistered when it terminates but DLL may
810 // be loaded several times (load/unload/load) into the same process in
811 // which case the registration will fail after the first time if we don't
812 // unregister the classes now
813 UnregisterWindowClasses();
816 free( wxCanvasClassName
);
817 free( wxCanvasClassNameNR
);
821 // ----------------------------------------------------------------------------
823 // ----------------------------------------------------------------------------
827 m_printMode
= wxPRINT_WINDOWS
;
834 // ----------------------------------------------------------------------------
835 // wxApp idle handling
836 // ----------------------------------------------------------------------------
838 void wxApp::OnIdle(wxIdleEvent
& WXUNUSED(event
))
840 #if wxUSE_DC_CACHEING
841 // automated DC cache management: clear the cached DCs and bitmap
842 // if it's likely that the app has finished with them, that is, we
843 // get an idle event and we're not dragging anything.
844 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
845 wxMSWDCImpl::ClearCache();
846 #endif // wxUSE_DC_CACHEING
849 void wxApp::WakeUpIdle()
851 // Send the top window a dummy message so idle handler processing will
852 // start up again. Doing it this way ensures that the idle handler
853 // wakes up in the right thread (see also wxWakeUpMainThread() which does
854 // the same for the main app thread only)
855 wxWindow
* const topWindow
= wxTheApp
->GetTopWindow();
858 HWND hwndTop
= GetHwndOf(topWindow
);
860 // Do not post WM_NULL if there's already a pending WM_NULL to avoid
861 // overflowing the message queue.
863 // Notice that due to a limitation of PeekMessage() API (which handles
864 // 0,0 range specially), we have to check the range from 0-1 instead.
865 // This still makes it possible to overflow the queue with WM_NULLs by
866 // interspersing the calles to WakeUpIdle() with windows creation but
867 // it should be rather hard to do it accidentally.
869 if ( !::PeekMessage(&msg
, hwndTop
, 0, 1, PM_NOREMOVE
) ||
870 ::PeekMessage(&msg
, hwndTop
, 1, 1, PM_NOREMOVE
) )
872 if ( !::PostMessage(hwndTop
, WM_NULL
, 0, 0) )
874 // should never happen
875 wxLogLastError(wxT("PostMessage(WM_NULL)"));
881 // ----------------------------------------------------------------------------
882 // other wxApp event hanlders
883 // ----------------------------------------------------------------------------
885 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
887 // Windows will terminate the process soon after we return from
888 // WM_ENDSESSION handler or when we delete our last window, so make sure we
889 // at least execute our cleanup code before
891 // prevent the window from being destroyed when the corresponding wxTLW is
892 // destroyed: this will result in a leak of a HWND, of course, but who
893 // cares when the process is being killed anyhow
894 if ( !wxTopLevelWindows
.empty() )
895 wxTopLevelWindows
[0]->SetHWND(0);
897 const int rc
= OnExit();
901 // calling exit() instead of ExitProcess() or not doing anything at all and
902 // being killed by Windows has the advantage of executing the dtors of
907 // Default behaviour: close the application with prompts. The
908 // user can veto the close, and therefore the end session.
909 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
913 if (!GetTopWindow()->Close(!event
.CanVeto()))
918 // ----------------------------------------------------------------------------
919 // system DLL versions
920 // ----------------------------------------------------------------------------
922 // these functions have trivial inline implementations for CE
925 #if wxUSE_DYNLIB_CLASS
930 // helper function: retrieve the DLL version by using DllGetVersion(), returns
931 // 0 if the DLL doesn't export such function
932 int CallDllGetVersion(wxDynamicLibrary
& dll
)
934 // now check if the function is available during run-time
935 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dll
);
936 if ( !pfnDllGetVersion
)
940 dvi
.cbSize
= sizeof(dvi
);
942 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
945 wxLogApiError(_T("DllGetVersion"), hr
);
950 return 100*dvi
.dwMajorVersion
+ dvi
.dwMinorVersion
;
953 } // anonymous namespace
956 int wxApp::GetComCtl32Version()
960 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
961 // but as its value should be the same both times it doesn't matter
962 static int s_verComCtl32
= -1;
964 if ( s_verComCtl32
== -1 )
966 // we're prepared to handle the errors
969 // the DLL should really be available
970 wxDynamicLibrary
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
);
971 if ( !dllComCtl32
.IsLoaded() )
977 // try DllGetVersion() for recent DLLs
978 s_verComCtl32
= CallDllGetVersion(dllComCtl32
);
980 // if DllGetVersion() is unavailable either during compile or
981 // run-time, try to guess the version otherwise
982 if ( !s_verComCtl32
)
984 // InitCommonControlsEx is unique to 4.70 and later
985 void *pfn
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx"));
988 // not found, must be 4.00
993 // many symbols appeared in comctl32 4.71, could use any of
994 // them except may be DllInstall()
995 pfn
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB"));
998 // not found, must be 4.70
1003 // found, must be 4.71 or later
1004 s_verComCtl32
= 471;
1010 return s_verComCtl32
;
1014 int wxApp::GetShell32Version()
1016 static int s_verShell32
= -1;
1017 if ( s_verShell32
== -1 )
1019 // we're prepared to handle the errors
1022 wxDynamicLibrary
dllShell32(_T("shell32.dll"), wxDL_VERBATIM
);
1023 if ( dllShell32
.IsLoaded() )
1025 s_verShell32
= CallDllGetVersion(dllShell32
);
1027 if ( !s_verShell32
)
1029 // there doesn't seem to be any way to distinguish between 4.00
1030 // and 4.70 (starting from 4.71 we have DllGetVersion()) so
1031 // just assume it is 4.0
1035 else // failed load the DLL?
1041 return s_verShell32
;
1044 #else // !wxUSE_DYNLIB_CLASS
1047 int wxApp::GetComCtl32Version()
1053 int wxApp::GetShell32Version()
1058 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
1060 #endif // !__WXWINCE__
1062 // ----------------------------------------------------------------------------
1063 // Yield to incoming messages
1064 // ----------------------------------------------------------------------------
1066 bool wxApp::Yield(bool onlyIfNeeded
)
1069 static bool s_inYield
= false;
1073 if ( !onlyIfNeeded
)
1075 wxFAIL_MSG( wxT("wxYield called recursively" ) );
1081 // set the flag and don't forget to reset it before returning
1083 wxON_BLOCK_EXIT_SET(s_inYield
, false);
1087 // disable log flushing from here because a call to wxYield() shouldn't
1088 // normally result in message boxes popping up &c
1091 // ensure the logs will be flashed again when we exit
1092 wxON_BLOCK_EXIT0(wxLog::Resume
);
1096 // we don't want to process WM_QUIT from here - it should be processed in
1097 // the main event loop in order to stop it
1098 wxEventLoopGuarantor dummyLoopIfNeeded
;
1100 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
1101 msg
.message
!= WM_QUIT
)
1104 wxMutexGuiLeaveOrEnter();
1105 #endif // wxUSE_THREADS
1107 if ( !wxTheApp
->Dispatch() )
1111 // if there are pending events, we must process them.
1112 ProcessPendingEvents();
1117 #if wxUSE_EXCEPTIONS
1119 // ----------------------------------------------------------------------------
1120 // exception handling
1121 // ----------------------------------------------------------------------------
1123 bool wxApp::OnExceptionInMainLoop()
1125 // ask the user about what to do: use the Win32 API function here as it
1126 // could be dangerous to use any wxWidgets code in this state
1131 _T("An unhandled exception occurred. Press \"Abort\" to \
1132 terminate the program,\r\n\
1133 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
1134 _T("Unhandled exception"),
1135 MB_ABORTRETRYIGNORE
|
1145 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
1156 #endif // wxUSE_EXCEPTIONS