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