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