]> git.saurik.com Git - wxWidgets.git/blame - src/msw/app.cpp
handle NULL BSTRs as empty ones per Microsoft convention
[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"
3a3dde0d 43 #include "wx/crt.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
2ddff00c 216 wxEventLoopBase * const evtLoop = wxEventLoop::GetActive();
031943ac
VZ
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
a8ff046b
VZ
269#if wxUSE_TIMER
270
b46b1d59 271wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
c2ca375c 272{
b46b1d59
VZ
273 return new wxMSWTimerImpl(timer);
274}
275
a8ff046b
VZ
276#endif // wxUSE_TIMER
277
2ddff00c 278wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
b46b1d59
VZ
279{
280 return new wxEventLoop;
5d262fdd 281}
c2ca375c 282
e2478fde
VZ
283// ===========================================================================
284// wxApp implementation
e5c0b16a 285// ===========================================================================
589f0e3e 286
94826170
VZ
287int wxApp::m_nCmdShow = SW_SHOWNORMAL;
288
e5c0b16a 289// ---------------------------------------------------------------------------
e2478fde 290// wxWin macros
e5c0b16a
VZ
291// ---------------------------------------------------------------------------
292
f6bcfd97 293IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
e5c0b16a 294
f6bcfd97
BP
295BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
296 EVT_IDLE(wxApp::OnIdle)
297 EVT_END_SESSION(wxApp::OnEndSession)
298 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
299END_EVENT_TABLE()
e5c0b16a 300
94826170
VZ
301// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
302// fails
303class wxCallBaseCleanup
304{
305public:
306 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
307 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
308
309 void Dismiss() { m_app = NULL; }
310
311private:
312 wxApp *m_app;
313};
314
e5c0b16a 315//// Initialize
05e2b077 316bool wxApp::Initialize(int& argc, wxChar **argv)
2bda0e17 317{
94826170
VZ
318 if ( !wxAppBase::Initialize(argc, argv) )
319 return false;
320
321 // ensure that base cleanup is done if we return too early
322 wxCallBaseCleanup callBaseCleanup(this);
323
46fa338b
RR
324#ifdef __WXWINCE__
325 wxString tmp = GetAppName();
326 tmp += wxT("ClassName");
d6f2a891 327 wxCanvasClassName = wxStrdup( tmp.wc_str() );
46fa338b 328 tmp += wxT("NR");
d6f2a891 329 wxCanvasClassNameNR = wxStrdup( tmp.wc_str() );
46fa338b
RR
330 HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL );
331 if (hWnd)
332 {
333 SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) );
334 return false;
335 }
336#endif
337
a71d815b 338#if !defined(__WXMICROWIN__)
a5e0e655 339 InitCommonControls();
a71d815b 340#endif // !defined(__WXMICROWIN__)
2bda0e17 341
afafd942
JS
342#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
343 SHInitExtraControls();
344#endif
345
d5ea3919
JS
346#ifndef __WXWINCE__
347 // Don't show a message box if a function such as SHGetFileInfo
348 // fails to find a device.
349 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
350#endif
ad9835c9 351
360ae33f 352 wxOleInitialize();
2bda0e17 353
aa0b7e1e 354 RegisterWindowClasses();
2bda0e17 355
1bffa913 356 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
2bda0e17 357
4676948b 358#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 359 wxSetKeyboardHook(true);
04ef50df 360#endif
2bda0e17 361
94826170
VZ
362 callBaseCleanup.Dismiss();
363
364 return true;
2bda0e17
KB
365}
366
42e69d6b
VZ
367// ---------------------------------------------------------------------------
368// RegisterWindowClasses
369// ---------------------------------------------------------------------------
589f0e3e 370
b782f2e0
VZ
371// TODO we should only register classes really used by the app. For this it
372// would be enough to just delay the class registration until an attempt
373// to create a window of this class is made.
bb6290e3 374bool wxApp::RegisterWindowClasses()
2bda0e17 375{
42e69d6b 376 WNDCLASS wndclass;
03baf031 377 wxZeroMemory(wndclass);
e5c0b16a 378
193fe989
VZ
379 // for each class we register one with CS_(V|H)REDRAW style and one
380 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
381 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
382 static const long styleNoRedraw = CS_DBLCLKS;
383
42e69d6b 384 // the fields which are common to all classes
e5c0b16a 385 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
e5c0b16a 386 wndclass.hInstance = wxhInstance;
42e69d6b 387 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
42e69d6b 388
b9691677
VZ
389 // register the class for all normal windows
390 wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
03baf031 391 wndclass.lpszClassName = wxCanvasClassName;
b782f2e0 392 wndclass.style = styleNormal;
e5c0b16a 393
42e69d6b 394 if ( !RegisterClass(&wndclass) )
e5c0b16a 395 {
f6bcfd97 396 wxLogLastError(wxT("RegisterClass(frame)"));
e5c0b16a
VZ
397 }
398
193fe989 399 // "no redraw" frame
03baf031 400 wndclass.lpszClassName = wxCanvasClassNameNR;
193fe989
VZ
401 wndclass.style = styleNoRedraw;
402
403 if ( !RegisterClass(&wndclass) )
404 {
f6bcfd97 405 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
193fe989
VZ
406 }
407
e5c0b16a 408 // Register the MDI frame window class.
42e69d6b 409 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
b782f2e0
VZ
410 wndclass.lpszClassName = wxMDIFrameClassName;
411 wndclass.style = styleNormal;
42e69d6b
VZ
412
413 if ( !RegisterClass(&wndclass) )
e5c0b16a 414 {
f6bcfd97 415 wxLogLastError(wxT("RegisterClass(MDI parent)"));
e5c0b16a
VZ
416 }
417
193fe989 418 // "no redraw" MDI frame
b782f2e0 419 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
193fe989
VZ
420 wndclass.style = styleNoRedraw;
421
422 if ( !RegisterClass(&wndclass) )
423 {
f6bcfd97 424 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
193fe989
VZ
425 }
426
e5c0b16a 427 // Register the MDI child frame window class.
42e69d6b
VZ
428 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
429 wndclass.lpszClassName = wxMDIChildFrameClassName;
b782f2e0 430 wndclass.style = styleNormal;
42e69d6b
VZ
431
432 if ( !RegisterClass(&wndclass) )
e5c0b16a 433 {
f6bcfd97 434 wxLogLastError(wxT("RegisterClass(MDI child)"));
e5c0b16a
VZ
435 }
436
193fe989
VZ
437 // "no redraw" MDI child frame
438 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
439 wndclass.style = styleNoRedraw;
440
441 if ( !RegisterClass(&wndclass) )
442 {
f6bcfd97 443 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
193fe989
VZ
444 }
445
77c46f00 446 return true;
2bda0e17
KB
447}
448
9787a4b6
VZ
449// ---------------------------------------------------------------------------
450// UnregisterWindowClasses
451// ---------------------------------------------------------------------------
452
453bool wxApp::UnregisterWindowClasses()
454{
77c46f00 455 bool retval = true;
9787a4b6 456
c67d6888 457#ifndef __WXMICROWIN__
9787a4b6 458 // MDI frame window class.
03baf031 459 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
9787a4b6
VZ
460 {
461 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
462
77c46f00 463 retval = false;
9787a4b6
VZ
464 }
465
466 // "no redraw" MDI frame
03baf031 467 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
468 {
469 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
470
77c46f00 471 retval = false;
9787a4b6
VZ
472 }
473
474 // MDI child frame window class.
03baf031 475 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
9787a4b6
VZ
476 {
477 wxLogLastError(wxT("UnregisterClass(MDI child)"));
478
77c46f00 479 retval = false;
9787a4b6
VZ
480 }
481
482 // "no redraw" MDI child frame
03baf031 483 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
484 {
485 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
486
77c46f00 487 retval = false;
9787a4b6
VZ
488 }
489
03baf031
VZ
490 // canvas class name
491 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
9787a4b6
VZ
492 {
493 wxLogLastError(wxT("UnregisterClass(canvas)"));
494
77c46f00 495 retval = false;
9787a4b6
VZ
496 }
497
03baf031 498 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
9787a4b6
VZ
499 {
500 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
501
77c46f00 502 retval = false;
9787a4b6 503 }
03baf031
VZ
504#endif // __WXMICROWIN__
505
9787a4b6
VZ
506 return retval;
507}
508
bb6290e3 509void wxApp::CleanUp()
2bda0e17 510{
7a9dfa3c
VZ
511 // all objects pending for deletion must be deleted first, otherwise we
512 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
513 // call wouldn't succeed as long as any windows still exist), so call the
514 // base class method first and only then do our clean up
515 wxAppBase::CleanUp();
516
4676948b 517#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 518 wxSetKeyboardHook(false);
04ef50df 519#endif
2bda0e17 520
360ae33f 521 wxOleUninitialize();
2bda0e17 522
9787a4b6
VZ
523 // for an EXE the classes are unregistered when it terminates but DLL may
524 // be loaded several times (load/unload/load) into the same process in
525 // which case the registration will fail after the first time if we don't
526 // unregister the classes now
527 UnregisterWindowClasses();
9787a4b6 528
1bffa913 529 delete wxWinHandleHash;
94826170 530 wxWinHandleHash = NULL;
a71d815b 531
46fa338b
RR
532#ifdef __WXWINCE__
533 free( wxCanvasClassName );
534 free( wxCanvasClassNameNR );
535#endif
2bda0e17
KB
536}
537
94826170
VZ
538// ----------------------------------------------------------------------------
539// wxApp ctor/dtor
540// ----------------------------------------------------------------------------
589f0e3e 541
bb6290e3 542wxApp::wxApp()
2bda0e17 543{
e5c0b16a 544 m_printMode = wxPRINT_WINDOWS;
2bda0e17
KB
545}
546
589f0e3e
JS
547wxApp::~wxApp()
548{
589f0e3e
JS
549}
550
6046e57a
VZ
551// ----------------------------------------------------------------------------
552// wxApp idle handling
553// ----------------------------------------------------------------------------
554
cb3c7fdd 555void wxApp::OnIdle(wxIdleEvent& WXUNUSED(event))
2bda0e17 556{
aef94d68
JS
557#if wxUSE_DC_CACHEING
558 // automated DC cache management: clear the cached DCs and bitmap
559 // if it's likely that the app has finished with them, that is, we
560 // get an idle event and we're not dragging anything.
4624defa 561 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
aef94d68
JS
562 wxDC::ClearCache();
563#endif // wxUSE_DC_CACHEING
2bda0e17
KB
564}
565
e2478fde
VZ
566void wxApp::WakeUpIdle()
567{
568 // Send the top window a dummy message so idle handler processing will
569 // start up again. Doing it this way ensures that the idle handler
570 // wakes up in the right thread (see also wxWakeUpMainThread() which does
571 // the same for the main app thread only)
572 wxWindow *topWindow = wxTheApp->GetTopWindow();
573 if ( topWindow )
574 {
575 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
576 {
577 // should never happen
578 wxLogLastError(wxT("PostMessage(WM_NULL)"));
579 }
580 }
581}
582
6046e57a
VZ
583// ----------------------------------------------------------------------------
584// other wxApp event hanlders
585// ----------------------------------------------------------------------------
586
57c208c5 587void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
387a3b02
JS
588{
589 if (GetTopWindow())
77c46f00 590 GetTopWindow()->Close(true);
387a3b02
JS
591}
592
593// Default behaviour: close the application with prompts. The
594// user can veto the close, and therefore the end session.
595void wxApp::OnQueryEndSession(wxCloseEvent& event)
596{
597 if (GetTopWindow())
598 {
599 if (!GetTopWindow()->Close(!event.CanVeto()))
77c46f00 600 event.Veto(true);
387a3b02
JS
601 }
602}
603
6046e57a
VZ
604// ----------------------------------------------------------------------------
605// miscellaneous
606// ----------------------------------------------------------------------------
607
6d167489
VZ
608/* static */
609int wxApp::GetComCtl32Version()
610{
fd7b70bd 611#if defined(__WXMICROWIN__) || defined(__WXWINCE__)
04ef50df
JS
612 return 0;
613#else
6d167489 614 // cache the result
9fc6c21c
VZ
615 //
616 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
617 // but as its value should be the same both times it doesn't matter
bdc72a22
VZ
618 static int s_verComCtl32 = -1;
619
6d167489
VZ
620 if ( s_verComCtl32 == -1 )
621 {
bdc72a22 622 // initally assume no comctl32.dll at all
6d167489
VZ
623 s_verComCtl32 = 0;
624
9fc6c21c
VZ
625 // we're prepared to handle the errors
626 wxLogNull noLog;
ad9835c9 627
64c288fa 628#if wxUSE_DYNLIB_CLASS
bdc72a22 629 // do we have it?
9fc6c21c 630 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
6d167489
VZ
631
632 // if so, then we can check for the version
9fc6c21c 633 if ( dllComCtl32.IsLoaded() )
bb6290e3 634 {
25a11614 635 // now check if the function is available during run-time
9fc6c21c
VZ
636 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dllComCtl32 );
637 if ( pfnDllGetVersion )
638 {
639 DLLVERSIONINFO dvi;
640 dvi.cbSize = sizeof(dvi);
641
642 HRESULT hr = (*pfnDllGetVersion)(&dvi);
643 if ( FAILED(hr) )
6d167489 644 {
9fc6c21c
VZ
645 wxLogApiError(_T("DllGetVersion"), hr);
646 }
647 else
648 {
649 // this is incompatible with _WIN32_IE values, but
650 // compatible with the other values returned by
651 // GetComCtl32Version()
652 s_verComCtl32 = 100*dvi.dwMajorVersion +
653 dvi.dwMinorVersion;
654 }
655 }
bdc72a22 656
9fc6c21c
VZ
657 // if DllGetVersion() is unavailable either during compile or
658 // run-time, try to guess the version otherwise
659 if ( !s_verComCtl32 )
660 {
661 // InitCommonControlsEx is unique to 4.70 and later
662 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
663 if ( !pfn )
664 {
665 // not found, must be 4.00
666 s_verComCtl32 = 400;
6d167489 667 }
9fc6c21c 668 else // 4.70+
bdc72a22 669 {
9fc6c21c
VZ
670 // many symbols appeared in comctl32 4.71, could use any of
671 // them except may be DllInstall()
672 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
673 if ( !pfn )
bdc72a22 674 {
9fc6c21c
VZ
675 // not found, must be 4.70
676 s_verComCtl32 = 470;
bdc72a22
VZ
677 }
678 else
679 {
9fc6c21c
VZ
680 // found, must be 4.71 or later
681 s_verComCtl32 = 471;
bdc72a22 682 }
6d167489 683 }
9fc6c21c 684 }
ef094fa0 685 }
ad9835c9 686#endif
bb6290e3 687 }
6d167489
VZ
688
689 return s_verComCtl32;
9fc6c21c 690#endif // Microwin/!Microwin
bb6290e3
JS
691}
692
2bda0e17 693// Yield to incoming messages
cb2713bf 694
8461e4c2 695bool wxApp::Yield(bool onlyIfNeeded)
2bda0e17 696{
8461e4c2 697 // MT-FIXME
77c46f00 698 static bool s_inYield = false;
8461e4c2 699
e30285ab 700#if wxUSE_LOG
2ed3265e
VZ
701 // disable log flushing from here because a call to wxYield() shouldn't
702 // normally result in message boxes popping up &c
703 wxLog::Suspend();
e30285ab 704#endif // wxUSE_LOG
2ed3265e 705
8461e4c2
VZ
706 if ( s_inYield )
707 {
708 if ( !onlyIfNeeded )
709 {
710 wxFAIL_MSG( wxT("wxYield called recursively" ) );
711 }
33ac7e6f 712
77c46f00 713 return false;
8461e4c2
VZ
714 }
715
77c46f00 716 s_inYield = true;
cb2713bf 717
8e193f38
VZ
718 // we don't want to process WM_QUIT from here - it should be processed in
719 // the main event loop in order to stop it
e5c0b16a 720 MSG msg;
8e193f38
VZ
721 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
722 msg.message != WM_QUIT )
e5c0b16a 723 {
5b615ed8
VZ
724#if wxUSE_THREADS
725 wxMutexGuiLeaveOrEnter();
726#endif // wxUSE_THREADS
727
1bf77ee5 728 if ( !wxTheApp->Dispatch() )
e5c0b16a
VZ
729 break;
730 }
8e193f38 731
8461e4c2
VZ
732 // if there are pending events, we must process them.
733 ProcessPendingEvents();
e5c0b16a 734
e30285ab 735#if wxUSE_LOG
2ed3265e
VZ
736 // let the logs be flashed again
737 wxLog::Resume();
e30285ab 738#endif // wxUSE_LOG
2ed3265e 739
77c46f00 740 s_inYield = false;
cb2713bf 741
77c46f00 742 return true;
2bda0e17 743}
094637f6 744
6046e57a
VZ
745#if wxUSE_EXCEPTIONS
746
747// ----------------------------------------------------------------------------
748// exception handling
749// ----------------------------------------------------------------------------
750
751bool wxApp::OnExceptionInMainLoop()
752{
753 // ask the user about what to do: use the Win32 API function here as it
77ffb593 754 // could be dangerous to use any wxWidgets code in this state
6046e57a
VZ
755 switch (
756 ::MessageBox
757 (
758 NULL,
759 _T("An unhandled exception occurred. Press \"Abort\" to \
760terminate the program,\r\n\
761\"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
762 _T("Unhandled exception"),
763 MB_ABORTRETRYIGNORE |
a71d815b 764 MB_ICONERROR|
6046e57a
VZ
765 MB_TASKMODAL
766 )
767 )
768 {
769 case IDABORT:
770 throw;
771
772 default:
773 wxFAIL_MSG( _T("unexpected MessageBox() return code") );
774 // fall through
775
776 case IDRETRY:
777 return false;
778
779 case IDIGNORE:
780 return true;
781 }
782}
783
784#endif // wxUSE_EXCEPTIONS