]> git.saurik.com Git - wxWidgets.git/blame - src/msw/app.cpp
wxAUI: maintain minimum size of panes across dock/undock.
[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
ad9835c9 28 #include "wx/dynarray.h"
e5c0b16a
VZ
29 #include "wx/frame.h"
30 #include "wx/app.h"
31 #include "wx/utils.h"
32 #include "wx/gdicmn.h"
33 #include "wx/pen.h"
34 #include "wx/brush.h"
35 #include "wx/cursor.h"
36 #include "wx/icon.h"
37 #include "wx/palette.h"
38 #include "wx/dc.h"
39 #include "wx/dialog.h"
40 #include "wx/msgdlg.h"
41 #include "wx/intl.h"
72cdf4c9 42 #include "wx/wxchar.h"
31f6de22 43 #include "wx/log.h"
2bda0e17
KB
44#endif
45
e2478fde 46#include "wx/apptrait.h"
7104f65d 47#include "wx/filename.h"
2bda0e17 48#include "wx/module.h"
9fc6c21c 49#include "wx/dynlib.h"
031943ac 50#include "wx/evtloop.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
4676948b 112#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2bda0e17 113extern void wxSetKeyboardHook(bool doIt);
04ef50df 114#endif
2bda0e17 115
193fe989
VZ
116// NB: all "NoRedraw" classes must have the same names as the "normal" classes
117// with NR suffix - wxWindow::MSWCreate() supposes this
46fa338b 118#ifdef __WXWINCE__
7a4d2469
RN
119WXDLLIMPEXP_CORE wxChar *wxCanvasClassName;
120WXDLLIMPEXP_CORE wxChar *wxCanvasClassNameNR;
46fa338b 121#else
7a4d2469
RN
122WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName = wxT("wxWindowClass");
123WXDLLIMPEXP_CORE const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
46fa338b 124#endif
7a4d2469
RN
125WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
126WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
127WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
128WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
2bda0e17 129
94826170
VZ
130// ----------------------------------------------------------------------------
131// private functions
132// ----------------------------------------------------------------------------
2bda0e17 133
94826170 134LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
3b415ba4 135
e5c0b16a 136// ===========================================================================
e2478fde
VZ
137// wxGUIAppTraits implementation
138// ===========================================================================
139
140// private class which we use to pass parameters from BeforeChildWaitLoop() to
141// AfterChildWaitLoop()
142struct ChildWaitLoopData
143{
144 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
145 {
146 wd = wd_;
147 winActive = winActive_;
148 }
149
150 wxWindowDisabler *wd;
151 wxWindow *winActive;
152};
153
154void *wxGUIAppTraits::BeforeChildWaitLoop()
155{
156 /*
157 We use a dirty hack here to disable all application windows (which we
158 must do because otherwise the calls to wxYield() could lead to some very
159 unexpected reentrancies in the users code) but to avoid losing
160 focus/activation entirely when the child process terminates which would
161 happen if we simply disabled everything using wxWindowDisabler. Indeed,
162 remember that Windows will never activate a disabled window and when the
163 last childs window is closed and Windows looks for a window to activate
164 all our windows are still disabled. There is no way to enable them in
165 time because we don't know when the childs windows are going to be
166 closed, so the solution we use here is to keep one special tiny frame
167 enabled all the time. Then when the child terminates it will get
168 activated and when we close it below -- after reenabling all the other
169 windows! -- the previously active window becomes activated again and
170 everything is ok.
171 */
172 wxBeginBusyCursor();
173
174 // first disable all existing windows
175 wxWindowDisabler *wd = new wxWindowDisabler;
176
177 // then create an "invisible" frame: it has minimal size, is positioned
178 // (hopefully) outside the screen and doesn't appear on the taskbar
179 wxWindow *winActive = new wxFrame
180 (
181 wxTheApp->GetTopWindow(),
fda7962d
JS
182 wxID_ANY,
183 wxEmptyString,
e2478fde
VZ
184 wxPoint(32600, 32600),
185 wxSize(1, 1),
186 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
187 );
188 winActive->Show();
189
190 return new ChildWaitLoopData(wd, winActive);
191}
192
193void wxGUIAppTraits::AlwaysYield()
194{
195 wxYield();
196}
197
198void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
199{
200 wxEndBusyCursor();
201
0588f8d7 202 ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
e2478fde
VZ
203
204 delete data->wd;
205
206 // finally delete the dummy frame and, as wd has been already destroyed and
207 // the other windows reenabled, the activation is going to return to the
208 // window which had had it before
209 data->winActive->Destroy();
51036b44
VZ
210
211 // also delete the temporary data object itself
212 delete data;
e2478fde
VZ
213}
214
215bool wxGUIAppTraits::DoMessageFromThreadWait()
216{
1bf77ee5
VZ
217 // we should return false only if the app should exit, i.e. only if
218 // Dispatch() determines that the main event loop should terminate
031943ac
VZ
219 wxEventLoop *evtLoop = wxEventLoop::GetActive();
220 if ( !evtLoop || !evtLoop->Pending() )
221 {
222 // no events means no quit event
223 return true;
224 }
225
226 return evtLoop->Dispatch();
e2478fde
VZ
227}
228
324899f6 229wxToolkitInfo& wxGUIAppTraits::GetToolkitInfo()
a8eaaeb2 230{
1bf77ee5 231 static wxToolkitInfo info;
324899f6
VS
232 wxToolkitInfo& baseInfo = wxAppTraits::GetToolkitInfo();
233 info.versionMajor = baseInfo.versionMajor;
234 info.versionMinor = baseInfo.versionMinor;
235 info.os = baseInfo.os;
a8eaaeb2
VS
236 info.shortName = _T("msw");
237 info.name = _T("wxMSW");
238#ifdef __WXUNIVERSAL__
239 info.shortName << _T("univ");
240 info.name << _T("/wxUniversal");
241#endif
324899f6 242 return info;
a8eaaeb2
VS
243}
244
e2478fde
VZ
245// ===========================================================================
246// wxApp implementation
e5c0b16a 247// ===========================================================================
589f0e3e 248
94826170
VZ
249int wxApp::m_nCmdShow = SW_SHOWNORMAL;
250
e5c0b16a 251// ---------------------------------------------------------------------------
e2478fde 252// wxWin macros
e5c0b16a
VZ
253// ---------------------------------------------------------------------------
254
f6bcfd97 255IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
e5c0b16a 256
f6bcfd97
BP
257BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
258 EVT_IDLE(wxApp::OnIdle)
259 EVT_END_SESSION(wxApp::OnEndSession)
260 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
261END_EVENT_TABLE()
e5c0b16a 262
94826170
VZ
263// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
264// fails
265class wxCallBaseCleanup
266{
267public:
268 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
269 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
270
271 void Dismiss() { m_app = NULL; }
272
273private:
274 wxApp *m_app;
275};
276
e5c0b16a 277//// Initialize
05e2b077 278bool wxApp::Initialize(int& argc, wxChar **argv)
2bda0e17 279{
94826170
VZ
280 if ( !wxAppBase::Initialize(argc, argv) )
281 return false;
282
283 // ensure that base cleanup is done if we return too early
284 wxCallBaseCleanup callBaseCleanup(this);
285
46fa338b
RR
286#ifdef __WXWINCE__
287 wxString tmp = GetAppName();
288 tmp += wxT("ClassName");
289 wxCanvasClassName = wxStrdup( tmp.c_str() );
290 tmp += wxT("NR");
291 wxCanvasClassNameNR = wxStrdup( tmp.c_str() );
292 HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL );
293 if (hWnd)
294 {
295 SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) );
296 return false;
297 }
298#endif
299
a71d815b 300#if !defined(__WXMICROWIN__)
a5e0e655 301 InitCommonControls();
a71d815b 302#endif // !defined(__WXMICROWIN__)
2bda0e17 303
afafd942
JS
304#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
305 SHInitExtraControls();
306#endif
307
d5ea3919
JS
308#ifndef __WXWINCE__
309 // Don't show a message box if a function such as SHGetFileInfo
310 // fails to find a device.
311 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
312#endif
ad9835c9 313
360ae33f 314 wxOleInitialize();
2bda0e17 315
aa0b7e1e 316 RegisterWindowClasses();
2bda0e17 317
1bffa913 318 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
2bda0e17 319
4676948b 320#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 321 wxSetKeyboardHook(true);
04ef50df 322#endif
2bda0e17 323
94826170
VZ
324 callBaseCleanup.Dismiss();
325
326 return true;
2bda0e17
KB
327}
328
42e69d6b
VZ
329// ---------------------------------------------------------------------------
330// RegisterWindowClasses
331// ---------------------------------------------------------------------------
589f0e3e 332
b782f2e0
VZ
333// TODO we should only register classes really used by the app. For this it
334// would be enough to just delay the class registration until an attempt
335// to create a window of this class is made.
bb6290e3 336bool wxApp::RegisterWindowClasses()
2bda0e17 337{
42e69d6b 338 WNDCLASS wndclass;
03baf031 339 wxZeroMemory(wndclass);
e5c0b16a 340
193fe989
VZ
341 // for each class we register one with CS_(V|H)REDRAW style and one
342 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
343 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
344 static const long styleNoRedraw = CS_DBLCLKS;
345
42e69d6b 346 // the fields which are common to all classes
e5c0b16a 347 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
e5c0b16a 348 wndclass.hInstance = wxhInstance;
42e69d6b 349 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
42e69d6b 350
b9691677
VZ
351 // register the class for all normal windows
352 wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
03baf031 353 wndclass.lpszClassName = wxCanvasClassName;
b782f2e0 354 wndclass.style = styleNormal;
e5c0b16a 355
42e69d6b 356 if ( !RegisterClass(&wndclass) )
e5c0b16a 357 {
f6bcfd97 358 wxLogLastError(wxT("RegisterClass(frame)"));
e5c0b16a
VZ
359 }
360
193fe989 361 // "no redraw" frame
03baf031 362 wndclass.lpszClassName = wxCanvasClassNameNR;
193fe989
VZ
363 wndclass.style = styleNoRedraw;
364
365 if ( !RegisterClass(&wndclass) )
366 {
f6bcfd97 367 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
193fe989
VZ
368 }
369
e5c0b16a 370 // Register the MDI frame window class.
42e69d6b 371 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
b782f2e0
VZ
372 wndclass.lpszClassName = wxMDIFrameClassName;
373 wndclass.style = styleNormal;
42e69d6b
VZ
374
375 if ( !RegisterClass(&wndclass) )
e5c0b16a 376 {
f6bcfd97 377 wxLogLastError(wxT("RegisterClass(MDI parent)"));
e5c0b16a
VZ
378 }
379
193fe989 380 // "no redraw" MDI frame
b782f2e0 381 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
193fe989
VZ
382 wndclass.style = styleNoRedraw;
383
384 if ( !RegisterClass(&wndclass) )
385 {
f6bcfd97 386 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
193fe989
VZ
387 }
388
e5c0b16a 389 // Register the MDI child frame window class.
42e69d6b
VZ
390 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
391 wndclass.lpszClassName = wxMDIChildFrameClassName;
b782f2e0 392 wndclass.style = styleNormal;
42e69d6b
VZ
393
394 if ( !RegisterClass(&wndclass) )
e5c0b16a 395 {
f6bcfd97 396 wxLogLastError(wxT("RegisterClass(MDI child)"));
e5c0b16a
VZ
397 }
398
193fe989
VZ
399 // "no redraw" MDI child frame
400 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
401 wndclass.style = styleNoRedraw;
402
403 if ( !RegisterClass(&wndclass) )
404 {
f6bcfd97 405 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
193fe989
VZ
406 }
407
77c46f00 408 return true;
2bda0e17
KB
409}
410
9787a4b6
VZ
411// ---------------------------------------------------------------------------
412// UnregisterWindowClasses
413// ---------------------------------------------------------------------------
414
415bool wxApp::UnregisterWindowClasses()
416{
77c46f00 417 bool retval = true;
9787a4b6 418
c67d6888 419#ifndef __WXMICROWIN__
9787a4b6 420 // MDI frame window class.
03baf031 421 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
9787a4b6
VZ
422 {
423 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
424
77c46f00 425 retval = false;
9787a4b6
VZ
426 }
427
428 // "no redraw" MDI frame
03baf031 429 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
430 {
431 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
432
77c46f00 433 retval = false;
9787a4b6
VZ
434 }
435
436 // MDI child frame window class.
03baf031 437 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
9787a4b6
VZ
438 {
439 wxLogLastError(wxT("UnregisterClass(MDI child)"));
440
77c46f00 441 retval = false;
9787a4b6
VZ
442 }
443
444 // "no redraw" MDI child frame
03baf031 445 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
9787a4b6
VZ
446 {
447 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
448
77c46f00 449 retval = false;
9787a4b6
VZ
450 }
451
03baf031
VZ
452 // canvas class name
453 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
9787a4b6
VZ
454 {
455 wxLogLastError(wxT("UnregisterClass(canvas)"));
456
77c46f00 457 retval = false;
9787a4b6
VZ
458 }
459
03baf031 460 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
9787a4b6
VZ
461 {
462 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
463
77c46f00 464 retval = false;
9787a4b6 465 }
03baf031
VZ
466#endif // __WXMICROWIN__
467
9787a4b6
VZ
468 return retval;
469}
470
bb6290e3 471void wxApp::CleanUp()
2bda0e17 472{
7a9dfa3c
VZ
473 // all objects pending for deletion must be deleted first, otherwise we
474 // would crash when they use wxWinHandleHash (and UnregisterWindowClasses()
475 // call wouldn't succeed as long as any windows still exist), so call the
476 // base class method first and only then do our clean up
477 wxAppBase::CleanUp();
478
4676948b 479#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 480 wxSetKeyboardHook(false);
04ef50df 481#endif
2bda0e17 482
360ae33f 483 wxOleUninitialize();
2bda0e17 484
9787a4b6
VZ
485 // for an EXE the classes are unregistered when it terminates but DLL may
486 // be loaded several times (load/unload/load) into the same process in
487 // which case the registration will fail after the first time if we don't
488 // unregister the classes now
489 UnregisterWindowClasses();
9787a4b6 490
1bffa913 491 delete wxWinHandleHash;
94826170 492 wxWinHandleHash = NULL;
a71d815b 493
46fa338b
RR
494#ifdef __WXWINCE__
495 free( wxCanvasClassName );
496 free( wxCanvasClassNameNR );
497#endif
2bda0e17
KB
498}
499
94826170
VZ
500// ----------------------------------------------------------------------------
501// wxApp ctor/dtor
502// ----------------------------------------------------------------------------
589f0e3e 503
bb6290e3 504wxApp::wxApp()
2bda0e17 505{
e5c0b16a 506 m_printMode = wxPRINT_WINDOWS;
2bda0e17
KB
507}
508
589f0e3e
JS
509wxApp::~wxApp()
510{
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;
ad9835c9 591
64c288fa 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 }
ad9835c9 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
51036b44
VZ
756void wxApp::DoMessage(WXMSG *pMsg)
757{
758 wxEventLoop *evtLoop = wxEventLoop::GetActive();
759 if ( evtLoop )
760 evtLoop->ProcessMessage(pMsg);
761}
762
763bool wxApp::DoMessage()
764{
765 wxEventLoop *evtLoop = wxEventLoop::GetActive();
766 return evtLoop ? evtLoop->Dispatch() : false;
767}
768
769bool wxApp::ProcessMessage(WXMSG* pMsg)
770{
771 wxEventLoop *evtLoop = wxEventLoop::GetActive();
772 return evtLoop && evtLoop->PreProcessMessage(pMsg);
773}
774
775#endif // WXWIN_COMPATIBILITY_2_4