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