1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
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/thread.h"
61 // define the array of MSG strutures
62 WX_DECLARE_OBJARRAY(MSG
, wxMsgArray
);
64 #include "wx/arrimpl.cpp"
66 WX_DEFINE_OBJARRAY(wxMsgArray
);
67 #endif // wxUSE_THREADS
70 #include "wx/tooltip.h"
71 #endif // wxUSE_TOOLTIPS
73 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
74 // compilers don't support it (missing headers, libs, ...)
75 #if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
79 #endif // broken compilers
88 #if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__WXMICROWIN__)) && !defined(__CYGWIN10__))
92 // ----------------------------------------------------------------------------
93 // conditional compilation
94 // ----------------------------------------------------------------------------
96 // The macro _WIN32_IE is defined by commctrl.h (unless it had already been
97 // defined before) and shows us what common control features are available
98 // during the compile time (it doesn't mean that they will be available during
99 // the run-time, use GetComCtl32Version() to test for them!). The possible
102 // 0x0200 for comctl32.dll 4.00 shipped with Win95/NT 4.0
103 // 0x0300 4.70 IE 3.x
104 // 0x0400 4.71 IE 4.0
105 // 0x0401 4.72 IE 4.01 and Win98
106 // 0x0500 5.80 IE 5.x
107 // 0x0500 5.81 Win2k/ME
111 // use maximal set of features by default, we check for them during
113 #define _WIN32_IE 0x0600
116 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
117 !defined(__CYGWIN__) && !defined(__WXWINCE__) && \
118 (!defined(_MSC_VER) || (_MSC_VER > 1100))
122 // ---------------------------------------------------------------------------
124 // ---------------------------------------------------------------------------
126 extern wxList WXDLLEXPORT wxPendingDelete
;
128 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
129 extern void wxSetKeyboardHook(bool doIt
);
134 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
135 // with NR suffix - wxWindow::MSWCreate() supposes this
136 const wxChar
*wxCanvasClassName
= wxT("wxWindowClass");
137 const wxChar
*wxCanvasClassNameNR
= wxT("wxWindowClassNR");
138 const wxChar
*wxMDIFrameClassName
= wxT("wxMDIFrameClass");
139 const wxChar
*wxMDIFrameClassNameNoRedraw
= wxT("wxMDIFrameClassNR");
140 const wxChar
*wxMDIChildFrameClassName
= wxT("wxMDIChildFrameClass");
141 const wxChar
*wxMDIChildFrameClassNameNoRedraw
= wxT("wxMDIChildFrameClassNR");
143 HBRUSH wxDisableButtonBrush
= (HBRUSH
) 0;
145 // ----------------------------------------------------------------------------
147 // ----------------------------------------------------------------------------
149 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
151 // ===========================================================================
152 // wxGUIAppTraits implementation
153 // ===========================================================================
155 // private class which we use to pass parameters from BeforeChildWaitLoop() to
156 // AfterChildWaitLoop()
157 struct ChildWaitLoopData
159 ChildWaitLoopData(wxWindowDisabler
*wd_
, wxWindow
*winActive_
)
162 winActive
= winActive_
;
165 wxWindowDisabler
*wd
;
169 void *wxGUIAppTraits::BeforeChildWaitLoop()
172 We use a dirty hack here to disable all application windows (which we
173 must do because otherwise the calls to wxYield() could lead to some very
174 unexpected reentrancies in the users code) but to avoid losing
175 focus/activation entirely when the child process terminates which would
176 happen if we simply disabled everything using wxWindowDisabler. Indeed,
177 remember that Windows will never activate a disabled window and when the
178 last childs window is closed and Windows looks for a window to activate
179 all our windows are still disabled. There is no way to enable them in
180 time because we don't know when the childs windows are going to be
181 closed, so the solution we use here is to keep one special tiny frame
182 enabled all the time. Then when the child terminates it will get
183 activated and when we close it below -- after reenabling all the other
184 windows! -- the previously active window becomes activated again and
189 // first disable all existing windows
190 wxWindowDisabler
*wd
= new wxWindowDisabler
;
192 // then create an "invisible" frame: it has minimal size, is positioned
193 // (hopefully) outside the screen and doesn't appear on the taskbar
194 wxWindow
*winActive
= new wxFrame
196 wxTheApp
->GetTopWindow(),
199 wxPoint(32600, 32600),
201 wxDEFAULT_FRAME_STYLE
| wxFRAME_NO_TASKBAR
205 return new ChildWaitLoopData(wd
, winActive
);
208 void wxGUIAppTraits::AlwaysYield()
213 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
)
217 const ChildWaitLoopData
* const data
= (ChildWaitLoopData
*)dataOrig
;
221 // finally delete the dummy frame and, as wd has been already destroyed and
222 // the other windows reenabled, the activation is going to return to the
223 // window which had had it before
224 data
->winActive
->Destroy();
227 bool wxGUIAppTraits::DoMessageFromThreadWait()
229 return !wxTheApp
|| wxTheApp
->DoMessage();
232 wxToolkitInfo
& wxGUIAppTraits::GetToolkitInfo()
234 static wxToolkitInfo info
;
235 wxToolkitInfo
& baseInfo
= wxAppTraits::GetToolkitInfo();
236 info
.versionMajor
= baseInfo
.versionMajor
;
237 info
.versionMinor
= baseInfo
.versionMinor
;
238 info
.os
= baseInfo
.os
;
239 info
.shortName
= _T("msw");
240 info
.name
= _T("wxMSW");
241 #ifdef __WXUNIVERSAL__
242 info
.shortName
<< _T("univ");
243 info
.name
<< _T("/wxUniversal");
248 // ===========================================================================
249 // wxApp implementation
250 // ===========================================================================
252 int wxApp::m_nCmdShow
= SW_SHOWNORMAL
;
254 // ---------------------------------------------------------------------------
256 // ---------------------------------------------------------------------------
258 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
260 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
261 EVT_IDLE(wxApp::OnIdle
)
262 EVT_END_SESSION(wxApp::OnEndSession
)
263 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
266 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
268 class wxCallBaseCleanup
271 wxCallBaseCleanup(wxApp
*app
) : m_app(app
) { }
272 ~wxCallBaseCleanup() { if ( m_app
) m_app
->wxAppBase::CleanUp(); }
274 void Dismiss() { m_app
= NULL
; }
281 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
283 if ( !wxAppBase::Initialize(argc
, argv
) )
286 // ensure that base cleanup is done if we return too early
287 wxCallBaseCleanup
callBaseCleanup(this);
289 // the first thing to do is to check if we're trying to run an Unicode
290 // program under Win9x w/o MSLU emulation layer - if so, abort right now
291 // as it has no chance to work
292 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
293 if ( wxGetOsVersion() != wxWINDOWS_NT
&& wxGetOsVersion() != wxWINDOWS_CE
)
295 // note that we can use MessageBoxW() as it's implemented even under
296 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
297 // used by wxLocale are not
301 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
302 _T("wxWindows Fatal Error"),
308 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
310 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
311 InitCommonControls();
314 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
317 // for OLE, enlarge message queue to be as large as possible
319 while (!SetMessageQueue(iMsg
) && (iMsg
-= 8))
324 // we need to initialize OLE library
326 if ( FAILED(::CoInitializeEx(NULL
, COINIT_MULTITHREADED
)) )
327 wxLogError(_("Cannot initialize OLE"));
329 if ( FAILED(::OleInitialize(NULL
)) )
330 wxLogError(_("Cannot initialize OLE"));
337 if (!Ctl3dRegister(wxhInstance
))
338 wxLogError(wxT("Cannot register CTL3D"));
340 Ctl3dAutoSubclass(wxhInstance
);
341 #endif // wxUSE_CTL3D
343 RegisterWindowClasses();
345 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
346 // Create the brush for disabling bitmap buttons
349 lb
.lbStyle
= BS_PATTERN
;
351 lb
.lbHatch
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") );
354 wxDisableButtonBrush
= ::CreateBrushIndirect( & lb
);
355 ::DeleteObject( (HGDIOBJ
)lb
.lbHatch
);
357 //else: wxWindows resources are probably not linked in
364 wxWinHandleHash
= new wxWinHashTable(wxKEY_INTEGER
, 100);
366 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
367 // PLEASE DO NOT ALTER THIS.
368 #if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
369 extern char wxDummyChar
;
370 if (wxDummyChar
) wxDummyChar
++;
373 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
374 wxSetKeyboardHook(TRUE
);
377 callBaseCleanup
.Dismiss();
382 // ---------------------------------------------------------------------------
383 // RegisterWindowClasses
384 // ---------------------------------------------------------------------------
386 // TODO we should only register classes really used by the app. For this it
387 // would be enough to just delay the class registration until an attempt
388 // to create a window of this class is made.
389 bool wxApp::RegisterWindowClasses()
392 wxZeroMemory(wndclass
);
394 // for each class we register one with CS_(V|H)REDRAW style and one
395 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
396 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
397 static const long styleNoRedraw
= CS_DBLCLKS
;
399 // the fields which are common to all classes
400 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
401 wndclass
.hInstance
= wxhInstance
;
402 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
404 // Register the frame window class.
405 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1);
406 wndclass
.lpszClassName
= wxCanvasClassName
;
407 wndclass
.style
= styleNormal
;
409 if ( !RegisterClass(&wndclass
) )
411 wxLogLastError(wxT("RegisterClass(frame)"));
415 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
416 wndclass
.style
= styleNoRedraw
;
418 if ( !RegisterClass(&wndclass
) )
420 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
423 // Register the MDI frame window class.
424 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
425 wndclass
.lpszClassName
= wxMDIFrameClassName
;
426 wndclass
.style
= styleNormal
;
428 if ( !RegisterClass(&wndclass
) )
430 wxLogLastError(wxT("RegisterClass(MDI parent)"));
433 // "no redraw" MDI frame
434 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
435 wndclass
.style
= styleNoRedraw
;
437 if ( !RegisterClass(&wndclass
) )
439 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
442 // Register the MDI child frame window class.
443 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
444 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
445 wndclass
.style
= styleNormal
;
447 if ( !RegisterClass(&wndclass
) )
449 wxLogLastError(wxT("RegisterClass(MDI child)"));
452 // "no redraw" MDI child frame
453 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
454 wndclass
.style
= styleNoRedraw
;
456 if ( !RegisterClass(&wndclass
) )
458 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
464 // ---------------------------------------------------------------------------
465 // UnregisterWindowClasses
466 // ---------------------------------------------------------------------------
468 bool wxApp::UnregisterWindowClasses()
472 #ifndef __WXMICROWIN__
473 // MDI frame window class.
474 if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) )
476 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
481 // "no redraw" MDI frame
482 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) )
484 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
489 // MDI child frame window class.
490 if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) )
492 wxLogLastError(wxT("UnregisterClass(MDI child)"));
497 // "no redraw" MDI child frame
498 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) )
500 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
506 if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) )
508 wxLogLastError(wxT("UnregisterClass(canvas)"));
513 if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) )
515 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
519 #endif // __WXMICROWIN__
524 void wxApp::CleanUp()
526 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
527 wxSetKeyboardHook(FALSE
);
534 if ( wxDisableButtonBrush
)
535 ::DeleteObject( wxDisableButtonBrush
);
545 // for an EXE the classes are unregistered when it terminates but DLL may
546 // be loaded several times (load/unload/load) into the same process in
547 // which case the registration will fail after the first time if we don't
548 // unregister the classes now
549 UnregisterWindowClasses();
552 Ctl3dUnregister(wxhInstance
);
555 delete wxWinHandleHash
;
556 wxWinHandleHash
= NULL
;
558 wxAppBase::CleanUp();
561 // ----------------------------------------------------------------------------
563 // ----------------------------------------------------------------------------
567 m_printMode
= wxPRINT_WINDOWS
;
572 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
573 // don't come from main(), so we have to free them
577 // m_argv elements were allocated by wxStrdup()
581 // but m_argv itself -- using new[]
585 bool wxApp::Initialized()
592 #else // Assume initialized if DLL (no way of telling)
598 * Get and process a message, returning FALSE if WM_QUIT
599 * received (and also set the flag telling the app to exit the main loop)
602 bool wxApp::DoMessage()
604 BOOL rc
= ::GetMessage(&s_currentMsg
, (HWND
) NULL
, 0, 0);
614 // should never happen, but let's test for it nevertheless
615 wxLogLastError(wxT("GetMessage"));
620 wxASSERT_MSG( wxThread::IsMain(),
621 wxT("only the main thread can process Windows messages") );
623 static bool s_hadGuiLock
= TRUE
;
624 static wxMsgArray s_aSavedMessages
;
626 // if a secondary thread owns is doing GUI calls, save all messages for
627 // later processing - we can't process them right now because it will
628 // lead to recursive library calls (and we're not reentrant)
629 if ( !wxGuiOwnedByMainThread() )
631 s_hadGuiLock
= FALSE
;
633 // leave out WM_COMMAND messages: too dangerous, sometimes
634 // the message will be processed twice
635 if ( !wxIsWaitingForThread() ||
636 s_currentMsg
.message
!= WM_COMMAND
)
638 s_aSavedMessages
.Add(s_currentMsg
);
645 // have we just regained the GUI lock? if so, post all of the saved
648 // FIXME of course, it's not _exactly_ the same as processing the
649 // messages normally - expect some things to break...
654 size_t count
= s_aSavedMessages
.GetCount();
655 for ( size_t n
= 0; n
< count
; n
++ )
657 MSG
& msg
= s_aSavedMessages
[n
];
659 DoMessage((WXMSG
*)&msg
);
662 s_aSavedMessages
.Empty();
665 #endif // wxUSE_THREADS
667 // Process the message
668 DoMessage((WXMSG
*)&s_currentMsg
);
674 void wxApp::DoMessage(WXMSG
*pMsg
)
676 if ( !ProcessMessage(pMsg
) )
678 ::TranslateMessage((MSG
*)pMsg
);
679 ::DispatchMessage((MSG
*)pMsg
);
684 * Keep trying to process messages until WM_QUIT
687 * If there are messages to be processed, they will all be
688 * processed and OnIdle will not be called.
689 * When there are no more messages, OnIdle is called.
690 * If OnIdle requests more time,
691 * it will be repeatedly called so long as there are no pending messages.
692 * A 'feature' of this is that once OnIdle has decided that no more processing
693 * is required, then it won't get processing time until further messages
694 * are processed (it'll sit in DoMessage).
697 int wxApp::MainLoop()
701 while ( m_keepGoing
)
704 wxMutexGuiLeaveOrEnter();
705 #endif // wxUSE_THREADS
707 while ( !Pending() && ProcessIdle() )
710 // a message came or no more idle processing to do
714 return s_currentMsg
.wParam
;
717 void wxApp::ExitMainLoop()
719 // this will set m_keepGoing to FALSE a bit later
720 ::PostQuitMessage(0);
723 bool wxApp::Pending()
725 return ::PeekMessage(&s_currentMsg
, 0, 0, 0, PM_NOREMOVE
) != 0;
728 void wxApp::Dispatch()
734 * Give all windows a chance to preprocess
735 * the message. Some may have accelerator tables, or have
739 bool wxApp::ProcessMessage(WXMSG
*wxmsg
)
741 MSG
*msg
= (MSG
*)wxmsg
;
742 HWND hwnd
= msg
->hwnd
;
743 wxWindow
*wndThis
= wxGetWindowFromHWND((WXHWND
)hwnd
);
745 // this may happen if the event occured in a standard modeless dialog (the
746 // only example of which I know of is the find/replace dialog) - then call
747 // IsDialogMessage() to make TAB navigation in it work
750 // we need to find the dialog containing this control as
751 // IsDialogMessage() just eats all the messages (i.e. returns TRUE for
752 // them) if we call it for the control itself
753 while ( hwnd
&& ::GetWindowLong(hwnd
, GWL_STYLE
) & WS_CHILD
)
755 hwnd
= ::GetParent(hwnd
);
758 return hwnd
&& ::IsDialogMessage(hwnd
, msg
) != 0;
762 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
763 // popup the tooltip bubbles
764 if ( (msg
->message
== WM_MOUSEMOVE
) )
766 wxToolTip
*tt
= wndThis
->GetToolTip();
769 tt
->RelayEvent(wxmsg
);
772 #endif // wxUSE_TOOLTIPS
774 // allow the window to prevent certain messages from being
775 // translated/processed (this is currently used by wxTextCtrl to always
776 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
777 if ( !wndThis
->MSWShouldPreProcessMessage(wxmsg
) )
782 // try translations first: the accelerators override everything
785 for ( wnd
= wndThis
; wnd
; wnd
= wnd
->GetParent() )
787 if ( wnd
->MSWTranslateMessage(wxmsg
))
790 // stop at first top level window, i.e. don't try to process the key
791 // strokes originating in a dialog using the accelerators of the parent
792 // frame - this doesn't make much sense
793 if ( wnd
->IsTopLevel() )
797 // now try the other hooks (kbd navigation is handled here): we start from
798 // wndThis->GetParent() because wndThis->MSWProcessMessage() was already
800 for ( wnd
= wndThis
->GetParent(); wnd
; wnd
= wnd
->GetParent() )
802 if ( wnd
->MSWProcessMessage(wxmsg
) )
806 // no special preprocessing for this message, dispatch it normally
810 // this is a temporary hack and will be replaced by using wxEventLoop in the
813 // it is needed to allow other event loops (currently only one: the modal
814 // dialog one) to reset the OnIdle() semaphore because otherwise OnIdle()
815 // wouldn't do anything while a modal dialog shown from OnIdle() call is shown.
816 bool wxIsInOnIdleFlag
= FALSE
;
818 void wxApp::OnIdle(wxIdleEvent
& event
)
820 // Avoid recursion (via ProcessEvent default case)
821 if ( wxIsInOnIdleFlag
)
824 wxIsInOnIdleFlag
= TRUE
;
826 wxAppBase::OnIdle(event
);
828 #if wxUSE_DC_CACHEING
829 // automated DC cache management: clear the cached DCs and bitmap
830 // if it's likely that the app has finished with them, that is, we
831 // get an idle event and we're not dragging anything.
832 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
834 #endif // wxUSE_DC_CACHEING
836 wxIsInOnIdleFlag
= FALSE
;
839 void wxApp::WakeUpIdle()
841 // Send the top window a dummy message so idle handler processing will
842 // start up again. Doing it this way ensures that the idle handler
843 // wakes up in the right thread (see also wxWakeUpMainThread() which does
844 // the same for the main app thread only)
845 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
848 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
850 // should never happen
851 wxLogLastError(wxT("PostMessage(WM_NULL)"));
856 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
859 GetTopWindow()->Close(TRUE
);
862 // Default behaviour: close the application with prompts. The
863 // user can veto the close, and therefore the end session.
864 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
868 if (!GetTopWindow()->Close(!event
.CanVeto()))
874 int wxApp::GetComCtl32Version()
876 #if defined(__WXMICROWIN__) || defined(__WXWINCE__)
881 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
882 // but as its value should be the same both times it doesn't matter
883 static int s_verComCtl32
= -1;
885 if ( s_verComCtl32
== -1 )
887 // initally assume no comctl32.dll at all
890 // we're prepared to handle the errors
894 wxDynamicLibrary
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
);
896 // if so, then we can check for the version
897 if ( dllComCtl32
.IsLoaded() )
899 // try to use DllGetVersion() if available in _headers_
900 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32
);
901 if ( pfnDllGetVersion
)
904 dvi
.cbSize
= sizeof(dvi
);
906 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
909 wxLogApiError(_T("DllGetVersion"), hr
);
913 // this is incompatible with _WIN32_IE values, but
914 // compatible with the other values returned by
915 // GetComCtl32Version()
916 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
921 // if DllGetVersion() is unavailable either during compile or
922 // run-time, try to guess the version otherwise
923 if ( !s_verComCtl32
)
925 // InitCommonControlsEx is unique to 4.70 and later
926 void *pfn
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx"));
929 // not found, must be 4.00
934 // many symbols appeared in comctl32 4.71, could use any of
935 // them except may be DllInstall()
936 pfn
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB"));
939 // not found, must be 4.70
944 // found, must be 4.71 or later
952 return s_verComCtl32
;
953 #endif // Microwin/!Microwin
956 // Yield to incoming messages
958 bool wxApp::Yield(bool onlyIfNeeded
)
961 static bool s_inYield
= FALSE
;
964 // disable log flushing from here because a call to wxYield() shouldn't
965 // normally result in message boxes popping up &c
973 wxFAIL_MSG( wxT("wxYield called recursively" ) );
981 // we don't want to process WM_QUIT from here - it should be processed in
982 // the main event loop in order to stop it
984 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
985 msg
.message
!= WM_QUIT
)
988 wxMutexGuiLeaveOrEnter();
989 #endif // wxUSE_THREADS
991 if ( !wxTheApp
->DoMessage() )
995 // if there are pending events, we must process them.
996 ProcessPendingEvents();
999 // let the logs be flashed again