1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
21 #pragma implementation "app.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
27 #if defined(__BORLANDC__)
35 #include "wx/gdicmn.h"
38 #include "wx/cursor.h"
40 #include "wx/palette.h"
42 #include "wx/dialog.h"
43 #include "wx/msgdlg.h"
45 #include "wx/dynarray.h"
46 #include "wx/wxchar.h"
51 #include "wx/apptrait.h"
52 #include "wx/cmdline.h"
53 #include "wx/filename.h"
54 #include "wx/module.h"
56 #include "wx/msw/private.h"
59 #include "wx/thread.h"
61 // define the array of MSG strutures
62 WX_DECLARE_OBJARRAY(MSG
, wxMsgArray
);
64 #include "wx/arrimpl.cpp"
66 WX_DEFINE_OBJARRAY(wxMsgArray
);
67 #endif // wxUSE_THREADS
70 #include "wx/tooltip.h"
71 #endif // wxUSE_TOOLTIPS
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__)
79 #endif // broken compilers
88 #if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__WXMICROWIN__)) && !defined(__CYGWIN10__))
92 #ifndef __WXMICROWIN__
93 #include "wx/msw/msvcrt.h"
96 // ----------------------------------------------------------------------------
97 // conditional compilation
98 // ----------------------------------------------------------------------------
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
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)
113 // minimal set of features by default
114 #define _WIN32_IE 0x0200
117 #if _WIN32_IE >= 0x0300 && \
118 (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
123 // ---------------------------------------------------------------------------
125 // ---------------------------------------------------------------------------
127 extern wxChar
*wxBuffer
;
128 extern wxList WXDLLEXPORT wxPendingDelete
;
129 #ifndef __WXMICROWIN__
130 extern void wxSetKeyboardHook(bool doIt
);
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");
144 HICON wxSTD_FRAME_ICON
= (HICON
) NULL
;
145 HICON wxSTD_MDICHILDFRAME_ICON
= (HICON
) NULL
;
146 HICON wxSTD_MDIPARENTFRAME_ICON
= (HICON
) NULL
;
148 HICON wxDEFAULT_FRAME_ICON
= (HICON
) NULL
;
149 HICON wxDEFAULT_MDICHILDFRAME_ICON
= (HICON
) NULL
;
150 HICON wxDEFAULT_MDIPARENTFRAME_ICON
= (HICON
) NULL
;
152 HBRUSH wxDisableButtonBrush
= (HBRUSH
) 0;
154 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
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
166 #if wxUSE_ON_FATAL_EXCEPTION
167 static bool gs_handleExceptions
= FALSE
;
170 // ===========================================================================
171 // wxGUIAppTraits implementation
172 // ===========================================================================
174 // private class which we use to pass parameters from BeforeChildWaitLoop() to
175 // AfterChildWaitLoop()
176 struct ChildWaitLoopData
178 ChildWaitLoopData(wxWindowDisabler
*wd_
, wxWindow
*winActive_
)
181 winActive
= winActive_
;
184 wxWindowDisabler
*wd
;
188 void *wxGUIAppTraits::BeforeChildWaitLoop()
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
208 // first disable all existing windows
209 wxWindowDisabler
*wd
= new wxWindowDisabler
;
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
215 wxTheApp
->GetTopWindow(),
218 wxPoint(32600, 32600),
220 wxDEFAULT_FRAME_STYLE
| wxFRAME_NO_TASKBAR
224 return new ChildWaitLoopData(wd
, winActive
);
227 void wxGUIAppTraits::AlwaysYield()
232 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig
)
236 const ChildWaitLoopData
* const data
= (ChildWaitLoopData
*)dataOrig
;
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();
246 bool wxGUIAppTraits::DoMessageFromThreadWait()
248 return !wxTheApp
|| wxTheApp
->DoMessage();
251 // ===========================================================================
252 // wxApp implementation
253 // ===========================================================================
255 // ---------------------------------------------------------------------------
257 // ---------------------------------------------------------------------------
259 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
261 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
262 EVT_IDLE(wxApp::OnIdle
)
263 EVT_END_SESSION(wxApp::OnEndSession
)
264 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
268 bool wxApp::Initialize()
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
)
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
282 _T("This program uses Unicode and requires Windows NT/2000/XP.\nProgram aborted."),
283 _T("wxWindows Fatal Error"),
289 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
291 wxBuffer
= new wxChar
[1500]; // FIXME
293 wxClassInfo::InitializeClasses();
296 wxPendingEventsLocker
= new wxCriticalSection
;
299 wxTheColourDatabase
= new wxColourDatabase(wxKEY_STRING
);
300 wxTheColourDatabase
->Initialize();
302 wxInitializeStockLists();
303 wxInitializeStockObjects();
305 wxBitmap::InitStandardHandlers();
307 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
308 InitCommonControls();
311 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
314 // for OLE, enlarge message queue to be as large as possible
316 while (!SetMessageQueue(iMsg
) && (iMsg
-= 8))
321 // we need to initialize OLE library
322 if ( FAILED(::OleInitialize(NULL
)) )
323 wxLogError(_("Cannot initialize OLE"));
329 if (!Ctl3dRegister(wxhInstance
))
330 wxLogError(wxT("Cannot register CTL3D"));
332 Ctl3dAutoSubclass(wxhInstance
);
333 #endif // wxUSE_CTL3D
335 // VZ: these icons are not in wx.rc anyhow (but should they?)!
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"));
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"));
346 RegisterWindowClasses();
348 #ifndef __WXMICROWIN__
349 // Create the brush for disabling bitmap buttons
352 lb
.lbStyle
= BS_PATTERN
;
354 lb
.lbHatch
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") );
357 wxDisableButtonBrush
= ::CreateBrushIndirect( & lb
);
358 ::DeleteObject( (HGDIOBJ
)lb
.lbHatch
);
360 //else: wxWindows resources are probably not linked in
367 wxWinHandleHash
= new wxWinHashTable(wxKEY_INTEGER
, 100);
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
++;
376 #ifndef __WXMICROWIN__
377 wxSetKeyboardHook(TRUE
);
380 wxModule::RegisterModules();
381 if (!wxModule::InitializeModules())
386 // ---------------------------------------------------------------------------
387 // RegisterWindowClasses
388 // ---------------------------------------------------------------------------
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()
396 wxZeroMemory(wndclass
);
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
;
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
);
408 // Register the frame window class.
409 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1);
410 wndclass
.lpszClassName
= wxCanvasClassName
;
411 wndclass
.style
= styleNormal
;
413 if ( !RegisterClass(&wndclass
) )
415 wxLogLastError(wxT("RegisterClass(frame)"));
419 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
420 wndclass
.style
= styleNoRedraw
;
422 if ( !RegisterClass(&wndclass
) )
424 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
427 // Register the MDI frame window class.
428 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
429 wndclass
.lpszClassName
= wxMDIFrameClassName
;
430 wndclass
.style
= styleNormal
;
432 if ( !RegisterClass(&wndclass
) )
434 wxLogLastError(wxT("RegisterClass(MDI parent)"));
437 // "no redraw" MDI frame
438 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
439 wndclass
.style
= styleNoRedraw
;
441 if ( !RegisterClass(&wndclass
) )
443 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
446 // Register the MDI child frame window class.
447 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
448 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
449 wndclass
.style
= styleNormal
;
451 if ( !RegisterClass(&wndclass
) )
453 wxLogLastError(wxT("RegisterClass(MDI child)"));
456 // "no redraw" MDI child frame
457 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
458 wndclass
.style
= styleNoRedraw
;
460 if ( !RegisterClass(&wndclass
) )
462 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
468 // ---------------------------------------------------------------------------
469 // UnregisterWindowClasses
470 // ---------------------------------------------------------------------------
472 bool wxApp::UnregisterWindowClasses()
476 #ifndef __WXMICROWIN__
477 // MDI frame window class.
478 if ( !::UnregisterClass(wxMDIFrameClassName
, wxhInstance
) )
480 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
485 // "no redraw" MDI frame
486 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw
, wxhInstance
) )
488 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
493 // MDI child frame window class.
494 if ( !::UnregisterClass(wxMDIChildFrameClassName
, wxhInstance
) )
496 wxLogLastError(wxT("UnregisterClass(MDI child)"));
501 // "no redraw" MDI child frame
502 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw
, wxhInstance
) )
504 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
510 if ( !::UnregisterClass(wxCanvasClassName
, wxhInstance
) )
512 wxLogLastError(wxT("UnregisterClass(canvas)"));
517 if ( !::UnregisterClass(wxCanvasClassNameNR
, wxhInstance
) )
519 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
523 #endif // __WXMICROWIN__
528 // ---------------------------------------------------------------------------
529 // Convert Windows to argc, argv style
530 // ---------------------------------------------------------------------------
532 void wxApp::ConvertToStandardCommandArgs(const char* lpCmdLine
)
534 // break the command line in words
536 wxCmdLineParser::ConvertStringToArgs(wxConvertMB2WX(lpCmdLine
));
538 // +1 here for the program name
539 argc
= args
.GetCount() + 1;
541 // and +1 here for the terminating NULL
542 argv
= new wxChar
*[argc
+ 1];
544 argv
[0] = new wxChar
[260]; // 260 is MAX_PATH value from windef.h
545 ::GetModuleFileName(wxhInstance
, argv
[0], 260);
547 // also set the app name from argv[0]
549 wxFileName::SplitPath(argv
[0], NULL
, &name
, NULL
);
551 // but don't override the name already set by the user code, if any
552 if ( GetAppName().empty() )
555 // copy all the other arguments to wxApp::argv[]
556 for ( int i
= 1; i
< argc
; i
++ )
558 argv
[i
] = copystring(args
[i
- 1]);
561 // argv[] must be NULL-terminated
565 //// Cleans up any wxWindows internal structures left lying around
567 void wxApp::CleanUp()
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();
578 // this will flush the old messages if any
579 delete wxLog::SetActiveTarget(new wxLogStderr
);
582 // One last chance for pending objects to be cleaned up
583 wxTheApp
->DeletePendingObjects();
585 wxModule::CleanUpModules();
587 wxDeleteStockObjects();
589 // Destroy all GDI lists, etc.
590 wxDeleteStockLists();
592 delete wxTheColourDatabase
;
593 wxTheColourDatabase
= NULL
;
595 wxBitmap::CleanUpHandlers();
600 //// WINDOWS-SPECIFIC CLEANUP
602 #ifndef __WXMICROWIN__
603 wxSetKeyboardHook(FALSE
);
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
);
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
);
624 if ( wxDisableButtonBrush
)
625 ::DeleteObject( wxDisableButtonBrush
);
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
640 Ctl3dUnregister(wxhInstance
);
643 delete wxWinHandleHash
;
644 wxWinHandleHash
= NULL
; // Set to null in case anything later tries to ref it.
646 delete wxPendingEvents
;
647 wxPendingEvents
= NULL
; // Set to null because wxAppBase::wxEvtHandler is destroyed later.
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
654 ((wxEvtHandler
&) wxDefaultValidator
).ClearEventLocker();
655 #endif // wxUSE_VALIDATORS
656 #endif // wxUSE_THREADS
658 wxClassInfo::CleanUpClasses();
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)
670 wxLogMessage(wxT("There were memory leaks."));
671 wxDebugContext::Dump();
672 wxDebugContext::PrintStatistics();
674 // wxDebugContext::SetStream(NULL, NULL);
678 // do it as the very last thing because everything else can log messages
679 delete wxLog::SetActiveTarget(NULL
);
683 //----------------------------------------------------------------------
684 // Entry point helpers, used by wxPython
685 //----------------------------------------------------------------------
687 int WXDLLEXPORT
wxEntryStart( int WXUNUSED(argc
), char** WXUNUSED(argv
) )
689 return wxApp::Initialize();
692 int WXDLLEXPORT
wxEntryInitGui()
694 return wxTheApp
->OnInitGui();
697 void WXDLLEXPORT
wxEntryCleanup()
703 #if !defined(_WINDLL) || (defined(_WINDLL) && defined(WXMAKINGDLL))
705 // temporarily disable this warning which would be generated in release builds
708 #pragma warning(disable: 4715) // not all control paths return a value
711 //----------------------------------------------------------------------
712 // Main wxWindows entry point
713 //----------------------------------------------------------------------
714 int wxEntry(WXHINSTANCE hInstance
,
715 WXHINSTANCE
WXUNUSED(hPrevInstance
),
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
);
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();
739 // take everything into a try-except block to be able to call
740 // OnFatalException() if necessary
741 #if wxUSE_ON_FATAL_EXCEPTION
744 wxhInstance
= (HINSTANCE
) hInstance
;
746 if (!wxEntryStart(0,0))
749 // create the application object or ensure that one already exists
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.") );
758 wxTheApp
= (wxApp
*) (*wxApp::GetInitializerFunction()) ();
761 wxCHECK_MSG( wxTheApp
, 0, wxT("You have to define an instance of wxApp!") );
763 // save the WinMain() parameters
764 if (lpCmdLine
) // MicroWindows passes NULL
765 wxTheApp
->ConvertToStandardCommandArgs(lpCmdLine
);
766 wxTheApp
->m_nCmdShow
= nCmdShow
;
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.
773 wxLog::SetTimestamp(NULL
);
775 #endif // __VISUALC__
778 int retValue
= wxEntryInitGui() && wxTheApp
->OnInit() ? 0 : -1;
789 // we want to initialize, but not run or exit immediately.
793 //else: app initialization failed, so we skipped OnRun()
795 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
798 // Forcibly delete the window.
799 if ( topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
800 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
802 topWindow
->Close(TRUE
);
803 wxTheApp
->DeletePendingObjects();
808 wxTheApp
->SetTopWindow(NULL
);
812 retValue
= wxTheApp
->OnExit();
818 #if wxUSE_ON_FATAL_EXCEPTION
820 __except ( gs_handleExceptions
? EXCEPTION_EXECUTE_HANDLER
821 : EXCEPTION_CONTINUE_SEARCH
) {
824 // give the user a chance to do something special about this
825 wxTheApp
->OnFatalException();
828 ::ExitProcess(3); // the same exit code as abort()
832 #endif // wxUSE_ON_FATAL_EXCEPTION
835 // restore warning state
837 #pragma warning(default: 4715) // not all control paths return a value
842 //----------------------------------------------------------------------
843 // Entry point for wxWindows + the App in a DLL
844 //----------------------------------------------------------------------
846 int wxEntry(WXHINSTANCE hInstance
)
848 wxhInstance
= (HINSTANCE
) hInstance
;
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.
856 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
857 "No initializer - use IMPLEMENT_APP macro." );
859 wxTheApp
= (* wxApp::GetInitializerFunction()) ();
862 wxCHECK_MSG( wxTheApp
, 0, "You have to define an instance of wxApp!" );
865 wxTheApp
->argv
= NULL
;
871 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
872 if ( topWindow
&& topWindow
->GetHWND())
874 topWindow
->Show(TRUE
);
881 //// Static member initialization
887 m_printMode
= wxPRINT_WINDOWS
;
893 // Delete command-line args
895 for (i
= 0; i
< argc
; i
++)
902 bool wxApp::Initialized()
909 #else // Assume initialized if DLL (no way of telling)
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)
919 bool wxApp::DoMessage()
921 BOOL rc
= ::GetMessage(&s_currentMsg
, (HWND
) NULL
, 0, 0);
931 // should never happen, but let's test for it nevertheless
932 wxLogLastError(wxT("GetMessage"));
937 wxASSERT_MSG( wxThread::IsMain(),
938 wxT("only the main thread can process Windows messages") );
940 static bool s_hadGuiLock
= TRUE
;
941 static wxMsgArray s_aSavedMessages
;
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() )
948 s_hadGuiLock
= FALSE
;
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
)
955 s_aSavedMessages
.Add(s_currentMsg
);
962 // have we just regained the GUI lock? if so, post all of the saved
965 // FIXME of course, it's not _exactly_ the same as processing the
966 // messages normally - expect some things to break...
971 size_t count
= s_aSavedMessages
.GetCount();
972 for ( size_t n
= 0; n
< count
; n
++ )
974 MSG
& msg
= s_aSavedMessages
[n
];
976 DoMessage((WXMSG
*)&msg
);
979 s_aSavedMessages
.Empty();
982 #endif // wxUSE_THREADS
984 // Process the message
985 DoMessage((WXMSG
*)&s_currentMsg
);
991 void wxApp::DoMessage(WXMSG
*pMsg
)
993 if ( !ProcessMessage(pMsg
) )
995 ::TranslateMessage((MSG
*)pMsg
);
996 ::DispatchMessage((MSG
*)pMsg
);
1001 * Keep trying to process messages until WM_QUIT
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).
1014 int wxApp::MainLoop()
1018 while ( m_keepGoing
)
1021 wxMutexGuiLeaveOrEnter();
1022 #endif // wxUSE_THREADS
1024 while ( !Pending() && ProcessIdle() )
1027 // a message came or no more idle processing to do
1031 return s_currentMsg
.wParam
;
1034 // Returns TRUE if more time is needed.
1035 bool wxApp::ProcessIdle()
1038 event
.SetEventObject(this);
1039 ProcessEvent(event
);
1041 return event
.MoreRequested();
1044 void wxApp::ExitMainLoop()
1046 // this will set m_keepGoing to FALSE a bit later
1047 ::PostQuitMessage(0);
1050 bool wxApp::Pending()
1052 return ::PeekMessage(&s_currentMsg
, 0, 0, 0, PM_NOREMOVE
) != 0;
1055 void wxApp::Dispatch()
1061 * Give all windows a chance to preprocess
1062 * the message. Some may have accelerator tables, or have
1063 * MDI complications.
1066 bool wxApp::ProcessMessage(WXMSG
*wxmsg
)
1068 MSG
*msg
= (MSG
*)wxmsg
;
1069 HWND hwnd
= msg
->hwnd
;
1070 wxWindow
*wndThis
= wxGetWindowFromHWND((WXHWND
)hwnd
);
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
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
)
1082 hwnd
= ::GetParent(hwnd
);
1085 return hwnd
&& ::IsDialogMessage(hwnd
, msg
) != 0;
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
) )
1093 wxToolTip
*tt
= wndThis
->GetToolTip();
1096 tt
->RelayEvent(wxmsg
);
1099 #endif // wxUSE_TOOLTIPS
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
) )
1109 // try translations first: the accelerators override everything
1112 for ( wnd
= wndThis
; wnd
; wnd
= wnd
->GetParent() )
1114 if ( wnd
->MSWTranslateMessage(wxmsg
))
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() )
1124 // now try the other hooks (kbd navigation is handled here): we start from
1125 // wndThis->GetParent() because wndThis->MSWProcessMessage() was already
1127 for ( wnd
= wndThis
->GetParent(); wnd
; wnd
= wnd
->GetParent() )
1129 if ( wnd
->MSWProcessMessage(wxmsg
) )
1133 // no special preprocessing for this message, dispatch it normally
1137 // this is a temporary hack and will be replaced by using wxEventLoop in the
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
;
1145 void wxApp::OnIdle(wxIdleEvent
& event
)
1147 // Avoid recursion (via ProcessEvent default case)
1148 if ( wxIsInOnIdleFlag
)
1151 wxIsInOnIdleFlag
= TRUE
;
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();
1162 // 'Garbage' collection of windows deleted with Close().
1163 DeletePendingObjects();
1166 // flush the logged messages if any
1167 wxLog::FlushActive();
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
))
1176 #endif // wxUSE_DC_CACHEING
1178 // Send OnIdle events to all windows
1179 if ( SendIdleEvents() )
1181 // SendIdleEvents() returns TRUE if at least one window requested more
1183 event
.RequestMore(TRUE
);
1186 wxIsInOnIdleFlag
= FALSE
;
1189 // Send idle event to all top-level windows
1190 bool wxApp::SendIdleEvents()
1192 bool needMore
= FALSE
;
1194 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
1197 wxWindow
* win
= node
->GetData();
1198 if (SendIdleEvents(win
))
1200 node
= node
->GetNext();
1206 // Send idle event to window and all subwindows
1207 bool wxApp::SendIdleEvents(wxWindow
* win
)
1210 event
.SetEventObject(win
);
1211 win
->GetEventHandler()->ProcessEvent(event
);
1213 bool needMore
= event
.MoreRequested();
1215 wxWindowList::Node
*node
= win
->GetChildren().GetFirst();
1218 wxWindow
*win
= node
->GetData();
1219 if (SendIdleEvents(win
))
1222 node
= node
->GetNext();
1228 void wxApp::WakeUpIdle()
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();
1237 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
1239 // should never happen
1240 wxLogLastError(wxT("PostMessage(WM_NULL)"));
1245 void wxApp::DeletePendingObjects()
1247 wxNode
*node
= wxPendingDelete
.GetFirst();
1250 wxObject
*obj
= node
->GetData();
1254 if (wxPendingDelete
.Member(obj
))
1257 // Deleting one object may have deleted other pending
1258 // objects, so start from beginning of list again.
1259 node
= wxPendingDelete
.GetFirst();
1263 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
1266 GetTopWindow()->Close(TRUE
);
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
)
1275 if (!GetTopWindow()->Close(!event
.CanVeto()))
1280 typedef struct _WXADllVersionInfo
1283 DWORD dwMajorVersion
; // Major version
1284 DWORD dwMinorVersion
; // Minor version
1285 DWORD dwBuildNumber
; // Build number
1286 DWORD dwPlatformID
; // DLLVER_PLATFORM_*
1287 } WXADLLVERSIONINFO
;
1289 typedef HRESULT (CALLBACK
* WXADLLGETVERSIONPROC
)(WXADLLVERSIONINFO
*);
1292 int wxApp::GetComCtl32Version()
1294 #ifdef __WXMICROWIN__
1298 static int s_verComCtl32
= -1;
1300 wxCRIT_SECT_DECLARE(csComCtl32
);
1301 wxCRIT_SECT_LOCKER(lock
, csComCtl32
);
1303 if ( s_verComCtl32
== -1 )
1305 // initally assume no comctl32.dll at all
1309 HMODULE hModuleComCtl32
= ::GetModuleHandle(wxT("COMCTL32"));
1310 BOOL bFreeComCtl32
= FALSE
;
1311 if(!hModuleComCtl32
)
1313 hModuleComCtl32
= ::LoadLibrary(wxT("COMCTL32.DLL")) ;
1316 bFreeComCtl32
= TRUE
;
1320 // if so, then we can check for the version
1321 if ( hModuleComCtl32
)
1323 // try to use DllGetVersion() if available in _headers_
1324 WXADLLGETVERSIONPROC pfnDllGetVersion
= (WXADLLGETVERSIONPROC
)
1325 ::GetProcAddress(hModuleComCtl32
, "DllGetVersion");
1326 if ( pfnDllGetVersion
)
1328 WXADLLVERSIONINFO dvi
;
1329 dvi
.cbSize
= sizeof(dvi
);
1331 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
1334 wxLogApiError(_T("DllGetVersion"), hr
);
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
+
1345 // DllGetVersion() unavailable either during compile or
1346 // run-time, try to guess the version otherwise
1347 if ( !s_verComCtl32
)
1349 // InitCommonControlsEx is unique to 4.70 and later
1350 FARPROC theProc
= ::GetProcAddress
1353 "InitCommonControlsEx"
1358 // not found, must be 4.00
1359 s_verComCtl32
= 400;
1363 // many symbols appeared in comctl32 4.71, could use
1364 // any of them except may be DllInstall
1365 theProc
= ::GetProcAddress
1372 // not found, must be 4.70
1373 s_verComCtl32
= 470;
1377 // found, must be 4.71
1378 s_verComCtl32
= 471;
1386 ::FreeLibrary(hModuleComCtl32
) ;
1390 return s_verComCtl32
;
1394 // Yield to incoming messages
1396 bool wxApp::Yield(bool onlyIfNeeded
)
1399 static bool s_inYield
= FALSE
;
1402 // disable log flushing from here because a call to wxYield() shouldn't
1403 // normally result in message boxes popping up &c
1409 if ( !onlyIfNeeded
)
1411 wxFAIL_MSG( wxT("wxYield called recursively" ) );
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
1422 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
1423 msg
.message
!= WM_QUIT
)
1426 wxMutexGuiLeaveOrEnter();
1427 #endif // wxUSE_THREADS
1429 if ( !wxTheApp
->DoMessage() )
1433 // if there are pending events, we must process them.
1434 ProcessPendingEvents();
1437 // let the logs be flashed again
1446 bool wxHandleFatalExceptions(bool doit
)
1448 #if wxUSE_ON_FATAL_EXCEPTION
1449 // assume this can only be called from the main thread
1450 gs_handleExceptions
= doit
;
1454 wxFAIL_MSG(_T("set wxUSE_ON_FATAL_EXCEPTION to 1 to use this function"));
1461 //-----------------------------------------------------------------------------
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))