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