]> git.saurik.com Git - wxWidgets.git/blame - src/msw/app.cpp
include wx/thread.h in debug build which is needed after last change
[wxWidgets.git] / src / msw / app.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
a71d815b 2// Name: src/msw/app.cpp
2bda0e17
KB
3// Purpose: wxApp
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
e5c0b16a
VZ
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
2bda0e17 20// For compilers that support precompilation, includes "wx.h".
2bda0e17
KB
21#include "wx/wxprec.h"
22
23#if defined(__BORLANDC__)
e5c0b16a 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
27#ifndef WX_PRECOMP
57bd4c60 28 #include "wx/msw/wrapcctl.h"
ad9835c9 29 #include "wx/dynarray.h"
e5c0b16a
VZ
30 #include "wx/frame.h"
31 #include "wx/app.h"
32 #include "wx/utils.h"
33 #include "wx/gdicmn.h"
34 #include "wx/pen.h"
35 #include "wx/brush.h"
36 #include "wx/cursor.h"
37 #include "wx/icon.h"
38 #include "wx/palette.h"
39 #include "wx/dc.h"
40 #include "wx/dialog.h"
41 #include "wx/msgdlg.h"
42 #include "wx/intl.h"
72cdf4c9 43 #include "wx/wxchar.h"
31f6de22 44 #include "wx/log.h"
02761f6c 45 #include "wx/module.h"
2bda0e17
KB
46#endif
47
e2478fde 48#include "wx/apptrait.h"
7104f65d 49#include "wx/filename.h"
9fc6c21c 50#include "wx/dynlib.h"
031943ac 51#include "wx/evtloop.h"
4bf78aae 52
4286a5b5 53#include "wx/msw/private.h"
360ae33f 54#include "wx/msw/ole/oleutils.h"
4286a5b5 55
8614c467
VZ
56#if wxUSE_TOOLTIPS
57 #include "wx/tooltip.h"
58#endif // wxUSE_TOOLTIPS
59
c42404a5
VZ
60// OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
61// compilers don't support it (missing headers, libs, ...)
2bdf7154 62#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
e5c0b16a
VZ
63 #undef wxUSE_OLE
64
65 #define wxUSE_OLE 0
66#endif // broken compilers
67
afafd942 68#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
58b76be1
VZ
69 #include <ole2.h>
70 #include <aygshell.h>
afafd942
JS
71#endif
72
e5c0b16a 73#if wxUSE_OLE
6e0d9d43 74 #include <ole2.h>
d05237ea 75#endif
ce3ed50d 76
2bda0e17 77#include <string.h>
a5e0e655 78#include <ctype.h>
2bda0e17 79
261fb041 80#include "wx/msw/missing.h"
6046e57a 81
25a11614
VZ
82// instead of including <shlwapi.h> which is not part of the core SDK and not
83// shipped at all with other compilers, we always define the parts of it we
84// need here ourselves
85//
86// NB: DLLVER_PLATFORM_WINDOWS will be defined if shlwapi.h had been somehow
87// included already
88#ifndef DLLVER_PLATFORM_WINDOWS
89 // hopefully we don't need to change packing as DWORDs should be already
90 // correctly aligned
91 struct DLLVERSIONINFO
92 {
93 DWORD cbSize;
94 DWORD dwMajorVersion; // Major version
95 DWORD dwMinorVersion; // Minor version
96 DWORD dwBuildNumber; // Build number
97 DWORD dwPlatformID; // DLLVER_PLATFORM_*
98 };
99
100 typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
101#endif // defined(DLLVERSIONINFO)
102
238a6044 103
e5c0b16a
VZ
104// ---------------------------------------------------------------------------
105// global variables
106// ---------------------------------------------------------------------------
107
4676948b 108#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2bda0e17 109extern void wxSetKeyboardHook(bool doIt);
04ef50df 110#endif
2bda0e17 111
193fe989
VZ
112// NB: all "NoRedraw" classes must have the same names as the "normal" classes
113// with NR suffix - wxWindow::MSWCreate() supposes this
46fa338b 114#ifdef __WXWINCE__
7a4d2469
RN
115WXDLLIMPEXP_CORE wxChar *wxCanvasClassName;
116WXDLLIMPEXP_CORE wxChar *wxCanvasClassNameNR;
46fa338b 117#else
7a4d2469
RN
118WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName = wxT("wxWindowClass");
119WXDLLIMPEXP_CORE const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
46fa338b 120#endif
7a4d2469
RN
121WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
122WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
123WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
124WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
2bda0e17 125
94826170
VZ
126// ----------------------------------------------------------------------------
127// private functions
128// ----------------------------------------------------------------------------
2bda0e17 129
94826170 130LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
3b415ba4 131
e5c0b16a 132// ===========================================================================
e2478fde
VZ
133// wxGUIAppTraits implementation
134// ===========================================================================
135
136// private class which we use to pass parameters from BeforeChildWaitLoop() to
137// AfterChildWaitLoop()
138struct ChildWaitLoopData
139{
140 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
141 {
142 wd = wd_;
143 winActive = winActive_;
144 }
145
146 wxWindowDisabler *wd;
147 wxWindow *winActive;
148};
149
150void *wxGUIAppTraits::BeforeChildWaitLoop()
151{
152 /*
153 We use a dirty hack here to disable all application windows (which we
154 must do because otherwise the calls to wxYield() could lead to some very
155 unexpected reentrancies in the users code) but to avoid losing
156 focus/activation entirely when the child process terminates which would
157 happen if we simply disabled everything using wxWindowDisabler. Indeed,
158 remember that Windows will never activate a disabled window and when the
159 last childs window is closed and Windows looks for a window to activate
160 all our windows are still disabled. There is no way to enable them in
161 time because we don't know when the childs windows are going to be
162 closed, so the solution we use here is to keep one special tiny frame
163 enabled all the time. Then when the child terminates it will get
164 activated and when we close it below -- after reenabling all the other
165 windows! -- the previously active window becomes activated again and
166 everything is ok.
167 */
168 wxBeginBusyCursor();
169
170 // first disable all existing windows
171 wxWindowDisabler *wd = new wxWindowDisabler;
172
173 // then create an "invisible" frame: it has minimal size, is positioned
174 // (hopefully) outside the screen and doesn't appear on the taskbar
175 wxWindow *winActive = new wxFrame
176 (
177 wxTheApp->GetTopWindow(),
fda7962d
JS
178 wxID_ANY,
179 wxEmptyString,
e2478fde
VZ
180 wxPoint(32600, 32600),
181 wxSize(1, 1),
182 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
183 );
184 winActive->Show();
185
186 return new ChildWaitLoopData(wd, winActive);
187}
188
189void wxGUIAppTraits::AlwaysYield()
190{
191 wxYield();
192}
193
194void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
195{
196 wxEndBusyCursor();
197
0588f8d7 198 ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
e2478fde
VZ
199
200 delete data->wd;
201
202 // finally delete the dummy frame and, as wd has been already destroyed and
203 // the other windows reenabled, the activation is going to return to the
204 // window which had had it before
205 data->winActive->Destroy();
51036b44
VZ
206
207 // also delete the temporary data object itself
208 delete data;
e2478fde
VZ
209}
210
211bool wxGUIAppTraits::DoMessageFromThreadWait()
212{
1bf77ee5
VZ
213 // we should return false only if the app should exit, i.e. only if
214 // Dispatch() determines that the main event loop should terminate
031943ac
VZ
215 wxEventLoop *evtLoop = wxEventLoop::GetActive();
216 if ( !evtLoop || !evtLoop->Pending() )
217 {
218 // no events means no quit event
219 return true;
220 }
221
222 return evtLoop->Dispatch();
e2478fde
VZ
223}
224
e570a44b
VZ
225DWORD wxGUIAppTraits::WaitForThread(WXHANDLE hThread)
226{
535920ff
VZ
227 // if we don't have a running event loop, we shouldn't wait for the
228 // messages as we never remove them from the message queue and so we enter
229 // an infinite loop as MsgWaitForMultipleObjects() keeps returning
230 // WAIT_OBJECT_0 + 1
231 if ( !wxEventLoop::GetActive() )
232 return DoSimpleWaitForThread(hThread);
233
e570a44b
VZ
234 return ::MsgWaitForMultipleObjects
235 (
236 1, // number of objects to wait for
237 (HANDLE *)&hThread, // the objects
238 false, // wait for any objects, not all
239 INFINITE, // no timeout
261fb041
WS
240 QS_ALLINPUT | // return as soon as there are any events
241 QS_ALLPOSTMESSAGE
e570a44b
VZ
242 );
243}
244
8bb6b2c0 245wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const
a8eaaeb2 246{
8bb6b2c0
VZ
247 OSVERSIONINFO info;
248 wxZeroMemory(info);
249
250 // on Windows, the toolkit version is the same of the OS version
251 // as Windows integrates the OS kernel with the GUI toolkit.
252 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
253 if ( ::GetVersionEx(&info) )
254 {
255 if ( majVer )
256 *majVer = info.dwMajorVersion;
257 if ( minVer )
258 *minVer = info.dwMinorVersion;
259 }
260
261#if defined(__WXHANDHELD__) || defined(__WXWINCE__)
262 return wxPORT_WINCE;
263#else
264 return wxPORT_MSW;
a8eaaeb2 265#endif
a8eaaeb2
VS
266}
267
e2478fde
VZ
268// ===========================================================================
269// wxApp implementation
e5c0b16a 270// ===========================================================================
589f0e3e 271
94826170
VZ
272int wxApp::m_nCmdShow = SW_SHOWNORMAL;
273
e5c0b16a 274// ---------------------------------------------------------------------------
e2478fde 275// wxWin macros
e5c0b16a
VZ
276// ---------------------------------------------------------------------------
277
f6bcfd97 278IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
e5c0b16a 279
f6bcfd97
BP
280BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
281 EVT_IDLE(wxApp::OnIdle)
282 EVT_END_SESSION(wxApp::OnEndSession)
283 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
284END_EVENT_TABLE()
e5c0b16a 285
94826170
VZ
286// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
287// fails
288class wxCallBaseCleanup
289{
290public:
291 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
292 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
293
294 void Dismiss() { m_app = NULL; }
295
296private:
297 wxApp *m_app;
298};
299
e5c0b16a 300//// Initialize
05e2b077 301bool wxApp::Initialize(int& argc, wxChar **argv)
2bda0e17 302{
94826170
VZ
303 if ( !wxAppBase::Initialize(argc, argv) )
304 return false;
305
306 // ensure that base cleanup is done if we return too early
307 wxCallBaseCleanup callBaseCleanup(this);
308
46fa338b
RR
309#ifdef __WXWINCE__
310 wxString tmp = GetAppName();
311 tmp += wxT("ClassName");
312 wxCanvasClassName = wxStrdup( tmp.c_str() );
313 tmp += wxT("NR");
314 wxCanvasClassNameNR = wxStrdup( tmp.c_str() );
315 HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL );
316 if (hWnd)
317 {
318 SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) );
319 return false;
320 }
321#endif
322
a71d815b 323#if !defined(__WXMICROWIN__)
a5e0e655 324 InitCommonControls();
a71d815b 325#endif // !defined(__WXMICROWIN__)
2bda0e17 326
afafd942
JS
327#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
328 SHInitExtraControls();
329#endif
330
d5ea3919
JS
331#ifndef __WXWINCE__
332 // Don't show a message box if a function such as SHGetFileInfo
333 // fails to find a device.
334 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
335#endif
ad9835c9 336
360ae33f 337 wxOleInitialize();
2bda0e17 338
aa0b7e1e 339 RegisterWindowClasses();
2bda0e17 340
1bffa913 341 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
2bda0e17 342
4676948b 343#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 344 wxSetKeyboardHook(true);
04ef50df 345#endif
2bda0e17 346
94826170
VZ
347 callBaseCleanup.Dismiss();
348
349 return true;
2bda0e17
KB
350}
351
42e69d6b
VZ
352// ---------------------------------------------------------------------------
353// RegisterWindowClasses
354// ---------------------------------------------------------------------------
589f0e3e 355
b782f2e0
VZ
356// TODO we should only register classes really used by the app. For this it
357// would be enough to just delay the class registration until an attempt
358// to create a window of this class is made.
bb6290e3 359bool wxApp::RegisterWindowClasses()
2bda0e17 360{
42e69d6b 361 WNDCLASS wndclass;
03baf031 362 wxZeroMemory(wndclass);
e5c0b16a 363
193fe989
VZ
364 // for each class we register one with CS_(V|H)REDRAW style and one
365 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
366 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
367 static const long styleNoRedraw = CS_DBLCLKS;
368
42e69d6b 369 // the fields which are common to all classes
e5c0b16a 370 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
e5c0b16a 371 wndclass.hInstance = wxhInstance;
42e69d6b 372 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
42e69d6b 373
b9691677
VZ
374 // register the class for all normal windows
375 wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
03baf031 376 wndclass.lpszClassName = wxCanvasClassName;
b782f2e0 377 wndclass.style = styleNormal;
e5c0b16a 378
42e69d6b 379 if ( !RegisterClass(&wndclass) )
e5c0b16a 380 {
f6bcfd97 381 wxLogLastError(wxT("RegisterClass(frame)"));
e5c0b16a
VZ
382 }
383
193fe989 384 // "no redraw" frame
03baf031 385 wndclass.lpszClassName = wxCanvasClassNameNR;
193fe989
VZ
386 wndclass.style = styleNoRedraw;
387
388 if ( !RegisterClass(&wndclass) )
389 {
f6bcfd97 390 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
193fe989
VZ
391 }
392
e5c0b16a 393 // Register the MDI frame window class.
42e69d6b 394 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
b782f2e0
VZ
395 wndclass.lpszClassName = wxMDIFrameClassName;
396 wndclass.style = styleNormal;
42e69d6b
VZ
397
398 if ( !RegisterClass(&wndclass) )
e5c0b16a 399 {
f6bcfd97 400 wxLogLastError(wxT("RegisterClass(MDI parent)"));
e5c0b16a
VZ
401 }
402
193fe989 403 // "no redraw" MDI frame
b782f2e0 404 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
193fe989
VZ
405 wndclass.style = styleNoRedraw;
406
407 if ( !RegisterClass(&wndclass) )
408 {
f6bcfd97 409 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
193fe989
VZ
410 }
411
e5c0b16a 412 // Register the MDI child frame window class.
42e69d6b
VZ
413 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
414 wndclass.lpszClassName = wxMDIChildFrameClassName;
b782f2e0 415 wndclass.style = styleNormal;
42e69d6b
VZ
416
417 if ( !RegisterClass(&wndclass) )
e5c0b16a 418 {
f6bcfd97 419 wxLogLastError(wxT("RegisterClass(MDI child)"));
e5c0b16a
VZ
420 }
421
193fe989
VZ
422 // "no redraw" MDI child frame
423 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
424 wndclass.style = styleNoRedraw;
425
426 if ( !RegisterClass(&wndclass) )
427 {
f6bcfd97 428 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
193fe989
VZ
429 }
430
77c46f00 431 return true;
2bda0e17
KB
432}
433
9787a4b6
VZ
434// ---------------------------------------------------------------------------
435// UnregisterWindowClasses
436// ---------------------------------------------------------------------------
437
438bool wxApp::UnregisterWindowClasses()
439{
77c46f00 440 bool retval = true;
9787a4b6 441
c67d6888 442#ifndef __WXMICROWIN__
9787a4b6 443 // MDI frame window class.
03baf031 444 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
9787a4b6
VZ
445 {
446 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
447
77c46f00 448 retval = false;
9787a4b6
VZ
449 }
450
451 // "no redraw" MDI frame
03baf031 452 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
453 {
454 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
455
77c46f00 456 retval = false;
9787a4b6
VZ
457 }
458
459 // MDI child frame window class.
03baf031 460 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
9787a4b6
VZ
461 {
462 wxLogLastError(wxT("UnregisterClass(MDI child)"));
463
77c46f00 464 retval = false;
9787a4b6
VZ
465 }
466
467 // "no redraw" MDI child frame
03baf031 468 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
469 {
470 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
471
77c46f00 472 retval = false;
9787a4b6
VZ
473 }
474
03baf031
VZ
475 // canvas class name
476 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
9787a4b6
VZ
477 {
478 wxLogLastError(wxT("UnregisterClass(canvas)"));
479
77c46f00 480 retval = false;
9787a4b6
VZ
481 }
482
03baf031 483 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
9787a4b6
VZ
484 {
485 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
486
77c46f00 487 retval = false;
9787a4b6 488 }
03baf031
VZ
489#endif // __WXMICROWIN__
490
9787a4b6
VZ
491 return retval;
492}
493
bb6290e3 494void wxApp::CleanUp()
2bda0e17 495{
7a9dfa3c
VZ
496 // all objects pending for deletion must be deleted first, otherwise we
497 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
498 // call wouldn't succeed as long as any windows still exist), so call the
499 // base class method first and only then do our clean up
500 wxAppBase::CleanUp();
501
4676948b 502#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 503 wxSetKeyboardHook(false);
04ef50df 504#endif
2bda0e17 505
360ae33f 506 wxOleUninitialize();
2bda0e17 507
9787a4b6
VZ
508 // for an EXE the classes are unregistered when it terminates but DLL may
509 // be loaded several times (load/unload/load) into the same process in
510 // which case the registration will fail after the first time if we don't
511 // unregister the classes now
512 UnregisterWindowClasses();
9787a4b6 513
1bffa913 514 delete wxWinHandleHash;
94826170 515 wxWinHandleHash = NULL;
a71d815b 516
46fa338b
RR
517#ifdef __WXWINCE__
518 free( wxCanvasClassName );
519 free( wxCanvasClassNameNR );
520#endif
2bda0e17
KB
521}
522
94826170
VZ
523// ----------------------------------------------------------------------------
524// wxApp ctor/dtor
525// ----------------------------------------------------------------------------
589f0e3e 526
bb6290e3 527wxApp::wxApp()
2bda0e17 528{
e5c0b16a 529 m_printMode = wxPRINT_WINDOWS;
2bda0e17
KB
530}
531
589f0e3e
JS
532wxApp::~wxApp()
533{
589f0e3e
JS
534}
535
6046e57a
VZ
536// ----------------------------------------------------------------------------
537// wxApp idle handling
538// ----------------------------------------------------------------------------
539
2bda0e17
KB
540void wxApp::OnIdle(wxIdleEvent& event)
541{
955a9197 542 wxAppBase::OnIdle(event);
c54f78a2 543
aef94d68
JS
544#if wxUSE_DC_CACHEING
545 // automated DC cache management: clear the cached DCs and bitmap
546 // if it's likely that the app has finished with them, that is, we
547 // get an idle event and we're not dragging anything.
4624defa 548 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
aef94d68
JS
549 wxDC::ClearCache();
550#endif // wxUSE_DC_CACHEING
2bda0e17
KB
551}
552
e2478fde
VZ
553void wxApp::WakeUpIdle()
554{
555 // Send the top window a dummy message so idle handler processing will
556 // start up again. Doing it this way ensures that the idle handler
557 // wakes up in the right thread (see also wxWakeUpMainThread() which does
558 // the same for the main app thread only)
559 wxWindow *topWindow = wxTheApp->GetTopWindow();
560 if ( topWindow )
561 {
562 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
563 {
564 // should never happen
565 wxLogLastError(wxT("PostMessage(WM_NULL)"));
566 }
567 }
568}
569
6046e57a
VZ
570// ----------------------------------------------------------------------------
571// other wxApp event hanlders
572// ----------------------------------------------------------------------------
573
57c208c5 574void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
387a3b02
JS
575{
576 if (GetTopWindow())
77c46f00 577 GetTopWindow()->Close(true);
387a3b02
JS
578}
579
580// Default behaviour: close the application with prompts. The
581// user can veto the close, and therefore the end session.
582void wxApp::OnQueryEndSession(wxCloseEvent& event)
583{
584 if (GetTopWindow())
585 {
586 if (!GetTopWindow()->Close(!event.CanVeto()))
77c46f00 587 event.Veto(true);
387a3b02
JS
588 }
589}
590
6046e57a
VZ
591// ----------------------------------------------------------------------------
592// miscellaneous
593// ----------------------------------------------------------------------------
594
6d167489
VZ
595/* static */
596int wxApp::GetComCtl32Version()
597{
fd7b70bd 598#if defined(__WXMICROWIN__) || defined(__WXWINCE__)
04ef50df
JS
599 return 0;
600#else
6d167489 601 // cache the result
9fc6c21c
VZ
602 //
603 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
604 // but as its value should be the same both times it doesn't matter
bdc72a22
VZ
605 static int s_verComCtl32 = -1;
606
6d167489
VZ
607 if ( s_verComCtl32 == -1 )
608 {
bdc72a22 609 // initally assume no comctl32.dll at all
6d167489
VZ
610 s_verComCtl32 = 0;
611
9fc6c21c
VZ
612 // we're prepared to handle the errors
613 wxLogNull noLog;
ad9835c9 614
64c288fa 615#if wxUSE_DYNLIB_CLASS
bdc72a22 616 // do we have it?
9fc6c21c 617 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
6d167489
VZ
618
619 // if so, then we can check for the version
9fc6c21c 620 if ( dllComCtl32.IsLoaded() )
bb6290e3 621 {
25a11614 622 // now check if the function is available during run-time
9fc6c21c
VZ
623 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
624 if ( pfnDllGetVersion )
625 {
626 DLLVERSIONINFO dvi;
627 dvi.cbSize = sizeof(dvi);
628
629 HRESULT hr = (*pfnDllGetVersion)(&dvi);
630 if ( FAILED(hr) )
6d167489 631 {
9fc6c21c
VZ
632 wxLogApiError(_T("DllGetVersion"), hr);
633 }
634 else
635 {
636 // this is incompatible with _WIN32_IE values, but
637 // compatible with the other values returned by
638 // GetComCtl32Version()
639 s_verComCtl32 = 100*dvi.dwMajorVersion +
640 dvi.dwMinorVersion;
641 }
642 }
bdc72a22 643
9fc6c21c
VZ
644 // if DllGetVersion() is unavailable either during compile or
645 // run-time, try to guess the version otherwise
646 if ( !s_verComCtl32 )
647 {
648 // InitCommonControlsEx is unique to 4.70 and later
649 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
650 if ( !pfn )
651 {
652 // not found, must be 4.00
653 s_verComCtl32 = 400;
6d167489 654 }
9fc6c21c 655 else // 4.70+
bdc72a22 656 {
9fc6c21c
VZ
657 // many symbols appeared in comctl32 4.71, could use any of
658 // them except may be DllInstall()
659 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
660 if ( !pfn )
bdc72a22 661 {
9fc6c21c
VZ
662 // not found, must be 4.70
663 s_verComCtl32 = 470;
bdc72a22
VZ
664 }
665 else
666 {
9fc6c21c
VZ
667 // found, must be 4.71 or later
668 s_verComCtl32 = 471;
bdc72a22 669 }
6d167489 670 }
9fc6c21c 671 }
ef094fa0 672 }
ad9835c9 673#endif
bb6290e3 674 }
6d167489
VZ
675
676 return s_verComCtl32;
9fc6c21c 677#endif // Microwin/!Microwin
bb6290e3
JS
678}
679
2bda0e17 680// Yield to incoming messages
cb2713bf 681
8461e4c2 682bool wxApp::Yield(bool onlyIfNeeded)
2bda0e17 683{
8461e4c2 684 // MT-FIXME
77c46f00 685 static bool s_inYield = false;
8461e4c2 686
e30285ab 687#if wxUSE_LOG
2ed3265e
VZ
688 // disable log flushing from here because a call to wxYield() shouldn't
689 // normally result in message boxes popping up &c
690 wxLog::Suspend();
e30285ab 691#endif // wxUSE_LOG
2ed3265e 692
8461e4c2
VZ
693 if ( s_inYield )
694 {
695 if ( !onlyIfNeeded )
696 {
697 wxFAIL_MSG( wxT("wxYield called recursively" ) );
698 }
33ac7e6f 699
77c46f00 700 return false;
8461e4c2
VZ
701 }
702
77c46f00 703 s_inYield = true;
cb2713bf 704
8e193f38
VZ
705 // we don't want to process WM_QUIT from here - it should be processed in
706 // the main event loop in order to stop it
e5c0b16a 707 MSG msg;
8e193f38
VZ
708 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
709 msg.message != WM_QUIT )
e5c0b16a 710 {
5b615ed8
VZ
711#if wxUSE_THREADS
712 wxMutexGuiLeaveOrEnter();
713#endif // wxUSE_THREADS
714
1bf77ee5 715 if ( !wxTheApp->Dispatch() )
e5c0b16a
VZ
716 break;
717 }
8e193f38 718
8461e4c2
VZ
719 // if there are pending events, we must process them.
720 ProcessPendingEvents();
e5c0b16a 721
e30285ab 722#if wxUSE_LOG
2ed3265e
VZ
723 // let the logs be flashed again
724 wxLog::Resume();
e30285ab 725#endif // wxUSE_LOG
2ed3265e 726
77c46f00 727 s_inYield = false;
cb2713bf 728
77c46f00 729 return true;
2bda0e17 730}
094637f6 731
6046e57a
VZ
732#if wxUSE_EXCEPTIONS
733
734// ----------------------------------------------------------------------------
735// exception handling
736// ----------------------------------------------------------------------------
737
738bool wxApp::OnExceptionInMainLoop()
739{
740 // ask the user about what to do: use the Win32 API function here as it
77ffb593 741 // could be dangerous to use any wxWidgets code in this state
6046e57a
VZ
742 switch (
743 ::MessageBox
744 (
745 NULL,
746 _T("An unhandled exception occurred. Press \"Abort\" to \
747terminate the program,\r\n\
748\"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
749 _T("Unhandled exception"),
750 MB_ABORTRETRYIGNORE |
a71d815b 751 MB_ICONERROR|
6046e57a
VZ
752 MB_TASKMODAL
753 )
754 )
755 {
756 case IDABORT:
757 throw;
758
759 default:
760 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
761 // fall through
762
763 case IDRETRY:
764 return false;
765
766 case IDIGNORE:
767 return true;
768 }
769}
770
771#endif // wxUSE_EXCEPTIONS