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 )) && \
118 // ---------------------------------------------------------------------------
120 // ---------------------------------------------------------------------------
122 extern wxList WXDLLEXPORT wxPendingDelete
;
123 #ifndef __WXMICROWIN__
124 extern void wxSetKeyboardHook(bool doIt
);
129 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
130 // with NR suffix - wxWindow::MSWCreate() supposes this
131 const wxChar
*wxCanvasClassName
= wxT("wxWindowClass");
132 const wxChar
*wxCanvasClassNameNR
= wxT("wxWindowClassNR");
133 const wxChar
*wxMDIFrameClassName
= wxT("wxMDIFrameClass");
134 const wxChar
*wxMDIFrameClassNameNoRedraw
= wxT("wxMDIFrameClassNR");
135 const wxChar
*wxMDIChildFrameClassName
= wxT("wxMDIChildFrameClass");
136 const wxChar
*wxMDIChildFrameClassNameNoRedraw
= wxT("wxMDIChildFrameClassNR");
138 HBRUSH wxDisableButtonBrush
= (HBRUSH
) 0;
140 // ----------------------------------------------------------------------------
142 // ----------------------------------------------------------------------------
144 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
146 // ===========================================================================
147 // wxGUIAppTraits implementation
148 // ===========================================================================
150 // private class which we use to pass parameters from BeforeChildWaitLoop() to
151 // AfterChildWaitLoop()
152 struct ChildWaitLoopData
154 ChildWaitLoopData(wxWindowDisabler
*wd_
, wxWindow
*winActive_
)
157 winActive
= winActive_
;
160 wxWindowDisabler
*wd
;
164 void *wxGUIAppTraits::BeforeChildWaitLoop()
167 We use a dirty hack here to disable all application windows (which we
168 must do because otherwise the calls to wxYield() could lead to some very
169 unexpected reentrancies in the users code) but to avoid losing
170 focus/activation entirely when the child process terminates which would
171 happen if we simply disabled everything using wxWindowDisabler. Indeed,
172 remember that Windows will never activate a disabled window and when the
173 last childs window is closed and Windows looks for a window to activate
174 all our windows are still disabled. There is no way to enable them in
175 time because we don't know when the childs windows are going to be
176 closed, so the solution we use here is to keep one special tiny frame
177 enabled all the time. Then when the child terminates it will get
178 activated and when we close it below -- after reenabling all the other
179 windows! -- the previously active window becomes activated again and
184 // first disable all existing windows
185 wxWindowDisabler
*wd
= new wxWindowDisabler
;
187 // then create an "invisible" frame: it has minimal size, is positioned
188 // (hopefully) outside the screen and doesn't appear on the taskbar
189 wxWindow
*winActive
= new wxFrame
191 wxTheApp
->GetTopWindow(),
194 wxPoint(32600, 32600),
196 wxDEFAULT_FRAME_STYLE
| wxFRAME_NO_TASKBAR
200 return new ChildWaitLoopData(wd
, winActive
);
203 void wxGUIAppTraits::AlwaysYield()
208 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
)
212 const ChildWaitLoopData
* const data
= (ChildWaitLoopData
*)dataOrig
;
216 // finally delete the dummy frame and, as wd has been already destroyed and
217 // the other windows reenabled, the activation is going to return to the
218 // window which had had it before
219 data
->winActive
->Destroy();
222 bool wxGUIAppTraits::DoMessageFromThreadWait()
224 return !wxTheApp
|| wxTheApp
->DoMessage();
227 // ===========================================================================
228 // wxApp implementation
229 // ===========================================================================
231 int wxApp::m_nCmdShow
= SW_SHOWNORMAL
;
233 // ---------------------------------------------------------------------------
235 // ---------------------------------------------------------------------------
237 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
239 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
240 EVT_IDLE(wxApp::OnIdle
)
241 EVT_END_SESSION(wxApp::OnEndSession
)
242 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
245 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
247 class wxCallBaseCleanup
250 wxCallBaseCleanup(wxApp
*app
) : m_app(app
) { }
251 ~wxCallBaseCleanup() { if ( m_app
) m_app
->wxAppBase::CleanUp(); }
253 void Dismiss() { m_app
= NULL
; }
260 bool wxApp::Initialize(int& argc
, wxChar
**argv
)
262 if ( !wxAppBase::Initialize(argc
, argv
) )
265 // ensure that base cleanup is done if we return too early
266 wxCallBaseCleanup
callBaseCleanup(this);
268 // the first thing to do is to check if we're trying to run an Unicode
269 // program under Win9x w/o MSLU emulation layer - if so, abort right now
270 // as it has no chance to work
271 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
272 if ( wxGetOsVersion() != wxWINDOWS_NT
)
274 // note that we can use MessageBoxW() as it's implemented even under
275 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
276 // used by wxLocale are not
280 _T("This program uses Unicode and requires Windows NT/2000/XP.\nProgram aborted."),
281 _T("wxWindows Fatal Error"),
287 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
289 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
290 InitCommonControls();
293 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
296 // for OLE, enlarge message queue to be as large as possible
298 while (!SetMessageQueue(iMsg
) && (iMsg
-= 8))
303 // we need to initialize OLE library
304 if ( FAILED(::OleInitialize(NULL
)) )
305 wxLogError(_("Cannot initialize OLE"));
311 if (!Ctl3dRegister(wxhInstance
))
312 wxLogError(wxT("Cannot register CTL3D"));
314 Ctl3dAutoSubclass(wxhInstance
);
315 #endif // wxUSE_CTL3D
317 RegisterWindowClasses();
319 #ifndef __WXMICROWIN__
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 #ifndef __WXMICROWIN__
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 #ifndef __WXMICROWIN__
501 wxSetKeyboardHook(FALSE
);
508 if ( wxDisableButtonBrush
)
509 ::DeleteObject( wxDisableButtonBrush
);
515 // for an EXE the classes are unregistered when it terminates but DLL may
516 // be loaded several times (load/unload/load) into the same process in
517 // which case the registration will fail after the first time if we don't
518 // unregister the classes now
519 UnregisterWindowClasses();
522 Ctl3dUnregister(wxhInstance
);
525 delete wxWinHandleHash
;
526 wxWinHandleHash
= NULL
;
528 wxAppBase::CleanUp();
531 // ----------------------------------------------------------------------------
533 // ----------------------------------------------------------------------------
537 m_printMode
= wxPRINT_WINDOWS
;
542 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
543 // don't come from main(), so we have to free them
547 // m_argv elements were allocated by wxStrdup()
551 // but m_argv itself -- using new[]
555 bool wxApp::Initialized()
562 #else // Assume initialized if DLL (no way of telling)
568 * Get and process a message, returning FALSE if WM_QUIT
569 * received (and also set the flag telling the app to exit the main loop)
572 bool wxApp::DoMessage()
574 BOOL rc
= ::GetMessage(&s_currentMsg
, (HWND
) NULL
, 0, 0);
584 // should never happen, but let's test for it nevertheless
585 wxLogLastError(wxT("GetMessage"));
590 wxASSERT_MSG( wxThread::IsMain(),
591 wxT("only the main thread can process Windows messages") );
593 static bool s_hadGuiLock
= TRUE
;
594 static wxMsgArray s_aSavedMessages
;
596 // if a secondary thread owns is doing GUI calls, save all messages for
597 // later processing - we can't process them right now because it will
598 // lead to recursive library calls (and we're not reentrant)
599 if ( !wxGuiOwnedByMainThread() )
601 s_hadGuiLock
= FALSE
;
603 // leave out WM_COMMAND messages: too dangerous, sometimes
604 // the message will be processed twice
605 if ( !wxIsWaitingForThread() ||
606 s_currentMsg
.message
!= WM_COMMAND
)
608 s_aSavedMessages
.Add(s_currentMsg
);
615 // have we just regained the GUI lock? if so, post all of the saved
618 // FIXME of course, it's not _exactly_ the same as processing the
619 // messages normally - expect some things to break...
624 size_t count
= s_aSavedMessages
.GetCount();
625 for ( size_t n
= 0; n
< count
; n
++ )
627 MSG
& msg
= s_aSavedMessages
[n
];
629 DoMessage((WXMSG
*)&msg
);
632 s_aSavedMessages
.Empty();
635 #endif // wxUSE_THREADS
637 // Process the message
638 DoMessage((WXMSG
*)&s_currentMsg
);
644 void wxApp::DoMessage(WXMSG
*pMsg
)
646 if ( !ProcessMessage(pMsg
) )
648 ::TranslateMessage((MSG
*)pMsg
);
649 ::DispatchMessage((MSG
*)pMsg
);
654 * Keep trying to process messages until WM_QUIT
657 * If there are messages to be processed, they will all be
658 * processed and OnIdle will not be called.
659 * When there are no more messages, OnIdle is called.
660 * If OnIdle requests more time,
661 * it will be repeatedly called so long as there are no pending messages.
662 * A 'feature' of this is that once OnIdle has decided that no more processing
663 * is required, then it won't get processing time until further messages
664 * are processed (it'll sit in DoMessage).
667 int wxApp::MainLoop()
671 while ( m_keepGoing
)
674 wxMutexGuiLeaveOrEnter();
675 #endif // wxUSE_THREADS
677 while ( !Pending() && ProcessIdle() )
680 // a message came or no more idle processing to do
684 return s_currentMsg
.wParam
;
687 // Returns TRUE if more time is needed.
688 bool wxApp::ProcessIdle()
691 event
.SetEventObject(this);
694 return event
.MoreRequested();
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 // If there are pending events, we must process them: pending events
807 // are either events to the threads other than main or events posted
808 // with wxPostEvent() functions
809 // GRG: I have moved this here so that all pending events are processed
810 // before starting to delete any objects. This behaves better (in
811 // particular, wrt wxPostEvent) and is coherent with wxGTK's current
812 // behaviour. Changed Feb/2000 before 2.1.14
813 ProcessPendingEvents();
815 // 'Garbage' collection of windows deleted with Close().
816 DeletePendingObjects();
819 // flush the logged messages if any
820 wxLog::FlushActive();
823 #if wxUSE_DC_CACHEING
824 // automated DC cache management: clear the cached DCs and bitmap
825 // if it's likely that the app has finished with them, that is, we
826 // get an idle event and we're not dragging anything.
827 if (!::GetKeyState(MK_LBUTTON
) && !::GetKeyState(MK_MBUTTON
) && !::GetKeyState(MK_RBUTTON
))
829 #endif // wxUSE_DC_CACHEING
831 // Send OnIdle events to all windows
832 if ( SendIdleEvents() )
834 // SendIdleEvents() returns TRUE if at least one window requested more
836 event
.RequestMore(TRUE
);
839 wxIsInOnIdleFlag
= FALSE
;
842 // Send idle event to all top-level windows
843 bool wxApp::SendIdleEvents()
845 bool needMore
= FALSE
;
847 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
850 wxWindow
* win
= node
->GetData();
851 if (SendIdleEvents(win
))
853 node
= node
->GetNext();
859 // Send idle event to window and all subwindows
860 bool wxApp::SendIdleEvents(wxWindow
* win
)
863 event
.SetEventObject(win
);
864 win
->GetEventHandler()->ProcessEvent(event
);
866 bool needMore
= event
.MoreRequested();
868 wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
871 wxWindow
*win
= node
->GetData();
872 if (SendIdleEvents(win
))
875 node
= node
->GetNext();
881 void wxApp::WakeUpIdle()
883 // Send the top window a dummy message so idle handler processing will
884 // start up again. Doing it this way ensures that the idle handler
885 // wakes up in the right thread (see also wxWakeUpMainThread() which does
886 // the same for the main app thread only)
887 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
890 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
892 // should never happen
893 wxLogLastError(wxT("PostMessage(WM_NULL)"));
898 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
901 GetTopWindow()->Close(TRUE
);
904 // Default behaviour: close the application with prompts. The
905 // user can veto the close, and therefore the end session.
906 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
910 if (!GetTopWindow()->Close(!event
.CanVeto()))
915 typedef struct _WXADllVersionInfo
918 DWORD dwMajorVersion
; // Major version
919 DWORD dwMinorVersion
; // Minor version
920 DWORD dwBuildNumber
; // Build number
921 DWORD dwPlatformID
; // DLLVER_PLATFORM_*
924 typedef HRESULT (CALLBACK
* WXADLLGETVERSIONPROC
)(WXADLLVERSIONINFO
*);
927 int wxApp::GetComCtl32Version()
929 #ifdef __WXMICROWIN__
933 static int s_verComCtl32
= -1;
935 wxCRIT_SECT_DECLARE(csComCtl32
);
936 wxCRIT_SECT_LOCKER(lock
, csComCtl32
);
938 if ( s_verComCtl32
== -1 )
940 // initally assume no comctl32.dll at all
944 HMODULE hModuleComCtl32
= ::GetModuleHandle(wxT("COMCTL32"));
945 BOOL bFreeComCtl32
= FALSE
;
948 hModuleComCtl32
= ::LoadLibrary(wxT("COMCTL32.DLL")) ;
951 bFreeComCtl32
= TRUE
;
955 // if so, then we can check for the version
956 if ( hModuleComCtl32
)
958 // try to use DllGetVersion() if available in _headers_
959 WXADLLGETVERSIONPROC pfnDllGetVersion
= (WXADLLGETVERSIONPROC
)
960 ::GetProcAddress(hModuleComCtl32
, "DllGetVersion");
961 if ( pfnDllGetVersion
)
963 WXADLLVERSIONINFO dvi
;
964 dvi
.cbSize
= sizeof(dvi
);
966 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
969 wxLogApiError(_T("DllGetVersion"), hr
);
973 // this is incompatible with _WIN32_IE values, but
974 // compatible with the other values returned by
975 // GetComCtl32Version()
976 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
980 // DllGetVersion() unavailable either during compile or
981 // run-time, try to guess the version otherwise
982 if ( !s_verComCtl32
)
984 // InitCommonControlsEx is unique to 4.70 and later
985 FARPROC theProc
= ::GetProcAddress
988 "InitCommonControlsEx"
993 // not found, must be 4.00
998 // many symbols appeared in comctl32 4.71, could use
999 // any of them except may be DllInstall
1000 theProc
= ::GetProcAddress
1007 // not found, must be 4.70
1008 s_verComCtl32
= 470;
1012 // found, must be 4.71
1013 s_verComCtl32
= 471;
1021 ::FreeLibrary(hModuleComCtl32
) ;
1025 return s_verComCtl32
;
1029 // Yield to incoming messages
1031 bool wxApp::Yield(bool onlyIfNeeded
)
1034 static bool s_inYield
= FALSE
;
1037 // disable log flushing from here because a call to wxYield() shouldn't
1038 // normally result in message boxes popping up &c
1044 if ( !onlyIfNeeded
)
1046 wxFAIL_MSG( wxT("wxYield called recursively" ) );
1054 // we don't want to process WM_QUIT from here - it should be processed in
1055 // the main event loop in order to stop it
1057 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
1058 msg
.message
!= WM_QUIT
)
1061 wxMutexGuiLeaveOrEnter();
1062 #endif // wxUSE_THREADS
1064 if ( !wxTheApp
->DoMessage() )
1068 // if there are pending events, we must process them.
1069 ProcessPendingEvents();
1072 // let the logs be flashed again