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 // ===========================================================================
233 // wxApp implementation
234 // ===========================================================================
236 int wxApp::m_nCmdShow
= SW_SHOWNORMAL
;
238 // ---------------------------------------------------------------------------
240 // ---------------------------------------------------------------------------
242 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
244 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
245 EVT_IDLE(wxApp::OnIdle
)
246 EVT_END_SESSION(wxApp::OnEndSession
)
247 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
250 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
252 class wxCallBaseCleanup
255 wxCallBaseCleanup(wxApp
*app
) : m_app(app
) { }
256 ~wxCallBaseCleanup() { if ( m_app
) m_app
->wxAppBase::CleanUp(); }
258 void Dismiss() { m_app
= NULL
; }
265 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
267 if ( !wxAppBase::Initialize(argc
, argv
) )
270 // ensure that base cleanup is done if we return too early
271 wxCallBaseCleanup
callBaseCleanup(this);
273 // the first thing to do is to check if we're trying to run an Unicode
274 // program under Win9x w/o MSLU emulation layer - if so, abort right now
275 // as it has no chance to work
276 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
277 if ( wxGetOsVersion() != wxWINDOWS_NT
&& wxGetOsVersion() != wxWINDOWS_CE
)
279 // note that we can use MessageBoxW() as it's implemented even under
280 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
281 // used by wxLocale are not
285 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
286 _T("wxWindows Fatal Error"),
292 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
294 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
295 InitCommonControls();
298 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
301 // for OLE, enlarge message queue to be as large as possible
303 while (!SetMessageQueue(iMsg
) && (iMsg
-= 8))
308 // we need to initialize OLE library
310 if ( FAILED(::CoInitializeEx(NULL
, COINIT_MULTITHREADED
)) )
311 wxLogError(_("Cannot initialize OLE"));
313 if ( FAILED(::OleInitialize(NULL
)) )
314 wxLogError(_("Cannot initialize OLE"));
321 if (!Ctl3dRegister(wxhInstance
))
322 wxLogError(wxT("Cannot register CTL3D"));
324 Ctl3dAutoSubclass(wxhInstance
);
325 #endif // wxUSE_CTL3D
327 RegisterWindowClasses();
329 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
330 // Create the brush for disabling bitmap buttons
333 lb
.lbStyle
= BS_PATTERN
;
335 lb
.lbHatch
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") );
338 wxDisableButtonBrush
= ::CreateBrushIndirect( & lb
);
339 ::DeleteObject( (HGDIOBJ
)lb
.lbHatch
);
341 //else: wxWindows resources are probably not linked in
348 wxWinHandleHash
= new wxWinHashTable(wxKEY_INTEGER
, 100);
350 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
351 // PLEASE DO NOT ALTER THIS.
352 #if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
353 extern char wxDummyChar
;
354 if (wxDummyChar
) wxDummyChar
++;
357 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
358 wxSetKeyboardHook(TRUE
);
361 callBaseCleanup
.Dismiss();
366 // ---------------------------------------------------------------------------
367 // RegisterWindowClasses
368 // ---------------------------------------------------------------------------
370 // TODO we should only register classes really used by the app. For this it
371 // would be enough to just delay the class registration until an attempt
372 // to create a window of this class is made.
373 bool wxApp::RegisterWindowClasses()
376 wxZeroMemory(wndclass
);
378 // for each class we register one with CS_(V|H)REDRAW style and one
379 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
380 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
381 static const long styleNoRedraw
= CS_DBLCLKS
;
383 // the fields which are common to all classes
384 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
385 wndclass
.hInstance
= wxhInstance
;
386 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
388 // Register the frame window class.
389 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1);
390 wndclass
.lpszClassName
= wxCanvasClassName
;
391 wndclass
.style
= styleNormal
;
393 if ( !RegisterClass(&wndclass
) )
395 wxLogLastError(wxT("RegisterClass(frame)"));
399 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
400 wndclass
.style
= styleNoRedraw
;
402 if ( !RegisterClass(&wndclass
) )
404 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
407 // Register the MDI frame window class.
408 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
409 wndclass
.lpszClassName
= wxMDIFrameClassName
;
410 wndclass
.style
= styleNormal
;
412 if ( !RegisterClass(&wndclass
) )
414 wxLogLastError(wxT("RegisterClass(MDI parent)"));
417 // "no redraw" MDI frame
418 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
419 wndclass
.style
= styleNoRedraw
;
421 if ( !RegisterClass(&wndclass
) )
423 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
426 // Register the MDI child frame window class.
427 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
428 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
429 wndclass
.style
= styleNormal
;
431 if ( !RegisterClass(&wndclass
) )
433 wxLogLastError(wxT("RegisterClass(MDI child)"));
436 // "no redraw" MDI child frame
437 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
438 wndclass
.style
= styleNoRedraw
;
440 if ( !RegisterClass(&wndclass
) )
442 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
448 // ---------------------------------------------------------------------------
449 // UnregisterWindowClasses
450 // ---------------------------------------------------------------------------
452 bool wxApp::UnregisterWindowClasses()
456 #ifndef __WXMICROWIN__
457 // MDI frame window class.
458 if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) )
460 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
465 // "no redraw" MDI frame
466 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) )
468 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
473 // MDI child frame window class.
474 if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) )
476 wxLogLastError(wxT("UnregisterClass(MDI child)"));
481 // "no redraw" MDI child frame
482 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) )
484 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
490 if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) )
492 wxLogLastError(wxT("UnregisterClass(canvas)"));
497 if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) )
499 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
503 #endif // __WXMICROWIN__
508 void wxApp::CleanUp()
510 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
511 wxSetKeyboardHook(FALSE
);
518 if ( wxDisableButtonBrush
)
519 ::DeleteObject( wxDisableButtonBrush
);
529 // for an EXE the classes are unregistered when it terminates but DLL may
530 // be loaded several times (load/unload/load) into the same process in
531 // which case the registration will fail after the first time if we don't
532 // unregister the classes now
533 UnregisterWindowClasses();
536 Ctl3dUnregister(wxhInstance
);
539 delete wxWinHandleHash
;
540 wxWinHandleHash
= NULL
;
542 wxAppBase::CleanUp();
545 // ----------------------------------------------------------------------------
547 // ----------------------------------------------------------------------------
551 m_printMode
= wxPRINT_WINDOWS
;
556 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
557 // don't come from main(), so we have to free them
561 // m_argv elements were allocated by wxStrdup()
565 // but m_argv itself -- using new[]
569 bool wxApp::Initialized()
576 #else // Assume initialized if DLL (no way of telling)
582 * Get and process a message, returning FALSE if WM_QUIT
583 * received (and also set the flag telling the app to exit the main loop)
586 bool wxApp::DoMessage()
588 BOOL rc
= ::GetMessage(&s_currentMsg
, (HWND
) NULL
, 0, 0);
598 // should never happen, but let's test for it nevertheless
599 wxLogLastError(wxT("GetMessage"));
604 wxASSERT_MSG( wxThread::IsMain(),
605 wxT("only the main thread can process Windows messages") );
607 static bool s_hadGuiLock
= TRUE
;
608 static wxMsgArray s_aSavedMessages
;
610 // if a secondary thread owns is doing GUI calls, save all messages for
611 // later processing - we can't process them right now because it will
612 // lead to recursive library calls (and we're not reentrant)
613 if ( !wxGuiOwnedByMainThread() )
615 s_hadGuiLock
= FALSE
;
617 // leave out WM_COMMAND messages: too dangerous, sometimes
618 // the message will be processed twice
619 if ( !wxIsWaitingForThread() ||
620 s_currentMsg
.message
!= WM_COMMAND
)
622 s_aSavedMessages
.Add(s_currentMsg
);
629 // have we just regained the GUI lock? if so, post all of the saved
632 // FIXME of course, it's not _exactly_ the same as processing the
633 // messages normally - expect some things to break...
638 size_t count
= s_aSavedMessages
.GetCount();
639 for ( size_t n
= 0; n
< count
; n
++ )
641 MSG
& msg
= s_aSavedMessages
[n
];
643 DoMessage((WXMSG
*)&msg
);
646 s_aSavedMessages
.Empty();
649 #endif // wxUSE_THREADS
651 // Process the message
652 DoMessage((WXMSG
*)&s_currentMsg
);
658 void wxApp::DoMessage(WXMSG
*pMsg
)
660 if ( !ProcessMessage(pMsg
) )
662 ::TranslateMessage((MSG
*)pMsg
);
663 ::DispatchMessage((MSG
*)pMsg
);
668 * Keep trying to process messages until WM_QUIT
671 * If there are messages to be processed, they will all be
672 * processed and OnIdle will not be called.
673 * When there are no more messages, OnIdle is called.
674 * If OnIdle requests more time,
675 * it will be repeatedly called so long as there are no pending messages.
676 * A 'feature' of this is that once OnIdle has decided that no more processing
677 * is required, then it won't get processing time until further messages
678 * are processed (it'll sit in DoMessage).
681 int wxApp::MainLoop()
685 while ( m_keepGoing
)
688 wxMutexGuiLeaveOrEnter();
689 #endif // wxUSE_THREADS
691 while ( !Pending() && ProcessIdle() )
694 // a message came or no more idle processing to do
698 return s_currentMsg
.wParam
;
701 void wxApp::ExitMainLoop()
703 // this will set m_keepGoing to FALSE a bit later
704 ::PostQuitMessage(0);
707 bool wxApp::Pending()
709 return ::PeekMessage(&s_currentMsg
, 0, 0, 0, PM_NOREMOVE
) != 0;
712 void wxApp::Dispatch()
718 * Give all windows a chance to preprocess
719 * the message. Some may have accelerator tables, or have
723 bool wxApp::ProcessMessage(WXMSG
*wxmsg
)
725 MSG
*msg
= (MSG
*)wxmsg
;
726 HWND hwnd
= msg
->hwnd
;
727 wxWindow
*wndThis
= wxGetWindowFromHWND((WXHWND
)hwnd
);
729 // this may happen if the event occured in a standard modeless dialog (the
730 // only example of which I know of is the find/replace dialog) - then call
731 // IsDialogMessage() to make TAB navigation in it work
734 // we need to find the dialog containing this control as
735 // IsDialogMessage() just eats all the messages (i.e. returns TRUE for
736 // them) if we call it for the control itself
737 while ( hwnd
&& ::GetWindowLong(hwnd
, GWL_STYLE
) & WS_CHILD
)
739 hwnd
= ::GetParent(hwnd
);
742 return hwnd
&& ::IsDialogMessage(hwnd
, msg
) != 0;
746 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
747 // popup the tooltip bubbles
748 if ( (msg
->message
== WM_MOUSEMOVE
) )
750 wxToolTip
*tt
= wndThis
->GetToolTip();
753 tt
->RelayEvent(wxmsg
);
756 #endif // wxUSE_TOOLTIPS
758 // allow the window to prevent certain messages from being
759 // translated/processed (this is currently used by wxTextCtrl to always
760 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
761 if ( !wndThis
->MSWShouldPreProcessMessage(wxmsg
) )
766 // try translations first: the accelerators override everything
769 for ( wnd
= wndThis
; wnd
; wnd
= wnd
->GetParent() )
771 if ( wnd
->MSWTranslateMessage(wxmsg
))
774 // stop at first top level window, i.e. don't try to process the key
775 // strokes originating in a dialog using the accelerators of the parent
776 // frame - this doesn't make much sense
777 if ( wnd
->IsTopLevel() )
781 // now try the other hooks (kbd navigation is handled here): we start from
782 // wndThis->GetParent() because wndThis->MSWProcessMessage() was already
784 for ( wnd
= wndThis
->GetParent(); wnd
; wnd
= wnd
->GetParent() )
786 if ( wnd
->MSWProcessMessage(wxmsg
) )
790 // no special preprocessing for this message, dispatch it normally
794 // this is a temporary hack and will be replaced by using wxEventLoop in the
797 // it is needed to allow other event loops (currently only one: the modal
798 // dialog one) to reset the OnIdle() semaphore because otherwise OnIdle()
799 // wouldn't do anything while a modal dialog shown from OnIdle() call is shown.
800 bool wxIsInOnIdleFlag
= FALSE
;
802 void wxApp::OnIdle(wxIdleEvent
& event
)
804 // Avoid recursion (via ProcessEvent default case)
805 if ( wxIsInOnIdleFlag
)
808 wxIsInOnIdleFlag
= TRUE
;
810 wxAppBase::OnIdle(event
);
812 #if wxUSE_DC_CACHEING
813 // automated DC cache management: clear the cached DCs and bitmap
814 // if it's likely that the app has finished with them, that is, we
815 // get an idle event and we're not dragging anything.
816 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
818 #endif // wxUSE_DC_CACHEING
820 wxIsInOnIdleFlag
= FALSE
;
823 void wxApp::WakeUpIdle()
825 // Send the top window a dummy message so idle handler processing will
826 // start up again. Doing it this way ensures that the idle handler
827 // wakes up in the right thread (see also wxWakeUpMainThread() which does
828 // the same for the main app thread only)
829 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
832 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
834 // should never happen
835 wxLogLastError(wxT("PostMessage(WM_NULL)"));
840 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
843 GetTopWindow()->Close(TRUE
);
846 // Default behaviour: close the application with prompts. The
847 // user can veto the close, and therefore the end session.
848 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
852 if (!GetTopWindow()->Close(!event
.CanVeto()))
858 int wxApp::GetComCtl32Version()
860 #if defined(__WXMICROWIN__) || defined(__WXWINCE__)
865 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
866 // but as its value should be the same both times it doesn't matter
867 static int s_verComCtl32
= -1;
869 if ( s_verComCtl32
== -1 )
871 // initally assume no comctl32.dll at all
874 // we're prepared to handle the errors
878 wxDynamicLibrary
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
);
880 // if so, then we can check for the version
881 if ( dllComCtl32
.IsLoaded() )
883 // try to use DllGetVersion() if available in _headers_
884 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32
);
885 if ( pfnDllGetVersion
)
888 dvi
.cbSize
= sizeof(dvi
);
890 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
893 wxLogApiError(_T("DllGetVersion"), hr
);
897 // this is incompatible with _WIN32_IE values, but
898 // compatible with the other values returned by
899 // GetComCtl32Version()
900 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
905 // if DllGetVersion() is unavailable either during compile or
906 // run-time, try to guess the version otherwise
907 if ( !s_verComCtl32
)
909 // InitCommonControlsEx is unique to 4.70 and later
910 void *pfn
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx"));
913 // not found, must be 4.00
918 // many symbols appeared in comctl32 4.71, could use any of
919 // them except may be DllInstall()
920 pfn
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB"));
923 // not found, must be 4.70
928 // found, must be 4.71 or later
936 return s_verComCtl32
;
937 #endif // Microwin/!Microwin
940 // Yield to incoming messages
942 bool wxApp::Yield(bool onlyIfNeeded
)
945 static bool s_inYield
= FALSE
;
948 // disable log flushing from here because a call to wxYield() shouldn't
949 // normally result in message boxes popping up &c
957 wxFAIL_MSG( wxT("wxYield called recursively" ) );
965 // we don't want to process WM_QUIT from here - it should be processed in
966 // the main event loop in order to stop it
968 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
969 msg
.message
!= WM_QUIT
)
972 wxMutexGuiLeaveOrEnter();
973 #endif // wxUSE_THREADS
975 if ( !wxTheApp
->DoMessage() )
979 // if there are pending events, we must process them.
980 ProcessPendingEvents();
983 // let the logs be flashed again