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/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 #include "wx/msw/wrapcctl.h"
90 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
91 !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \
92 (!defined(_MSC_VER) || (_MSC_VER > 1100))
96 // ---------------------------------------------------------------------------
98 // ---------------------------------------------------------------------------
100 extern wxList WXDLLEXPORT wxPendingDelete
;
102 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
103 extern void wxSetKeyboardHook(bool doIt
);
108 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
109 // with NR suffix - wxWindow::MSWCreate() supposes this
110 const wxChar
*wxCanvasClassName
= wxT("wxWindowClass");
111 const wxChar
*wxCanvasClassNameNR
= wxT("wxWindowClassNR");
112 const wxChar
*wxMDIFrameClassName
= wxT("wxMDIFrameClass");
113 const wxChar
*wxMDIFrameClassNameNoRedraw
= wxT("wxMDIFrameClassNR");
114 const wxChar
*wxMDIChildFrameClassName
= wxT("wxMDIChildFrameClass");
115 const wxChar
*wxMDIChildFrameClassNameNoRedraw
= wxT("wxMDIChildFrameClassNR");
117 HBRUSH wxDisableButtonBrush
= (HBRUSH
) 0;
119 // ----------------------------------------------------------------------------
121 // ----------------------------------------------------------------------------
123 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
125 // ===========================================================================
126 // wxGUIAppTraits implementation
127 // ===========================================================================
129 // private class which we use to pass parameters from BeforeChildWaitLoop() to
130 // AfterChildWaitLoop()
131 struct ChildWaitLoopData
133 ChildWaitLoopData(wxWindowDisabler
*wd_
, wxWindow
*winActive_
)
136 winActive
= winActive_
;
139 wxWindowDisabler
*wd
;
143 void *wxGUIAppTraits::BeforeChildWaitLoop()
146 We use a dirty hack here to disable all application windows (which we
147 must do because otherwise the calls to wxYield() could lead to some very
148 unexpected reentrancies in the users code) but to avoid losing
149 focus/activation entirely when the child process terminates which would
150 happen if we simply disabled everything using wxWindowDisabler. Indeed,
151 remember that Windows will never activate a disabled window and when the
152 last childs window is closed and Windows looks for a window to activate
153 all our windows are still disabled. There is no way to enable them in
154 time because we don't know when the childs windows are going to be
155 closed, so the solution we use here is to keep one special tiny frame
156 enabled all the time. Then when the child terminates it will get
157 activated and when we close it below -- after reenabling all the other
158 windows! -- the previously active window becomes activated again and
163 // first disable all existing windows
164 wxWindowDisabler
*wd
= new wxWindowDisabler
;
166 // then create an "invisible" frame: it has minimal size, is positioned
167 // (hopefully) outside the screen and doesn't appear on the taskbar
168 wxWindow
*winActive
= new wxFrame
170 wxTheApp
->GetTopWindow(),
173 wxPoint(32600, 32600),
175 wxDEFAULT_FRAME_STYLE
| wxFRAME_NO_TASKBAR
179 return new ChildWaitLoopData(wd
, winActive
);
182 void wxGUIAppTraits::AlwaysYield()
187 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
)
191 const ChildWaitLoopData
* const data
= (ChildWaitLoopData
*)dataOrig
;
195 // finally delete the dummy frame and, as wd has been already destroyed and
196 // the other windows reenabled, the activation is going to return to the
197 // window which had had it before
198 data
->winActive
->Destroy();
201 bool wxGUIAppTraits::DoMessageFromThreadWait()
203 return !wxTheApp
|| wxTheApp
->DoMessage();
206 wxToolkitInfo
& wxGUIAppTraits::GetToolkitInfo()
208 static wxToolkitInfo info
;
209 wxToolkitInfo
& baseInfo
= wxAppTraits::GetToolkitInfo();
210 info
.versionMajor
= baseInfo
.versionMajor
;
211 info
.versionMinor
= baseInfo
.versionMinor
;
212 info
.os
= baseInfo
.os
;
213 info
.shortName
= _T("msw");
214 info
.name
= _T("wxMSW");
215 #ifdef __WXUNIVERSAL__
216 info
.shortName
<< _T("univ");
217 info
.name
<< _T("/wxUniversal");
222 // ===========================================================================
223 // wxApp implementation
224 // ===========================================================================
226 int wxApp::m_nCmdShow
= SW_SHOWNORMAL
;
228 // ---------------------------------------------------------------------------
230 // ---------------------------------------------------------------------------
232 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
234 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
235 EVT_IDLE(wxApp::OnIdle
)
236 EVT_END_SESSION(wxApp::OnEndSession
)
237 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
240 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
242 class wxCallBaseCleanup
245 wxCallBaseCleanup(wxApp
*app
) : m_app(app
) { }
246 ~wxCallBaseCleanup() { if ( m_app
) m_app
->wxAppBase::CleanUp(); }
248 void Dismiss() { m_app
= NULL
; }
255 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
257 if ( !wxAppBase::Initialize(argc
, argv
) )
260 // ensure that base cleanup is done if we return too early
261 wxCallBaseCleanup
callBaseCleanup(this);
263 // the first thing to do is to check if we're trying to run an Unicode
264 // program under Win9x w/o MSLU emulation layer - if so, abort right now
265 // as it has no chance to work
266 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
267 if ( wxGetOsVersion() != wxWINDOWS_NT
&& wxGetOsVersion() != wxWINDOWS_CE
)
269 // note that we can use MessageBoxW() as it's implemented even under
270 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
271 // used by wxLocale are not
275 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
276 _T("wxWindows Fatal Error"),
282 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
284 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
285 InitCommonControls();
288 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
291 // for OLE, enlarge message queue to be as large as possible
293 while (!SetMessageQueue(iMsg
) && (iMsg
-= 8))
298 // we need to initialize OLE library
300 if ( FAILED(::CoInitializeEx(NULL
, COINIT_MULTITHREADED
)) )
301 wxLogError(_("Cannot initialize OLE"));
303 if ( FAILED(::OleInitialize(NULL
)) )
304 wxLogError(_("Cannot initialize OLE"));
311 if (!Ctl3dRegister(wxhInstance
))
312 wxLogError(wxT("Cannot register CTL3D"));
314 Ctl3dAutoSubclass(wxhInstance
);
315 #endif // wxUSE_CTL3D
317 RegisterWindowClasses();
319 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
320 // Create the brush for disabling bitmap buttons
323 lb
.lbStyle
= BS_PATTERN
;
325 lb
.lbHatch
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") );
328 wxDisableButtonBrush
= ::CreateBrushIndirect( & lb
);
329 ::DeleteObject( (HGDIOBJ
)lb
.lbHatch
);
331 //else: wxWindows resources are probably not linked in
338 wxWinHandleHash
= new wxWinHashTable(wxKEY_INTEGER
, 100);
340 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
341 // PLEASE DO NOT ALTER THIS.
342 #if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
343 extern char wxDummyChar
;
344 if (wxDummyChar
) wxDummyChar
++;
347 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
348 wxSetKeyboardHook(TRUE
);
351 callBaseCleanup
.Dismiss();
356 // ---------------------------------------------------------------------------
357 // RegisterWindowClasses
358 // ---------------------------------------------------------------------------
360 // TODO we should only register classes really used by the app. For this it
361 // would be enough to just delay the class registration until an attempt
362 // to create a window of this class is made.
363 bool wxApp::RegisterWindowClasses()
366 wxZeroMemory(wndclass
);
368 // for each class we register one with CS_(V|H)REDRAW style and one
369 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
370 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
371 static const long styleNoRedraw
= CS_DBLCLKS
;
373 // the fields which are common to all classes
374 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
375 wndclass
.hInstance
= wxhInstance
;
376 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
378 // Register the frame window class.
379 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1);
380 wndclass
.lpszClassName
= wxCanvasClassName
;
381 wndclass
.style
= styleNormal
;
383 if ( !RegisterClass(&wndclass
) )
385 wxLogLastError(wxT("RegisterClass(frame)"));
389 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
390 wndclass
.style
= styleNoRedraw
;
392 if ( !RegisterClass(&wndclass
) )
394 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
397 // Register the MDI frame window class.
398 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
399 wndclass
.lpszClassName
= wxMDIFrameClassName
;
400 wndclass
.style
= styleNormal
;
402 if ( !RegisterClass(&wndclass
) )
404 wxLogLastError(wxT("RegisterClass(MDI parent)"));
407 // "no redraw" MDI frame
408 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
409 wndclass
.style
= styleNoRedraw
;
411 if ( !RegisterClass(&wndclass
) )
413 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
416 // Register the MDI child frame window class.
417 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
418 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
419 wndclass
.style
= styleNormal
;
421 if ( !RegisterClass(&wndclass
) )
423 wxLogLastError(wxT("RegisterClass(MDI child)"));
426 // "no redraw" MDI child frame
427 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
428 wndclass
.style
= styleNoRedraw
;
430 if ( !RegisterClass(&wndclass
) )
432 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
438 // ---------------------------------------------------------------------------
439 // UnregisterWindowClasses
440 // ---------------------------------------------------------------------------
442 bool wxApp::UnregisterWindowClasses()
446 #ifndef __WXMICROWIN__
447 // MDI frame window class.
448 if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) )
450 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
455 // "no redraw" MDI frame
456 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) )
458 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
463 // MDI child frame window class.
464 if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) )
466 wxLogLastError(wxT("UnregisterClass(MDI child)"));
471 // "no redraw" MDI child frame
472 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) )
474 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
480 if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) )
482 wxLogLastError(wxT("UnregisterClass(canvas)"));
487 if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) )
489 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
493 #endif // __WXMICROWIN__
498 void wxApp::CleanUp()
500 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
501 wxSetKeyboardHook(FALSE
);
508 if ( wxDisableButtonBrush
)
509 ::DeleteObject( wxDisableButtonBrush
);
519 // for an EXE the classes are unregistered when it terminates but DLL may
520 // be loaded several times (load/unload/load) into the same process in
521 // which case the registration will fail after the first time if we don't
522 // unregister the classes now
523 UnregisterWindowClasses();
526 Ctl3dUnregister(wxhInstance
);
529 delete wxWinHandleHash
;
530 wxWinHandleHash
= NULL
;
532 wxAppBase::CleanUp();
535 // ----------------------------------------------------------------------------
537 // ----------------------------------------------------------------------------
541 m_printMode
= wxPRINT_WINDOWS
;
546 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
547 // don't come from main(), so we have to free them
551 // m_argv elements were allocated by wxStrdup()
555 // but m_argv itself -- using new[]
559 bool wxApp::Initialized()
566 #else // Assume initialized if DLL (no way of telling)
572 * Get and process a message, returning FALSE if WM_QUIT
573 * received (and also set the flag telling the app to exit the main loop)
576 bool wxApp::DoMessage()
578 BOOL rc
= ::GetMessage(&s_currentMsg
, (HWND
) NULL
, 0, 0);
588 // should never happen, but let's test for it nevertheless
589 wxLogLastError(wxT("GetMessage"));
594 wxASSERT_MSG( wxThread::IsMain(),
595 wxT("only the main thread can process Windows messages") );
597 static bool s_hadGuiLock
= TRUE
;
598 static wxMsgArray s_aSavedMessages
;
600 // if a secondary thread owns is doing GUI calls, save all messages for
601 // later processing - we can't process them right now because it will
602 // lead to recursive library calls (and we're not reentrant)
603 if ( !wxGuiOwnedByMainThread() )
605 s_hadGuiLock
= FALSE
;
607 // leave out WM_COMMAND messages: too dangerous, sometimes
608 // the message will be processed twice
609 if ( !wxIsWaitingForThread() ||
610 s_currentMsg
.message
!= WM_COMMAND
)
612 s_aSavedMessages
.Add(s_currentMsg
);
619 // have we just regained the GUI lock? if so, post all of the saved
622 // FIXME of course, it's not _exactly_ the same as processing the
623 // messages normally - expect some things to break...
628 size_t count
= s_aSavedMessages
.GetCount();
629 for ( size_t n
= 0; n
< count
; n
++ )
631 MSG
& msg
= s_aSavedMessages
[n
];
633 DoMessage((WXMSG
*)&msg
);
636 s_aSavedMessages
.Empty();
639 #endif // wxUSE_THREADS
641 // Process the message
642 DoMessage((WXMSG
*)&s_currentMsg
);
648 void wxApp::DoMessage(WXMSG
*pMsg
)
650 if ( !ProcessMessage(pMsg
) )
652 ::TranslateMessage((MSG
*)pMsg
);
653 ::DispatchMessage((MSG
*)pMsg
);
658 * Keep trying to process messages until WM_QUIT
661 * If there are messages to be processed, they will all be
662 * processed and OnIdle will not be called.
663 * When there are no more messages, OnIdle is called.
664 * If OnIdle requests more time,
665 * it will be repeatedly called so long as there are no pending messages.
666 * A 'feature' of this is that once OnIdle has decided that no more processing
667 * is required, then it won't get processing time until further messages
668 * are processed (it'll sit in DoMessage).
671 int wxApp::MainLoop()
675 while ( m_keepGoing
)
678 wxMutexGuiLeaveOrEnter();
679 #endif // wxUSE_THREADS
681 while ( !Pending() && ProcessIdle() )
684 // a message came or no more idle processing to do
688 return s_currentMsg
.wParam
;
691 void wxApp::ExitMainLoop()
693 // this will set m_keepGoing to FALSE a bit later
694 ::PostQuitMessage(0);
697 bool wxApp::Pending()
699 return ::PeekMessage(&s_currentMsg
, 0, 0, 0, PM_NOREMOVE
) != 0;
702 void wxApp::Dispatch()
708 * Give all windows a chance to preprocess
709 * the message. Some may have accelerator tables, or have
713 bool wxApp::ProcessMessage(WXMSG
*wxmsg
)
715 MSG
*msg
= (MSG
*)wxmsg
;
716 HWND hwnd
= msg
->hwnd
;
717 wxWindow
*wndThis
= wxGetWindowFromHWND((WXHWND
)hwnd
);
719 // this may happen if the event occured in a standard modeless dialog (the
720 // only example of which I know of is the find/replace dialog) - then call
721 // IsDialogMessage() to make TAB navigation in it work
724 // we need to find the dialog containing this control as
725 // IsDialogMessage() just eats all the messages (i.e. returns TRUE for
726 // them) if we call it for the control itself
727 while ( hwnd
&& ::GetWindowLong(hwnd
, GWL_STYLE
) & WS_CHILD
)
729 hwnd
= ::GetParent(hwnd
);
732 return hwnd
&& ::IsDialogMessage(hwnd
, msg
) != 0;
736 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
737 // popup the tooltip bubbles
738 if ( (msg
->message
== WM_MOUSEMOVE
) )
740 wxToolTip
*tt
= wndThis
->GetToolTip();
743 tt
->RelayEvent(wxmsg
);
746 #endif // wxUSE_TOOLTIPS
748 // allow the window to prevent certain messages from being
749 // translated/processed (this is currently used by wxTextCtrl to always
750 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
751 if ( !wndThis
->MSWShouldPreProcessMessage(wxmsg
) )
756 // try translations first: the accelerators override everything
759 for ( wnd
= wndThis
; wnd
; wnd
= wnd
->GetParent() )
761 if ( wnd
->MSWTranslateMessage(wxmsg
))
764 // stop at first top level window, i.e. don't try to process the key
765 // strokes originating in a dialog using the accelerators of the parent
766 // frame - this doesn't make much sense
767 if ( wnd
->IsTopLevel() )
771 // now try the other hooks (kbd navigation is handled here): we start from
772 // wndThis->GetParent() because wndThis->MSWProcessMessage() was already
774 for ( wnd
= wndThis
->GetParent(); wnd
; wnd
= wnd
->GetParent() )
776 if ( wnd
->MSWProcessMessage(wxmsg
) )
780 // no special preprocessing for this message, dispatch it normally
784 // this is a temporary hack and will be replaced by using wxEventLoop in the
787 // it is needed to allow other event loops (currently only one: the modal
788 // dialog one) to reset the OnIdle() semaphore because otherwise OnIdle()
789 // wouldn't do anything while a modal dialog shown from OnIdle() call is shown.
790 bool wxIsInOnIdleFlag
= FALSE
;
792 void wxApp::OnIdle(wxIdleEvent
& event
)
794 // Avoid recursion (via ProcessEvent default case)
795 if ( wxIsInOnIdleFlag
)
798 wxIsInOnIdleFlag
= TRUE
;
800 wxAppBase::OnIdle(event
);
802 #if wxUSE_DC_CACHEING
803 // automated DC cache management: clear the cached DCs and bitmap
804 // if it's likely that the app has finished with them, that is, we
805 // get an idle event and we're not dragging anything.
806 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
808 #endif // wxUSE_DC_CACHEING
810 wxIsInOnIdleFlag
= FALSE
;
813 void wxApp::WakeUpIdle()
815 // Send the top window a dummy message so idle handler processing will
816 // start up again. Doing it this way ensures that the idle handler
817 // wakes up in the right thread (see also wxWakeUpMainThread() which does
818 // the same for the main app thread only)
819 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
822 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
824 // should never happen
825 wxLogLastError(wxT("PostMessage(WM_NULL)"));
830 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
833 GetTopWindow()->Close(TRUE
);
836 // Default behaviour: close the application with prompts. The
837 // user can veto the close, and therefore the end session.
838 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
842 if (!GetTopWindow()->Close(!event
.CanVeto()))
848 int wxApp::GetComCtl32Version()
850 //FIX ME FOR DIGITALMARS!!
851 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__)
856 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
857 // but as its value should be the same both times it doesn't matter
858 static int s_verComCtl32
= -1;
860 if ( s_verComCtl32
== -1 )
862 // initally assume no comctl32.dll at all
865 // we're prepared to handle the errors
869 wxDynamicLibrary
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
);
871 // if so, then we can check for the version
872 if ( dllComCtl32
.IsLoaded() )
874 #ifdef DLLVER_PLATFORM_WINDOWS
875 // try to use DllGetVersion() if available in _headers_
876 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC
, DllGetVersion
, dllComCtl32
);
877 if ( pfnDllGetVersion
)
880 dvi
.cbSize
= sizeof(dvi
);
882 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
885 wxLogApiError(_T("DllGetVersion"), hr
);
889 // this is incompatible with _WIN32_IE values, but
890 // compatible with the other values returned by
891 // GetComCtl32Version()
892 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
898 // if DllGetVersion() is unavailable either during compile or
899 // run-time, try to guess the version otherwise
900 if ( !s_verComCtl32
)
902 // InitCommonControlsEx is unique to 4.70 and later
903 void *pfn
= dllComCtl32
.GetSymbol(_T("InitCommonControlsEx"));
906 // not found, must be 4.00
911 // many symbols appeared in comctl32 4.71, could use any of
912 // them except may be DllInstall()
913 pfn
= dllComCtl32
.GetSymbol(_T("InitializeFlatSB"));
916 // not found, must be 4.70
921 // found, must be 4.71 or later
929 return s_verComCtl32
;
930 #endif // Microwin/!Microwin
933 // Yield to incoming messages
935 bool wxApp::Yield(bool onlyIfNeeded
)
938 static bool s_inYield
= FALSE
;
941 // disable log flushing from here because a call to wxYield() shouldn't
942 // normally result in message boxes popping up &c
950 wxFAIL_MSG( wxT("wxYield called recursively" ) );
958 // we don't want to process WM_QUIT from here - it should be processed in
959 // the main event loop in order to stop it
961 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
962 msg
.message
!= WM_QUIT
)
965 wxMutexGuiLeaveOrEnter();
966 #endif // wxUSE_THREADS
968 if ( !wxTheApp
->DoMessage() )
972 // if there are pending events, we must process them.
973 ProcessPendingEvents();
976 // let the logs be flashed again