wxBase/GUI separation: 1st step, wxMSW should build, all the rest is broken
[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 #ifdef __GNUG__
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/cmdline.h"
53 #include "wx/filename.h"
54 #include "wx/module.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 #if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__WXMICROWIN__)) && !defined(__CYGWIN10__))
89 #include <commctrl.h>
90 #endif
91
92 #ifndef __WXMICROWIN__
93 #include "wx/msw/msvcrt.h"
94 #endif
95
96 // ----------------------------------------------------------------------------
97 // conditional compilation
98 // ----------------------------------------------------------------------------
99
100 // The macro _WIN32_IE is defined by commctrl.h (unless it had already been
101 // defined before) and shows us what common control features are available
102 // during the compile time (it doesn't mean that they will be available during
103 // the run-time, use GetComCtl32Version() to test for them!). The possible
104 // values are:
105 //
106 // 0x0200 for comctl32.dll 4.00 shipped with Win95/NT 4.0
107 // 0x0300 4.70 IE 3.x
108 // 0x0400 4.71 IE 4.0
109 // 0x0401 4.72 IE 4.01 and Win98
110 // 0x0500 5.00 IE 5.x and NT 5.0 (Win2000)
111
112 #ifndef _WIN32_IE
113 // minimal set of features by default
114 #define _WIN32_IE 0x0200
115 #endif
116
117 #if _WIN32_IE >= 0x0300 && \
118 (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
119 !defined(__CYGWIN__)
120 #include <shlwapi.h>
121 #endif
122
123 // ---------------------------------------------------------------------------
124 // global variables
125 // ---------------------------------------------------------------------------
126
127 extern wxChar *wxBuffer;
128 extern wxList WXDLLEXPORT wxPendingDelete;
129 #ifndef __WXMICROWIN__
130 extern void wxSetKeyboardHook(bool doIt);
131 #endif
132
133 MSG s_currentMsg;
134
135 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
136 // with NR suffix - wxWindow::MSWCreate() supposes this
137 const wxChar *wxCanvasClassName = wxT("wxWindowClass");
138 const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
139 const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
140 const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
141 const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
142 const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
143
144 HICON wxSTD_FRAME_ICON = (HICON) NULL;
145 HICON wxSTD_MDICHILDFRAME_ICON = (HICON) NULL;
146 HICON wxSTD_MDIPARENTFRAME_ICON = (HICON) NULL;
147
148 HICON wxDEFAULT_FRAME_ICON = (HICON) NULL;
149 HICON wxDEFAULT_MDICHILDFRAME_ICON = (HICON) NULL;
150 HICON wxDEFAULT_MDIPARENTFRAME_ICON = (HICON) NULL;
151
152 HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
153
154 LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
155
156 // FIXME wxUSE_ON_FATAL_EXCEPTION is only supported for VC++ now because it
157 // needs compiler support for Win32 SEH. Others (especially Borland)
158 // probably have it too, but I'm not sure about how it works
159 // JACS: get 'Cannot use __try in functions that require unwinding
160 // in Unicode mode, so disabling.
161 #if !defined(__VISUALC__) || defined(__WIN16__) || defined(UNICODE)
162 #undef wxUSE_ON_FATAL_EXCEPTION
163 #define wxUSE_ON_FATAL_EXCEPTION 0
164 #endif // VC++
165
166 #if wxUSE_ON_FATAL_EXCEPTION
167 static bool gs_handleExceptions = FALSE;
168 #endif
169
170 // ===========================================================================
171 // wxGUIAppTraits implementation
172 // ===========================================================================
173
174 // private class which we use to pass parameters from BeforeChildWaitLoop() to
175 // AfterChildWaitLoop()
176 struct ChildWaitLoopData
177 {
178 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
179 {
180 wd = wd_;
181 winActive = winActive_;
182 }
183
184 wxWindowDisabler *wd;
185 wxWindow *winActive;
186 };
187
188 void *wxGUIAppTraits::BeforeChildWaitLoop()
189 {
190 /*
191 We use a dirty hack here to disable all application windows (which we
192 must do because otherwise the calls to wxYield() could lead to some very
193 unexpected reentrancies in the users code) but to avoid losing
194 focus/activation entirely when the child process terminates which would
195 happen if we simply disabled everything using wxWindowDisabler. Indeed,
196 remember that Windows will never activate a disabled window and when the
197 last childs window is closed and Windows looks for a window to activate
198 all our windows are still disabled. There is no way to enable them in
199 time because we don't know when the childs windows are going to be
200 closed, so the solution we use here is to keep one special tiny frame
201 enabled all the time. Then when the child terminates it will get
202 activated and when we close it below -- after reenabling all the other
203 windows! -- the previously active window becomes activated again and
204 everything is ok.
205 */
206 wxBeginBusyCursor();
207
208 // first disable all existing windows
209 wxWindowDisabler *wd = new wxWindowDisabler;
210
211 // then create an "invisible" frame: it has minimal size, is positioned
212 // (hopefully) outside the screen and doesn't appear on the taskbar
213 wxWindow *winActive = new wxFrame
214 (
215 wxTheApp->GetTopWindow(),
216 -1,
217 _T(""),
218 wxPoint(32600, 32600),
219 wxSize(1, 1),
220 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
221 );
222 winActive->Show();
223
224 return new ChildWaitLoopData(wd, winActive);
225 }
226
227 void wxGUIAppTraits::AlwaysYield()
228 {
229 wxYield();
230 }
231
232 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
233 {
234 wxEndBusyCursor();
235
236 const ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
237
238 delete data->wd;
239
240 // finally delete the dummy frame and, as wd has been already destroyed and
241 // the other windows reenabled, the activation is going to return to the
242 // window which had had it before
243 data->winActive->Destroy();
244 }
245
246 bool wxGUIAppTraits::DoMessageFromThreadWait()
247 {
248 return !wxTheApp || wxTheApp->DoMessage();
249 }
250
251 // ===========================================================================
252 // wxApp implementation
253 // ===========================================================================
254
255 // ---------------------------------------------------------------------------
256 // wxWin macros
257 // ---------------------------------------------------------------------------
258
259 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
260
261 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
262 EVT_IDLE(wxApp::OnIdle)
263 EVT_END_SESSION(wxApp::OnEndSession)
264 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
265 END_EVENT_TABLE()
266
267 //// Initialize
268 bool wxApp::Initialize()
269 {
270 // the first thing to do is to check if we're trying to run an Unicode
271 // program under Win9x w/o MSLU emulation layer - if so, abort right now
272 // as it has no chance to work
273 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
274 if ( wxGetOsVersion() != wxWINDOWS_NT )
275 {
276 // note that we can use MessageBoxW() as it's implemented even under
277 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
278 // used by wxLocale are not
279 ::MessageBox
280 (
281 NULL,
282 _T("This program uses Unicode and requires Windows NT/2000/XP.\nProgram aborted."),
283 _T("wxWindows Fatal Error"),
284 MB_ICONERROR | MB_OK
285 );
286
287 return FALSE;
288 }
289 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
290
291 wxBuffer = new wxChar[1500]; // FIXME
292
293 wxClassInfo::InitializeClasses();
294
295 #if wxUSE_THREADS
296 wxPendingEventsLocker = new wxCriticalSection;
297 #endif
298
299 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
300 wxTheColourDatabase->Initialize();
301
302 wxInitializeStockLists();
303 wxInitializeStockObjects();
304
305 wxBitmap::InitStandardHandlers();
306
307 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
308 InitCommonControls();
309 #endif // __WIN95__
310
311 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
312
313 #ifdef __WIN16__
314 // for OLE, enlarge message queue to be as large as possible
315 int iMsg = 96;
316 while (!SetMessageQueue(iMsg) && (iMsg -= 8))
317 ;
318 #endif // Win16
319
320 #if wxUSE_OLE
321 // we need to initialize OLE library
322 if ( FAILED(::OleInitialize(NULL)) )
323 wxLogError(_("Cannot initialize OLE"));
324 #endif
325
326 #endif // wxUSE_OLE
327
328 #if wxUSE_CTL3D
329 if (!Ctl3dRegister(wxhInstance))
330 wxLogError(wxT("Cannot register CTL3D"));
331
332 Ctl3dAutoSubclass(wxhInstance);
333 #endif // wxUSE_CTL3D
334
335 // VZ: these icons are not in wx.rc anyhow (but should they?)!
336 #if 0
337 wxSTD_FRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_FRAME"));
338 wxSTD_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_MDIPARENTFRAME"));
339 wxSTD_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_MDICHILDFRAME"));
340
341 wxDEFAULT_FRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_FRAME"));
342 wxDEFAULT_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_MDIPARENTFRAME"));
343 wxDEFAULT_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_MDICHILDFRAME"));
344 #endif // 0
345
346 RegisterWindowClasses();
347
348 #ifndef __WXMICROWIN__
349 // Create the brush for disabling bitmap buttons
350
351 LOGBRUSH lb;
352 lb.lbStyle = BS_PATTERN;
353 lb.lbColor = 0;
354 lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
355 if ( lb.lbHatch )
356 {
357 wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
358 ::DeleteObject( (HGDIOBJ)lb.lbHatch );
359 }
360 //else: wxWindows resources are probably not linked in
361 #endif
362
363 #if wxUSE_PENWINDOWS
364 wxRegisterPenWin();
365 #endif
366
367 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
368
369 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
370 // PLEASE DO NOT ALTER THIS.
371 #if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
372 extern char wxDummyChar;
373 if (wxDummyChar) wxDummyChar++;
374 #endif
375
376 #ifndef __WXMICROWIN__
377 wxSetKeyboardHook(TRUE);
378 #endif
379
380 wxModule::RegisterModules();
381 if (!wxModule::InitializeModules())
382 return FALSE;
383 return TRUE;
384 }
385
386 // ---------------------------------------------------------------------------
387 // RegisterWindowClasses
388 // ---------------------------------------------------------------------------
389
390 // TODO we should only register classes really used by the app. For this it
391 // would be enough to just delay the class registration until an attempt
392 // to create a window of this class is made.
393 bool wxApp::RegisterWindowClasses()
394 {
395 WNDCLASS wndclass;
396 wxZeroMemory(wndclass);
397
398 // for each class we register one with CS_(V|H)REDRAW style and one
399 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
400 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
401 static const long styleNoRedraw = CS_DBLCLKS;
402
403 // the fields which are common to all classes
404 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
405 wndclass.hInstance = wxhInstance;
406 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
407
408 // Register the frame window class.
409 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
410 wndclass.lpszClassName = wxCanvasClassName;
411 wndclass.style = styleNormal;
412
413 if ( !RegisterClass(&wndclass) )
414 {
415 wxLogLastError(wxT("RegisterClass(frame)"));
416 }
417
418 // "no redraw" frame
419 wndclass.lpszClassName = wxCanvasClassNameNR;
420 wndclass.style = styleNoRedraw;
421
422 if ( !RegisterClass(&wndclass) )
423 {
424 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
425 }
426
427 // Register the MDI frame window class.
428 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
429 wndclass.lpszClassName = wxMDIFrameClassName;
430 wndclass.style = styleNormal;
431
432 if ( !RegisterClass(&wndclass) )
433 {
434 wxLogLastError(wxT("RegisterClass(MDI parent)"));
435 }
436
437 // "no redraw" MDI frame
438 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
439 wndclass.style = styleNoRedraw;
440
441 if ( !RegisterClass(&wndclass) )
442 {
443 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
444 }
445
446 // Register the MDI child frame window class.
447 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
448 wndclass.lpszClassName = wxMDIChildFrameClassName;
449 wndclass.style = styleNormal;
450
451 if ( !RegisterClass(&wndclass) )
452 {
453 wxLogLastError(wxT("RegisterClass(MDI child)"));
454 }
455
456 // "no redraw" MDI child frame
457 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
458 wndclass.style = styleNoRedraw;
459
460 if ( !RegisterClass(&wndclass) )
461 {
462 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
463 }
464
465 return TRUE;
466 }
467
468 // ---------------------------------------------------------------------------
469 // UnregisterWindowClasses
470 // ---------------------------------------------------------------------------
471
472 bool wxApp::UnregisterWindowClasses()
473 {
474 bool retval = TRUE;
475
476 #ifndef __WXMICROWIN__
477 // MDI frame window class.
478 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
479 {
480 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
481
482 retval = FALSE;
483 }
484
485 // "no redraw" MDI frame
486 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
487 {
488 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
489
490 retval = FALSE;
491 }
492
493 // MDI child frame window class.
494 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
495 {
496 wxLogLastError(wxT("UnregisterClass(MDI child)"));
497
498 retval = FALSE;
499 }
500
501 // "no redraw" MDI child frame
502 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
503 {
504 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
505
506 retval = FALSE;
507 }
508
509 // canvas class name
510 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
511 {
512 wxLogLastError(wxT("UnregisterClass(canvas)"));
513
514 retval = FALSE;
515 }
516
517 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
518 {
519 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
520
521 retval = FALSE;
522 }
523 #endif // __WXMICROWIN__
524
525 return retval;
526 }
527
528 // ---------------------------------------------------------------------------
529 // Convert Windows to argc, argv style
530 // ---------------------------------------------------------------------------
531
532 void wxApp::ConvertToStandardCommandArgs(const char* lpCmdLine)
533 {
534 // break the command line in words
535 wxArrayString args =
536 wxCmdLineParser::ConvertStringToArgs(wxConvertMB2WX(lpCmdLine));
537
538 // +1 here for the program name
539 argc = args.GetCount() + 1;
540
541 // and +1 here for the terminating NULL
542 argv = new wxChar *[argc + 1];
543
544 argv[0] = new wxChar[260]; // 260 is MAX_PATH value from windef.h
545 ::GetModuleFileName(wxhInstance, argv[0], 260);
546
547 // also set the app name from argv[0]
548 wxString name;
549 wxFileName::SplitPath(argv[0], NULL, &name, NULL);
550
551 // but don't override the name already set by the user code, if any
552 if ( GetAppName().empty() )
553 SetAppName(name);
554
555 // copy all the other arguments to wxApp::argv[]
556 for ( int i = 1; i < argc; i++ )
557 {
558 argv[i] = copystring(args[i - 1]);
559 }
560
561 // argv[] must be NULL-terminated
562 argv[argc] = NULL;
563 }
564
565 //// Cleans up any wxWindows internal structures left lying around
566
567 void wxApp::CleanUp()
568 {
569 //// COMMON CLEANUP
570
571 #if wxUSE_LOG
572 // flush the logged messages if any and install a 'safer' log target: the
573 // default one (wxLogGui) can't be used after the resources are freed just
574 // below and the user suppliedo ne might be even more unsafe (using any
575 // wxWindows GUI function is unsafe starting from now)
576 wxLog::DontCreateOnDemand();
577
578 // this will flush the old messages if any
579 delete wxLog::SetActiveTarget(new wxLogStderr);
580 #endif // wxUSE_LOG
581
582 // One last chance for pending objects to be cleaned up
583 wxTheApp->DeletePendingObjects();
584
585 wxModule::CleanUpModules();
586
587 wxDeleteStockObjects();
588
589 // Destroy all GDI lists, etc.
590 wxDeleteStockLists();
591
592 delete wxTheColourDatabase;
593 wxTheColourDatabase = NULL;
594
595 wxBitmap::CleanUpHandlers();
596
597 delete[] wxBuffer;
598 wxBuffer = NULL;
599
600 //// WINDOWS-SPECIFIC CLEANUP
601
602 #ifndef __WXMICROWIN__
603 wxSetKeyboardHook(FALSE);
604 #endif
605
606 #if wxUSE_PENWINDOWS
607 wxCleanUpPenWin();
608 #endif
609
610 if (wxSTD_FRAME_ICON)
611 DestroyIcon(wxSTD_FRAME_ICON);
612 if (wxSTD_MDICHILDFRAME_ICON)
613 DestroyIcon(wxSTD_MDICHILDFRAME_ICON);
614 if (wxSTD_MDIPARENTFRAME_ICON)
615 DestroyIcon(wxSTD_MDIPARENTFRAME_ICON);
616
617 if (wxDEFAULT_FRAME_ICON)
618 DestroyIcon(wxDEFAULT_FRAME_ICON);
619 if (wxDEFAULT_MDICHILDFRAME_ICON)
620 DestroyIcon(wxDEFAULT_MDICHILDFRAME_ICON);
621 if (wxDEFAULT_MDIPARENTFRAME_ICON)
622 DestroyIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
623
624 if ( wxDisableButtonBrush )
625 ::DeleteObject( wxDisableButtonBrush );
626
627 #if wxUSE_OLE
628 ::OleUninitialize();
629 #endif
630
631 #ifdef WXMAKINGDLL
632 // for an EXE the classes are unregistered when it terminates but DLL may
633 // be loaded several times (load/unload/load) into the same process in
634 // which case the registration will fail after the first time if we don't
635 // unregister the classes now
636 UnregisterWindowClasses();
637 #endif // WXMAKINGDLL
638
639 #if wxUSE_CTL3D
640 Ctl3dUnregister(wxhInstance);
641 #endif
642
643 delete wxWinHandleHash;
644 wxWinHandleHash = NULL; // Set to null in case anything later tries to ref it.
645
646 delete wxPendingEvents;
647 wxPendingEvents = NULL; // Set to null because wxAppBase::wxEvtHandler is destroyed later.
648
649 #if wxUSE_THREADS
650 delete wxPendingEventsLocker;
651 wxPendingEventsLocker = NULL; // Set to null because wxAppBase::wxEvtHandler is destroyed later.
652 // If we don't do the following, we get an apparent memory leak
653 #if wxUSE_VALIDATORS
654 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
655 #endif // wxUSE_VALIDATORS
656 #endif // wxUSE_THREADS
657
658 wxClassInfo::CleanUpClasses();
659
660 delete wxTheApp;
661 wxTheApp = NULL;
662
663 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
664 // At this point we want to check if there are any memory
665 // blocks that aren't part of the wxDebugContext itself,
666 // as a special case. Then when dumping we need to ignore
667 // wxDebugContext, too.
668 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
669 {
670 wxLogMessage(wxT("There were memory leaks."));
671 wxDebugContext::Dump();
672 wxDebugContext::PrintStatistics();
673 }
674 // wxDebugContext::SetStream(NULL, NULL);
675 #endif
676
677 #if wxUSE_LOG
678 // do it as the very last thing because everything else can log messages
679 delete wxLog::SetActiveTarget(NULL);
680 #endif // wxUSE_LOG
681 }
682
683 //----------------------------------------------------------------------
684 // Entry point helpers, used by wxPython
685 //----------------------------------------------------------------------
686
687 int WXDLLEXPORT wxEntryStart( int WXUNUSED(argc), char** WXUNUSED(argv) )
688 {
689 return wxApp::Initialize();
690 }
691
692 int WXDLLEXPORT wxEntryInitGui()
693 {
694 return wxTheApp->OnInitGui();
695 }
696
697 void WXDLLEXPORT wxEntryCleanup()
698 {
699 wxApp::CleanUp();
700 }
701
702
703 #if !defined(_WINDLL) || (defined(_WINDLL) && defined(WXMAKINGDLL))
704
705 // temporarily disable this warning which would be generated in release builds
706 // because of __try
707 #ifdef __VISUALC__
708 #pragma warning(disable: 4715) // not all control paths return a value
709 #endif // Visual C++
710
711 //----------------------------------------------------------------------
712 // Main wxWindows entry point
713 //----------------------------------------------------------------------
714 int wxEntry(WXHINSTANCE hInstance,
715 WXHINSTANCE WXUNUSED(hPrevInstance),
716 char *lpCmdLine,
717 int nCmdShow,
718 bool enterLoop)
719 {
720 // do check for memory leaks on program exit
721 // (another useful flag is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free
722 // deallocated memory which may be used to simulate low-memory condition)
723 #ifndef __WXMICROWIN__
724 wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
725 #endif
726
727 #ifdef __MWERKS__
728 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
729 // This seems to be necessary since there are 'rogue'
730 // objects present at this point (perhaps global objects?)
731 // Setting a checkpoint will ignore them as far as the
732 // memory checking facility is concerned.
733 // Of course you may argue that memory allocated in globals should be
734 // checked, but this is a reasonable compromise.
735 wxDebugContext::SetCheckpoint();
736 #endif
737 #endif
738
739 // take everything into a try-except block to be able to call
740 // OnFatalException() if necessary
741 #if wxUSE_ON_FATAL_EXCEPTION
742 __try {
743 #endif
744 wxhInstance = (HINSTANCE) hInstance;
745
746 if (!wxEntryStart(0,0))
747 return 0;
748
749 // create the application object or ensure that one already exists
750 if (!wxTheApp)
751 {
752 // The app may have declared a global application object, but we recommend
753 // the IMPLEMENT_APP macro is used instead, which sets an initializer
754 // function for delayed, dynamic app object construction.
755 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
756 wxT("No initializer - use IMPLEMENT_APP macro.") );
757
758 wxTheApp = (wxApp*) (*wxApp::GetInitializerFunction()) ();
759 }
760
761 wxCHECK_MSG( wxTheApp, 0, wxT("You have to define an instance of wxApp!") );
762
763 // save the WinMain() parameters
764 if (lpCmdLine) // MicroWindows passes NULL
765 wxTheApp->ConvertToStandardCommandArgs(lpCmdLine);
766 wxTheApp->m_nCmdShow = nCmdShow;
767
768 // We really don't want timestamps by default, because it means
769 // we can't simply double-click on the error message and get to that
770 // line in the source. So VC++ at least, let's have a sensible default.
771 #ifdef __VISUALC__
772 #if wxUSE_LOG
773 wxLog::SetTimestamp(NULL);
774 #endif // wxUSE_LOG
775 #endif // __VISUALC__
776
777 // init the app
778 int retValue = wxEntryInitGui() && wxTheApp->OnInit() ? 0 : -1;
779
780 if ( retValue == 0 )
781 {
782 if ( enterLoop )
783 {
784 // run the main loop
785 wxTheApp->OnRun();
786 }
787 else
788 {
789 // we want to initialize, but not run or exit immediately.
790 return 1;
791 }
792 }
793 //else: app initialization failed, so we skipped OnRun()
794
795 wxWindow *topWindow = wxTheApp->GetTopWindow();
796 if ( topWindow )
797 {
798 // Forcibly delete the window.
799 if ( topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
800 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
801 {
802 topWindow->Close(TRUE);
803 wxTheApp->DeletePendingObjects();
804 }
805 else
806 {
807 delete topWindow;
808 wxTheApp->SetTopWindow(NULL);
809 }
810 }
811
812 retValue = wxTheApp->OnExit();
813
814 wxEntryCleanup();
815
816 return retValue;
817
818 #if wxUSE_ON_FATAL_EXCEPTION
819 }
820 __except ( gs_handleExceptions ? EXCEPTION_EXECUTE_HANDLER
821 : EXCEPTION_CONTINUE_SEARCH ) {
822 if ( wxTheApp )
823 {
824 // give the user a chance to do something special about this
825 wxTheApp->OnFatalException();
826 }
827
828 ::ExitProcess(3); // the same exit code as abort()
829
830 // NOTREACHED
831 }
832 #endif // wxUSE_ON_FATAL_EXCEPTION
833 }
834
835 // restore warning state
836 #ifdef __VISUALC__
837 #pragma warning(default: 4715) // not all control paths return a value
838 #endif // Visual C++
839
840 #else /* _WINDLL */
841
842 //----------------------------------------------------------------------
843 // Entry point for wxWindows + the App in a DLL
844 //----------------------------------------------------------------------
845
846 int wxEntry(WXHINSTANCE hInstance)
847 {
848 wxhInstance = (HINSTANCE) hInstance;
849 wxEntryStart(0, 0);
850
851 // The app may have declared a global application object, but we recommend
852 // the IMPLEMENT_APP macro is used instead, which sets an initializer function
853 // for delayed, dynamic app object construction.
854 if (!wxTheApp)
855 {
856 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
857 "No initializer - use IMPLEMENT_APP macro." );
858
859 wxTheApp = (* wxApp::GetInitializerFunction()) ();
860 }
861
862 wxCHECK_MSG( wxTheApp, 0, "You have to define an instance of wxApp!" );
863
864 wxTheApp->argc = 0;
865 wxTheApp->argv = NULL;
866
867 wxEntryInitGui();
868
869 wxTheApp->OnInit();
870
871 wxWindow *topWindow = wxTheApp->GetTopWindow();
872 if ( topWindow && topWindow->GetHWND())
873 {
874 topWindow->Show(TRUE);
875 }
876
877 return 1;
878 }
879 #endif // _WINDLL
880
881 //// Static member initialization
882
883 wxApp::wxApp()
884 {
885 argc = 0;
886 argv = NULL;
887 m_printMode = wxPRINT_WINDOWS;
888 m_auto3D = TRUE;
889 }
890
891 wxApp::~wxApp()
892 {
893 // Delete command-line args
894 int i;
895 for (i = 0; i < argc; i++)
896 {
897 delete[] argv[i];
898 }
899 delete[] argv;
900 }
901
902 bool wxApp::Initialized()
903 {
904 #ifndef _WINDLL
905 if (GetTopWindow())
906 return TRUE;
907 else
908 return FALSE;
909 #else // Assume initialized if DLL (no way of telling)
910 return TRUE;
911 #endif
912 }
913
914 /*
915 * Get and process a message, returning FALSE if WM_QUIT
916 * received (and also set the flag telling the app to exit the main loop)
917 *
918 */
919 bool wxApp::DoMessage()
920 {
921 BOOL rc = ::GetMessage(&s_currentMsg, (HWND) NULL, 0, 0);
922 if ( rc == 0 )
923 {
924 // got WM_QUIT
925 m_keepGoing = FALSE;
926
927 return FALSE;
928 }
929 else if ( rc == -1 )
930 {
931 // should never happen, but let's test for it nevertheless
932 wxLogLastError(wxT("GetMessage"));
933 }
934 else
935 {
936 #if wxUSE_THREADS
937 wxASSERT_MSG( wxThread::IsMain(),
938 wxT("only the main thread can process Windows messages") );
939
940 static bool s_hadGuiLock = TRUE;
941 static wxMsgArray s_aSavedMessages;
942
943 // if a secondary thread owns is doing GUI calls, save all messages for
944 // later processing - we can't process them right now because it will
945 // lead to recursive library calls (and we're not reentrant)
946 if ( !wxGuiOwnedByMainThread() )
947 {
948 s_hadGuiLock = FALSE;
949
950 // leave out WM_COMMAND messages: too dangerous, sometimes
951 // the message will be processed twice
952 if ( !wxIsWaitingForThread() ||
953 s_currentMsg.message != WM_COMMAND )
954 {
955 s_aSavedMessages.Add(s_currentMsg);
956 }
957
958 return TRUE;
959 }
960 else
961 {
962 // have we just regained the GUI lock? if so, post all of the saved
963 // messages
964 //
965 // FIXME of course, it's not _exactly_ the same as processing the
966 // messages normally - expect some things to break...
967 if ( !s_hadGuiLock )
968 {
969 s_hadGuiLock = TRUE;
970
971 size_t count = s_aSavedMessages.GetCount();
972 for ( size_t n = 0; n < count; n++ )
973 {
974 MSG& msg = s_aSavedMessages[n];
975
976 DoMessage((WXMSG *)&msg);
977 }
978
979 s_aSavedMessages.Empty();
980 }
981 }
982 #endif // wxUSE_THREADS
983
984 // Process the message
985 DoMessage((WXMSG *)&s_currentMsg);
986 }
987
988 return TRUE;
989 }
990
991 void wxApp::DoMessage(WXMSG *pMsg)
992 {
993 if ( !ProcessMessage(pMsg) )
994 {
995 ::TranslateMessage((MSG *)pMsg);
996 ::DispatchMessage((MSG *)pMsg);
997 }
998 }
999
1000 /*
1001 * Keep trying to process messages until WM_QUIT
1002 * received.
1003 *
1004 * If there are messages to be processed, they will all be
1005 * processed and OnIdle will not be called.
1006 * When there are no more messages, OnIdle is called.
1007 * If OnIdle requests more time,
1008 * it will be repeatedly called so long as there are no pending messages.
1009 * A 'feature' of this is that once OnIdle has decided that no more processing
1010 * is required, then it won't get processing time until further messages
1011 * are processed (it'll sit in DoMessage).
1012 */
1013
1014 int wxApp::MainLoop()
1015 {
1016 m_keepGoing = TRUE;
1017
1018 while ( m_keepGoing )
1019 {
1020 #if wxUSE_THREADS
1021 wxMutexGuiLeaveOrEnter();
1022 #endif // wxUSE_THREADS
1023
1024 while ( !Pending() && ProcessIdle() )
1025 ;
1026
1027 // a message came or no more idle processing to do
1028 DoMessage();
1029 }
1030
1031 return s_currentMsg.wParam;
1032 }
1033
1034 // Returns TRUE if more time is needed.
1035 bool wxApp::ProcessIdle()
1036 {
1037 wxIdleEvent event;
1038 event.SetEventObject(this);
1039 ProcessEvent(event);
1040
1041 return event.MoreRequested();
1042 }
1043
1044 void wxApp::ExitMainLoop()
1045 {
1046 // this will set m_keepGoing to FALSE a bit later
1047 ::PostQuitMessage(0);
1048 }
1049
1050 bool wxApp::Pending()
1051 {
1052 return ::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0;
1053 }
1054
1055 void wxApp::Dispatch()
1056 {
1057 DoMessage();
1058 }
1059
1060 /*
1061 * Give all windows a chance to preprocess
1062 * the message. Some may have accelerator tables, or have
1063 * MDI complications.
1064 */
1065
1066 bool wxApp::ProcessMessage(WXMSG *wxmsg)
1067 {
1068 MSG *msg = (MSG *)wxmsg;
1069 HWND hwnd = msg->hwnd;
1070 wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd);
1071
1072 // this may happen if the event occured in a standard modeless dialog (the
1073 // only example of which I know of is the find/replace dialog) - then call
1074 // IsDialogMessage() to make TAB navigation in it work
1075 if ( !wndThis )
1076 {
1077 // we need to find the dialog containing this control as
1078 // IsDialogMessage() just eats all the messages (i.e. returns TRUE for
1079 // them) if we call it for the control itself
1080 while ( hwnd && ::GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD )
1081 {
1082 hwnd = ::GetParent(hwnd);
1083 }
1084
1085 return hwnd && ::IsDialogMessage(hwnd, msg) != 0;
1086 }
1087
1088 #if wxUSE_TOOLTIPS
1089 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
1090 // popup the tooltip bubbles
1091 if ( (msg->message == WM_MOUSEMOVE) )
1092 {
1093 wxToolTip *tt = wndThis->GetToolTip();
1094 if ( tt )
1095 {
1096 tt->RelayEvent(wxmsg);
1097 }
1098 }
1099 #endif // wxUSE_TOOLTIPS
1100
1101 // allow the window to prevent certain messages from being
1102 // translated/processed (this is currently used by wxTextCtrl to always
1103 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
1104 if ( !wndThis->MSWShouldPreProcessMessage(wxmsg) )
1105 {
1106 return FALSE;
1107 }
1108
1109 // try translations first: the accelerators override everything
1110 wxWindow *wnd;
1111
1112 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
1113 {
1114 if ( wnd->MSWTranslateMessage(wxmsg))
1115 return TRUE;
1116
1117 // stop at first top level window, i.e. don't try to process the key
1118 // strokes originating in a dialog using the accelerators of the parent
1119 // frame - this doesn't make much sense
1120 if ( wnd->IsTopLevel() )
1121 break;
1122 }
1123
1124 // now try the other hooks (kbd navigation is handled here): we start from
1125 // wndThis->GetParent() because wndThis->MSWProcessMessage() was already
1126 // called above
1127 for ( wnd = wndThis->GetParent(); wnd; wnd = wnd->GetParent() )
1128 {
1129 if ( wnd->MSWProcessMessage(wxmsg) )
1130 return TRUE;
1131 }
1132
1133 // no special preprocessing for this message, dispatch it normally
1134 return FALSE;
1135 }
1136
1137 // this is a temporary hack and will be replaced by using wxEventLoop in the
1138 // future
1139 //
1140 // it is needed to allow other event loops (currently only one: the modal
1141 // dialog one) to reset the OnIdle() semaphore because otherwise OnIdle()
1142 // wouldn't do anything while a modal dialog shown from OnIdle() call is shown.
1143 bool wxIsInOnIdleFlag = FALSE;
1144
1145 void wxApp::OnIdle(wxIdleEvent& event)
1146 {
1147 // Avoid recursion (via ProcessEvent default case)
1148 if ( wxIsInOnIdleFlag )
1149 return;
1150
1151 wxIsInOnIdleFlag = TRUE;
1152
1153 // If there are pending events, we must process them: pending events
1154 // are either events to the threads other than main or events posted
1155 // with wxPostEvent() functions
1156 // GRG: I have moved this here so that all pending events are processed
1157 // before starting to delete any objects. This behaves better (in
1158 // particular, wrt wxPostEvent) and is coherent with wxGTK's current
1159 // behaviour. Changed Feb/2000 before 2.1.14
1160 ProcessPendingEvents();
1161
1162 // 'Garbage' collection of windows deleted with Close().
1163 DeletePendingObjects();
1164
1165 #if wxUSE_LOG
1166 // flush the logged messages if any
1167 wxLog::FlushActive();
1168 #endif // wxUSE_LOG
1169
1170 #if wxUSE_DC_CACHEING
1171 // automated DC cache management: clear the cached DCs and bitmap
1172 // if it's likely that the app has finished with them, that is, we
1173 // get an idle event and we're not dragging anything.
1174 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
1175 wxDC::ClearCache();
1176 #endif // wxUSE_DC_CACHEING
1177
1178 // Send OnIdle events to all windows
1179 if ( SendIdleEvents() )
1180 {
1181 // SendIdleEvents() returns TRUE if at least one window requested more
1182 // idle events
1183 event.RequestMore(TRUE);
1184 }
1185
1186 wxIsInOnIdleFlag = FALSE;
1187 }
1188
1189 // Send idle event to all top-level windows
1190 bool wxApp::SendIdleEvents()
1191 {
1192 bool needMore = FALSE;
1193
1194 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
1195 while (node)
1196 {
1197 wxWindow* win = node->GetData();
1198 if (SendIdleEvents(win))
1199 needMore = TRUE;
1200 node = node->GetNext();
1201 }
1202
1203 return needMore;
1204 }
1205
1206 // Send idle event to window and all subwindows
1207 bool wxApp::SendIdleEvents(wxWindow* win)
1208 {
1209 wxIdleEvent event;
1210 event.SetEventObject(win);
1211 win->GetEventHandler()->ProcessEvent(event);
1212
1213 bool needMore = event.MoreRequested();
1214
1215 wxWindowList::Node *node = win->GetChildren().GetFirst();
1216 while ( node )
1217 {
1218 wxWindow *win = node->GetData();
1219 if (SendIdleEvents(win))
1220 needMore = TRUE;
1221
1222 node = node->GetNext();
1223 }
1224
1225 return needMore;
1226 }
1227
1228 void wxApp::WakeUpIdle()
1229 {
1230 // Send the top window a dummy message so idle handler processing will
1231 // start up again. Doing it this way ensures that the idle handler
1232 // wakes up in the right thread (see also wxWakeUpMainThread() which does
1233 // the same for the main app thread only)
1234 wxWindow *topWindow = wxTheApp->GetTopWindow();
1235 if ( topWindow )
1236 {
1237 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
1238 {
1239 // should never happen
1240 wxLogLastError(wxT("PostMessage(WM_NULL)"));
1241 }
1242 }
1243 }
1244
1245 void wxApp::DeletePendingObjects()
1246 {
1247 wxNode *node = wxPendingDelete.GetFirst();
1248 while (node)
1249 {
1250 wxObject *obj = node->GetData();
1251
1252 delete obj;
1253
1254 if (wxPendingDelete.Member(obj))
1255 delete node;
1256
1257 // Deleting one object may have deleted other pending
1258 // objects, so start from beginning of list again.
1259 node = wxPendingDelete.GetFirst();
1260 }
1261 }
1262
1263 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
1264 {
1265 if (GetTopWindow())
1266 GetTopWindow()->Close(TRUE);
1267 }
1268
1269 // Default behaviour: close the application with prompts. The
1270 // user can veto the close, and therefore the end session.
1271 void wxApp::OnQueryEndSession(wxCloseEvent& event)
1272 {
1273 if (GetTopWindow())
1274 {
1275 if (!GetTopWindow()->Close(!event.CanVeto()))
1276 event.Veto(TRUE);
1277 }
1278 }
1279
1280 typedef struct _WXADllVersionInfo
1281 {
1282 DWORD cbSize;
1283 DWORD dwMajorVersion; // Major version
1284 DWORD dwMinorVersion; // Minor version
1285 DWORD dwBuildNumber; // Build number
1286 DWORD dwPlatformID; // DLLVER_PLATFORM_*
1287 } WXADLLVERSIONINFO;
1288
1289 typedef HRESULT (CALLBACK* WXADLLGETVERSIONPROC)(WXADLLVERSIONINFO *);
1290
1291 /* static */
1292 int wxApp::GetComCtl32Version()
1293 {
1294 #ifdef __WXMICROWIN__
1295 return 0;
1296 #else
1297 // cache the result
1298 static int s_verComCtl32 = -1;
1299
1300 wxCRIT_SECT_DECLARE(csComCtl32);
1301 wxCRIT_SECT_LOCKER(lock, csComCtl32);
1302
1303 if ( s_verComCtl32 == -1 )
1304 {
1305 // initally assume no comctl32.dll at all
1306 s_verComCtl32 = 0;
1307
1308 // do we have it?
1309 HMODULE hModuleComCtl32 = ::GetModuleHandle(wxT("COMCTL32"));
1310 BOOL bFreeComCtl32 = FALSE ;
1311 if(!hModuleComCtl32)
1312 {
1313 hModuleComCtl32 = ::LoadLibrary(wxT("COMCTL32.DLL")) ;
1314 if(hModuleComCtl32)
1315 {
1316 bFreeComCtl32 = TRUE ;
1317 }
1318 }
1319
1320 // if so, then we can check for the version
1321 if ( hModuleComCtl32 )
1322 {
1323 // try to use DllGetVersion() if available in _headers_
1324 WXADLLGETVERSIONPROC pfnDllGetVersion = (WXADLLGETVERSIONPROC)
1325 ::GetProcAddress(hModuleComCtl32, "DllGetVersion");
1326 if ( pfnDllGetVersion )
1327 {
1328 WXADLLVERSIONINFO dvi;
1329 dvi.cbSize = sizeof(dvi);
1330
1331 HRESULT hr = (*pfnDllGetVersion)(&dvi);
1332 if ( FAILED(hr) )
1333 {
1334 wxLogApiError(_T("DllGetVersion"), hr);
1335 }
1336 else
1337 {
1338 // this is incompatible with _WIN32_IE values, but
1339 // compatible with the other values returned by
1340 // GetComCtl32Version()
1341 s_verComCtl32 = 100*dvi.dwMajorVersion +
1342 dvi.dwMinorVersion;
1343 }
1344 }
1345 // DllGetVersion() unavailable either during compile or
1346 // run-time, try to guess the version otherwise
1347 if ( !s_verComCtl32 )
1348 {
1349 // InitCommonControlsEx is unique to 4.70 and later
1350 FARPROC theProc = ::GetProcAddress
1351 (
1352 hModuleComCtl32,
1353 "InitCommonControlsEx"
1354 );
1355
1356 if ( !theProc )
1357 {
1358 // not found, must be 4.00
1359 s_verComCtl32 = 400;
1360 }
1361 else
1362 {
1363 // many symbols appeared in comctl32 4.71, could use
1364 // any of them except may be DllInstall
1365 theProc = ::GetProcAddress
1366 (
1367 hModuleComCtl32,
1368 "InitializeFlatSB"
1369 );
1370 if ( !theProc )
1371 {
1372 // not found, must be 4.70
1373 s_verComCtl32 = 470;
1374 }
1375 else
1376 {
1377 // found, must be 4.71
1378 s_verComCtl32 = 471;
1379 }
1380 }
1381 }
1382 }
1383
1384 if(bFreeComCtl32)
1385 {
1386 ::FreeLibrary(hModuleComCtl32) ;
1387 }
1388 }
1389
1390 return s_verComCtl32;
1391 #endif
1392 }
1393
1394 // Yield to incoming messages
1395
1396 bool wxApp::Yield(bool onlyIfNeeded)
1397 {
1398 // MT-FIXME
1399 static bool s_inYield = FALSE;
1400
1401 #if wxUSE_LOG
1402 // disable log flushing from here because a call to wxYield() shouldn't
1403 // normally result in message boxes popping up &c
1404 wxLog::Suspend();
1405 #endif // wxUSE_LOG
1406
1407 if ( s_inYield )
1408 {
1409 if ( !onlyIfNeeded )
1410 {
1411 wxFAIL_MSG( wxT("wxYield called recursively" ) );
1412 }
1413
1414 return FALSE;
1415 }
1416
1417 s_inYield = TRUE;
1418
1419 // we don't want to process WM_QUIT from here - it should be processed in
1420 // the main event loop in order to stop it
1421 MSG msg;
1422 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
1423 msg.message != WM_QUIT )
1424 {
1425 #if wxUSE_THREADS
1426 wxMutexGuiLeaveOrEnter();
1427 #endif // wxUSE_THREADS
1428
1429 if ( !wxTheApp->DoMessage() )
1430 break;
1431 }
1432
1433 // if there are pending events, we must process them.
1434 ProcessPendingEvents();
1435
1436 #if wxUSE_LOG
1437 // let the logs be flashed again
1438 wxLog::Resume();
1439 #endif // wxUSE_LOG
1440
1441 s_inYield = FALSE;
1442
1443 return TRUE;
1444 }
1445
1446 bool wxHandleFatalExceptions(bool doit)
1447 {
1448 #if wxUSE_ON_FATAL_EXCEPTION
1449 // assume this can only be called from the main thread
1450 gs_handleExceptions = doit;
1451
1452 return TRUE;
1453 #else
1454 wxFAIL_MSG(_T("set wxUSE_ON_FATAL_EXCEPTION to 1 to use this function"));
1455
1456 (void)doit;
1457 return FALSE;
1458 #endif
1459 }
1460
1461 //-----------------------------------------------------------------------------
1462
1463 // For some reason, with MSVC++ 1.5, WinMain isn't linked in properly
1464 // if in a separate file. So include it here to ensure it's linked.
1465 #if (defined(__VISUALC__) && !defined(__WIN32__)) || (defined(__GNUWIN32__) && !defined(__WINE__) && !defined(WXMAKINGDLL))
1466 #include "main.cpp"
1467 #endif