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