]> git.saurik.com Git - wxWidgets.git/blame - src/msw/app.cpp
Correct making the newly inserted menu item owner drawn in some cases.
[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
6c9a19aa 7// Copyright: (c) Julian Smart
65571936 8// Licence: wxWindows licence
2bda0e17
KB
9/////////////////////////////////////////////////////////////////////////////
10
e5c0b16a
VZ
11// ===========================================================================
12// declarations
13// ===========================================================================
14
15// ---------------------------------------------------------------------------
16// headers
17// ---------------------------------------------------------------------------
18
2bda0e17 19// For compilers that support precompilation, includes "wx.h".
2bda0e17
KB
20#include "wx/wxprec.h"
21
22#if defined(__BORLANDC__)
e5c0b16a 23 #pragma hdrstop
2bda0e17
KB
24#endif
25
26#ifndef WX_PRECOMP
57bd4c60 27 #include "wx/msw/wrapcctl.h"
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"
3a3dde0d 42 #include "wx/crt.h"
31f6de22 43 #include "wx/log.h"
02761f6c 44 #include "wx/module.h"
2bda0e17
KB
45#endif
46
e2478fde 47#include "wx/apptrait.h"
7104f65d 48#include "wx/filename.h"
9fc6c21c 49#include "wx/dynlib.h"
031943ac 50#include "wx/evtloop.h"
204abcd4 51#include "wx/thread.h"
fcf92c3a 52#include "wx/scopeguard.h"
d9698bd4 53#include "wx/vector.h"
4bf78aae 54
4286a5b5 55#include "wx/msw/private.h"
025f7d77 56#include "wx/msw/dc.h"
360ae33f 57#include "wx/msw/ole/oleutils.h"
c2ca375c 58#include "wx/msw/private/timer.h"
4286a5b5 59
8614c467
VZ
60#if wxUSE_TOOLTIPS
61 #include "wx/tooltip.h"
62#endif // wxUSE_TOOLTIPS
63
c42404a5
VZ
64// OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
65// compilers don't support it (missing headers, libs, ...)
f172cb82 66#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__)
e5c0b16a
VZ
67 #undef wxUSE_OLE
68
69 #define wxUSE_OLE 0
70#endif // broken compilers
71
afafd942 72#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
58b76be1
VZ
73 #include <ole2.h>
74 #include <aygshell.h>
afafd942
JS
75#endif
76
e5c0b16a 77#if wxUSE_OLE
6e0d9d43 78 #include <ole2.h>
d05237ea 79#endif
ce3ed50d 80
2bda0e17 81#include <string.h>
a5e0e655 82#include <ctype.h>
2bda0e17 83
261fb041 84#include "wx/msw/missing.h"
6046e57a 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
05b4b8ee
VZ
107#ifndef ATTACH_PARENT_PROCESS
108 #define ATTACH_PARENT_PROCESS ((DWORD)-1)
109#endif
238a6044 110
e5c0b16a
VZ
111// ---------------------------------------------------------------------------
112// global variables
113// ---------------------------------------------------------------------------
114
4676948b 115#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2bda0e17 116extern void wxSetKeyboardHook(bool doIt);
04ef50df 117#endif
2bda0e17 118
c76fb545
VZ
119// because of mingw32 4.3 bug this struct can't be inside the namespace below:
120// see http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/110282
d9698bd4
VZ
121struct ClassRegInfo
122{
563cf28f
VZ
123 ClassRegInfo(const wxChar *name)
124 : regname(name),
125 regnameNR(regname + wxApp::GetNoRedrawClassSuffix())
126 {
127 }
d9698bd4
VZ
128
129 // the name of the registered class with and without CS_[HV]REDRAW styles
9106ea70
VZ
130 wxString regname;
131 wxString regnameNR;
d9698bd4
VZ
132};
133
c76fb545
VZ
134namespace
135{
136
d9698bd4
VZ
137wxVector<ClassRegInfo> gs_regClassesInfo;
138
139} // anonymous namespace
2bda0e17 140
94826170
VZ
141// ----------------------------------------------------------------------------
142// private functions
143// ----------------------------------------------------------------------------
2bda0e17 144
94826170 145LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
3b415ba4 146
e5c0b16a 147// ===========================================================================
e2478fde
VZ
148// wxGUIAppTraits implementation
149// ===========================================================================
150
151// private class which we use to pass parameters from BeforeChildWaitLoop() to
152// AfterChildWaitLoop()
153struct ChildWaitLoopData
154{
155 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
156 {
157 wd = wd_;
158 winActive = winActive_;
159 }
160
161 wxWindowDisabler *wd;
162 wxWindow *winActive;
163};
164
165void *wxGUIAppTraits::BeforeChildWaitLoop()
166{
167 /*
168 We use a dirty hack here to disable all application windows (which we
169 must do because otherwise the calls to wxYield() could lead to some very
170 unexpected reentrancies in the users code) but to avoid losing
171 focus/activation entirely when the child process terminates which would
172 happen if we simply disabled everything using wxWindowDisabler. Indeed,
173 remember that Windows will never activate a disabled window and when the
0ec1064b 174 last child's window is closed and Windows looks for a window to activate
e2478fde 175 all our windows are still disabled. There is no way to enable them in
0ec1064b
VZ
176 time because we don't know when the child's windows are going to be
177 closed, so the solution we use here is to keep one special tiny dialog
e2478fde 178 enabled all the time. Then when the child terminates it will get
0ec1064b 179 activated and when we close it below -- after re-enabling all the other
e2478fde
VZ
180 windows! -- the previously active window becomes activated again and
181 everything is ok.
182 */
183 wxBeginBusyCursor();
184
185 // first disable all existing windows
186 wxWindowDisabler *wd = new wxWindowDisabler;
187
0ec1064b
VZ
188 // then create an "invisible" dialog: it has minimal size, is positioned
189 // (hopefully) outside the screen and doesn't appear in the Alt-TAB list
190 // (unlike the frames, which is why we use a dialog here)
191 wxWindow *winActive = new wxDialog
e2478fde
VZ
192 (
193 wxTheApp->GetTopWindow(),
fda7962d
JS
194 wxID_ANY,
195 wxEmptyString,
e2478fde 196 wxPoint(32600, 32600),
0ec1064b 197 wxSize(1, 1)
e2478fde
VZ
198 );
199 winActive->Show();
200
201 return new ChildWaitLoopData(wd, winActive);
202}
203
e2478fde
VZ
204void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
205{
206 wxEndBusyCursor();
207
0588f8d7 208 ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
e2478fde
VZ
209
210 delete data->wd;
211
0ec1064b
VZ
212 // finally delete the dummy dialog and, as wd has been already destroyed
213 // and the other windows reenabled, the activation is going to return to
214 // the window which had had it before
e2478fde 215 data->winActive->Destroy();
51036b44
VZ
216
217 // also delete the temporary data object itself
218 delete data;
e2478fde
VZ
219}
220
dd1af40c 221#if wxUSE_THREADS
e2478fde
VZ
222bool wxGUIAppTraits::DoMessageFromThreadWait()
223{
1bf77ee5
VZ
224 // we should return false only if the app should exit, i.e. only if
225 // Dispatch() determines that the main event loop should terminate
2ddff00c 226 wxEventLoopBase * const evtLoop = wxEventLoop::GetActive();
031943ac
VZ
227 if ( !evtLoop || !evtLoop->Pending() )
228 {
229 // no events means no quit event
230 return true;
231 }
232
233 return evtLoop->Dispatch();
e2478fde
VZ
234}
235
b95a7c31 236DWORD wxGUIAppTraits::WaitForThread(WXHANDLE hThread, int flags)
e570a44b 237{
ef0fdf39
VZ
238 // We only ever dispatch messages from the main thread and, additionally,
239 // even from the main thread we shouldn't wait for the message if we don't
240 // have a running event loop as we would never remove them from the message
241 // queue then and so we would enter an infinite loop as
242 // MsgWaitForMultipleObjects() keeps returning WAIT_OBJECT_0 + 1.
b95a7c31
VZ
243 if ( flags == wxTHREAD_WAIT_BLOCK ||
244 !wxIsMainThread() ||
245 !wxEventLoop::GetActive() )
246 {
247 // Simple blocking wait.
535920ff 248 return DoSimpleWaitForThread(hThread);
b95a7c31 249 }
535920ff 250
e570a44b
VZ
251 return ::MsgWaitForMultipleObjects
252 (
253 1, // number of objects to wait for
254 (HANDLE *)&hThread, // the objects
255 false, // wait for any objects, not all
256 INFINITE, // no timeout
261fb041
WS
257 QS_ALLINPUT | // return as soon as there are any events
258 QS_ALLPOSTMESSAGE
e570a44b
VZ
259 );
260}
dd1af40c 261#endif // wxUSE_THREADS
e570a44b 262
8bb6b2c0 263wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const
a8eaaeb2 264{
8bb6b2c0
VZ
265 OSVERSIONINFO info;
266 wxZeroMemory(info);
267
268 // on Windows, the toolkit version is the same of the OS version
269 // as Windows integrates the OS kernel with the GUI toolkit.
270 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
271 if ( ::GetVersionEx(&info) )
272 {
273 if ( majVer )
274 *majVer = info.dwMajorVersion;
275 if ( minVer )
276 *minVer = info.dwMinorVersion;
277 }
278
279#if defined(__WXHANDHELD__) || defined(__WXWINCE__)
280 return wxPORT_WINCE;
281#else
282 return wxPORT_MSW;
a8eaaeb2 283#endif
a8eaaeb2
VS
284}
285
a8ff046b
VZ
286#if wxUSE_TIMER
287
b46b1d59 288wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
c2ca375c 289{
b46b1d59
VZ
290 return new wxMSWTimerImpl(timer);
291}
292
a8ff046b
VZ
293#endif // wxUSE_TIMER
294
2ddff00c 295wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
b46b1d59
VZ
296{
297 return new wxEventLoop;
5d262fdd 298}
c2ca375c 299
784ee7d5
VZ
300// ---------------------------------------------------------------------------
301// Stuff for using console from the GUI applications
302// ---------------------------------------------------------------------------
303
304#ifndef __WXWINCE__
305
14ca3a3b
VZ
306#if wxUSE_DYNLIB_CLASS
307
784ee7d5
VZ
308#include <wx/dynlib.h>
309
310namespace
311{
312
313/*
314 Helper class to manipulate console from a GUI app.
315
316 Notice that console output is available in the GUI app only if:
317 - AttachConsole() returns TRUE (which means it never works under pre-XP)
318 - we have a valid STD_ERROR_HANDLE
319 - command history hasn't been changed since our startup
320
321 To check if all these conditions are verified, you need to simple call
322 IsOkToUse(). It will check the first two conditions above the first time it
323 is called (and if this fails, the subsequent calls will return immediately)
324 and also recheck the last one every time it is called.
325 */
326class wxConsoleStderr
327{
328public:
329 // default ctor does nothing, call Init() before using this class
330 wxConsoleStderr()
331 {
332 m_hStderr = INVALID_HANDLE_VALUE;
333 m_historyLen =
334 m_dataLen =
335 m_dataLine = 0;
336
337 m_ok = -1;
338 }
339
340 ~wxConsoleStderr()
341 {
342 if ( m_hStderr != INVALID_HANDLE_VALUE )
343 {
344 if ( !::FreeConsole() )
345 {
9a83f860 346 wxLogLastError(wxT("FreeConsole"));
784ee7d5
VZ
347 }
348 }
349 }
350
351 // return true if we were successfully initialized and there had been no
352 // console activity which would interfere with our output since then
353 bool IsOkToUse() const
354 {
355 if ( m_ok == -1 )
356 {
5c33522f 357 wxConsoleStderr * const self = const_cast<wxConsoleStderr *>(this);
784ee7d5
VZ
358 self->m_ok = self->DoInit();
359
360 // no need to call IsHistoryUnchanged() as we just initialized
361 // m_history anyhow
362 return m_ok == 1;
363 }
364
365 return m_ok && IsHistoryUnchanged();
366 }
367
368
369 // output the provided text on the console, return true if ok
370 bool Write(const wxString& text);
371
372private:
373 // called by Init() once only to do the real initialization
374 bool DoInit();
375
376 // retrieve the command line history into the provided buffer and return
377 // its length
378 int GetCommandHistory(wxWxCharBuffer& buf) const;
379
380 // check if the console history has changed
381 bool IsHistoryUnchanged() const;
382
383 int m_ok; // initially -1, set to true or false by Init()
384
385 wxDynamicLibrary m_dllKernel32;
386
387 HANDLE m_hStderr; // console handle, if it's valid we must call
388 // FreeConsole() (even if m_ok != 1)
389
390 wxWxCharBuffer m_history; // command history on startup
391 int m_historyLen; // length command history buffer
392
393 wxCharBuffer m_data; // data between empty line and cursor position
394 int m_dataLen; // length data buffer
395 int m_dataLine; // line offset
396
397 typedef DWORD (WINAPI *GetConsoleCommandHistory_t)(LPTSTR sCommands,
398 DWORD nBufferLength,
399 LPCTSTR sExeName);
400 typedef DWORD (WINAPI *GetConsoleCommandHistoryLength_t)(LPCTSTR sExeName);
401
402 GetConsoleCommandHistory_t m_pfnGetConsoleCommandHistory;
403 GetConsoleCommandHistoryLength_t m_pfnGetConsoleCommandHistoryLength;
404
c0c133e1 405 wxDECLARE_NO_COPY_CLASS(wxConsoleStderr);
784ee7d5
VZ
406};
407
408bool wxConsoleStderr::DoInit()
409{
410 HANDLE hStderr = ::GetStdHandle(STD_ERROR_HANDLE);
411
412 if ( hStderr == INVALID_HANDLE_VALUE || !hStderr )
413 return false;
414
9a83f860 415 if ( !m_dllKernel32.Load(wxT("kernel32.dll")) )
784ee7d5
VZ
416 return false;
417
418 typedef BOOL (WINAPI *AttachConsole_t)(DWORD dwProcessId);
419 AttachConsole_t wxDL_INIT_FUNC(pfn, AttachConsole, m_dllKernel32);
420
421 if ( !pfnAttachConsole || !pfnAttachConsole(ATTACH_PARENT_PROCESS) )
422 return false;
423
424 // console attached, set m_hStderr now to ensure that we free it in the
425 // dtor
426 m_hStderr = hStderr;
427
428 wxDL_INIT_FUNC_AW(m_pfn, GetConsoleCommandHistory, m_dllKernel32);
429 if ( !m_pfnGetConsoleCommandHistory )
430 return false;
431
432 wxDL_INIT_FUNC_AW(m_pfn, GetConsoleCommandHistoryLength, m_dllKernel32);
433 if ( !m_pfnGetConsoleCommandHistoryLength )
434 return false;
435
436 // remember the current command history to be able to compare with it later
437 // in IsHistoryUnchanged()
438 m_historyLen = GetCommandHistory(m_history);
439 if ( !m_history )
440 return false;
441
442
443 // now find the first blank line above the current position
444 CONSOLE_SCREEN_BUFFER_INFO csbi;
445
446 if ( !::GetConsoleScreenBufferInfo(m_hStderr, &csbi) )
447 {
9a83f860 448 wxLogLastError(wxT("GetConsoleScreenBufferInfo"));
784ee7d5
VZ
449 return false;
450 }
451
452 COORD pos;
453 pos.X = 0;
454 pos.Y = csbi.dwCursorPosition.Y + 1;
455
456 // we decide that a line is empty if first 4 characters are spaces
457 DWORD ret;
458 char buf[4];
459 do
460 {
461 pos.Y--;
462 if ( !::ReadConsoleOutputCharacterA(m_hStderr, buf, WXSIZEOF(buf),
463 pos, &ret) )
464 {
9a83f860 465 wxLogLastError(wxT("ReadConsoleOutputCharacterA"));
784ee7d5
VZ
466 return false;
467 }
468 } while ( wxStrncmp(" ", buf, WXSIZEOF(buf)) != 0 );
469
470 // calculate line offset and length of data
471 m_dataLine = csbi.dwCursorPosition.Y - pos.Y;
472 m_dataLen = m_dataLine*csbi.dwMaximumWindowSize.X + csbi.dwCursorPosition.X;
473
474 if ( m_dataLen > 0 )
475 {
476 m_data.extend(m_dataLen);
477 if ( !::ReadConsoleOutputCharacterA(m_hStderr, m_data.data(), m_dataLen,
478 pos, &ret) )
479 {
9a83f860 480 wxLogLastError(wxT("ReadConsoleOutputCharacterA"));
784ee7d5
VZ
481 return false;
482 }
483 }
484
485 return true;
486}
487
488int wxConsoleStderr::GetCommandHistory(wxWxCharBuffer& buf) const
489{
490 // these functions are internal and may only be called by cmd.exe
9a83f860 491 static const wxChar *CMD_EXE = wxT("cmd.exe");
784ee7d5
VZ
492
493 const int len = m_pfnGetConsoleCommandHistoryLength(CMD_EXE);
494 if ( len )
495 {
496 buf.extend(len);
1033a7cc
VZ
497
498 int len2 = m_pfnGetConsoleCommandHistory(buf.data(), len, CMD_EXE);
499
500#if !wxUSE_UNICODE
501 // there seems to be a bug in the GetConsoleCommandHistoryA(), it
502 // returns the length of Unicode string and not ANSI one
503 len2 /= 2;
504#endif // !wxUSE_UNICODE
505
575cabba
VZ
506 if ( len2 != len )
507 {
9a83f860 508 wxFAIL_MSG( wxT("failed getting history?") );
575cabba 509 }
784ee7d5
VZ
510 }
511
512 return len;
513}
514
515bool wxConsoleStderr::IsHistoryUnchanged() const
516{
9a83f860 517 wxASSERT_MSG( m_ok == 1, wxT("shouldn't be called if not initialized") );
784ee7d5
VZ
518
519 // get (possibly changed) command history
520 wxWxCharBuffer history;
521 const int historyLen = GetCommandHistory(history);
522
523 // and compare it with the original one
524 return historyLen == m_historyLen && history &&
525 memcmp(m_history, history, historyLen) == 0;
526}
527
528bool wxConsoleStderr::Write(const wxString& text)
529{
530 wxASSERT_MSG( m_hStderr != INVALID_HANDLE_VALUE,
9a83f860 531 wxT("should only be called if Init() returned true") );
784ee7d5
VZ
532
533 // get current position
534 CONSOLE_SCREEN_BUFFER_INFO csbi;
535 if ( !::GetConsoleScreenBufferInfo(m_hStderr, &csbi) )
536 {
9a83f860 537 wxLogLastError(wxT("GetConsoleScreenBufferInfo"));
784ee7d5
VZ
538 return false;
539 }
540
541 // and calculate new position (where is empty line)
542 csbi.dwCursorPosition.X = 0;
543 csbi.dwCursorPosition.Y -= m_dataLine;
544
545 if ( !::SetConsoleCursorPosition(m_hStderr, csbi.dwCursorPosition) )
546 {
9a83f860 547 wxLogLastError(wxT("SetConsoleCursorPosition"));
784ee7d5
VZ
548 return false;
549 }
550
551 DWORD ret;
9a83f860 552 if ( !::FillConsoleOutputCharacter(m_hStderr, wxT(' '), m_dataLen,
784ee7d5
VZ
553 csbi.dwCursorPosition, &ret) )
554 {
9a83f860 555 wxLogLastError(wxT("FillConsoleOutputCharacter"));
784ee7d5
VZ
556 return false;
557 }
558
017dc06b 559 if ( !::WriteConsole(m_hStderr, text.t_str(), text.length(), &ret, NULL) )
784ee7d5 560 {
9a83f860 561 wxLogLastError(wxT("WriteConsole"));
784ee7d5
VZ
562 return false;
563 }
564
565 WriteConsoleA(m_hStderr, m_data, m_dataLen, &ret, 0);
566
567 return true;
568}
569
570wxConsoleStderr s_consoleStderr;
571
572} // anonymous namespace
573
574bool wxGUIAppTraits::CanUseStderr()
575{
576 return s_consoleStderr.IsOkToUse();
577}
578
579bool wxGUIAppTraits::WriteToStderr(const wxString& text)
580{
581 return s_consoleStderr.IsOkToUse() && s_consoleStderr.Write(text);
582}
583
14ca3a3b
VZ
584#else // !wxUSE_DYNLIB_CLASS
585
586bool wxGUIAppTraits::CanUseStderr()
587{
588 return false;
589}
590
591bool wxGUIAppTraits::WriteToStderr(const wxString& WXUNUSED(text))
592{
593 return false;
594}
595
596#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
597
784ee7d5
VZ
598#endif // !__WXWINCE__
599
e2478fde
VZ
600// ===========================================================================
601// wxApp implementation
e5c0b16a 602// ===========================================================================
589f0e3e 603
94826170
VZ
604int wxApp::m_nCmdShow = SW_SHOWNORMAL;
605
e5c0b16a 606// ---------------------------------------------------------------------------
e2478fde 607// wxWin macros
e5c0b16a
VZ
608// ---------------------------------------------------------------------------
609
f6bcfd97 610IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
e5c0b16a 611
f6bcfd97
BP
612BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
613 EVT_IDLE(wxApp::OnIdle)
614 EVT_END_SESSION(wxApp::OnEndSession)
615 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
616END_EVENT_TABLE()
e5c0b16a 617
94826170
VZ
618// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
619// fails
620class wxCallBaseCleanup
621{
622public:
623 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
624 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
625
626 void Dismiss() { m_app = NULL; }
627
628private:
629 wxApp *m_app;
630};
631
e5c0b16a 632//// Initialize
05e2b077 633bool wxApp::Initialize(int& argc, wxChar **argv)
2bda0e17 634{
94826170
VZ
635 if ( !wxAppBase::Initialize(argc, argv) )
636 return false;
637
638 // ensure that base cleanup is done if we return too early
639 wxCallBaseCleanup callBaseCleanup(this);
640
a71d815b 641#if !defined(__WXMICROWIN__)
a5e0e655 642 InitCommonControls();
a71d815b 643#endif // !defined(__WXMICROWIN__)
2bda0e17 644
afafd942
JS
645#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
646 SHInitExtraControls();
647#endif
648
d5ea3919
JS
649#ifndef __WXWINCE__
650 // Don't show a message box if a function such as SHGetFileInfo
651 // fails to find a device.
652 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
653#endif
ad9835c9 654
360ae33f 655 wxOleInitialize();
2bda0e17 656
4676948b 657#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 658 wxSetKeyboardHook(true);
04ef50df 659#endif
2bda0e17 660
94826170
VZ
661 callBaseCleanup.Dismiss();
662
663 return true;
2bda0e17
KB
664}
665
42e69d6b 666// ---------------------------------------------------------------------------
d9698bd4 667// Win32 window class registration
42e69d6b 668// ---------------------------------------------------------------------------
589f0e3e 669
d9698bd4
VZ
670/* static */
671const wxChar *wxApp::GetRegisteredClassName(const wxChar *name,
672 int bgBrushCol,
673 int extraStyles)
bcbb1359 674{
d9698bd4
VZ
675 const size_t count = gs_regClassesInfo.size();
676 for ( size_t n = 0; n < count; n++ )
bcbb1359 677 {
563cf28f 678 if ( gs_regClassesInfo[n].regname == name )
64accea5 679 return gs_regClassesInfo[n].regname.c_str();
bcbb1359 680 }
bcbb1359 681
d9698bd4 682 // we need to register this class
42e69d6b 683 WNDCLASS wndclass;
03baf031 684 wxZeroMemory(wndclass);
e5c0b16a 685
e5c0b16a 686 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
5431e4a6 687 wndclass.hInstance = wxGetInstance();
d9698bd4
VZ
688 wndclass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
689 wndclass.hbrBackground = (HBRUSH)wxUIntToPtr(bgBrushCol + 1);
690 wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | extraStyles;
691
692
563cf28f 693 ClassRegInfo regClass(name);
017dc06b 694 wndclass.lpszClassName = regClass.regname.t_str();
d9698bd4 695 if ( !::RegisterClass(&wndclass) )
9787a4b6 696 {
d9698bd4
VZ
697 wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
698 regClass.regname));
699 return NULL;
700 }
9787a4b6 701
d9698bd4 702 wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW);
017dc06b 703 wndclass.lpszClassName = regClass.regnameNR.t_str();
d9698bd4
VZ
704 if ( !::RegisterClass(&wndclass) )
705 {
706 wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
707 regClass.regname));
5431e4a6 708 ::UnregisterClass(regClass.regname.c_str(), wxGetInstance());
d9698bd4 709 return NULL;
9787a4b6
VZ
710 }
711
d9698bd4 712 gs_regClassesInfo.push_back(regClass);
9787a4b6 713
d9698bd4
VZ
714 // take care to return the pointer which will remain valid after the
715 // function returns (it could be invalidated later if new elements are
716 // added to the vector and it's reallocated but this shouldn't matter as
717 // this pointer should be used right now, not stored)
017dc06b 718 return gs_regClassesInfo.back().regname.t_str();
bcbb1359 719}
9787a4b6 720
d9698bd4 721bool wxApp::IsRegisteredClassName(const wxString& name)
bcbb1359 722{
d9698bd4
VZ
723 const size_t count = gs_regClassesInfo.size();
724 for ( size_t n = 0; n < count; n++ )
725 {
726 if ( gs_regClassesInfo[n].regname == name ||
727 gs_regClassesInfo[n].regnameNR == name )
728 return true;
729 }
9787a4b6 730
d9698bd4
VZ
731 return false;
732}
9787a4b6 733
d9698bd4
VZ
734void wxApp::UnregisterWindowClasses()
735{
736 const size_t count = gs_regClassesInfo.size();
737 for ( size_t n = 0; n < count; n++ )
738 {
739 const ClassRegInfo& regClass = gs_regClassesInfo[n];
5431e4a6 740 if ( !::UnregisterClass(regClass.regname.c_str(), wxGetInstance()) )
d9698bd4
VZ
741 {
742 wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
743 regClass.regname));
744 }
9787a4b6 745
5431e4a6 746 if ( !::UnregisterClass(regClass.regnameNR.c_str(), wxGetInstance()) )
d9698bd4
VZ
747 {
748 wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
749 regClass.regnameNR));
750 }
751 }
03baf031 752
d9698bd4 753 gs_regClassesInfo.clear();
9787a4b6
VZ
754}
755
bb6290e3 756void wxApp::CleanUp()
2bda0e17 757{
dca0f651
VZ
758 // all objects pending for deletion must be deleted first, otherwise
759 // UnregisterWindowClasses() call wouldn't succeed (because windows
760 // using the classes being unregistered still exist), so call the base
761 // class method first and only then do our clean up
7a9dfa3c
VZ
762 wxAppBase::CleanUp();
763
4676948b 764#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 765 wxSetKeyboardHook(false);
04ef50df 766#endif
2bda0e17 767
360ae33f 768 wxOleUninitialize();
2bda0e17 769
9787a4b6
VZ
770 // for an EXE the classes are unregistered when it terminates but DLL may
771 // be loaded several times (load/unload/load) into the same process in
772 // which case the registration will fail after the first time if we don't
773 // unregister the classes now
774 UnregisterWindowClasses();
2bda0e17
KB
775}
776
94826170
VZ
777// ----------------------------------------------------------------------------
778// wxApp ctor/dtor
779// ----------------------------------------------------------------------------
589f0e3e 780
bb6290e3 781wxApp::wxApp()
2bda0e17 782{
e5c0b16a 783 m_printMode = wxPRINT_WINDOWS;
2bda0e17
KB
784}
785
589f0e3e
JS
786wxApp::~wxApp()
787{
589f0e3e
JS
788}
789
6046e57a
VZ
790// ----------------------------------------------------------------------------
791// wxApp idle handling
792// ----------------------------------------------------------------------------
793
cb3c7fdd 794void wxApp::OnIdle(wxIdleEvent& WXUNUSED(event))
2bda0e17 795{
aef94d68
JS
796#if wxUSE_DC_CACHEING
797 // automated DC cache management: clear the cached DCs and bitmap
798 // if it's likely that the app has finished with them, that is, we
799 // get an idle event and we're not dragging anything.
4624defa 800 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
888dde65 801 wxMSWDCImpl::ClearCache();
aef94d68 802#endif // wxUSE_DC_CACHEING
2bda0e17
KB
803}
804
e2478fde
VZ
805void wxApp::WakeUpIdle()
806{
807 // Send the top window a dummy message so idle handler processing will
808 // start up again. Doing it this way ensures that the idle handler
809 // wakes up in the right thread (see also wxWakeUpMainThread() which does
810 // the same for the main app thread only)
1a18f241 811 wxWindow * const topWindow = wxTheApp->GetTopWindow();
e2478fde
VZ
812 if ( topWindow )
813 {
1a18f241
VZ
814 HWND hwndTop = GetHwndOf(topWindow);
815
816 // Do not post WM_NULL if there's already a pending WM_NULL to avoid
817 // overflowing the message queue.
818 //
819 // Notice that due to a limitation of PeekMessage() API (which handles
820 // 0,0 range specially), we have to check the range from 0-1 instead.
821 // This still makes it possible to overflow the queue with WM_NULLs by
822 // interspersing the calles to WakeUpIdle() with windows creation but
823 // it should be rather hard to do it accidentally.
824 MSG msg;
825 if ( !::PeekMessage(&msg, hwndTop, 0, 1, PM_NOREMOVE) ||
826 ::PeekMessage(&msg, hwndTop, 1, 1, PM_NOREMOVE) )
e2478fde 827 {
1a18f241
VZ
828 if ( !::PostMessage(hwndTop, WM_NULL, 0, 0) )
829 {
830 // should never happen
831 wxLogLastError(wxT("PostMessage(WM_NULL)"));
832 }
e2478fde
VZ
833 }
834 }
4a00d37c
JS
835#if wxUSE_THREADS
836 else
837 wxWakeUpMainThread();
838#endif // wxUSE_THREADS
e2478fde
VZ
839}
840
6046e57a
VZ
841// ----------------------------------------------------------------------------
842// other wxApp event hanlders
843// ----------------------------------------------------------------------------
844
57c208c5 845void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
387a3b02 846{
9fb99466 847 // Windows will terminate the process soon after we return from
8c6dcbd0
VZ
848 // WM_ENDSESSION handler or when we delete our last window, so make sure we
849 // at least execute our cleanup code before
850
851 // prevent the window from being destroyed when the corresponding wxTLW is
852 // destroyed: this will result in a leak of a HWND, of course, but who
853 // cares when the process is being killed anyhow
854 if ( !wxTopLevelWindows.empty() )
855 wxTopLevelWindows[0]->SetHWND(0);
856
9fb99466
VZ
857 const int rc = OnExit();
858
859 wxEntryCleanup();
860
861 // calling exit() instead of ExitProcess() or not doing anything at all and
862 // being killed by Windows has the advantage of executing the dtors of
863 // global objects
864 exit(rc);
387a3b02
JS
865}
866
867// Default behaviour: close the application with prompts. The
868// user can veto the close, and therefore the end session.
869void wxApp::OnQueryEndSession(wxCloseEvent& event)
870{
871 if (GetTopWindow())
872 {
873 if (!GetTopWindow()->Close(!event.CanVeto()))
77c46f00 874 event.Veto(true);
387a3b02
JS
875 }
876}
877
6046e57a 878// ----------------------------------------------------------------------------
5e9b921d 879// system DLL versions
6046e57a
VZ
880// ----------------------------------------------------------------------------
881
6b4296f7
VZ
882// these functions have trivial inline implementations for CE
883#ifndef __WXWINCE__
884
5e9b921d
VZ
885#if wxUSE_DYNLIB_CLASS
886
887namespace
888{
889
890// helper function: retrieve the DLL version by using DllGetVersion(), returns
891// 0 if the DLL doesn't export such function
892int CallDllGetVersion(wxDynamicLibrary& dll)
893{
894 // now check if the function is available during run-time
895 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dll );
896 if ( !pfnDllGetVersion )
897 return 0;
898
899 DLLVERSIONINFO dvi;
900 dvi.cbSize = sizeof(dvi);
901
902 HRESULT hr = (*pfnDllGetVersion)(&dvi);
903 if ( FAILED(hr) )
904 {
9a83f860 905 wxLogApiError(wxT("DllGetVersion"), hr);
5e9b921d
VZ
906
907 return 0;
908 }
909
910 return 100*dvi.dwMajorVersion + dvi.dwMinorVersion;
911}
912
913} // anonymous namespace
914
6d167489
VZ
915/* static */
916int wxApp::GetComCtl32Version()
917{
6d167489 918 // cache the result
9fc6c21c
VZ
919 //
920 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
921 // but as its value should be the same both times it doesn't matter
bdc72a22
VZ
922 static int s_verComCtl32 = -1;
923
6d167489
VZ
924 if ( s_verComCtl32 == -1 )
925 {
9fc6c21c
VZ
926 // we're prepared to handle the errors
927 wxLogNull noLog;
ad9835c9 928
e2d4ce7d
VZ
929 // we don't want to load comctl32.dll, it should be already loaded but,
930 // depending on the OS version and the presence of the manifest, it can
931 // be either v5 or v6 and instead of trying to guess it just get the
932 // handle of the already loaded version
9a83f860 933 wxLoadedDLL dllComCtl32(wxT("comctl32.dll"));
5e9b921d
VZ
934 if ( !dllComCtl32.IsLoaded() )
935 {
936 s_verComCtl32 = 0;
937 return 0;
938 }
6d167489 939
5e9b921d
VZ
940 // try DllGetVersion() for recent DLLs
941 s_verComCtl32 = CallDllGetVersion(dllComCtl32);
942
943 // if DllGetVersion() is unavailable either during compile or
944 // run-time, try to guess the version otherwise
945 if ( !s_verComCtl32 )
bb6290e3 946 {
5e9b921d 947 // InitCommonControlsEx is unique to 4.70 and later
9a83f860 948 void *pfn = dllComCtl32.GetSymbol(wxT("InitCommonControlsEx"));
5e9b921d 949 if ( !pfn )
9fc6c21c 950 {
5e9b921d
VZ
951 // not found, must be 4.00
952 s_verComCtl32 = 400;
9fc6c21c 953 }
5e9b921d 954 else // 4.70+
9fc6c21c 955 {
5e9b921d
VZ
956 // many symbols appeared in comctl32 4.71, could use any of
957 // them except may be DllInstall()
9a83f860 958 pfn = dllComCtl32.GetSymbol(wxT("InitializeFlatSB"));
9fc6c21c
VZ
959 if ( !pfn )
960 {
5e9b921d
VZ
961 // not found, must be 4.70
962 s_verComCtl32 = 470;
6d167489 963 }
5e9b921d 964 else
bdc72a22 965 {
5e9b921d
VZ
966 // found, must be 4.71 or later
967 s_verComCtl32 = 471;
6d167489 968 }
9fc6c21c 969 }
ef094fa0 970 }
bb6290e3 971 }
6d167489
VZ
972
973 return s_verComCtl32;
bb6290e3
JS
974}
975
5e9b921d
VZ
976/* static */
977int wxApp::GetShell32Version()
978{
979 static int s_verShell32 = -1;
980 if ( s_verShell32 == -1 )
981 {
982 // we're prepared to handle the errors
983 wxLogNull noLog;
984
9a83f860 985 wxDynamicLibrary dllShell32(wxT("shell32.dll"), wxDL_VERBATIM);
5e9b921d
VZ
986 if ( dllShell32.IsLoaded() )
987 {
988 s_verShell32 = CallDllGetVersion(dllShell32);
989
990 if ( !s_verShell32 )
991 {
992 // there doesn't seem to be any way to distinguish between 4.00
993 // and 4.70 (starting from 4.71 we have DllGetVersion()) so
994 // just assume it is 4.0
995 s_verShell32 = 400;
996 }
997 }
998 else // failed load the DLL?
999 {
1000 s_verShell32 = 0;
1001 }
1002 }
1003
1004 return s_verShell32;
1005}
1006
1007#else // !wxUSE_DYNLIB_CLASS
1008
1009/* static */
1010int wxApp::GetComCtl32Version()
1011{
1012 return 0;
1013}
1014
1015/* static */
1016int wxApp::GetShell32Version()
1017{
1018 return 0;
1019}
1020
1021#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
1022
6b4296f7
VZ
1023#endif // !__WXWINCE__
1024
6046e57a
VZ
1025#if wxUSE_EXCEPTIONS
1026
1027// ----------------------------------------------------------------------------
1028// exception handling
1029// ----------------------------------------------------------------------------
1030
1031bool wxApp::OnExceptionInMainLoop()
1032{
1033 // ask the user about what to do: use the Win32 API function here as it
77ffb593 1034 // could be dangerous to use any wxWidgets code in this state
6046e57a
VZ
1035 switch (
1036 ::MessageBox
1037 (
1038 NULL,
9a83f860 1039 wxT("An unhandled exception occurred. Press \"Abort\" to \
6046e57a
VZ
1040terminate the program,\r\n\
1041\"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
9a83f860 1042 wxT("Unhandled exception"),
6046e57a 1043 MB_ABORTRETRYIGNORE |
a71d815b 1044 MB_ICONERROR|
6046e57a
VZ
1045 MB_TASKMODAL
1046 )
1047 )
1048 {
1049 case IDABORT:
1050 throw;
1051
1052 default:
9a83f860 1053 wxFAIL_MSG( wxT("unexpected MessageBox() return code") );
6046e57a
VZ
1054 // fall through
1055
1056 case IDRETRY:
1057 return false;
1058
1059 case IDIGNORE:
1060 return true;
1061 }
1062}
1063
1064#endif // wxUSE_EXCEPTIONS