use wxEventLoop in wxApp under wxMSW; factored out common code from wxX11/wxMotif...
[wxWidgets.git] / src / msw / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: app.cpp
3 // Purpose: wxApp
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "app.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #if defined(__BORLANDC__)
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #include "wx/app.h"
34 #include "wx/utils.h"
35 #include "wx/gdicmn.h"
36 #include "wx/pen.h"
37 #include "wx/brush.h"
38 #include "wx/cursor.h"
39 #include "wx/icon.h"
40 #include "wx/palette.h"
41 #include "wx/dc.h"
42 #include "wx/dialog.h"
43 #include "wx/msgdlg.h"
44 #include "wx/intl.h"
45 #include "wx/dynarray.h"
46 #include "wx/wxchar.h"
47 #include "wx/icon.h"
48 #include "wx/log.h"
49 #endif
50
51 #include "wx/apptrait.h"
52 #include "wx/filename.h"
53 #include "wx/module.h"
54 #include "wx/dynlib.h"
55
56 #include "wx/msw/private.h"
57
58 #if wxUSE_THREADS
59 #include "wx/thread.h"
60
61 // define the array of MSG strutures
62 WX_DECLARE_OBJARRAY(MSG, wxMsgArray);
63
64 #include "wx/arrimpl.cpp"
65
66 WX_DEFINE_OBJARRAY(wxMsgArray);
67 #endif // wxUSE_THREADS
68
69 #if wxUSE_TOOLTIPS
70 #include "wx/tooltip.h"
71 #endif // wxUSE_TOOLTIPS
72
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__)
76 #undef wxUSE_OLE
77
78 #define wxUSE_OLE 0
79 #endif // broken compilers
80
81 #if wxUSE_OLE
82 #include <ole2.h>
83 #endif
84
85 #include <string.h>
86 #include <ctype.h>
87
88 #include "wx/msw/wrapcctl.h"
89
90 #if (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
91 !defined(__CYGWIN__) && !defined(__DIGITALMARS__) && !defined(__WXWINCE__) && \
92 (!defined(_MSC_VER) || (_MSC_VER > 1100))
93 #include <shlwapi.h>
94 #endif
95
96 // ---------------------------------------------------------------------------
97 // global variables
98 // ---------------------------------------------------------------------------
99
100 extern wxList WXDLLEXPORT wxPendingDelete;
101
102 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
103 extern void wxSetKeyboardHook(bool doIt);
104 #endif
105
106 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
107 // with NR suffix - wxWindow::MSWCreate() supposes this
108 const wxChar *wxCanvasClassName = wxT("wxWindowClass");
109 const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
110 const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
111 const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
112 const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
113 const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
114
115 HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
116
117 // ----------------------------------------------------------------------------
118 // private functions
119 // ----------------------------------------------------------------------------
120
121 LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
122
123 // ===========================================================================
124 // wxGUIAppTraits implementation
125 // ===========================================================================
126
127 // private class which we use to pass parameters from BeforeChildWaitLoop() to
128 // AfterChildWaitLoop()
129 struct ChildWaitLoopData
130 {
131 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
132 {
133 wd = wd_;
134 winActive = winActive_;
135 }
136
137 wxWindowDisabler *wd;
138 wxWindow *winActive;
139 };
140
141 void *wxGUIAppTraits::BeforeChildWaitLoop()
142 {
143 /*
144 We use a dirty hack here to disable all application windows (which we
145 must do because otherwise the calls to wxYield() could lead to some very
146 unexpected reentrancies in the users code) but to avoid losing
147 focus/activation entirely when the child process terminates which would
148 happen if we simply disabled everything using wxWindowDisabler. Indeed,
149 remember that Windows will never activate a disabled window and when the
150 last childs window is closed and Windows looks for a window to activate
151 all our windows are still disabled. There is no way to enable them in
152 time because we don't know when the childs windows are going to be
153 closed, so the solution we use here is to keep one special tiny frame
154 enabled all the time. Then when the child terminates it will get
155 activated and when we close it below -- after reenabling all the other
156 windows! -- the previously active window becomes activated again and
157 everything is ok.
158 */
159 wxBeginBusyCursor();
160
161 // first disable all existing windows
162 wxWindowDisabler *wd = new wxWindowDisabler;
163
164 // then create an "invisible" frame: it has minimal size, is positioned
165 // (hopefully) outside the screen and doesn't appear on the taskbar
166 wxWindow *winActive = new wxFrame
167 (
168 wxTheApp->GetTopWindow(),
169 wxID_ANY,
170 wxEmptyString,
171 wxPoint(32600, 32600),
172 wxSize(1, 1),
173 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
174 );
175 winActive->Show();
176
177 return new ChildWaitLoopData(wd, winActive);
178 }
179
180 void wxGUIAppTraits::AlwaysYield()
181 {
182 wxYield();
183 }
184
185 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
186 {
187 wxEndBusyCursor();
188
189 const ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
190
191 delete data->wd;
192
193 // finally delete the dummy frame and, as wd has been already destroyed and
194 // the other windows reenabled, the activation is going to return to the
195 // window which had had it before
196 data->winActive->Destroy();
197 }
198
199 bool wxGUIAppTraits::DoMessageFromThreadWait()
200 {
201 // we should return false only if the app should exit, i.e. only if
202 // Dispatch() determines that the main event loop should terminate
203 return !wxTheApp || wxTheApp->Dispatch();
204 }
205
206 wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo()
207 {
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");
218 #endif
219 return info;
220 }
221
222 // ===========================================================================
223 // wxApp implementation
224 // ===========================================================================
225
226 int wxApp::m_nCmdShow = SW_SHOWNORMAL;
227
228 // ---------------------------------------------------------------------------
229 // wxWin macros
230 // ---------------------------------------------------------------------------
231
232 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
233
234 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
235 EVT_IDLE(wxApp::OnIdle)
236 EVT_END_SESSION(wxApp::OnEndSession)
237 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
238 END_EVENT_TABLE()
239
240 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
241 // fails
242 class wxCallBaseCleanup
243 {
244 public:
245 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
246 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
247
248 void Dismiss() { m_app = NULL; }
249
250 private:
251 wxApp *m_app;
252 };
253
254 //// Initialize
255 bool wxApp::Initialize(int& argc, wxChar **argv)
256 {
257 if ( !wxAppBase::Initialize(argc, argv) )
258 return false;
259
260 // ensure that base cleanup is done if we return too early
261 wxCallBaseCleanup callBaseCleanup(this);
262
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 )
268 {
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
272 ::MessageBox
273 (
274 NULL,
275 _T("This program uses Unicode and requires Windows NT/2000/XP/CE.\nProgram aborted."),
276 _T("wxWindows Fatal Error"),
277 MB_ICONERROR | MB_OK
278 );
279
280 return FALSE;
281 }
282 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
283
284 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
285 InitCommonControls();
286 #endif // __WIN95__
287
288 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
289
290 #ifdef __WIN16__
291 // for OLE, enlarge message queue to be as large as possible
292 int iMsg = 96;
293 while (!SetMessageQueue(iMsg) && (iMsg -= 8))
294 ;
295 #endif // Win16
296
297 #if wxUSE_OLE
298 // we need to initialize OLE library
299 #ifdef __WXWINCE__
300 if ( FAILED(::CoInitializeEx(NULL, COINIT_MULTITHREADED)) )
301 wxLogError(_("Cannot initialize OLE"));
302 #else
303 if ( FAILED(::OleInitialize(NULL)) )
304 wxLogError(_("Cannot initialize OLE"));
305 #endif
306 #endif
307
308 #endif // wxUSE_OLE
309
310 #if wxUSE_CTL3D
311 if (!Ctl3dRegister(wxhInstance))
312 wxLogError(wxT("Cannot register CTL3D"));
313
314 Ctl3dAutoSubclass(wxhInstance);
315 #endif // wxUSE_CTL3D
316
317 RegisterWindowClasses();
318
319 #if defined(__WXMICROWIN__) && !defined(__WXWINCE__)
320 // Create the brush for disabling bitmap buttons
321
322 LOGBRUSH lb;
323 lb.lbStyle = BS_PATTERN;
324 lb.lbColor = 0;
325 lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
326 if ( lb.lbHatch )
327 {
328 wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
329 ::DeleteObject( (HGDIOBJ)lb.lbHatch );
330 }
331 //else: wxWindows resources are probably not linked in
332 #endif
333
334 #if wxUSE_PENWINDOWS
335 wxRegisterPenWin();
336 #endif
337
338 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
339
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++;
345 #endif
346
347 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
348 wxSetKeyboardHook(TRUE);
349 #endif
350
351 callBaseCleanup.Dismiss();
352
353 return true;
354 }
355
356 // ---------------------------------------------------------------------------
357 // RegisterWindowClasses
358 // ---------------------------------------------------------------------------
359
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()
364 {
365 WNDCLASS wndclass;
366 wxZeroMemory(wndclass);
367
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;
372
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);
377
378 // Register the frame window class.
379 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
380 wndclass.lpszClassName = wxCanvasClassName;
381 wndclass.style = styleNormal;
382
383 if ( !RegisterClass(&wndclass) )
384 {
385 wxLogLastError(wxT("RegisterClass(frame)"));
386 }
387
388 // "no redraw" frame
389 wndclass.lpszClassName = wxCanvasClassNameNR;
390 wndclass.style = styleNoRedraw;
391
392 if ( !RegisterClass(&wndclass) )
393 {
394 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
395 }
396
397 // Register the MDI frame window class.
398 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
399 wndclass.lpszClassName = wxMDIFrameClassName;
400 wndclass.style = styleNormal;
401
402 if ( !RegisterClass(&wndclass) )
403 {
404 wxLogLastError(wxT("RegisterClass(MDI parent)"));
405 }
406
407 // "no redraw" MDI frame
408 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
409 wndclass.style = styleNoRedraw;
410
411 if ( !RegisterClass(&wndclass) )
412 {
413 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
414 }
415
416 // Register the MDI child frame window class.
417 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
418 wndclass.lpszClassName = wxMDIChildFrameClassName;
419 wndclass.style = styleNormal;
420
421 if ( !RegisterClass(&wndclass) )
422 {
423 wxLogLastError(wxT("RegisterClass(MDI child)"));
424 }
425
426 // "no redraw" MDI child frame
427 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
428 wndclass.style = styleNoRedraw;
429
430 if ( !RegisterClass(&wndclass) )
431 {
432 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
433 }
434
435 return TRUE;
436 }
437
438 // ---------------------------------------------------------------------------
439 // UnregisterWindowClasses
440 // ---------------------------------------------------------------------------
441
442 bool wxApp::UnregisterWindowClasses()
443 {
444 bool retval = TRUE;
445
446 #ifndef __WXMICROWIN__
447 // MDI frame window class.
448 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
449 {
450 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
451
452 retval = FALSE;
453 }
454
455 // "no redraw" MDI frame
456 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
457 {
458 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
459
460 retval = FALSE;
461 }
462
463 // MDI child frame window class.
464 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
465 {
466 wxLogLastError(wxT("UnregisterClass(MDI child)"));
467
468 retval = FALSE;
469 }
470
471 // "no redraw" MDI child frame
472 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
473 {
474 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
475
476 retval = FALSE;
477 }
478
479 // canvas class name
480 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
481 {
482 wxLogLastError(wxT("UnregisterClass(canvas)"));
483
484 retval = FALSE;
485 }
486
487 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
488 {
489 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
490
491 retval = FALSE;
492 }
493 #endif // __WXMICROWIN__
494
495 return retval;
496 }
497
498 void wxApp::CleanUp()
499 {
500 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
501 wxSetKeyboardHook(FALSE);
502 #endif
503
504 #if wxUSE_PENWINDOWS
505 wxCleanUpPenWin();
506 #endif
507
508 if ( wxDisableButtonBrush )
509 ::DeleteObject( wxDisableButtonBrush );
510
511 #if wxUSE_OLE
512 #ifdef __WXWINCE__
513 ::CoUninitialize();
514 #else
515 ::OleUninitialize();
516 #endif
517 #endif
518
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();
524
525 #if wxUSE_CTL3D
526 Ctl3dUnregister(wxhInstance);
527 #endif
528
529 delete wxWinHandleHash;
530 wxWinHandleHash = NULL;
531
532 wxAppBase::CleanUp();
533 }
534
535 // ----------------------------------------------------------------------------
536 // wxApp ctor/dtor
537 // ----------------------------------------------------------------------------
538
539 wxApp::wxApp()
540 {
541 m_printMode = wxPRINT_WINDOWS;
542 }
543
544 wxApp::~wxApp()
545 {
546 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
547 // don't come from main(), so we have to free them
548
549 while ( argc )
550 {
551 // m_argv elements were allocated by wxStrdup()
552 free(argv[--argc]);
553 }
554
555 // but m_argv itself -- using new[]
556 delete [] argv;
557 }
558
559 bool wxApp::Initialized()
560 {
561 #ifndef _WINDLL
562 if (GetTopWindow())
563 return TRUE;
564 else
565 return FALSE;
566 #else // Assume initialized if DLL (no way of telling)
567 return TRUE;
568 #endif
569 }
570
571 // this is a temporary hack and will be replaced by using wxEventLoop in the
572 // future
573 //
574 // it is needed to allow other event loops (currently only one: the modal
575 // dialog one) to reset the OnIdle() semaphore because otherwise OnIdle()
576 // wouldn't do anything while a modal dialog shown from OnIdle() call is shown.
577 bool wxIsInOnIdleFlag = FALSE;
578
579 void wxApp::OnIdle(wxIdleEvent& event)
580 {
581 // Avoid recursion (via ProcessEvent default case)
582 if ( wxIsInOnIdleFlag )
583 return;
584
585 wxIsInOnIdleFlag = TRUE;
586
587 wxAppBase::OnIdle(event);
588
589 #if wxUSE_DC_CACHEING
590 // automated DC cache management: clear the cached DCs and bitmap
591 // if it's likely that the app has finished with them, that is, we
592 // get an idle event and we're not dragging anything.
593 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
594 wxDC::ClearCache();
595 #endif // wxUSE_DC_CACHEING
596
597 wxIsInOnIdleFlag = FALSE;
598 }
599
600 void wxApp::WakeUpIdle()
601 {
602 // Send the top window a dummy message so idle handler processing will
603 // start up again. Doing it this way ensures that the idle handler
604 // wakes up in the right thread (see also wxWakeUpMainThread() which does
605 // the same for the main app thread only)
606 wxWindow *topWindow = wxTheApp->GetTopWindow();
607 if ( topWindow )
608 {
609 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
610 {
611 // should never happen
612 wxLogLastError(wxT("PostMessage(WM_NULL)"));
613 }
614 }
615 }
616
617 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
618 {
619 if (GetTopWindow())
620 GetTopWindow()->Close(TRUE);
621 }
622
623 // Default behaviour: close the application with prompts. The
624 // user can veto the close, and therefore the end session.
625 void wxApp::OnQueryEndSession(wxCloseEvent& event)
626 {
627 if (GetTopWindow())
628 {
629 if (!GetTopWindow()->Close(!event.CanVeto()))
630 event.Veto(TRUE);
631 }
632 }
633
634 /* static */
635 int wxApp::GetComCtl32Version()
636 {
637 //FIX ME FOR DIGITALMARS!!
638 #if defined(__WXMICROWIN__) || defined(__WXWINCE__) || defined(__DIGITALMARS__)
639 return 0;
640 #else
641 // cache the result
642 //
643 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
644 // but as its value should be the same both times it doesn't matter
645 static int s_verComCtl32 = -1;
646
647 if ( s_verComCtl32 == -1 )
648 {
649 // initally assume no comctl32.dll at all
650 s_verComCtl32 = 0;
651
652 // we're prepared to handle the errors
653 wxLogNull noLog;
654
655 // do we have it?
656 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
657
658 // if so, then we can check for the version
659 if ( dllComCtl32.IsLoaded() )
660 {
661 #ifdef DLLVER_PLATFORM_WINDOWS
662 // try to use DllGetVersion() if available in _headers_
663 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
664 if ( pfnDllGetVersion )
665 {
666 DLLVERSIONINFO dvi;
667 dvi.cbSize = sizeof(dvi);
668
669 HRESULT hr = (*pfnDllGetVersion)(&dvi);
670 if ( FAILED(hr) )
671 {
672 wxLogApiError(_T("DllGetVersion"), hr);
673 }
674 else
675 {
676 // this is incompatible with _WIN32_IE values, but
677 // compatible with the other values returned by
678 // GetComCtl32Version()
679 s_verComCtl32 = 100*dvi.dwMajorVersion +
680 dvi.dwMinorVersion;
681 }
682 }
683 #endif
684
685 // if DllGetVersion() is unavailable either during compile or
686 // run-time, try to guess the version otherwise
687 if ( !s_verComCtl32 )
688 {
689 // InitCommonControlsEx is unique to 4.70 and later
690 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
691 if ( !pfn )
692 {
693 // not found, must be 4.00
694 s_verComCtl32 = 400;
695 }
696 else // 4.70+
697 {
698 // many symbols appeared in comctl32 4.71, could use any of
699 // them except may be DllInstall()
700 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
701 if ( !pfn )
702 {
703 // not found, must be 4.70
704 s_verComCtl32 = 470;
705 }
706 else
707 {
708 // found, must be 4.71 or later
709 s_verComCtl32 = 471;
710 }
711 }
712 }
713 }
714 }
715
716 return s_verComCtl32;
717 #endif // Microwin/!Microwin
718 }
719
720 // Yield to incoming messages
721
722 bool wxApp::Yield(bool onlyIfNeeded)
723 {
724 // MT-FIXME
725 static bool s_inYield = FALSE;
726
727 #if wxUSE_LOG
728 // disable log flushing from here because a call to wxYield() shouldn't
729 // normally result in message boxes popping up &c
730 wxLog::Suspend();
731 #endif // wxUSE_LOG
732
733 if ( s_inYield )
734 {
735 if ( !onlyIfNeeded )
736 {
737 wxFAIL_MSG( wxT("wxYield called recursively" ) );
738 }
739
740 return FALSE;
741 }
742
743 s_inYield = TRUE;
744
745 // we don't want to process WM_QUIT from here - it should be processed in
746 // the main event loop in order to stop it
747 MSG msg;
748 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
749 msg.message != WM_QUIT )
750 {
751 #if wxUSE_THREADS
752 wxMutexGuiLeaveOrEnter();
753 #endif // wxUSE_THREADS
754
755 if ( !wxTheApp->Dispatch() )
756 break;
757 }
758
759 // if there are pending events, we must process them.
760 ProcessPendingEvents();
761
762 #if wxUSE_LOG
763 // let the logs be flashed again
764 wxLog::Resume();
765 #endif // wxUSE_LOG
766
767 s_inYield = FALSE;
768
769 return TRUE;
770 }
771