Committing in .
[wxWidgets.git] / src / msw / app.cpp
0 / 1268 (  0%)
CommitLineData
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 and Markus Holzem
9// Licence: wxWindows license
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#endif
49
50#include "wx/log.h"
51#include "wx/module.h"
52
53#include "wx/msw/private.h"
54
55#if wxUSE_THREADS
56 #include "wx/thread.h"
57
58 // define the array of MSG strutures
59 WX_DECLARE_OBJARRAY(MSG, wxMsgArray);
60
61 #include "wx/arrimpl.cpp"
62
63 WX_DEFINE_OBJARRAY(wxMsgArray);
64#endif // wxUSE_THREADS
65
66#if wxUSE_WX_RESOURCES
67 #include "wx/resource.h"
68#endif
69
70// OLE is used for drag-and-drop, clipboard, OLE Automation...
71#ifndef wxUSE_NORLANDER_HEADERS
72#if defined(__GNUWIN32__) || defined(__SC__) || defined(__SALFORDC__)
73 #undef wxUSE_OLE
74
75 #define wxUSE_OLE 0
76#endif // broken compilers
77#endif
78
79#if wxUSE_OLE
80 #include <ole2.h>
81#endif
82
83#include <string.h>
84#include <ctype.h>
85
86#if (defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__) || defined(wxUSE_NORLANDER_HEADERS)
87 #include <commctrl.h>
88#endif
89
90#include "wx/msw/msvcrt.h"
91
92// ---------------------------------------------------------------------------
93// global variables
94// ---------------------------------------------------------------------------
95
96extern wxChar *wxBuffer;
97extern wxChar *wxOsVersion;
98extern wxList *wxWinHandleList;
99extern wxList WXDLLEXPORT wxPendingDelete;
100extern void wxSetKeyboardHook(bool doIt);
101extern wxCursor *g_globalCursor;
102
103HINSTANCE wxhInstance = 0;
104MSG s_currentMsg;
105wxApp *wxTheApp = NULL;
106
107// FIXME why not const? and not static?
108
109// NB: all "NoRedraw" classes must have the same names as the "normal" classes
110// with NR suffix - wxWindow::MSWCreate() supposes this
111wxChar wxFrameClassName[] = wxT("wxFrameClass");
112wxChar wxFrameClassNameNoRedraw[] = wxT("wxFrameClassNR");
113wxChar wxMDIFrameClassName[] = wxT("wxMDIFrameClass");
114wxChar wxMDIFrameClassNameNoRedraw[] = wxT("wxMDIFrameClassNR");
115wxChar wxMDIChildFrameClassName[] = wxT("wxMDIChildFrameClass");
116wxChar wxMDIChildFrameClassNameNoRedraw[] = wxT("wxMDIChildFrameClassNR");
117wxChar wxPanelClassName[] = wxT("wxPanelClass");
118wxChar wxCanvasClassName[] = wxT("wxCanvasClass");
119
120HICON wxSTD_FRAME_ICON = (HICON) NULL;
121HICON wxSTD_MDICHILDFRAME_ICON = (HICON) NULL;
122HICON wxSTD_MDIPARENTFRAME_ICON = (HICON) NULL;
123
124HICON wxDEFAULT_FRAME_ICON = (HICON) NULL;
125HICON wxDEFAULT_MDICHILDFRAME_ICON = (HICON) NULL;
126HICON wxDEFAULT_MDIPARENTFRAME_ICON = (HICON) NULL;
127
128HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
129
130LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
131
132#if wxUSE_RICHEDIT
133 // the handle to richedit DLL and the version of the DLL loaded
134 static HINSTANCE gs_hRichEdit = (HINSTANCE)NULL;
135 static int gs_verRichEdit = -1;
136#endif
137
138// ===========================================================================
139// implementation
140// ===========================================================================
141
142// ---------------------------------------------------------------------------
143// wxApp
144// ---------------------------------------------------------------------------
145
146#if !USE_SHARED_LIBRARY
147 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
148
149 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
150 EVT_IDLE(wxApp::OnIdle)
151 EVT_END_SESSION(wxApp::OnEndSession)
152 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
153 END_EVENT_TABLE()
154#endif
155
156//// Initialize
157bool wxApp::Initialize()
158{
159 // Some people may wish to use this, but
160 // probably it shouldn't be here by default.
161#ifdef __WXDEBUG__
162 // wxRedirectIOToConsole();
163#endif
164
165 wxBuffer = new wxChar[1500]; // FIXME
166
167 wxClassInfo::InitializeClasses();
168
169#if wxUSE_RESOURCES
170 wxGetResource(wxT("wxWindows"), wxT("OsVersion"), &wxOsVersion);
171#endif
172
173#if wxUSE_THREADS
174 wxPendingEventsLocker = new wxCriticalSection;
175#endif
176
177 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
178 wxTheColourDatabase->Initialize();
179
180 wxInitializeStockLists();
181 wxInitializeStockObjects();
182
183#if wxUSE_WX_RESOURCES
184 wxInitializeResourceSystem();
185#endif
186
187 wxBitmap::InitStandardHandlers();
188
189#if defined(__WIN95__)
190 InitCommonControls();
191
192#endif // __WIN95__
193
194#if wxUSE_OLE
195
196#ifdef __WIN16__
197 // for OLE, enlarge message queue to be as large as possible
198 int iMsg = 96;
199 while (!SetMessageQueue(iMsg) && (iMsg -= 8))
200 ;
201#endif // Win16
202 // we need to initialize OLE library
203 if ( FAILED(::OleInitialize(NULL)) )
204 wxLogError(_("Cannot initialize OLE"));
205#endif // wxUSE_OLE
206
207#if wxUSE_CTL3D
208 if (!Ctl3dRegister(wxhInstance))
209 wxLogError(wxT("Cannot register CTL3D"));
210
211 Ctl3dAutoSubclass(wxhInstance);
212#endif
213
214 g_globalCursor = new wxCursor;
215
216 // VZ: these icons are not in wx.rc anyhow (but should they?)!
217#if 0
218 wxSTD_FRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_FRAME"));
219 wxSTD_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_MDIPARENTFRAME"));
220 wxSTD_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_MDICHILDFRAME"));
221
222 wxDEFAULT_FRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_FRAME"));
223 wxDEFAULT_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_MDIPARENTFRAME"));
224 wxDEFAULT_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_MDICHILDFRAME"));
225#endif // 0
226
227 RegisterWindowClasses();
228
229 // Create the brush for disabling bitmap buttons
230
231 LOGBRUSH lb;
232 lb.lbStyle = BS_PATTERN;
233 lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
234 if ( lb.lbHatch )
235 {
236 wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
237 ::DeleteObject( (HGDIOBJ)lb.lbHatch );
238 }
239 //else: wxWindows resources are probably not linked in
240
241#if wxUSE_PENWINDOWS
242 wxRegisterPenWin();
243#endif
244
245 wxWinHandleList = new wxList(wxKEY_INTEGER);
246
247 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
248 // PLEASE DO NOT ALTER THIS.
249#if defined(__VISUALC__) && !defined(WXMAKINGDLL)
250 extern char wxDummyChar;
251 if (wxDummyChar) wxDummyChar++;
252#endif
253
254 wxSetKeyboardHook(TRUE);
255
256 wxModule::RegisterModules();
257 if (!wxModule::InitializeModules())
258 return FALSE;
259 return TRUE;
260}
261
262// ---------------------------------------------------------------------------
263// RegisterWindowClasses
264// ---------------------------------------------------------------------------
265
266// TODO we should only register classes really used by the app. For this it
267// would be enough to just delay the class registration until an attempt
268// to create a window of this class is made.
269bool wxApp::RegisterWindowClasses()
270{
271 WNDCLASS wndclass;
272
273 // for each class we register one with CS_(V|H)REDRAW style and one
274 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
275 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
276 static const long styleNoRedraw = CS_DBLCLKS;
277
278 // the fields which are common to all classes
279 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
280 wndclass.cbClsExtra = 0;
281 wndclass.cbWndExtra = sizeof( DWORD ); // VZ: what is this DWORD used for?
282 wndclass.hInstance = wxhInstance;
283 wndclass.hIcon = (HICON) NULL;
284 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
285 wndclass.lpszMenuName = NULL;
286
287 // Register the frame window class.
288 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
289 wndclass.lpszClassName = wxFrameClassName;
290 wndclass.style = styleNormal;
291
292 if ( !RegisterClass(&wndclass) )
293 {
294 wxLogLastError("RegisterClass(frame)");
295
296 return FALSE;
297 }
298
299 // "no redraw" frame
300 wndclass.lpszClassName = wxFrameClassNameNoRedraw;
301 wndclass.style = styleNoRedraw;
302
303 if ( !RegisterClass(&wndclass) )
304 {
305 wxLogLastError("RegisterClass(no redraw frame)");
306
307 return FALSE;
308 }
309
310 // Register the MDI frame window class.
311 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
312 wndclass.lpszClassName = wxMDIFrameClassName;
313 wndclass.style = styleNormal;
314
315 if ( !RegisterClass(&wndclass) )
316 {
317 wxLogLastError("RegisterClass(MDI parent)");
318
319 return FALSE;
320 }
321
322 // "no redraw" MDI frame
323 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
324 wndclass.style = styleNoRedraw;
325
326 if ( !RegisterClass(&wndclass) )
327 {
328 wxLogLastError("RegisterClass(no redraw MDI parent frame)");
329
330 return FALSE;
331 }
332
333 // Register the MDI child frame window class.
334 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
335 wndclass.lpszClassName = wxMDIChildFrameClassName;
336 wndclass.style = styleNormal;
337
338 if ( !RegisterClass(&wndclass) )
339 {
340 wxLogLastError("RegisterClass(MDI child)");
341
342 return FALSE;
343 }
344
345 // "no redraw" MDI child frame
346 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
347 wndclass.style = styleNoRedraw;
348
349 if ( !RegisterClass(&wndclass) )
350 {
351 wxLogLastError("RegisterClass(no redraw MDI child)");
352
353 return FALSE;
354 }
355
356 // Register the panel window class.
357 wndclass.hbrBackground = (HBRUSH) GetStockObject( LTGRAY_BRUSH );
358 wndclass.lpszClassName = wxPanelClassName;
359 wndclass.style = styleNormal;
360
361 if ( !RegisterClass(&wndclass) )
362 {
363 wxLogLastError("RegisterClass(panel)");
364
365 return FALSE;
366 }
367
368 // Register the canvas and textsubwindow class name
369 wndclass.hbrBackground = (HBRUSH)NULL;
370 wndclass.lpszClassName = wxCanvasClassName;
371
372 if ( !RegisterClass(&wndclass) )
373 {
374 wxLogLastError("RegisterClass(canvas)");
375
376 return FALSE;
377 }
378
379 return TRUE;
380}
381
382// ---------------------------------------------------------------------------
383// Convert Windows to argc, argv style
384// ---------------------------------------------------------------------------
385
386void wxApp::ConvertToStandardCommandArgs(char* lpCmdLine)
387{
388 wxStringList args;
389
390 wxString cmdLine(lpCmdLine);
391 int count = 0;
392
393 // Get application name
394 wxChar name[260]; // 260 is MAX_PATH value from windef.h
395 ::GetModuleFileName(wxhInstance, name, WXSIZEOF(name));
396
397 args.Add(name);
398 count++;
399
400 wxStrcpy(name, wxFileNameFromPath(name));
401 wxStripExtension(name);
402 wxTheApp->SetAppName(name);
403
404 // Break up string
405 // Treat strings enclosed in double-quotes as single arguments
406 int i = 0;
407 int len = cmdLine.Length();
408 while (i < len)
409 {
410 // Skip whitespace
411 while ((i < len) && wxIsspace(cmdLine.GetChar(i)))
412 i ++;
413
414 if (i < len)
415 {
416 if (cmdLine.GetChar(i) == wxT('"')) // We found the start of a string
417 {
418 i ++;
419 int first = i;
420 while ((i < len) && (cmdLine.GetChar(i) != wxT('"')))
421 i ++;
422
423 wxString arg(cmdLine.Mid(first, (i - first)));
424
425 args.Add(arg);
426 count ++;
427
428 if (i < len)
429 i ++; // Skip past 2nd quote
430 }
431 else // Unquoted argument
432 {
433 int first = i;
434 while ((i < len) && !wxIsspace(cmdLine.GetChar(i)))
435 i ++;
436
437 wxString arg(cmdLine.Mid(first, (i - first)));
438
439 args.Add(arg);
440 count ++;
441 }
442 }
443 }
444
445 wxTheApp->argv = new wxChar*[count + 1];
446 for (i = 0; i < count; i++)
447 {
448 wxString arg(args[i]);
449 wxTheApp->argv[i] = copystring((const wxChar*)arg);
450 }
451 wxTheApp->argv[count] = NULL; // argv[] is a NULL-terminated list
452 wxTheApp->argc = count;
453}
454
455//// Cleans up any wxWindows internal structures left lying around
456
457void wxApp::CleanUp()
458{
459 //// COMMON CLEANUP
460
461#if wxUSE_LOG
462 // flush the logged messages if any and install a 'safer' log target: the
463 // default one (wxLogGui) can't be used after the resources are freed just
464 // below and the user suppliedo ne might be even more unsafe (using any
465 // wxWindows GUI function is unsafe starting from now)
466 wxLog::DontCreateOnDemand();
467
468 // this will flush the old messages if any
469 delete wxLog::SetActiveTarget(new wxLogStderr);
470#endif // wxUSE_LOG
471
472 // One last chance for pending objects to be cleaned up
473 wxTheApp->DeletePendingObjects();
474
475 wxModule::CleanUpModules();
476
477#if wxUSE_WX_RESOURCES
478 wxCleanUpResourceSystem();
479
480 // wxDefaultResourceTable->ClearTable();
481#endif
482
483 // Indicate that the cursor can be freed, so that cursor won't be deleted
484 // by deleting the bitmap list before g_globalCursor goes out of scope
485 // (double deletion of the cursor).
486 wxSetCursor(wxNullCursor);
487 delete g_globalCursor;
488 g_globalCursor = NULL;
489
490 wxDeleteStockObjects();
491
492 // Destroy all GDI lists, etc.
493 wxDeleteStockLists();
494
495 delete wxTheColourDatabase;
496 wxTheColourDatabase = NULL;
497
498 wxBitmap::CleanUpHandlers();
499
500 delete[] wxBuffer;
501 wxBuffer = NULL;
502
503 //// WINDOWS-SPECIFIC CLEANUP
504
505 wxSetKeyboardHook(FALSE);
506
507#if wxUSE_RICHEDIT
508 if (gs_hRichEdit != (HINSTANCE) NULL)
509 FreeLibrary(gs_hRichEdit);
510#endif
511
512#if wxUSE_PENWINDOWS
513 wxCleanUpPenWin();
514#endif
515
516 if (wxSTD_FRAME_ICON)
517 DestroyIcon(wxSTD_FRAME_ICON);
518 if (wxSTD_MDICHILDFRAME_ICON)
519 DestroyIcon(wxSTD_MDICHILDFRAME_ICON);
520 if (wxSTD_MDIPARENTFRAME_ICON)
521 DestroyIcon(wxSTD_MDIPARENTFRAME_ICON);
522
523 if (wxDEFAULT_FRAME_ICON)
524 DestroyIcon(wxDEFAULT_FRAME_ICON);
525 if (wxDEFAULT_MDICHILDFRAME_ICON)
526 DestroyIcon(wxDEFAULT_MDICHILDFRAME_ICON);
527 if (wxDEFAULT_MDIPARENTFRAME_ICON)
528 DestroyIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
529
530 if ( wxDisableButtonBrush )
531 ::DeleteObject( wxDisableButtonBrush );
532
533#if wxUSE_OLE
534 ::OleUninitialize();
535#endif
536
537#if wxUSE_CTL3D
538 Ctl3dUnregister(wxhInstance);
539#endif
540
541 if (wxWinHandleList)
542 delete wxWinHandleList;
543
544 // GL: I'm annoyed ... I don't know where to put this and I don't want to
545 // create a module for that as it's part of the core.
546 delete wxPendingEvents;
547#if wxUSE_THREADS
548 delete wxPendingEventsLocker;
549 // If we don't do the following, we get an apparent memory leak.
550 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
551#endif
552
553 wxClassInfo::CleanUpClasses();
554
555 delete wxTheApp;
556 wxTheApp = NULL;
557
558#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
559 // At this point we want to check if there are any memory
560 // blocks that aren't part of the wxDebugContext itself,
561 // as a special case. Then when dumping we need to ignore
562 // wxDebugContext, too.
563 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
564 {
565 wxLogDebug(wxT("There were memory leaks."));
566 wxDebugContext::Dump();
567 wxDebugContext::PrintStatistics();
568 }
569 // wxDebugContext::SetStream(NULL, NULL);
570#endif
571
572#if wxUSE_LOG
573 // do it as the very last thing because everything else can log messages
574 delete wxLog::SetActiveTarget(NULL);
575#endif // wxUSE_LOG
576}
577
578#if !defined(_WINDLL) || (defined(_WINDLL) && defined(WXMAKINGDLL))
579
580// temporarily disable this warning which would be generated in release builds
581// because of __try
582#ifdef __VISUALC__
583 #pragma warning(disable: 4715) // not all control paths return a value
584#endif // Visual C++
585
586//// Main wxWindows entry point
587int wxEntry(WXHINSTANCE hInstance,
588 WXHINSTANCE WXUNUSED(hPrevInstance),
589 char *lpCmdLine,
590 int nCmdShow,
591 bool enterLoop)
592{
593 // do check for memory leaks on program exit
594 // (another useful flag is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free
595 // deallocated memory which may be used to simulate low-memory condition)
596 wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
597
598 // take everything into a try-except block in release build
599 // FIXME other compilers must support Win32 SEH (structured exception
600 // handling) too, just find the appropriate keyword in their docs!
601 // Please note that it's _not_ the same as C++ exceptions!
602#if !defined(__WXDEBUG__) && defined(__VISUALC__)
603 #define CATCH_PROGRAM_EXCEPTIONS
604
605 __try {
606#else
607 #undef CATCH_PROGRAM_EXCEPTIONS
608#endif
609 wxhInstance = (HINSTANCE) hInstance;
610
611 if (!wxApp::Initialize())
612 return 0;
613
614 // create the application object or ensure that one already exists
615 if (!wxTheApp)
616 {
617 // The app may have declared a global application object, but we recommend
618 // the IMPLEMENT_APP macro is used instead, which sets an initializer
619 // function for delayed, dynamic app object construction.
620 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
621 wxT("No initializer - use IMPLEMENT_APP macro.") );
622
623 wxTheApp = (*wxApp::GetInitializerFunction()) ();
624 }
625
626 wxCHECK_MSG( wxTheApp, 0, wxT("You have to define an instance of wxApp!") );
627
628 // save the WinMain() parameters
629 wxTheApp->ConvertToStandardCommandArgs(lpCmdLine);
630 wxTheApp->m_nCmdShow = nCmdShow;
631
632 // GUI-specific initialisation. In fact on Windows we don't have any,
633 // but this call is provided for compatibility across platforms.
634 wxTheApp->OnInitGui();
635
636 // We really don't want timestamps by default, because it means
637 // we can't simply double-click on the error message and get to that
638 // line in the source. So VC++ at least, let's have a sensible default.
639#ifdef __VISUALC__
640 wxLog::SetTimestamp(NULL);
641#endif
642
643 int retValue = 0;
644
645 if ( wxTheApp->OnInit() )
646 {
647 if ( enterLoop )
648 {
649 retValue = wxTheApp->OnRun();
650 }
651 else
652 // We want to initialize, but not run or exit immediately.
653 return 1;
654 }
655 //else: app initialization failed, so we skipped OnRun()
656
657 wxWindow *topWindow = wxTheApp->GetTopWindow();
658 if ( topWindow )
659 {
660 // Forcibly delete the window.
661 if ( topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
662 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
663 {
664 topWindow->Close(TRUE);
665 wxTheApp->DeletePendingObjects();
666 }
667 else
668 {
669 delete topWindow;
670 wxTheApp->SetTopWindow(NULL);
671 }
672 }
673
674 wxTheApp->OnExit();
675
676 wxApp::CleanUp();
677
678 return retValue;
679
680#ifdef CATCH_PROGRAM_EXCEPTIONS
681 }
682 __except ( EXCEPTION_EXECUTE_HANDLER ) {
683 /*
684 if ( wxTheApp )
685 wxTheApp->OnFatalException();
686 */
687
688 // using wxLog would be unsafe here
689 ::MessageBox(NULL,
690 _("Unrecoverable program error detected: "
691 " the application will terminate."),
692 _("Fatal Error"),
693 MB_APPLMODAL | MB_ICONSTOP | MB_OK);
694
695 ::ExitProcess(3); // the same exit code as abort()
696
697 // NOTREACHED
698 }
699#endif // CATCH_PROGRAM_EXCEPTIONS
700}
701
702// restore warning state
703#ifdef __VISUALC__
704 #pragma warning(default: 4715) // not all control paths return a value
705#endif // Visual C++
706
707#else /* _WINDLL */
708
709//// Entry point for DLLs
710
711int wxEntry(WXHINSTANCE hInstance)
712{
713 wxhInstance = (HINSTANCE) hInstance;
714 wxApp::Initialize();
715
716 // The app may have declared a global application object, but we recommend
717 // the IMPLEMENT_APP macro is used instead, which sets an initializer function
718 // for delayed, dynamic app object construction.
719 if (!wxTheApp)
720 {
721 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
722 "No initializer - use IMPLEMENT_APP macro." );
723
724 wxTheApp = (* wxApp::GetInitializerFunction()) ();
725 }
726
727 wxCHECK_MSG( wxTheApp, 0, "You have to define an instance of wxApp!" );
728
729 wxTheApp->argc = 0;
730 wxTheApp->argv = NULL;
731
732 wxTheApp->OnInitGui();
733
734 wxTheApp->OnInit();
735
736 wxWindow *topWindow = wxTheApp->GetTopWindow();
737 if ( topWindow && topWindow->GetHWND())
738 {
739 topWindow->Show(TRUE);
740 }
741
742 return 1;
743}
744#endif // _WINDLL
745
746//// Static member initialization
747
748wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
749
750wxApp::wxApp()
751{
752 m_topWindow = NULL;
753 wxTheApp = this;
754 m_wantDebugOutput = TRUE;
755
756 argc = 0;
757 argv = NULL;
758 m_printMode = wxPRINT_WINDOWS;
759 m_exitOnFrameDelete = TRUE;
760 m_auto3D = TRUE;
761}
762
763wxApp::~wxApp()
764{
765 // Delete command-line args
766 int i;
767 for (i = 0; i < argc; i++)
768 {
769 delete[] argv[i];
770 }
771 delete[] argv;
772}
773
774bool wxApp::Initialized()
775{
776#ifndef _WINDLL
777 if (GetTopWindow())
778 return TRUE;
779 else
780 return FALSE;
781#endif
782#ifdef _WINDLL // Assume initialized if DLL (no way of telling)
783 return TRUE;
784#endif
785}
786
787/*
788 * Get and process a message, returning FALSE if WM_QUIT
789 * received (and also set the flag telling the app to exit the main loop)
790 *
791 */
792bool wxApp::DoMessage()
793{
794 BOOL rc = ::GetMessage(&s_currentMsg, (HWND) NULL, 0, 0);
795 if ( rc == 0 )
796 {
797 // got WM_QUIT
798 m_keepGoing = FALSE;
799
800 return FALSE;
801 }
802 else if ( rc == -1 )
803 {
804 // should never happen, but let's test for it nevertheless
805 wxLogLastError("GetMessage");
806 }
807 else
808 {
809#if wxUSE_THREADS
810 wxASSERT_MSG( wxThread::IsMain(),
811 wxT("only the main thread can process Windows messages") );
812
813 static bool s_hadGuiLock = TRUE;
814 static wxMsgArray s_aSavedMessages;
815
816 // if a secondary thread owns is doing GUI calls, save all messages for
817 // later processing - we can't process them right now because it will
818 // lead to recursive library calls (and we're not reentrant)
819 if ( !wxGuiOwnedByMainThread() )
820 {
821 s_hadGuiLock = FALSE;
822
823 // leave out WM_COMMAND messages: too dangerous, sometimes
824 // the message will be processed twice
825 if ( !wxIsWaitingForThread() ||
826 s_currentMsg.message != WM_COMMAND )
827 {
828 s_aSavedMessages.Add(s_currentMsg);
829 }
830
831 return TRUE;
832 }
833 else
834 {
835 // have we just regained the GUI lock? if so, post all of the saved
836 // messages
837 //
838 // FIXME of course, it's not _exactly_ the same as processing the
839 // messages normally - expect some things to break...
840 if ( !s_hadGuiLock )
841 {
842 s_hadGuiLock = TRUE;
843
844 size_t count = s_aSavedMessages.Count();
845 for ( size_t n = 0; n < count; n++ )
846 {
847 MSG& msg = s_aSavedMessages[n];
848
849 if ( !ProcessMessage((WXMSG *)&msg) )
850 {
851 ::TranslateMessage(&msg);
852 ::DispatchMessage(&msg);
853 }
854 }
855
856 s_aSavedMessages.Empty();
857 }
858 }
859#endif // wxUSE_THREADS
860
861 // Process the message
862 if ( !ProcessMessage((WXMSG *)&s_currentMsg) )
863 {
864 ::TranslateMessage(&s_currentMsg);
865 ::DispatchMessage(&s_currentMsg);
866 }
867 }
868
869 return TRUE;
870}
871
872/*
873 * Keep trying to process messages until WM_QUIT
874 * received.
875 *
876 * If there are messages to be processed, they will all be
877 * processed and OnIdle will not be called.
878 * When there are no more messages, OnIdle is called.
879 * If OnIdle requests more time,
880 * it will be repeatedly called so long as there are no pending messages.
881 * A 'feature' of this is that once OnIdle has decided that no more processing
882 * is required, then it won't get processing time until further messages
883 * are processed (it'll sit in DoMessage).
884 */
885
886int wxApp::MainLoop()
887{
888 m_keepGoing = TRUE;
889
890 while ( m_keepGoing )
891 {
892#if wxUSE_THREADS
893 wxMutexGuiLeaveOrEnter();
894#endif // wxUSE_THREADS
895
896 while ( !::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) &&
897 ProcessIdle() )
898 {
899 }
900
901
902 DoMessage();
903 }
904
905 return s_currentMsg.wParam;
906}
907
908// Returns TRUE if more time is needed.
909bool wxApp::ProcessIdle()
910{
911 wxIdleEvent event;
912 event.SetEventObject(this);
913 ProcessEvent(event);
914
915 return event.MoreRequested();
916}
917
918void wxApp::ExitMainLoop()
919{
920 m_keepGoing = FALSE;
921}
922
923bool wxApp::Pending()
924{
925 return (::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0);
926}
927
928void wxApp::Dispatch()
929{
930 DoMessage();
931}
932
933/*
934 * Give all windows a chance to preprocess
935 * the message. Some may have accelerator tables, or have
936 * MDI complications.
937 */
938
939bool wxApp::ProcessMessage(WXMSG *wxmsg)
940{
941 MSG *msg = (MSG *)wxmsg;
942 HWND hWnd = msg->hwnd;
943 wxWindow *wndThis = wxFindWinFromHandle((WXHWND)hWnd), *wnd;
944
945 // for some composite controls (like a combobox), wndThis might be NULL
946 // because the subcontrol is not a wxWindow, but only the control itself
947 // is - try to catch this case
948 while ( hWnd && !wndThis )
949 {
950 hWnd = ::GetParent(hWnd);
951 wndThis = wxFindWinFromHandle((WXHWND)hWnd);
952 }
953
954 // Try translations first; find the youngest window with
955 // a translation table.
956 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
957 {
958 if ( wnd->MSWTranslateMessage(wxmsg) )
959 return TRUE;
960 }
961
962 // Anyone for a non-translation message? Try youngest descendants first.
963 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
964 {
965 if ( wnd->MSWProcessMessage(wxmsg) )
966 return TRUE;
967 }
968
969 return FALSE;
970}
971
972void wxApp::OnIdle(wxIdleEvent& event)
973{
974 static bool s_inOnIdle = FALSE;
975
976 // Avoid recursion (via ProcessEvent default case)
977 if ( s_inOnIdle )
978 return;
979
980 s_inOnIdle = TRUE;
981
982 // 'Garbage' collection of windows deleted with Close().
983 DeletePendingObjects();
984
985#if wxUSE_LOG
986 // flush the logged messages if any
987 wxLog *pLog = wxLog::GetActiveTarget();
988 if ( pLog != NULL && pLog->HasPendingMessages() )
989 pLog->Flush();
990#endif // wxUSE_LOG
991
992 // Send OnIdle events to all windows
993 if ( SendIdleEvents() )
994 {
995 // SendIdleEvents() returns TRUE if at least one window requested more
996 // idle events
997 event.RequestMore(TRUE);
998 }
999
1000 // If they are pending events, we must process them: pending events are
1001 // either events to the threads other than main or events posted with
1002 // wxPostEvent() functions
1003 ProcessPendingEvents();
1004
1005 s_inOnIdle = FALSE;
1006}
1007
1008// Send idle event to all top-level windows
1009bool wxApp::SendIdleEvents()
1010{
1011 bool needMore = FALSE;
1012
1013 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
1014 while (node)
1015 {
1016 wxWindow* win = node->GetData();
1017 if (SendIdleEvents(win))
1018 needMore = TRUE;
1019 node = node->GetNext();
1020 }
1021
1022 return needMore;
1023}
1024
1025// Send idle event to window and all subwindows
1026bool wxApp::SendIdleEvents(wxWindow* win)
1027{
1028 bool needMore = FALSE;
1029
1030 wxIdleEvent event;
1031 event.SetEventObject(win);
1032 win->GetEventHandler()->ProcessEvent(event);
1033
1034 if (event.MoreRequested())
1035 needMore = TRUE;
1036
1037 wxNode* node = win->GetChildren().First();
1038 while (node)
1039 {
1040 wxWindow* win = (wxWindow*) node->Data();
1041 if (SendIdleEvents(win))
1042 needMore = TRUE;
1043
1044 node = node->Next();
1045 }
1046 return needMore;
1047}
1048
1049void wxApp::DeletePendingObjects()
1050{
1051 wxNode *node = wxPendingDelete.First();
1052 while (node)
1053 {
1054 wxObject *obj = (wxObject *)node->Data();
1055
1056 delete obj;
1057
1058 if (wxPendingDelete.Member(obj))
1059 delete node;
1060
1061 // Deleting one object may have deleted other pending
1062 // objects, so start from beginning of list again.
1063 node = wxPendingDelete.First();
1064 }
1065}
1066
1067void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
1068{
1069 if (GetTopWindow())
1070 GetTopWindow()->Close(TRUE);
1071}
1072
1073// Default behaviour: close the application with prompts. The
1074// user can veto the close, and therefore the end session.
1075void wxApp::OnQueryEndSession(wxCloseEvent& event)
1076{
1077 if (GetTopWindow())
1078 {
1079 if (!GetTopWindow()->Close(!event.CanVeto()))
1080 event.Veto(TRUE);
1081 }
1082}
1083
1084#if wxUSE_RICHEDIT
1085
1086/* static */
1087bool wxApp::InitRichEdit(int version)
1088{
1089 wxCHECK_MSG( version >= 1 && version <= 3, FALSE,
1090 _T("incorrect richedit control version requested") );
1091
1092 if ( version <= gs_verRichEdit )
1093 {
1094 // we've already got this or better
1095 return TRUE;
1096 }
1097
1098 if ( gs_hRichEdit )
1099 {
1100 ::FreeLibrary(gs_hRichEdit);
1101 }
1102
1103 // always try load riched20.dll first - like this we won't have to reload
1104 // it later if we're first asked for RE 1 and then for RE 2 or 3
1105 wxString dllname = _T("riched20.dll");
1106 gs_hRichEdit = ::LoadLibrary(dllname);
1107 if ( !gs_hRichEdit && (version == 1) )
1108 {
1109 // fall back to RE 1
1110 dllname = _T("riched32.dll");
1111 gs_hRichEdit = ::LoadLibrary(dllname);
1112 }
1113
1114 if ( !gs_hRichEdit )
1115 {
1116 wxLogSysError(_("Could not load Rich Edit DLL '%s'"), dllname.c_str());
1117
1118 gs_verRichEdit = -1;
1119
1120 return FALSE;
1121 }
1122
1123 gs_verRichEdit = version;
1124
1125 return TRUE;
1126}
1127
1128#endif // wxUSE_RICHEDIT
1129
1130/* static */
1131int wxApp::GetComCtl32Version()
1132{
1133 // TODO should use DllGetVersion() instead of this hack
1134
1135 // cache the result
1136 static int s_verComCtl32 = -1; // MT-FIXME
1137
1138 if ( s_verComCtl32 == -1 )
1139 {
1140 s_verComCtl32 = 0;
1141
1142 // have we loaded COMCTL32 yet?
1143 HMODULE theModule = ::GetModuleHandle(wxT("COMCTL32"));
1144
1145 // if so, then we can check for the version
1146 if (theModule)
1147 {
1148 // InitCommonControlsEx is unique to 4.7 and later
1149 FARPROC theProc = ::GetProcAddress(theModule,
1150 _T("InitCommonControlsEx"));
1151
1152 if ( !theProc )
1153 { // not found, must be 4.00
1154 s_verComCtl32 = 400;
1155 }
1156 else
1157 {
1158 // The following symbol are unique to 4.71
1159 // DllInstall
1160 // FlatSB_EnableScrollBar FlatSB_GetScrollInfo FlatSB_GetScrollPos
1161 // FlatSB_GetScrollProp FlatSB_GetScrollRange FlatSB_SetScrollInfo
1162 // FlatSB_SetScrollPos FlatSB_SetScrollProp FlatSB_SetScrollRange
1163 // FlatSB_ShowScrollBar
1164 // _DrawIndirectImageList _DuplicateImageList
1165 // InitializeFlatSB
1166 // UninitializeFlatSB
1167 // we could check for any of these - I chose DllInstall
1168 FARPROC theProc = ::GetProcAddress(theModule, _T("DllInstall"));
1169 if ( !theProc )
1170 {
1171 // not found, must be 4.70
1172 s_verComCtl32 = 470;
1173 }
1174 else
1175 { // found, must be 4.71
1176 s_verComCtl32 = 471;
1177 }
1178 }
1179 }
1180 }
1181
1182 return s_verComCtl32;
1183}
1184
1185void wxExit()
1186{
1187 wxLogError(_("Fatal error: exiting"));
1188
1189 wxApp::CleanUp();
1190}
1191
1192// Yield to incoming messages
1193bool wxYield()
1194{
1195 // we don't want to process WM_QUIT from here - it should be processed in
1196 // the main event loop in order to stop it
1197
1198 MSG msg;
1199 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
1200 msg.message != WM_QUIT )
1201 {
1202 if ( !wxTheApp->DoMessage() )
1203 break;
1204 }
1205
1206 // If they are pending events, we must process them.
1207 wxTheApp->ProcessPendingEvents();
1208
1209 return TRUE;
1210}
1211
1212//-----------------------------------------------------------------------------
1213// wxWakeUpIdle
1214//-----------------------------------------------------------------------------
1215
1216void wxWakeUpIdle()
1217{
1218 // Send the top window a dummy message so idle handler processing will
1219 // start up again. Doing it this way ensures that the idle handler
1220 // wakes up in the right thread.
1221 wxWindow *topWindow = wxTheApp->GetTopWindow();
1222 if ( topWindow ) {
1223 HWND hWnd = (HWND)topWindow->GetHWND();
1224 ::PostMessage(hWnd, WM_NULL, 0, 0);
1225 }
1226}
1227
1228//-----------------------------------------------------------------------------
1229
1230wxIcon
1231wxApp::GetStdIcon(int which) const
1232{
1233 switch(which)
1234 {
1235 case wxICON_INFORMATION:
1236 return wxIcon("wxICON_INFO");
1237
1238 case wxICON_QUESTION:
1239 return wxIcon("wxICON_QUESTION");
1240
1241 case wxICON_EXCLAMATION:
1242 return wxIcon("wxICON_WARNING");
1243
1244 default:
1245 wxFAIL_MSG(wxT("requested non existent standard icon"));
1246 // still fall through
1247
1248 case wxICON_HAND:
1249 return wxIcon("wxICON_ERROR");
1250 }
1251}
1252
1253
1254HINSTANCE wxGetInstance()
1255{
1256 return wxhInstance;
1257}
1258
1259void wxSetInstance(HINSTANCE hInst)
1260{
1261 wxhInstance = hInst;
1262}
1263
1264// For some reason, with MSVC++ 1.5, WinMain isn't linked in properly
1265// if in a separate file. So include it here to ensure it's linked.
1266#if (defined(__VISUALC__) && !defined(__WIN32__)) || (defined(__GNUWIN32__) && !defined(__TWIN32__))
1267#include "main.cpp"
1268#endif