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