]> git.saurik.com Git - wxWidgets.git/blob - src/msw/app.cpp
thread fixes for MSW (samples doesn't compile currently under !MSW, will
[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 #ifdef __GNUG__
13 #pragma implementation "app.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #if defined(__BORLANDC__)
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/frame.h"
25 #include "wx/app.h"
26 #include "wx/utils.h"
27 #include "wx/gdicmn.h"
28 #include "wx/pen.h"
29 #include "wx/brush.h"
30 #include "wx/cursor.h"
31 #include "wx/icon.h"
32 #include "wx/palette.h"
33 #include "wx/dc.h"
34 #include "wx/dialog.h"
35 #include "wx/msgdlg.h"
36 #endif
37
38 #include "wx/msw/private.h"
39 #include "wx/log.h"
40 #include "wx/module.h"
41
42 #if wxUSE_THREADS
43 #include "wx/thread.h"
44
45 // define the array of MSG strutures
46 WX_DECLARE_OBJARRAY(MSG, wxMsgArray);
47
48 #include "wx/arrimpl.cpp"
49
50 WX_DEFINE_OBJARRAY(wxMsgArray);
51 #endif // wxUSE_THREADS
52
53 #if wxUSE_WX_RESOURCES
54 #include "wx/resource.h"
55 #endif
56
57 // To UG: there's no point in putting this #if here
58 // if you don't do the same for the Ole calls further down.
59 // Also, OLE is used not just for drag and drop (it's used by automatn.cpp).
60 // #if wxUSE_DRAG_AND_DROP
61 #if !defined(__GNUWIN32__) && !defined(__SC__)
62 #include <ole2.h>
63 #endif
64 // #endif
65
66 #include <string.h>
67 #include <ctype.h>
68
69 #if defined(__WIN95__) && !defined(__GNUWIN32__)
70 #include <commctrl.h>
71 #endif
72
73 // use debug CRT functions for memory leak detections in VC++ if we're not
74 // using wxWindows own methods
75 #if defined(__WXDEBUG__) && defined(_MSC_VER) && !wxUSE_GLOBAL_MEMORY_OPERATORS && !defined(__NO_VC_CRTDBG__)
76 #define wxUSE_VC_CRTDBG
77 #else
78 #undef wxUSE_VC_CRTDBG
79 #endif
80
81 #ifdef wxUSE_VC_CRTDBG
82 // VC++ uses this macro as debug/release mode indicator
83 #ifndef _DEBUG
84 #define _DEBUG
85 #endif
86
87 /* Need to undef new if including crtdbg.h */
88 #ifdef new
89 #undef new
90 #endif
91
92 #include <crtdbg.h>
93
94 #if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS && wxUSE_DEBUG_NEW_ALWAYS
95 #define new new(__FILE__,__LINE__)
96 #endif
97
98 #endif
99
100 extern char *wxBuffer;
101 extern char *wxOsVersion;
102 extern wxList *wxWinHandleList;
103 extern wxList WXDLLEXPORT wxPendingDelete;
104 extern void wxSetKeyboardHook(bool doIt);
105 extern wxCursor *g_globalCursor;
106
107 HINSTANCE wxhInstance = 0;
108 static MSG s_currentMsg;
109 wxApp *wxTheApp = NULL;
110
111 // @@ why not const? and not static?
112 char wxFrameClassName[] = "wxFrameClass";
113 char wxMDIFrameClassName[] = "wxMDIFrameClass";
114 char wxMDIChildFrameClassName[] = "wxMDIChildFrameClass";
115 char wxPanelClassName[] = "wxPanelClass";
116 char wxCanvasClassName[] = "wxCanvasClass";
117
118 HICON wxSTD_FRAME_ICON = NULL;
119 HICON wxSTD_MDICHILDFRAME_ICON = NULL;
120 HICON wxSTD_MDIPARENTFRAME_ICON = NULL;
121
122 HICON wxDEFAULT_FRAME_ICON = NULL;
123 HICON wxDEFAULT_MDICHILDFRAME_ICON = NULL;
124 HICON wxDEFAULT_MDIPARENTFRAME_ICON = NULL;
125
126 HBRUSH wxDisableButtonBrush = 0;
127
128 LRESULT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
129
130 #if !USE_SHARED_LIBRARY
131 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
132
133 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
134 EVT_IDLE(wxApp::OnIdle)
135 EVT_END_SESSION(wxApp::OnEndSession)
136 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
137 END_EVENT_TABLE()
138 #endif
139
140 long wxApp::sm_lastMessageTime = 0;
141
142 #ifdef __WIN95__
143 static HINSTANCE gs_hRichEdit = NULL;
144 #endif
145
146 //// Initialize
147
148 bool wxApp::Initialize()
149 {
150 // Some people may wish to use this, but
151 // probably it shouldn't be here by default.
152 #ifdef __WXDEBUG__
153 // wxRedirectIOToConsole();
154 #endif
155
156 wxBuffer = new char[1500];
157
158 #ifdef wxUSE_VC_CRTDBG
159 // do check for memory leaks on program exit
160 // (another useful flag is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free
161 // deallocated memory which may be used to simulate low-memory condition)
162 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
163 #endif // debug build under MS VC++
164
165 wxClassInfo::InitializeClasses();
166
167 #if wxUSE_RESOURCES
168 wxGetResource("wxWindows", "OsVersion", &wxOsVersion);
169 #endif
170
171 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
172 wxTheColourDatabase->Initialize();
173
174 wxInitializeStockLists();
175 wxInitializeStockObjects();
176
177 #if wxUSE_WX_RESOURCES
178 wxInitializeResourceSystem();
179 #endif
180
181 wxBitmap::InitStandardHandlers();
182
183 #if defined(__WIN95__)
184 InitCommonControls();
185 gs_hRichEdit = LoadLibrary("RICHED32.DLL");
186
187 if (gs_hRichEdit == NULL)
188 {
189 wxMessageBox("Could not initialise Rich Edit DLL");
190 }
191 #endif
192
193 int iMsg = 96;
194
195 // for OLE, enlarge message queue to be as large as possible
196 while (!SetMessageQueue(iMsg) && (iMsg -= 8));
197
198 /*
199 DWORD dwOleVer;
200 dwOleVer = CoBuildVersion();
201
202 // check the OLE library version
203 if (rmm != HIWORD(dwOleVer))
204 {
205 wxMessageBox("Incorrect version of OLE libraries.");
206 return FALSE;
207 }
208 */
209
210 #if !defined(__GNUWIN32__) && !defined(__SC__)
211 // we need to initialize OLE library
212 if ( FAILED(::OleInitialize(NULL)) )
213 wxFatalError(_("Cannot initialize OLE"));
214 #endif
215
216 #if CTL3D
217 if (!Ctl3dRegister(wxhInstance))
218 wxFatalError("Cannot register CTL3D");
219
220 Ctl3dAutoSubclass(wxhInstance);
221 #endif
222
223 g_globalCursor = new wxCursor;
224
225 wxSTD_FRAME_ICON = LoadIcon(wxhInstance, "wxSTD_FRAME");
226 wxSTD_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, "wxSTD_MDIPARENTFRAME");
227 wxSTD_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, "wxSTD_MDICHILDFRAME");
228
229 wxDEFAULT_FRAME_ICON = LoadIcon(wxhInstance, "wxDEFAULT_FRAME");
230 wxDEFAULT_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, "wxDEFAULT_MDIPARENTFRAME");
231 wxDEFAULT_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, "wxDEFAULT_MDICHILDFRAME");
232
233 RegisterWindowClasses();
234
235 // Create the brush for disabling bitmap buttons
236
237 LOGBRUSH lb ;
238 lb.lbStyle = BS_PATTERN;
239 lb.lbHatch = (int)LoadBitmap( wxhInstance, "wxDISABLE_BUTTON_BITMAP" ) ;
240 wxDisableButtonBrush = ::CreateBrushIndirect( & lb ) ;
241 ::DeleteObject( (HGDIOBJ)lb.lbHatch ) ;
242
243 #if wxUSE_PENWINDOWS
244 wxRegisterPenWin();
245 #endif
246
247 wxWinHandleList = new wxList(wxKEY_INTEGER);
248
249 // This is to foil optimizations in Visual C++ that
250 // throw out dummy.obj.
251 #if (_MSC_VER >= 800) && !defined(WXMAKINGDLL)
252 extern char wxDummyChar;
253 if (wxDummyChar) wxDummyChar++;
254 #endif
255
256 wxSetKeyboardHook(TRUE);
257
258 wxModule::RegisterModules();
259 if (!wxModule::InitializeModules())
260 return FALSE;
261 return TRUE;
262 }
263
264 //// RegisterWindowClasses
265
266 bool wxApp::RegisterWindowClasses()
267 {
268 ///////////////////////////////////////////////////////////////////////
269 // Register the frame window class.
270 WNDCLASS wndclass; // Structure used to register Windows class.
271
272 wndclass.style = CS_HREDRAW | CS_VREDRAW;
273 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
274 wndclass.cbClsExtra = 0;
275 wndclass.cbWndExtra = sizeof( DWORD ); // was 4
276 wndclass.hInstance = wxhInstance;
277 wndclass.hIcon = NULL; // wxSTD_FRAME_ICON;
278 wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
279 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1) ;
280 // wndclass.hbrBackground = GetStockObject( WHITE_BRUSH );
281 wndclass.lpszMenuName = NULL;
282 #ifdef _MULTIPLE_INSTANCES
283 sprintf( wxFrameClassName,"wxFrameClass%d", wxhInstance );
284 #endif
285 wndclass.lpszClassName = wxFrameClassName;
286
287 if (!RegisterClass( &wndclass ))
288 {
289 // wxFatalError("Can't register Frame Window class");
290 }
291
292 ///////////////////////////////////////////////////////////////////////
293 // Register the MDI frame window class.
294 WNDCLASS wndclass1; // Structure used to register Windows class.
295
296 wndclass1.style = CS_HREDRAW | CS_VREDRAW;
297 wndclass1.lpfnWndProc = (WNDPROC)wxWndProc;
298 wndclass1.cbClsExtra = 0;
299 wndclass1.cbWndExtra = sizeof( DWORD ); // was 4
300 wndclass1.hInstance = wxhInstance;
301 wndclass1.hIcon = NULL; // wxSTD_MDIPARENTFRAME_ICON;
302 wndclass1.hCursor = LoadCursor( NULL, IDC_ARROW );
303 // wndclass1.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1) ;
304 wndclass1.hbrBackground = NULL;
305 wndclass1.lpszMenuName = NULL;
306
307 wndclass1.lpszClassName = wxMDIFrameClassName;
308 if (!RegisterClass( &wndclass1 ))
309 {
310 // wxFatalError("Can't register MDI Frame window class");
311 // return FALSE;
312 }
313
314 ///////////////////////////////////////////////////////////////////////
315 // Register the MDI child frame window class.
316 WNDCLASS wndclass4; // Structure used to register Windows class.
317
318 wndclass4.style = CS_HREDRAW | CS_VREDRAW;
319 wndclass4.lpfnWndProc = (WNDPROC)wxWndProc;
320 wndclass4.cbClsExtra = 0;
321 wndclass4.cbWndExtra = sizeof( DWORD ); // was 4
322 wndclass4.hInstance = wxhInstance;
323 wndclass4.hIcon = NULL; // wxSTD_MDICHILDFRAME_ICON;
324 wndclass4.hCursor = LoadCursor( NULL, IDC_ARROW );
325 // TODO: perhaps this should be NULL so that Windows doesn't
326 // paint the background itself (would OnEraseBackground duplicate
327 // this?)
328 wndclass4.hbrBackground = (HBRUSH)(COLOR_WINDOW+1) ;
329 // wndclass4.hbrBackground = NULL;
330 wndclass4.lpszMenuName = NULL;
331 wndclass4.lpszClassName = wxMDIChildFrameClassName;
332
333 if (!RegisterClass( &wndclass4 ))
334 {
335 // wxFatalError("Can't register MDI child frame window class");
336 // return FALSE;
337 }
338
339 ///////////////////////////////////////////////////////////////////////
340 // Register the panel window class.
341 WNDCLASS wndclass2; // Structure used to register Windows class.
342 memset(&wndclass2, 0, sizeof(WNDCLASS)); // start with NULL defaults
343 // Use CS_OWNDC to avoid messing about restoring the context
344 // for every graphic operation.
345 wndclass2.style = CS_HREDRAW | CS_VREDRAW;
346 wndclass2.lpfnWndProc = (WNDPROC)wxWndProc;
347 wndclass2.cbClsExtra = 0;
348 wndclass2.cbWndExtra = sizeof( DWORD ); // was 4
349 wndclass2.hInstance = wxhInstance;
350 wndclass2.hIcon = NULL;
351 wndclass2.hCursor = NULL;
352 // wndclass2.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1) ;
353 wndclass2.hbrBackground = (HBRUSH) GetStockObject( LTGRAY_BRUSH );
354 wndclass2.lpszMenuName = NULL;
355 wndclass2.lpszClassName = wxPanelClassName;
356 if (!RegisterClass( &wndclass2 ))
357 {
358 // wxFatalError("Can't register Panel Window class");
359 // return FALSE;
360 }
361
362 ///////////////////////////////////////////////////////////////////////
363 // Register the canvas and textsubwindow class name
364 WNDCLASS wndclass3; // Structure used to register Windows class.
365 memset(&wndclass3, 0, sizeof(WNDCLASS)); // start with NULL defaults
366 // Use CS_OWNDC to avoid messing about restoring the context
367 // for every graphic operation.
368 // wndclass3.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS ;
369 // wxWin 2.0
370 wndclass3.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
371 wndclass3.lpfnWndProc = (WNDPROC)wxWndProc;
372 wndclass3.cbClsExtra = 0;
373 wndclass3.cbWndExtra = sizeof( DWORD ); // was 4
374 wndclass3.hInstance = wxhInstance;
375 wndclass3.hIcon = NULL;
376 wndclass3.hCursor = NULL;
377 // wndclass3.hbrBackground = (HBRUSH)(COLOR_WINDOW+1) ;
378 wndclass3.hbrBackground = NULL;
379 wndclass3.lpszMenuName = NULL;
380 wndclass3.lpszClassName = wxCanvasClassName;
381 if (!RegisterClass( &wndclass3))
382 {
383 // wxFatalError("Can't register Canvas class");
384 // return FALSE;
385 }
386
387 return TRUE;
388 }
389
390 //// Convert Windows to argc, argv style
391
392 void wxApp::ConvertToStandardCommandArgs(char* lpCmdLine)
393 {
394 wxStringList args;
395
396 wxString cmdLine(lpCmdLine);
397 int count = 0;
398
399 // Get application name
400 char name[260]; // 260 is MAX_PATH value from windef.h
401 ::GetModuleFileName(wxhInstance, name, WXSIZEOF(name));
402
403 // GNUWIN32 already fills in the first arg with the application name.
404 #if !defined(__GNUWIN32__)
405 args.Add(name);
406 count ++;
407 #endif
408
409 strcpy(name, wxFileNameFromPath(name));
410 wxStripExtension(name);
411 wxTheApp->SetAppName(name);
412
413 // Break up string
414 // Treat strings enclosed in double-quotes as single arguments
415 int i = 0;
416 int len = cmdLine.Length();
417 while (i < len)
418 {
419 // Skip whitespace
420 while ((i < len) && isspace(cmdLine.GetChar(i)))
421 i ++;
422
423 if (i < len)
424 {
425 if (cmdLine.GetChar(i) == '"') // We found the start of a string
426 {
427 i ++;
428 int first = i;
429 while ((i < len) && (cmdLine.GetChar(i) != '"'))
430 i ++;
431
432 wxString arg(cmdLine.Mid(first, (i - first)));
433
434 args.Add(arg);
435 count ++;
436
437 if (i < len)
438 i ++; // Skip past 2nd quote
439 }
440 else // Unquoted argument
441 {
442 int first = i;
443 while ((i < len) && !isspace(cmdLine.GetChar(i)))
444 i ++;
445
446 wxString arg(cmdLine.Mid(first, (i - first)));
447
448 args.Add(arg);
449 count ++;
450 }
451 }
452 }
453
454 wxTheApp->argv = new char*[count + 1];
455 for (i = 0; i < count; i++)
456 {
457 wxString arg(args[i]);
458 wxTheApp->argv[i] = copystring((const char*)arg);
459 }
460 wxTheApp->argv[count] = NULL; // argv[] is a NULL-terminated list
461 wxTheApp->argc = count;
462 }
463
464 //// Cleans up any wxWindows internal structures left lying around
465
466 void wxApp::CleanUp()
467 {
468 //// COMMON CLEANUP
469 wxModule::CleanUpModules();
470
471 #if wxUSE_WX_RESOURCES
472 wxCleanUpResourceSystem();
473
474 // wxDefaultResourceTable->ClearTable();
475 #endif
476
477 // Indicate that the cursor can be freed,
478 // so that cursor won't be deleted by deleting
479 // the bitmap list before g_globalCursor goes out
480 // of scope (double deletion of the cursor).
481 wxSetCursor(wxNullCursor);
482 delete g_globalCursor;
483
484 wxDeleteStockObjects() ;
485
486 // Destroy all GDI lists, etc.
487 wxDeleteStockLists();
488
489 delete wxTheColourDatabase;
490 wxTheColourDatabase = NULL;
491
492 wxBitmap::CleanUpHandlers();
493
494 delete[] wxBuffer;
495 wxBuffer = NULL;
496
497 //// WINDOWS-SPECIFIC CLEANUP
498
499 wxSetKeyboardHook(FALSE);
500
501 #ifdef __WIN95__
502 if (gs_hRichEdit != NULL)
503 FreeLibrary(gs_hRichEdit);
504 #endif
505
506 #if wxUSE_PENWINDOWS
507 wxCleanUpPenWin();
508 #endif
509
510 if (wxSTD_FRAME_ICON)
511 DestroyIcon(wxSTD_FRAME_ICON);
512 if (wxSTD_MDICHILDFRAME_ICON)
513 DestroyIcon(wxSTD_MDICHILDFRAME_ICON);
514 if (wxSTD_MDIPARENTFRAME_ICON)
515 DestroyIcon(wxSTD_MDIPARENTFRAME_ICON);
516
517 if (wxDEFAULT_FRAME_ICON)
518 DestroyIcon(wxDEFAULT_FRAME_ICON);
519 if (wxDEFAULT_MDICHILDFRAME_ICON)
520 DestroyIcon(wxDEFAULT_MDICHILDFRAME_ICON);
521 if (wxDEFAULT_MDIPARENTFRAME_ICON)
522 DestroyIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
523
524 if ( wxDisableButtonBrush )
525 ::DeleteObject( wxDisableButtonBrush ) ;
526
527 #if !defined(__GNUWIN32__) && !defined(__SC__)
528 ::OleUninitialize();
529 #endif
530
531 #if CTL3D
532 Ctl3dUnregister(wxhInstance);
533 #endif
534
535 if (wxWinHandleList)
536 delete wxWinHandleList ;
537
538 wxClassInfo::CleanUpClasses();
539
540 delete wxTheApp;
541 wxTheApp = NULL;
542
543 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
544 // At this point we want to check if there are any memory
545 // blocks that aren't part of the wxDebugContext itself,
546 // as a special case. Then when dumping we need to ignore
547 // wxDebugContext, too.
548 if (wxDebugContext::CountObjectsLeft() > 0)
549 {
550 wxLogDebug("There were memory leaks.");
551 wxDebugContext::Dump();
552 wxDebugContext::PrintStatistics();
553 }
554 // wxDebugContext::SetStream(NULL, NULL);
555 #endif
556
557 // do it as the very last thing because everything else can log messages
558 wxLog::DontCreateOnDemand();
559 delete wxLog::SetActiveTarget(NULL);
560 }
561
562 #if !defined(_WINDLL) || (defined(_WINDLL) && defined(WXMAKINGDLL))
563
564 //// Main wxWindows entry point
565 int wxEntry(WXHINSTANCE hInstance,
566 WXHINSTANCE WXUNUSED(hPrevInstance),
567 char *lpCmdLine,
568 int nCmdShow,
569 bool enterLoop)
570 {
571 #if !defined(__WXDEBUG__) && !defined(__BORLANDC__) && !defined(__WATCOMC__) // take everything into a try-except block in release build
572 try {
573 #endif
574
575 wxhInstance = (HINSTANCE) hInstance;
576
577 if (!wxApp::Initialize())
578 return 0;
579
580 // create the application object or ensure that one already exists
581 if (!wxTheApp)
582 {
583 // The app may have declared a global application object, but we recommend
584 // the IMPLEMENT_APP macro is used instead, which sets an initializer
585 // function for delayed, dynamic app object construction.
586 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
587 "No initializer - use IMPLEMENT_APP macro." );
588
589 wxTheApp = (*wxApp::GetInitializerFunction()) ();
590 }
591
592 wxCHECK_MSG( wxTheApp, 0, "You have to define an instance of wxApp!" );
593
594 // save the WinMain() parameters
595 wxTheApp->ConvertToStandardCommandArgs(lpCmdLine);
596 wxTheApp->m_nCmdShow = nCmdShow;
597
598 // GUI-specific initialisation. In fact on Windows we don't have any,
599 // but this call is provided for compatibility across platforms.
600 wxTheApp->OnInitGui() ;
601
602 int retValue = 0;
603
604 if ( wxTheApp->OnInit() )
605 {
606 if ( enterLoop )
607 {
608 retValue = wxTheApp->OnRun();
609 }
610 }
611 //else: app initialization failed, so we skipped OnRun()
612
613 wxWindow *topWindow = wxTheApp->GetTopWindow();
614 if ( topWindow )
615 {
616 // Forcibly delete the window.
617 if ( topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
618 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
619 {
620 topWindow->Close(TRUE);
621 wxTheApp->DeletePendingObjects();
622 }
623 else
624 {
625 delete topWindow;
626 wxTheApp->SetTopWindow(NULL);
627 }
628 }
629
630 wxTheApp->OnExit();
631
632 // flush the logged messages if any
633 wxLog *pLog = wxLog::GetActiveTarget();
634 if ( pLog != NULL && pLog->HasPendingMessages() )
635 pLog->Flush();
636
637
638 wxApp::CleanUp();
639
640 return retValue;
641 #if !defined(__WXDEBUG__) && !defined(__BORLANDC__) && !defined(__WATCOMC__) // catch exceptions only in release build
642 }
643 except ( EXCEPTION_EXECUTE_HANDLER ) {
644 /*
645 if ( wxTheApp )
646 wxTheApp->OnFatalException();
647 */
648
649 ::ExitProcess(3); // the same exit code as abort()
650 }
651 #endif //debug
652 }
653
654 #else /* _WINDLL */
655
656 //// Entry point for DLLs
657
658 int wxEntry(WXHINSTANCE hInstance)
659 {
660 wxhInstance = (HINSTANCE) hInstance;
661 wxApp::Initialize();
662
663 // The app may have declared a global application object, but we recommend
664 // the IMPLEMENT_APP macro is used instead, which sets an initializer function
665 // for delayed, dynamic app object construction.
666
667 if (!wxTheApp)
668 {
669 if (!wxApp::GetInitializerFunction())
670 {
671 MessageBox(NULL, "No initializer - use IMPLEMENT_APP macro.", "wxWindows Error", MB_APPLMODAL | MB_ICONSTOP | MB_OK);
672 return 0;
673 }
674
675 wxTheApp = (* wxApp::GetInitializerFunction()) ();
676 }
677
678 if (!wxTheApp) {
679 MessageBox(NULL, "You have to define an instance of wxApp!", "wxWindows Error", MB_APPLMODAL | MB_ICONSTOP | MB_OK);
680 return 0;
681 }
682
683 wxTheApp->argc = 0;
684 wxTheApp->argv = NULL;
685
686 wxTheApp->OnInitGui();
687
688 wxTheApp->OnInit();
689
690 if (wxTheApp->GetTopWindow() && wxTheApp->GetTopWindow()->GetHWND()) {
691 wxTheApp->GetTopWindow()->Show(TRUE);
692 }
693
694 return 1;
695 }
696 #endif // _WINDLL
697
698 //// Static member initialization
699
700 wxAppInitializerFunction wxApp::m_appInitFn = (wxAppInitializerFunction) NULL;
701
702 wxApp::wxApp()
703 {
704 m_topWindow = NULL;
705 wxTheApp = this;
706 m_className = "";
707 m_wantDebugOutput = TRUE ;
708 m_appName = "";
709 argc = 0;
710 argv = NULL;
711 #ifdef __WXMSW__
712 m_printMode = wxPRINT_WINDOWS;
713 #else
714 m_printMode = wxPRINT_POSTSCRIPT;
715 #endif
716 m_exitOnFrameDelete = TRUE;
717 m_auto3D = TRUE;
718 }
719
720 wxApp::~wxApp()
721 {
722 // Delete command-line args
723 int i;
724 for (i = 0; i < argc; i++)
725 {
726 delete[] argv[i];
727 }
728 delete[] argv;
729 }
730
731 bool wxApp::Initialized()
732 {
733 #ifndef _WINDLL
734 if (GetTopWindow())
735 return TRUE;
736 else
737 return FALSE;
738 #endif
739 #ifdef _WINDLL // Assume initialized if DLL (no way of telling)
740 return TRUE;
741 #endif
742 }
743
744 /*
745 * Get and process a message, returning FALSE if WM_QUIT
746 * received (and also set the flag telling the app to exit the main loop)
747 *
748 */
749 bool wxApp::DoMessage()
750 {
751 BOOL rc = ::GetMessage(&s_currentMsg, (HWND) NULL, 0, 0);
752 if ( rc == 0 )
753 {
754 // got WM_QUIT
755 m_keepGoing = FALSE;
756
757 return FALSE;
758 }
759 else if ( rc == -1 )
760 {
761 // should never happen, but let's test for it nevertheless
762 wxLogLastError("GetMessage");
763 }
764 else
765 {
766 #if wxUSE_THREADS
767 wxASSERT_MSG( wxThread::IsMain(),
768 "only the main thread can process Windows messages" );
769
770 static bool s_hadGuiLock = TRUE;
771 static wxMsgArray s_aSavedMessages;
772
773 // if a secondary thread owns is doing GUI calls, save all messages for
774 // later processing - we can't process them right now because it will
775 // lead to recursive library calls (and we're not reentrant)
776 if ( !wxGuiOwnedByMainThread() )
777 {
778 s_hadGuiLock = FALSE;
779
780 s_aSavedMessages.Add(s_currentMsg);
781
782 return TRUE;
783 }
784 else
785 {
786 // have we just regained the GUI lock? if so, post all of the saved
787 // messages
788 //
789 // FIXME of course, it's not _exactly_ the same as processing the
790 // messages normally - expect some things to break...
791 if ( !s_hadGuiLock )
792 {
793 s_hadGuiLock = TRUE;
794
795 size_t count = s_aSavedMessages.Count();
796 for ( size_t n = 0; n < count; n++ )
797 {
798 MSG& msg = s_aSavedMessages[n];
799
800 if ( !ProcessMessage((WXMSG *)&msg) )
801 {
802 ::TranslateMessage(&msg);
803 ::DispatchMessage(&msg);
804 }
805 }
806
807 s_aSavedMessages.Empty();
808 }
809 }
810 #endif // wxUSE_THREADS
811
812 // Process the message
813 if ( !ProcessMessage((WXMSG *)&s_currentMsg) )
814 {
815 ::TranslateMessage(&s_currentMsg);
816 wxApp::sm_lastMessageTime = s_currentMsg.time; /* MATTHEW: timeStamp impl. */
817 ::DispatchMessage(&s_currentMsg);
818 }
819 }
820
821 return TRUE;
822 }
823
824 /*
825 * Keep trying to process messages until WM_QUIT
826 * received.
827 *
828 * If there are messages to be processed, they will all be
829 * processed and OnIdle will not be called.
830 * When there are no more messages, OnIdle is called.
831 * If OnIdle requests more time,
832 * it will be repeatedly called so long as there are no pending messages.
833 * A 'feature' of this is that once OnIdle has decided that no more processing
834 * is required, then it won't get processing time until further messages
835 * are processed (it'll sit in DoMessage).
836 */
837
838 int wxApp::MainLoop()
839 {
840 m_keepGoing = TRUE;
841
842 while ( m_keepGoing )
843 {
844 #if wxUSE_THREADS
845 wxMutexGuiLeaveOrEnter();
846 #endif // wxUSE_THREADS
847
848 while ( !::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) &&
849 ProcessIdle() )
850 {
851 }
852
853 DoMessage();
854 }
855
856 return s_currentMsg.wParam;
857 }
858
859 // Returns TRUE if more time is needed.
860 bool wxApp::ProcessIdle()
861 {
862 wxIdleEvent event;
863 event.SetEventObject(this);
864 ProcessEvent(event);
865
866 return event.MoreRequested();
867 }
868
869 void wxApp::ExitMainLoop()
870 {
871 m_keepGoing = FALSE;
872 }
873
874 bool wxApp::Pending()
875 {
876 return (::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0) ;
877 }
878
879 void wxApp::Dispatch()
880 {
881 DoMessage();
882 }
883
884 /*
885 * Give all windows a chance to preprocess
886 * the message. Some may have accelerator tables, or have
887 * MDI complications.
888 */
889 bool wxApp::ProcessMessage(WXMSG *Msg)
890 {
891 MSG *msg = (MSG *)Msg;
892
893 HWND hWnd;
894
895 // Try translations first; find the youngest window with
896 // a translation table.
897 for (hWnd = msg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
898 {
899 wxWindow *wnd = wxFindWinFromHandle((WXHWND) hWnd);
900 if (wnd)
901 {
902 if (wnd->MSWTranslateMessage(Msg))
903 return TRUE;
904 }
905 }
906
907 // Anyone for a non-translation message? Try youngest descendants first.
908 for (hWnd = msg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
909 {
910 wxWindow *wnd = wxFindWinFromHandle((WXHWND) hWnd);
911 if (wnd)
912 {
913 if (wnd->MSWProcessMessage(Msg))
914 return TRUE;
915 }
916 }
917 return FALSE;
918 }
919
920 void wxApp::OnIdle(wxIdleEvent& event)
921 {
922 static bool s_inOnIdle = FALSE;
923
924 // Avoid recursion (via ProcessEvent default case)
925 if ( s_inOnIdle )
926 return;
927
928 s_inOnIdle = TRUE;
929
930 // 'Garbage' collection of windows deleted with Close().
931 DeletePendingObjects();
932
933 // flush the logged messages if any
934 wxLog *pLog = wxLog::GetActiveTarget();
935 if ( pLog != NULL && pLog->HasPendingMessages() )
936 pLog->Flush();
937
938 // Send OnIdle events to all windows
939 if ( SendIdleEvents() )
940 {
941 // SendIdleEvents() returns TRUE if at least one window requested more
942 // idle events
943 event.RequestMore(TRUE);
944 }
945
946 s_inOnIdle = FALSE;
947 }
948
949 // Send idle event to all top-level windows
950 bool wxApp::SendIdleEvents()
951 {
952 bool needMore = FALSE;
953 wxNode* node = wxTopLevelWindows.First();
954 while (node)
955 {
956 wxWindow* win = (wxWindow*) node->Data();
957 if (SendIdleEvents(win))
958 needMore = TRUE;
959
960 node = node->Next();
961 }
962
963 return needMore;
964 }
965
966 // Send idle event to window and all subwindows
967 bool wxApp::SendIdleEvents(wxWindow* win)
968 {
969 bool needMore = FALSE;
970
971 wxIdleEvent event;
972 event.SetEventObject(win);
973 win->GetEventHandler()->ProcessEvent(event);
974
975 if (event.MoreRequested())
976 needMore = TRUE;
977
978 wxNode* node = win->GetChildren().First();
979 while (node)
980 {
981 wxWindow* win = (wxWindow*) node->Data();
982 if (SendIdleEvents(win))
983 needMore = TRUE;
984
985 node = node->Next();
986 }
987 return needMore ;
988 }
989
990 void wxApp::DeletePendingObjects()
991 {
992 wxNode *node = wxPendingDelete.First();
993 while (node)
994 {
995 wxObject *obj = (wxObject *)node->Data();
996
997 delete obj;
998
999 if (wxPendingDelete.Member(obj))
1000 delete node;
1001
1002 // Deleting one object may have deleted other pending
1003 // objects, so start from beginning of list again.
1004 node = wxPendingDelete.First();
1005 }
1006 }
1007
1008 void wxApp::OnEndSession(wxCloseEvent& event)
1009 {
1010 if (GetTopWindow())
1011 GetTopWindow()->Close(TRUE);
1012 }
1013
1014 // Default behaviour: close the application with prompts. The
1015 // user can veto the close, and therefore the end session.
1016 void wxApp::OnQueryEndSession(wxCloseEvent& event)
1017 {
1018 if (GetTopWindow())
1019 {
1020 if (!GetTopWindow()->Close(!event.CanVeto()))
1021 event.Veto(TRUE);
1022 }
1023 }
1024
1025 wxLog* wxApp::CreateLogTarget()
1026 {
1027 return new wxLogGui;
1028 }
1029
1030 wxWindow* wxApp::GetTopWindow() const
1031 {
1032 if (m_topWindow)
1033 return m_topWindow;
1034 else if (wxTopLevelWindows.Number() > 0)
1035 return (wxWindow*) wxTopLevelWindows.First()->Data();
1036 else
1037 return NULL;
1038 }
1039
1040 int wxApp::GetComCtl32Version() const
1041 {
1042 // have we loaded COMCTL32 yet?
1043 HMODULE theModule = ::GetModuleHandle("COMCTL32");
1044 int version = 0;
1045
1046 // if so, then we can check for the version
1047 if (theModule)
1048 {
1049 // InitCommonControlsEx is unique to 4.7 and later
1050 FARPROC theProc = ::GetProcAddress(theModule, "InitCommonControlsEx");
1051
1052 if (! theProc)
1053 { // not found, must be 4.00
1054 version = 400;
1055 }
1056 else
1057 {
1058 // The following symbol are unique to 4.71
1059 // DllInstall
1060 // FlatSB_EnableScrollBar FlatSB_GetScrollInfo FlatSB_GetScrollPos
1061 // FlatSB_GetScrollProp FlatSB_GetScrollRange FlatSB_SetScrollInfo
1062 // FlatSB_SetScrollPos FlatSB_SetScrollProp FlatSB_SetScrollRange
1063 // FlatSB_ShowScrollBar
1064 // _DrawIndirectImageList _DuplicateImageList
1065 // InitializeFlatSB
1066 // UninitializeFlatSB
1067 // we could check for any of these - I chose DllInstall
1068 FARPROC theProc = ::GetProcAddress(theModule, "DllInstall");
1069 if (! theProc)
1070 {
1071 // not found, must be 4.70
1072 version = 470;
1073 }
1074 else
1075 { // found, must be 4.71
1076 version = 471;
1077 }
1078 }
1079 }
1080 return version;
1081 }
1082
1083 void wxExit()
1084 {
1085 wxApp::CleanUp();
1086 FatalAppExit(0, "Fatal error: exiting");
1087 }
1088
1089 // Yield to incoming messages
1090 bool wxYield()
1091 {
1092 MSG msg;
1093 // We want to go back to the main message loop
1094 // if we see a WM_QUIT. (?)
1095 while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) && msg.message != WM_QUIT)
1096 {
1097 if ( !wxTheApp->DoMessage() )
1098 break;
1099 }
1100
1101 return TRUE;
1102 }
1103
1104 HINSTANCE wxGetInstance()
1105 {
1106 return wxhInstance;
1107 }
1108
1109 // For some reason, with MSVC++ 1.5, WinMain isn't linked in properly
1110 // if in a separate file. So include it here to ensure it's linked.
1111 #if (defined(_MSC_VER) && !defined(__WIN32__)) || defined(__GNUWIN32__)
1112 #include "main.cpp"
1113 #endif