]> git.saurik.com Git - wxWidgets.git/blob - src/msw/app.cpp
1. wxIcon/wxCursor change, wxGDIImage class added
[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 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
96 extern wxChar *wxBuffer;
97 extern wxChar *wxOsVersion;
98 extern wxList *wxWinHandleList;
99 extern wxList WXDLLEXPORT wxPendingDelete;
100 extern void wxSetKeyboardHook(bool doIt);
101 extern wxCursor *g_globalCursor;
102
103 HINSTANCE wxhInstance = 0;
104 MSG s_currentMsg;
105 wxApp *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
111 wxChar wxFrameClassName[] = wxT("wxFrameClass");
112 wxChar wxFrameClassNameNoRedraw[] = wxT("wxFrameClassNR");
113 wxChar wxMDIFrameClassName[] = wxT("wxMDIFrameClass");
114 wxChar wxMDIFrameClassNameNoRedraw[] = wxT("wxMDIFrameClassNR");
115 wxChar wxMDIChildFrameClassName[] = wxT("wxMDIChildFrameClass");
116 wxChar wxMDIChildFrameClassNameNoRedraw[] = wxT("wxMDIChildFrameClassNR");
117 wxChar wxPanelClassName[] = wxT("wxPanelClass");
118 wxChar wxCanvasClassName[] = wxT("wxCanvasClass");
119
120 HICON wxSTD_FRAME_ICON = (HICON) NULL;
121 HICON wxSTD_MDICHILDFRAME_ICON = (HICON) NULL;
122 HICON wxSTD_MDIPARENTFRAME_ICON = (HICON) NULL;
123
124 HICON wxDEFAULT_FRAME_ICON = (HICON) NULL;
125 HICON wxDEFAULT_MDICHILDFRAME_ICON = (HICON) NULL;
126 HICON wxDEFAULT_MDIPARENTFRAME_ICON = (HICON) NULL;
127
128 HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
129
130 LRESULT 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
157 bool 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.
269 bool 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
386 void 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
457 void 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
587 int 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
711 int 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
748 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
749
750 wxApp::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
763 wxApp::~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
774 bool 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 */
792 bool 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
886 int 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.
909 bool wxApp::ProcessIdle()
910 {
911 wxIdleEvent event;
912 event.SetEventObject(this);
913 ProcessEvent(event);
914
915 return event.MoreRequested();
916 }
917
918 void wxApp::ExitMainLoop()
919 {
920 m_keepGoing = FALSE;
921 }
922
923 bool wxApp::Pending()
924 {
925 return (::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0);
926 }
927
928 void 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
939 bool 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
972 void 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
1009 bool 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
1026 bool 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
1049 void 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
1067 void 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.
1075 void 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 */
1087 bool 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 */
1131 int 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
1185 void wxExit()
1186 {
1187 wxLogError(_("Fatal error: exiting"));
1188
1189 wxApp::CleanUp();
1190 }
1191
1192 // Yield to incoming messages
1193 bool 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
1216 void 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
1230 wxIcon
1231 wxApp::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
1254 HINSTANCE wxGetInstance()
1255 {
1256 return wxhInstance;
1257 }
1258
1259 void 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