1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/app.cpp
3 // Purpose:     wxApp
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     04/01/98
7 // RCS-ID:      $Id: app.cpp 62085 2009-09-24 15:42:13Z JS $
8 // Copyright:   (c) Julian Smart
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15 
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19 
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22 
23 #if defined(__BORLANDC__)
24     #pragma hdrstop
25 #endif
26 
27 #ifndef WX_PRECOMP
28     #include "wx/msw/wrapcctl.h"
29     #include "wx/dynarray.h"
30     #include "wx/frame.h"
31     #include "wx/app.h"
32     #include "wx/utils.h"
33     #include "wx/gdicmn.h"
34     #include "wx/pen.h"
35     #include "wx/brush.h"
36     #include "wx/cursor.h"
37     #include "wx/icon.h"
38     #include "wx/palette.h"
39     #include "wx/dc.h"
40     #include "wx/dialog.h"
41     #include "wx/msgdlg.h"
42     #include "wx/intl.h"
43     #include "wx/wxchar.h"
44     #include "wx/log.h"
45     #include "wx/module.h"
46 #endif
47 
48 #include "wx/apptrait.h"
49 #include "wx/filename.h"
50 #include "wx/dynlib.h"
51 #include "wx/evtloop.h"
52 
53 #include "wx/msw/private.h"
54 #include "wx/msw/ole/oleutils.h"
55 
56 #if wxUSE_TOOLTIPS
57     #include "wx/tooltip.h"
58 #endif // wxUSE_TOOLTIPS
59 
60 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
61 // compilers don't support it (missing headers, libs, ...)
62 #if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
63     #undef wxUSE_OLE
64 
65     #define  wxUSE_OLE 0
66 #endif // broken compilers
67 
68 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
69     #include <ole2.h>
70     #include <aygshell.h>
71 #endif
72 
73 #if wxUSE_OLE
74     #include <ole2.h>
75 #endif
76 
77 #include <string.h>
78 #include <ctype.h>
79 
80 // For MB_TASKMODAL
81 #ifdef __WXWINCE__
82 #include "wx/msw/wince/missing.h"
83 #endif
84 
85 // instead of including <shlwapi.h> which is not part of the core SDK and not
86 // shipped at all with other compilers, we always define the parts of it we
87 // need here ourselves
88 //
89 // NB: DLLVER_PLATFORM_WINDOWS will be defined if shlwapi.h had been somehow
90 //     included already
91 #ifndef DLLVER_PLATFORM_WINDOWS
92     // hopefully we don't need to change packing as DWORDs should be already
93     // correctly aligned
94     struct DLLVERSIONINFO
95     {
96         DWORD cbSize;
97         DWORD dwMajorVersion;                   // Major version
98         DWORD dwMinorVersion;                   // Minor version
99         DWORD dwBuildNumber;                    // Build number
100         DWORD dwPlatformID;                     // DLLVER_PLATFORM_*
101     };
102 
103     typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
104 #endif // defined(DLLVERSIONINFO)
105 
106 
107 // ---------------------------------------------------------------------------
108 // global variables
109 // ---------------------------------------------------------------------------
110 
111 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
112 extern void wxSetKeyboardHook(bool doIt);
113 #endif
114 
115 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
116 //     with NR suffix - wxWindow::MSWCreate() supposes this
117 #ifdef __WXWINCE__
118 WXDLLIMPEXP_CORE       wxChar *wxCanvasClassName;
119 WXDLLIMPEXP_CORE       wxChar *wxCanvasClassNameNR;
120 #else
121 WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName        = wxT("wxWindowClass");
122 WXDLLIMPEXP_CORE const wxChar *wxCanvasClassNameNR      = wxT("wxWindowClassNR");
123 #endif
124 WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassName      = wxT("wxMDIFrameClass");
125 WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
126 WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
127 WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
128 
129 // ----------------------------------------------------------------------------
130 // private functions
131 // ----------------------------------------------------------------------------
132 
133 LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
134 
135 // ===========================================================================
136 // wxGUIAppTraits implementation
137 // ===========================================================================
138 
139 // private class which we use to pass parameters from BeforeChildWaitLoop() to
140 // AfterChildWaitLoop()
141 struct ChildWaitLoopData
142 {
ChildWaitLoopDataChildWaitLoopData143     ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
144     {
145         wd = wd_;
146         winActive = winActive_;
147     }
148 
149     wxWindowDisabler *wd;
150     wxWindow *winActive;
151 };
152 
BeforeChildWaitLoop()153 void *wxGUIAppTraits::BeforeChildWaitLoop()
154 {
155     /*
156        We use a dirty hack here to disable all application windows (which we
157        must do because otherwise the calls to wxYield() could lead to some very
158        unexpected reentrancies in the users code) but to avoid losing
159        focus/activation entirely when the child process terminates which would
160        happen if we simply disabled everything using wxWindowDisabler. Indeed,
161        remember that Windows will never activate a disabled window and when the
162        last childs window is closed and Windows looks for a window to activate
163        all our windows are still disabled. There is no way to enable them in
164        time because we don't know when the childs windows are going to be
165        closed, so the solution we use here is to keep one special tiny frame
166        enabled all the time. Then when the child terminates it will get
167        activated and when we close it below -- after reenabling all the other
168        windows! -- the previously active window becomes activated again and
169        everything is ok.
170      */
171     wxBeginBusyCursor();
172 
173     // first disable all existing windows
174     wxWindowDisabler *wd = new wxWindowDisabler;
175 
176     // then create an "invisible" frame: it has minimal size, is positioned
177     // (hopefully) outside the screen and doesn't appear on the taskbar
178     wxWindow *winActive = new wxFrame
179                     (
180                         wxTheApp->GetTopWindow(),
181                         wxID_ANY,
182                         wxEmptyString,
183                         wxPoint(32600, 32600),
184                         wxSize(1, 1),
185                         wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
186                     );
187     winActive->Show();
188 
189     return new ChildWaitLoopData(wd, winActive);
190 }
191 
AlwaysYield()192 void wxGUIAppTraits::AlwaysYield()
193 {
194     wxYield();
195 }
196 
AfterChildWaitLoop(void * dataOrig)197 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
198 {
199     wxEndBusyCursor();
200 
201     ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
202 
203     delete data->wd;
204 
205     // finally delete the dummy frame and, as wd has been already destroyed and
206     // the other windows reenabled, the activation is going to return to the
207     // window which had had it before
208     data->winActive->Destroy();
209 
210     // also delete the temporary data object itself
211     delete data;
212 }
213 
DoMessageFromThreadWait()214 bool wxGUIAppTraits::DoMessageFromThreadWait()
215 {
216     // we should return false only if the app should exit, i.e. only if
217     // Dispatch() determines that the main event loop should terminate
218     wxEventLoop *evtLoop = wxEventLoop::GetActive();
219     if ( !evtLoop || !evtLoop->Pending() )
220     {
221         // no events means no quit event
222         return true;
223     }
224 
225     return evtLoop->Dispatch();
226 }
227 
GetToolkitVersion(int * majVer,int * minVer) const228 wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const
229 {
230     OSVERSIONINFO info;
231     wxZeroMemory(info);
232 
233     // on Windows, the toolkit version is the same of the OS version
234     // as Windows integrates the OS kernel with the GUI toolkit.
235     info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
236     if ( ::GetVersionEx(&info) )
237     {
238         if ( majVer )
239             *majVer = info.dwMajorVersion;
240         if ( minVer )
241             *minVer = info.dwMinorVersion;
242     }
243 
244 #if defined(__WXHANDHELD__) || defined(__WXWINCE__)
245     return wxPORT_WINCE;
246 #else
247     return wxPORT_MSW;
248 #endif
249 }
250 
251 // ===========================================================================
252 // wxApp implementation
253 // ===========================================================================
254 
255 int wxApp::m_nCmdShow = SW_SHOWNORMAL;
256 
257 // ---------------------------------------------------------------------------
258 // wxWin macros
259 // ---------------------------------------------------------------------------
260 
261 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
262 
263 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
264     EVT_IDLE(wxApp::OnIdle)
265     EVT_END_SESSION(wxApp::OnEndSession)
266     EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
267 END_EVENT_TABLE()
268 
269 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
270 // fails
271 class wxCallBaseCleanup
272 {
273 public:
wxCallBaseCleanup(wxApp * app)274     wxCallBaseCleanup(wxApp *app) : m_app(app) { }
~wxCallBaseCleanup()275     ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
276 
Dismiss()277     void Dismiss() { m_app = NULL; }
278 
279 private:
280     wxApp *m_app;
281 };
282 
283 //// Initialize
Initialize(int & argc,wxChar ** argv)284 bool wxApp::Initialize(int& argc, wxChar **argv)
285 {
286     if ( !wxAppBase::Initialize(argc, argv) )
287         return false;
288 
289     // ensure that base cleanup is done if we return too early
290     wxCallBaseCleanup callBaseCleanup(this);
291 
292 #ifdef __WXWINCE__
293     wxString tmp = GetAppName();
294     tmp += wxT("ClassName");
295     wxCanvasClassName = wxStrdup( tmp.c_str() );
296     tmp += wxT("NR");
297     wxCanvasClassNameNR = wxStrdup( tmp.c_str() );
298     HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL );
299     if (hWnd)
300     {
301         SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) );
302         return false;
303     }
304 #endif
305 
306 #if !defined(__WXMICROWIN__)
307     InitCommonControls();
308 #endif // !defined(__WXMICROWIN__)
309 
310 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
311     SHInitExtraControls();
312 #endif
313 
314 #ifndef __WXWINCE__
315     // Don't show a message box if a function such as SHGetFileInfo
316     // fails to find a device.
317     SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
318 #endif
319 
320     wxOleInitialize();
321 
322     RegisterWindowClasses();
323 
324     wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
325 
326 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
327     wxSetKeyboardHook(true);
328 #endif
329 
330     callBaseCleanup.Dismiss();
331 
332     return true;
333 }
334 
335 // ---------------------------------------------------------------------------
336 // RegisterWindowClasses
337 // ---------------------------------------------------------------------------
338 
339 // TODO we should only register classes really used by the app. For this it
340 //      would be enough to just delay the class registration until an attempt
341 //      to create a window of this class is made.
RegisterWindowClasses()342 bool wxApp::RegisterWindowClasses()
343 {
344     WNDCLASS wndclass;
345     wxZeroMemory(wndclass);
346 
347     // for each class we register one with CS_(V|H)REDRAW style and one
348     // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
349     static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
350     static const long styleNoRedraw = CS_DBLCLKS;
351 
352     // the fields which are common to all classes
353     wndclass.lpfnWndProc   = (WNDPROC)wxWndProc;
354     wndclass.hInstance     = wxhInstance;
355     wndclass.hCursor       = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
356 
357     // register the class for all normal windows
358     wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
359     wndclass.lpszClassName = wxCanvasClassName;
360     wndclass.style         = styleNormal;
361 
362     if ( !RegisterClass(&wndclass) )
363     {
364         wxLogLastError(wxT("RegisterClass(frame)"));
365     }
366 
367     // "no redraw" frame
368     wndclass.lpszClassName = wxCanvasClassNameNR;
369     wndclass.style         = styleNoRedraw;
370 
371     if ( !RegisterClass(&wndclass) )
372     {
373         wxLogLastError(wxT("RegisterClass(no redraw frame)"));
374     }
375 
376     // Register the MDI frame window class.
377     wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
378     wndclass.lpszClassName = wxMDIFrameClassName;
379     wndclass.style         = styleNormal;
380 
381     if ( !RegisterClass(&wndclass) )
382     {
383         wxLogLastError(wxT("RegisterClass(MDI parent)"));
384     }
385 
386     // "no redraw" MDI frame
387     wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
388     wndclass.style         = styleNoRedraw;
389 
390     if ( !RegisterClass(&wndclass) )
391     {
392         wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
393     }
394 
395     // Register the MDI child frame window class.
396     wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
397     wndclass.lpszClassName = wxMDIChildFrameClassName;
398     wndclass.style         = styleNormal;
399 
400     if ( !RegisterClass(&wndclass) )
401     {
402         wxLogLastError(wxT("RegisterClass(MDI child)"));
403     }
404 
405     // "no redraw" MDI child frame
406     wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
407     wndclass.style         = styleNoRedraw;
408 
409     if ( !RegisterClass(&wndclass) )
410     {
411         wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
412     }
413 
414     return true;
415 }
416 
417 // ---------------------------------------------------------------------------
418 // UnregisterWindowClasses
419 // ---------------------------------------------------------------------------
420 
UnregisterWindowClasses()421 bool wxApp::UnregisterWindowClasses()
422 {
423     bool retval = true;
424 
425 #ifndef __WXMICROWIN__
426     // MDI frame window class.
427     if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
428     {
429         wxLogLastError(wxT("UnregisterClass(MDI parent)"));
430 
431         retval = false;
432     }
433 
434     // "no redraw" MDI frame
435     if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
436     {
437         wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
438 
439         retval = false;
440     }
441 
442     // MDI child frame window class.
443     if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
444     {
445         wxLogLastError(wxT("UnregisterClass(MDI child)"));
446 
447         retval = false;
448     }
449 
450     // "no redraw" MDI child frame
451     if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
452     {
453         wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
454 
455         retval = false;
456     }
457 
458     // canvas class name
459     if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
460     {
461         wxLogLastError(wxT("UnregisterClass(canvas)"));
462 
463         retval = false;
464     }
465 
466     if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
467     {
468         wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
469 
470         retval = false;
471     }
472 #endif // __WXMICROWIN__
473 
474     return retval;
475 }
476 
CleanUp()477 void wxApp::CleanUp()
478 {
479     // all objects pending for deletion must be deleted first, otherwise we
480     // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
481     // call wouldn't succeed as long as any windows still exist), so call the
482     // base class method first and only then do our clean up
483     wxAppBase::CleanUp();
484 
485 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
486     wxSetKeyboardHook(false);
487 #endif
488 
489     wxOleUninitialize();
490 
491     // for an EXE the classes are unregistered when it terminates but DLL may
492     // be loaded several times (load/unload/load) into the same process in
493     // which case the registration will fail after the first time if we don't
494     // unregister the classes now
495     UnregisterWindowClasses();
496 
497     delete wxWinHandleHash;
498     wxWinHandleHash = NULL;
499 
500 #ifdef __WXWINCE__
501     free( wxCanvasClassName );
502     free( wxCanvasClassNameNR );
503 #endif
504 }
505 
506 // ----------------------------------------------------------------------------
507 // wxApp ctor/dtor
508 // ----------------------------------------------------------------------------
509 
wxApp()510 wxApp::wxApp()
511 {
512     m_printMode = wxPRINT_WINDOWS;
513 }
514 
~wxApp()515 wxApp::~wxApp()
516 {
517 }
518 
519 // ----------------------------------------------------------------------------
520 // wxApp idle handling
521 // ----------------------------------------------------------------------------
522 
OnIdle(wxIdleEvent & event)523 void wxApp::OnIdle(wxIdleEvent& event)
524 {
525     wxAppBase::OnIdle(event);
526 
527 #if wxUSE_DC_CACHEING
528     // automated DC cache management: clear the cached DCs and bitmap
529     // if it's likely that the app has finished with them, that is, we
530     // get an idle event and we're not dragging anything.
531     if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
532         wxDC::ClearCache();
533 #endif // wxUSE_DC_CACHEING
534 }
535 
WakeUpIdle()536 void wxApp::WakeUpIdle()
537 {
538     // Send the top window a dummy message so idle handler processing will
539     // start up again.  Doing it this way ensures that the idle handler
540     // wakes up in the right thread (see also wxWakeUpMainThread() which does
541     // the same for the main app thread only)
542     wxWindow * const topWindow = wxTheApp->GetTopWindow();
543     if ( topWindow )
544     {
545         HWND hwndTop = GetHwndOf(topWindow);
546 
547         // Do not post WM_NULL if there's already a pending WM_NULL to avoid
548         // overflowing the message queue.
549         //
550         // Notice that due to a limitation of PeekMessage() API (which handles
551         // 0,0 range specially), we have to check the range from 0-1 instead.
552         // This still makes it possible to overflow the queue with WM_NULLs by
553         // interspersing the calles to WakeUpIdle() with windows creation but
554         // it should be rather hard to do it accidentally.
555         MSG msg;
556         if ( !::PeekMessage(&msg, hwndTop, 0, 1, PM_NOREMOVE) ||
557               ::PeekMessage(&msg, hwndTop, 1, 1, PM_NOREMOVE) )
558         {
559             if ( !::PostMessage(hwndTop, WM_NULL, 0, 0) )
560             {
561                 // should never happen
562                 wxLogLastError(wxT("PostMessage(WM_NULL)"));
563             }
564         }
565     }
566 #if wxUSE_THREADS
567     else
568         wxWakeUpMainThread();
569 #endif // wxUSE_THREADS
570 }
571 
572 // ----------------------------------------------------------------------------
573 // other wxApp event hanlders
574 // ----------------------------------------------------------------------------
575 
OnEndSession(wxCloseEvent & WXUNUSED (event))576 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
577 {
578     if (GetTopWindow())
579         GetTopWindow()->Close(true);
580 }
581 
582 // Default behaviour: close the application with prompts. The
583 // user can veto the close, and therefore the end session.
OnQueryEndSession(wxCloseEvent & event)584 void wxApp::OnQueryEndSession(wxCloseEvent& event)
585 {
586     if (GetTopWindow())
587     {
588         if (!GetTopWindow()->Close(!event.CanVeto()))
589             event.Veto(true);
590     }
591 }
592 
593 // ----------------------------------------------------------------------------
594 // miscellaneous
595 // ----------------------------------------------------------------------------
596 
597 /* static */
GetComCtl32Version()598 int wxApp::GetComCtl32Version()
599 {
600 #if defined(__WXMICROWIN__) || defined(__WXWINCE__)
601     return 0;
602 #else
603     // cache the result
604     //
605     // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
606     //     but as its value should be the same both times it doesn't matter
607     static int s_verComCtl32 = -1;
608 
609     if ( s_verComCtl32 == -1 )
610     {
611         // initally assume no comctl32.dll at all
612         s_verComCtl32 = 0;
613 
614         // we're prepared to handle the errors
615         wxLogNull noLog;
616 
617 #if wxUSE_DYNLIB_CLASS
618         // we don't want to load comctl32.dll, it should be already loaded but,
619         // depending on the OS version and the presence of the manifest, it can
620         // be either v5 or v6 and instead of trying to guess it just get the
621         // handle of the already loaded version
622         wxLoadedDLL dllComCtl32(_T("comctl32.dll"));
623         if ( !dllComCtl32.IsLoaded() )
624         {
625             s_verComCtl32 = 0;
626             return 0;
627         }
628 
629         // if so, then we can check for the version
630         if ( dllComCtl32.IsLoaded() )
631         {
632             // now check if the function is available during run-time
633             wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
634             if ( pfnDllGetVersion )
635             {
636                 DLLVERSIONINFO dvi;
637                 dvi.cbSize = sizeof(dvi);
638 
639                 HRESULT hr = (*pfnDllGetVersion)(&dvi);
640                 if ( FAILED(hr) )
641                 {
642                     wxLogApiError(_T("DllGetVersion"), hr);
643                 }
644                 else
645                 {
646                     // this is incompatible with _WIN32_IE values, but
647                     // compatible with the other values returned by
648                     // GetComCtl32Version()
649                     s_verComCtl32 = 100*dvi.dwMajorVersion +
650                                         dvi.dwMinorVersion;
651                 }
652             }
653 
654             // if DllGetVersion() is unavailable either during compile or
655             // run-time, try to guess the version otherwise
656             if ( !s_verComCtl32 )
657             {
658                 // InitCommonControlsEx is unique to 4.70 and later
659                 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
660                 if ( !pfn )
661                 {
662                     // not found, must be 4.00
663                     s_verComCtl32 = 400;
664                 }
665                 else // 4.70+
666                 {
667                     // many symbols appeared in comctl32 4.71, could use any of
668                     // them except may be DllInstall()
669                     pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
670                     if ( !pfn )
671                     {
672                         // not found, must be 4.70
673                         s_verComCtl32 = 470;
674                     }
675                     else
676                     {
677                         // found, must be 4.71 or later
678                         s_verComCtl32 = 471;
679                     }
680                 }
681             }
682         }
683 #endif // wxUSE_DYNLIB_CLASS
684     }
685 
686     return s_verComCtl32;
687 #endif // Microwin/!Microwin
688 }
689 
690 // Yield to incoming messages
691 
Yield(bool onlyIfNeeded)692 bool wxApp::Yield(bool onlyIfNeeded)
693 {
694     // MT-FIXME
695     static bool s_inYield = false;
696 
697 #if wxUSE_LOG
698     // disable log flushing from here because a call to wxYield() shouldn't
699     // normally result in message boxes popping up &c
700     wxLog::Suspend();
701 #endif // wxUSE_LOG
702 
703     if ( s_inYield )
704     {
705         if ( !onlyIfNeeded )
706         {
707             wxFAIL_MSG( wxT("wxYield called recursively" ) );
708         }
709 
710         return false;
711     }
712 
713     s_inYield = true;
714 
715     // we don't want to process WM_QUIT from here - it should be processed in
716     // the main event loop in order to stop it
717     wxEventLoopGuarantor dummyLoopIfNeeded;
718     MSG msg;
719     while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
720             msg.message != WM_QUIT )
721     {
722 #if wxUSE_THREADS
723         wxMutexGuiLeaveOrEnter();
724 #endif // wxUSE_THREADS
725 
726         if ( !wxTheApp->Dispatch() )
727             break;
728     }
729 
730     // if there are pending events, we must process them.
731     ProcessPendingEvents();
732 
733 #if wxUSE_LOG
734     // let the logs be flashed again
735     wxLog::Resume();
736 #endif // wxUSE_LOG
737 
738     s_inYield = false;
739 
740     return true;
741 }
742 
743 #if wxUSE_EXCEPTIONS
744 
745 // ----------------------------------------------------------------------------
746 // exception handling
747 // ----------------------------------------------------------------------------
748 
OnExceptionInMainLoop()749 bool wxApp::OnExceptionInMainLoop()
750 {
751     // ask the user about what to do: use the Win32 API function here as it
752     // could be dangerous to use any wxWidgets code in this state
753     switch (
754             ::MessageBox
755               (
756                 NULL,
757                 _T("An unhandled exception occurred. Press \"Abort\" to \
758 terminate the program,\r\n\
759 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
760                 _T("Unhandled exception"),
761                 MB_ABORTRETRYIGNORE |
762                 MB_ICONERROR|
763                 MB_TASKMODAL
764               )
765            )
766     {
767         case IDABORT:
768             throw;
769 
770         default:
771             wxFAIL_MSG( _T("unexpected MessageBox() return code") );
772             // fall through
773 
774         case IDRETRY:
775             return false;
776 
777         case IDIGNORE:
778             return true;
779     }
780 }
781 
782 #endif // wxUSE_EXCEPTIONS
783 
784 // ----------------------------------------------------------------------------
785 // deprecated event loop functions
786 // ----------------------------------------------------------------------------
787 
788 #if WXWIN_COMPATIBILITY_2_4
789 
DoMessage(WXMSG * pMsg)790 void wxApp::DoMessage(WXMSG *pMsg)
791 {
792     wxEventLoop *evtLoop = wxEventLoop::GetActive();
793     if ( evtLoop )
794         evtLoop->ProcessMessage(pMsg);
795 }
796 
DoMessage()797 bool wxApp::DoMessage()
798 {
799     wxEventLoop *evtLoop = wxEventLoop::GetActive();
800     return evtLoop ? evtLoop->Dispatch() : false;
801 }
802 
ProcessMessage(WXMSG * pMsg)803 bool wxApp::ProcessMessage(WXMSG* pMsg)
804 {
805     wxEventLoop *evtLoop = wxEventLoop::GetActive();
806     return evtLoop && evtLoop->PreProcessMessage(pMsg);
807 }
808 
809 #endif // WXWIN_COMPATIBILITY_2_4
810