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