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"
55 #include "wx/msw/private.h"
58 #include "wx/thread.h"
60 // define the array of MSG strutures
61 WX_DECLARE_OBJARRAY(MSG
, wxMsgArray
);
63 #include "wx/arrimpl.cpp"
65 WX_DEFINE_OBJARRAY(wxMsgArray
);
66 #endif // wxUSE_THREADS
69 #include "wx/tooltip.h"
70 #endif // wxUSE_TOOLTIPS
72 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
73 // compilers don't support it (missing headers, libs, ...)
74 #if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
78 #endif // broken compilers
87 #if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__WXMICROWIN__)) && !defined(__CYGWIN10__))
91 // ----------------------------------------------------------------------------
92 // conditional compilation
93 // ----------------------------------------------------------------------------
95 // The macro _WIN32_IE is defined by commctrl.h (unless it had already been
96 // defined before) and shows us what common control features are available
97 // during the compile time (it doesn't mean that they will be available during
98 // the run-time, use GetComCtl32Version() to test for them!). The possible
101 // 0x0200 for comctl32.dll 4.00 shipped with Win95/NT 4.0
102 // 0x0300 4.70 IE 3.x
103 // 0x0400 4.71 IE 4.0
104 // 0x0401 4.72 IE 4.01 and Win98
105 // 0x0500 5.00 IE 5.x and NT 5.0 (Win2000)
108 // minimal set of features by default
109 #define _WIN32_IE 0x0200
112 #if _WIN32_IE >= 0x0300 && \
113 (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
114 !defined(__CYGWIN__) && !defined(__WXWINCE__)
118 // ---------------------------------------------------------------------------
120 // ---------------------------------------------------------------------------
122 extern wxList WXDLLEXPORT wxPendingDelete
;
124 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
125 extern void wxSetKeyboardHook(bool doIt
);
130 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
131 // with NR suffix - wxWindow::MSWCreate() supposes this
132 const wxChar
*wxCanvasClassName
= wxT("wxWindowClass");
133 const wxChar
*wxCanvasClassNameNR
= wxT("wxWindowClassNR");
134 const wxChar
*wxMDIFrameClassName
= wxT("wxMDIFrameClass");
135 const wxChar
*wxMDIFrameClassNameNoRedraw
= wxT("wxMDIFrameClassNR");
136 const wxChar
*wxMDIChildFrameClassName
= wxT("wxMDIChildFrameClass");
137 const wxChar
*wxMDIChildFrameClassNameNoRedraw
= wxT("wxMDIChildFrameClassNR");
139 HBRUSH wxDisableButtonBrush
= (HBRUSH
) 0;
141 // ----------------------------------------------------------------------------
143 // ----------------------------------------------------------------------------
145 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
147 // ===========================================================================
148 // wxGUIAppTraits implementation
149 // ===========================================================================
151 // private class which we use to pass parameters from BeforeChildWaitLoop() to
152 // AfterChildWaitLoop()
153 struct ChildWaitLoopData
155 ChildWaitLoopData(wxWindowDisabler
*wd_
, wxWindow
*winActive_
)
158 winActive
= winActive_
;
161 wxWindowDisabler
*wd
;
165 void *wxGUIAppTraits::BeforeChildWaitLoop()
168 We use a dirty hack here to disable all application windows (which we
169 must do because otherwise the calls to wxYield() could lead to some very
170 unexpected reentrancies in the users code) but to avoid losing
171 focus/activation entirely when the child process terminates which would
172 happen if we simply disabled everything using wxWindowDisabler. Indeed,
173 remember that Windows will never activate a disabled window and when the
174 last childs window is closed and Windows looks for a window to activate
175 all our windows are still disabled. There is no way to enable them in
176 time because we don't know when the childs windows are going to be
177 closed, so the solution we use here is to keep one special tiny frame
178 enabled all the time. Then when the child terminates it will get
179 activated and when we close it below -- after reenabling all the other
180 windows! -- the previously active window becomes activated again and
185 // first disable all existing windows
186 wxWindowDisabler
*wd
= new wxWindowDisabler
;
188 // then create an "invisible" frame: it has minimal size, is positioned
189 // (hopefully) outside the screen and doesn't appear on the taskbar
190 wxWindow
*winActive
= new wxFrame
192 wxTheApp
->GetTopWindow(),
195 wxPoint(32600, 32600),
197 wxDEFAULT_FRAME_STYLE
| wxFRAME_NO_TASKBAR
201 return new ChildWaitLoopData(wd
, winActive
);
204 void wxGUIAppTraits::AlwaysYield()
209 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
)
213 const ChildWaitLoopData
* const data
= (ChildWaitLoopData
*)dataOrig
;
217 // finally delete the dummy frame and, as wd has been already destroyed and
218 // the other windows reenabled, the activation is going to return to the
219 // window which had had it before
220 data
->winActive
->Destroy();
223 bool wxGUIAppTraits::DoMessageFromThreadWait()
225 return !wxTheApp
|| wxTheApp
->DoMessage();
228 // ===========================================================================
229 // wxApp implementation
230 // ===========================================================================
232 int wxApp::m_nCmdShow
= SW_SHOWNORMAL
;
234 // ---------------------------------------------------------------------------
236 // ---------------------------------------------------------------------------
238 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
240 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
241 EVT_IDLE(wxApp::OnIdle
)
242 EVT_END_SESSION(wxApp::OnEndSession
)
243 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
246 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
248 class wxCallBaseCleanup
251 wxCallBaseCleanup(wxApp
*app
) : m_app(app
) { }
252 ~wxCallBaseCleanup() { if ( m_app
) m_app
->wxAppBase::CleanUp(); }
254 void Dismiss() { m_app
= NULL
; }
261 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
263 if ( !wxAppBase::Initialize(argc
, argv
) )
266 // ensure that base cleanup is done if we return too early
267 wxCallBaseCleanup
callBaseCleanup(this);
269 // the first thing to do is to check if we're trying to run an Unicode
270 // program under Win9x w/o MSLU emulation layer - if so, abort right now
271 // as it has no chance to work
272 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
273 if ( wxGetOsVersion() != wxWINDOWS_NT
&& wxGetOsVersion() != wxWINDOWS_CE
)
275 // note that we can use MessageBoxW() as it's implemented even under
276 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
277 // used by wxLocale are not
281 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
282 _T("wxWindows Fatal Error"),
288 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
290 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
291 InitCommonControls();
294 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
297 // for OLE, enlarge message queue to be as large as possible
299 while (!SetMessageQueue(iMsg
) && (iMsg
-= 8))
304 // we need to initialize OLE library
306 if ( FAILED(::CoInitializeEx(NULL
, COINIT_MULTITHREADED
)) )
307 wxLogError(_("Cannot initialize OLE"));
309 if ( FAILED(::OleInitialize(NULL
)) )
310 wxLogError(_("Cannot initialize OLE"));
317 if (!Ctl3dRegister(wxhInstance
))
318 wxLogError(wxT("Cannot register CTL3D"));
320 Ctl3dAutoSubclass(wxhInstance
);
321 #endif // wxUSE_CTL3D
323 RegisterWindowClasses();
325 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
326 // Create the brush for disabling bitmap buttons
329 lb
.lbStyle
= BS_PATTERN
;
331 lb
.lbHatch
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") );
334 wxDisableButtonBrush
= ::CreateBrushIndirect( & lb
);
335 ::DeleteObject( (HGDIOBJ
)lb
.lbHatch
);
337 //else: wxWindows resources are probably not linked in
344 wxWinHandleHash
= new wxWinHashTable(wxKEY_INTEGER
, 100);
346 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
347 // PLEASE DO NOT ALTER THIS.
348 #if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
349 extern char wxDummyChar
;
350 if (wxDummyChar
) wxDummyChar
++;
353 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
354 wxSetKeyboardHook(TRUE
);
357 callBaseCleanup
.Dismiss();
362 // ---------------------------------------------------------------------------
363 // RegisterWindowClasses
364 // ---------------------------------------------------------------------------
366 // TODO we should only register classes really used by the app. For this it
367 // would be enough to just delay the class registration until an attempt
368 // to create a window of this class is made.
369 bool wxApp::RegisterWindowClasses()
372 wxZeroMemory(wndclass
);
374 // for each class we register one with CS_(V|H)REDRAW style and one
375 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
376 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
377 static const long styleNoRedraw
= CS_DBLCLKS
;
379 // the fields which are common to all classes
380 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
381 wndclass
.hInstance
= wxhInstance
;
382 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
384 // Register the frame window class.
385 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1);
386 wndclass
.lpszClassName
= wxCanvasClassName
;
387 wndclass
.style
= styleNormal
;
389 if ( !RegisterClass(&wndclass
) )
391 wxLogLastError(wxT("RegisterClass(frame)"));
395 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
396 wndclass
.style
= styleNoRedraw
;
398 if ( !RegisterClass(&wndclass
) )
400 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
403 // Register the MDI frame window class.
404 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
405 wndclass
.lpszClassName
= wxMDIFrameClassName
;
406 wndclass
.style
= styleNormal
;
408 if ( !RegisterClass(&wndclass
) )
410 wxLogLastError(wxT("RegisterClass(MDI parent)"));
413 // "no redraw" MDI frame
414 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
415 wndclass
.style
= styleNoRedraw
;
417 if ( !RegisterClass(&wndclass
) )
419 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
422 // Register the MDI child frame window class.
423 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
424 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
425 wndclass
.style
= styleNormal
;
427 if ( !RegisterClass(&wndclass
) )
429 wxLogLastError(wxT("RegisterClass(MDI child)"));
432 // "no redraw" MDI child frame
433 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
434 wndclass
.style
= styleNoRedraw
;
436 if ( !RegisterClass(&wndclass
) )
438 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
444 // ---------------------------------------------------------------------------
445 // UnregisterWindowClasses
446 // ---------------------------------------------------------------------------
448 bool wxApp::UnregisterWindowClasses()
452 #ifndef __WXMICROWIN__
453 // MDI frame window class.
454 if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) )
456 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
461 // "no redraw" MDI frame
462 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) )
464 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
469 // MDI child frame window class.
470 if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) )
472 wxLogLastError(wxT("UnregisterClass(MDI child)"));
477 // "no redraw" MDI child frame
478 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) )
480 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
486 if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) )
488 wxLogLastError(wxT("UnregisterClass(canvas)"));
493 if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) )
495 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
499 #endif // __WXMICROWIN__
504 void wxApp::CleanUp()
506 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
507 wxSetKeyboardHook(FALSE
);
514 if ( wxDisableButtonBrush
)
515 ::DeleteObject( wxDisableButtonBrush
);
525 // for an EXE the classes are unregistered when it terminates but DLL may
526 // be loaded several times (load/unload/load) into the same process in
527 // which case the registration will fail after the first time if we don't
528 // unregister the classes now
529 UnregisterWindowClasses();
532 Ctl3dUnregister(wxhInstance
);
535 delete wxWinHandleHash
;
536 wxWinHandleHash
= NULL
;
538 wxAppBase::CleanUp();
541 // ----------------------------------------------------------------------------
543 // ----------------------------------------------------------------------------
547 m_printMode
= wxPRINT_WINDOWS
;
552 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
553 // don't come from main(), so we have to free them
557 // m_argv elements were allocated by wxStrdup()
561 // but m_argv itself -- using new[]
565 bool wxApp::Initialized()
572 #else // Assume initialized if DLL (no way of telling)
578 * Get and process a message, returning FALSE if WM_QUIT
579 * received (and also set the flag telling the app to exit the main loop)
582 bool wxApp::DoMessage()
584 BOOL rc
= ::GetMessage(&s_currentMsg
, (HWND
) NULL
, 0, 0);
594 // should never happen, but let's test for it nevertheless
595 wxLogLastError(wxT("GetMessage"));
600 wxASSERT_MSG( wxThread::IsMain(),
601 wxT("only the main thread can process Windows messages") );
603 static bool s_hadGuiLock
= TRUE
;
604 static wxMsgArray s_aSavedMessages
;
606 // if a secondary thread owns is doing GUI calls, save all messages for
607 // later processing - we can't process them right now because it will
608 // lead to recursive library calls (and we're not reentrant)
609 if ( !wxGuiOwnedByMainThread() )
611 s_hadGuiLock
= FALSE
;
613 // leave out WM_COMMAND messages: too dangerous, sometimes
614 // the message will be processed twice
615 if ( !wxIsWaitingForThread() ||
616 s_currentMsg
.message
!= WM_COMMAND
)
618 s_aSavedMessages
.Add(s_currentMsg
);
625 // have we just regained the GUI lock? if so, post all of the saved
628 // FIXME of course, it's not _exactly_ the same as processing the
629 // messages normally - expect some things to break...
634 size_t count
= s_aSavedMessages
.GetCount();
635 for ( size_t n
= 0; n
< count
; n
++ )
637 MSG
& msg
= s_aSavedMessages
[n
];
639 DoMessage((WXMSG
*)&msg
);
642 s_aSavedMessages
.Empty();
645 #endif // wxUSE_THREADS
647 // Process the message
648 DoMessage((WXMSG
*)&s_currentMsg
);
654 void wxApp::DoMessage(WXMSG
*pMsg
)
656 if ( !ProcessMessage(pMsg
) )
658 ::TranslateMessage((MSG
*)pMsg
);
659 ::DispatchMessage((MSG
*)pMsg
);
664 * Keep trying to process messages until WM_QUIT
667 * If there are messages to be processed, they will all be
668 * processed and OnIdle will not be called.
669 * When there are no more messages, OnIdle is called.
670 * If OnIdle requests more time,
671 * it will be repeatedly called so long as there are no pending messages.
672 * A 'feature' of this is that once OnIdle has decided that no more processing
673 * is required, then it won't get processing time until further messages
674 * are processed (it'll sit in DoMessage).
677 int wxApp::MainLoop()
681 while ( m_keepGoing
)
684 wxMutexGuiLeaveOrEnter();
685 #endif // wxUSE_THREADS
687 while ( !Pending() && ProcessIdle() )
690 // a message came or no more idle processing to do
694 return s_currentMsg
.wParam
;
697 void wxApp::ExitMainLoop()
699 // this will set m_keepGoing to FALSE a bit later
700 ::PostQuitMessage(0);
703 bool wxApp::Pending()
705 return ::PeekMessage(&s_currentMsg
, 0, 0, 0, PM_NOREMOVE
) != 0;
708 void wxApp::Dispatch()
714 * Give all windows a chance to preprocess
715 * the message. Some may have accelerator tables, or have
719 bool wxApp::ProcessMessage(WXMSG
*wxmsg
)
721 MSG
*msg
= (MSG
*)wxmsg
;
722 HWND hwnd
= msg
->hwnd
;
723 wxWindow
*wndThis
= wxGetWindowFromHWND((WXHWND
)hwnd
);
725 // this may happen if the event occured in a standard modeless dialog (the
726 // only example of which I know of is the find/replace dialog) - then call
727 // IsDialogMessage() to make TAB navigation in it work
730 // we need to find the dialog containing this control as
731 // IsDialogMessage() just eats all the messages (i.e. returns TRUE for
732 // them) if we call it for the control itself
733 while ( hwnd
&& ::GetWindowLong(hwnd
, GWL_STYLE
) & WS_CHILD
)
735 hwnd
= ::GetParent(hwnd
);
738 return hwnd
&& ::IsDialogMessage(hwnd
, msg
) != 0;
742 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
743 // popup the tooltip bubbles
744 if ( (msg
->message
== WM_MOUSEMOVE
) )
746 wxToolTip
*tt
= wndThis
->GetToolTip();
749 tt
->RelayEvent(wxmsg
);
752 #endif // wxUSE_TOOLTIPS
754 // allow the window to prevent certain messages from being
755 // translated/processed (this is currently used by wxTextCtrl to always
756 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
757 if ( !wndThis
->MSWShouldPreProcessMessage(wxmsg
) )
762 // try translations first: the accelerators override everything
765 for ( wnd
= wndThis
; wnd
; wnd
= wnd
->GetParent() )
767 if ( wnd
->MSWTranslateMessage(wxmsg
))
770 // stop at first top level window, i.e. don't try to process the key
771 // strokes originating in a dialog using the accelerators of the parent
772 // frame - this doesn't make much sense
773 if ( wnd
->IsTopLevel() )
777 // now try the other hooks (kbd navigation is handled here): we start from
778 // wndThis->GetParent() because wndThis->MSWProcessMessage() was already
780 for ( wnd
= wndThis
->GetParent(); wnd
; wnd
= wnd
->GetParent() )
782 if ( wnd
->MSWProcessMessage(wxmsg
) )
786 // no special preprocessing for this message, dispatch it normally
790 // this is a temporary hack and will be replaced by using wxEventLoop in the
793 // it is needed to allow other event loops (currently only one: the modal
794 // dialog one) to reset the OnIdle() semaphore because otherwise OnIdle()
795 // wouldn't do anything while a modal dialog shown from OnIdle() call is shown.
796 bool wxIsInOnIdleFlag
= FALSE
;
798 void wxApp::OnIdle(wxIdleEvent
& event
)
800 // Avoid recursion (via ProcessEvent default case)
801 if ( wxIsInOnIdleFlag
)
804 wxIsInOnIdleFlag
= TRUE
;
806 wxAppBase::OnIdle(event
);
808 #if wxUSE_DC_CACHEING
809 // automated DC cache management: clear the cached DCs and bitmap
810 // if it's likely that the app has finished with them, that is, we
811 // get an idle event and we're not dragging anything.
812 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
814 #endif // wxUSE_DC_CACHEING
816 wxIsInOnIdleFlag
= FALSE
;
819 void wxApp::WakeUpIdle()
821 // Send the top window a dummy message so idle handler processing will
822 // start up again. Doing it this way ensures that the idle handler
823 // wakes up in the right thread (see also wxWakeUpMainThread() which does
824 // the same for the main app thread only)
825 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
828 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
830 // should never happen
831 wxLogLastError(wxT("PostMessage(WM_NULL)"));
836 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
839 GetTopWindow()->Close(TRUE
);
842 // Default behaviour: close the application with prompts. The
843 // user can veto the close, and therefore the end session.
844 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
848 if (!GetTopWindow()->Close(!event
.CanVeto()))
853 typedef struct _WXADllVersionInfo
856 DWORD dwMajorVersion
; // Major version
857 DWORD dwMinorVersion
; // Minor version
858 DWORD dwBuildNumber
; // Build number
859 DWORD dwPlatformID
; // DLLVER_PLATFORM_*
862 typedef HRESULT (CALLBACK
* WXADLLGETVERSIONPROC
)(WXADLLVERSIONINFO
*);
865 int wxApp::GetComCtl32Version()
867 #if defined(__WXMICROWIN__) || defined(__WXWINCE__)
871 static int s_verComCtl32
= -1;
873 wxCRIT_SECT_DECLARE(csComCtl32
);
874 wxCRIT_SECT_LOCKER(lock
, csComCtl32
);
876 if ( s_verComCtl32
== -1 )
878 // initally assume no comctl32.dll at all
882 HMODULE hModuleComCtl32
= ::GetModuleHandle(wxT("COMCTL32"));
883 BOOL bFreeComCtl32
= FALSE
;
886 hModuleComCtl32
= ::LoadLibrary(wxT("COMCTL32.DLL")) ;
889 bFreeComCtl32
= TRUE
;
893 // if so, then we can check for the version
894 if ( hModuleComCtl32
)
896 // try to use DllGetVersion() if available in _headers_
897 WXADLLGETVERSIONPROC pfnDllGetVersion
= (WXADLLGETVERSIONPROC
)
898 ::GetProcAddress(hModuleComCtl32
, "DllGetVersion");
899 if ( pfnDllGetVersion
)
901 WXADLLVERSIONINFO dvi
;
902 dvi
.cbSize
= sizeof(dvi
);
904 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
907 wxLogApiError(_T("DllGetVersion"), hr
);
911 // this is incompatible with _WIN32_IE values, but
912 // compatible with the other values returned by
913 // GetComCtl32Version()
914 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
918 // DllGetVersion() unavailable either during compile or
919 // run-time, try to guess the version otherwise
920 if ( !s_verComCtl32
)
922 // InitCommonControlsEx is unique to 4.70 and later
923 FARPROC theProc
= ::GetProcAddress
926 "InitCommonControlsEx"
931 // not found, must be 4.00
936 // many symbols appeared in comctl32 4.71, could use
937 // any of them except may be DllInstall
938 theProc
= ::GetProcAddress
945 // not found, must be 4.70
950 // found, must be 4.71
959 ::FreeLibrary(hModuleComCtl32
) ;
963 return s_verComCtl32
;
967 // Yield to incoming messages
969 bool wxApp::Yield(bool onlyIfNeeded
)
972 static bool s_inYield
= FALSE
;
975 // disable log flushing from here because a call to wxYield() shouldn't
976 // normally result in message boxes popping up &c
984 wxFAIL_MSG( wxT("wxYield called recursively" ) );
992 // we don't want to process WM_QUIT from here - it should be processed in
993 // the main event loop in order to stop it
995 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
996 msg
.message
!= WM_QUIT
)
999 wxMutexGuiLeaveOrEnter();
1000 #endif // wxUSE_THREADS
1002 if ( !wxTheApp
->DoMessage() )
1006 // if there are pending events, we must process them.
1007 ProcessPendingEvents();
1010 // let the logs be flashed again