]> git.saurik.com Git - wxWidgets.git/blame - src/msw/app.cpp
adding missing newline at end of file
[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
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}
261
8bb6b2c0 262wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const
a8eaaeb2 263{
8bb6b2c0
VZ
264 OSVERSIONINFO info;
265 wxZeroMemory(info);
266
267 // on Windows, the toolkit version is the same of the OS version
268 // as Windows integrates the OS kernel with the GUI toolkit.
269 info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
270 if ( ::GetVersionEx(&info) )
271 {
272 if ( majVer )
273 *majVer = info.dwMajorVersion;
274 if ( minVer )
275 *minVer = info.dwMinorVersion;
276 }
277
278#if defined(__WXHANDHELD__) || defined(__WXWINCE__)
279 return wxPORT_WINCE;
280#else
281 return wxPORT_MSW;
a8eaaeb2 282#endif
a8eaaeb2
VS
283}
284
a8ff046b
VZ
285#if wxUSE_TIMER
286
b46b1d59 287wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
c2ca375c 288{
b46b1d59
VZ
289 return new wxMSWTimerImpl(timer);
290}
291
a8ff046b
VZ
292#endif // wxUSE_TIMER
293
2ddff00c 294wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
b46b1d59
VZ
295{
296 return new wxEventLoop;
5d262fdd 297}
c2ca375c 298
784ee7d5
VZ
299// ---------------------------------------------------------------------------
300// Stuff for using console from the GUI applications
301// ---------------------------------------------------------------------------
302
303#ifndef __WXWINCE__
304
14ca3a3b
VZ
305#if wxUSE_DYNLIB_CLASS
306
784ee7d5
VZ
307#include <wx/dynlib.h>
308
309namespace
310{
311
312/*
313 Helper class to manipulate console from a GUI app.
314
315 Notice that console output is available in the GUI app only if:
316 - AttachConsole() returns TRUE (which means it never works under pre-XP)
317 - we have a valid STD_ERROR_HANDLE
318 - command history hasn't been changed since our startup
319
320 To check if all these conditions are verified, you need to simple call
321 IsOkToUse(). It will check the first two conditions above the first time it
322 is called (and if this fails, the subsequent calls will return immediately)
323 and also recheck the last one every time it is called.
324 */
325class wxConsoleStderr
326{
327public:
328 // default ctor does nothing, call Init() before using this class
329 wxConsoleStderr()
330 {
331 m_hStderr = INVALID_HANDLE_VALUE;
332 m_historyLen =
333 m_dataLen =
334 m_dataLine = 0;
335
336 m_ok = -1;
337 }
338
339 ~wxConsoleStderr()
340 {
341 if ( m_hStderr != INVALID_HANDLE_VALUE )
342 {
343 if ( !::FreeConsole() )
344 {
9a83f860 345 wxLogLastError(wxT("FreeConsole"));
784ee7d5
VZ
346 }
347 }
348 }
349
350 // return true if we were successfully initialized and there had been no
351 // console activity which would interfere with our output since then
352 bool IsOkToUse() const
353 {
354 if ( m_ok == -1 )
355 {
5c33522f 356 wxConsoleStderr * const self = const_cast<wxConsoleStderr *>(this);
784ee7d5
VZ
357 self->m_ok = self->DoInit();
358
359 // no need to call IsHistoryUnchanged() as we just initialized
360 // m_history anyhow
361 return m_ok == 1;
362 }
363
364 return m_ok && IsHistoryUnchanged();
365 }
366
367
368 // output the provided text on the console, return true if ok
369 bool Write(const wxString& text);
370
371private:
372 // called by Init() once only to do the real initialization
373 bool DoInit();
374
375 // retrieve the command line history into the provided buffer and return
376 // its length
377 int GetCommandHistory(wxWxCharBuffer& buf) const;
378
379 // check if the console history has changed
380 bool IsHistoryUnchanged() const;
381
382 int m_ok; // initially -1, set to true or false by Init()
383
384 wxDynamicLibrary m_dllKernel32;
385
386 HANDLE m_hStderr; // console handle, if it's valid we must call
387 // FreeConsole() (even if m_ok != 1)
388
389 wxWxCharBuffer m_history; // command history on startup
390 int m_historyLen; // length command history buffer
391
392 wxCharBuffer m_data; // data between empty line and cursor position
393 int m_dataLen; // length data buffer
394 int m_dataLine; // line offset
395
396 typedef DWORD (WINAPI *GetConsoleCommandHistory_t)(LPTSTR sCommands,
397 DWORD nBufferLength,
398 LPCTSTR sExeName);
399 typedef DWORD (WINAPI *GetConsoleCommandHistoryLength_t)(LPCTSTR sExeName);
400
401 GetConsoleCommandHistory_t m_pfnGetConsoleCommandHistory;
402 GetConsoleCommandHistoryLength_t m_pfnGetConsoleCommandHistoryLength;
403
c0c133e1 404 wxDECLARE_NO_COPY_CLASS(wxConsoleStderr);
784ee7d5
VZ
405};
406
407bool wxConsoleStderr::DoInit()
408{
409 HANDLE hStderr = ::GetStdHandle(STD_ERROR_HANDLE);
410
411 if ( hStderr == INVALID_HANDLE_VALUE || !hStderr )
412 return false;
413
9a83f860 414 if ( !m_dllKernel32.Load(wxT("kernel32.dll")) )
784ee7d5
VZ
415 return false;
416
417 typedef BOOL (WINAPI *AttachConsole_t)(DWORD dwProcessId);
418 AttachConsole_t wxDL_INIT_FUNC(pfn, AttachConsole, m_dllKernel32);
419
420 if ( !pfnAttachConsole || !pfnAttachConsole(ATTACH_PARENT_PROCESS) )
421 return false;
422
423 // console attached, set m_hStderr now to ensure that we free it in the
424 // dtor
425 m_hStderr = hStderr;
426
427 wxDL_INIT_FUNC_AW(m_pfn, GetConsoleCommandHistory, m_dllKernel32);
428 if ( !m_pfnGetConsoleCommandHistory )
429 return false;
430
431 wxDL_INIT_FUNC_AW(m_pfn, GetConsoleCommandHistoryLength, m_dllKernel32);
432 if ( !m_pfnGetConsoleCommandHistoryLength )
433 return false;
434
435 // remember the current command history to be able to compare with it later
436 // in IsHistoryUnchanged()
437 m_historyLen = GetCommandHistory(m_history);
438 if ( !m_history )
439 return false;
440
441
442 // now find the first blank line above the current position
443 CONSOLE_SCREEN_BUFFER_INFO csbi;
444
445 if ( !::GetConsoleScreenBufferInfo(m_hStderr, &csbi) )
446 {
9a83f860 447 wxLogLastError(wxT("GetConsoleScreenBufferInfo"));
784ee7d5
VZ
448 return false;
449 }
450
451 COORD pos;
452 pos.X = 0;
453 pos.Y = csbi.dwCursorPosition.Y + 1;
454
455 // we decide that a line is empty if first 4 characters are spaces
456 DWORD ret;
457 char buf[4];
458 do
459 {
460 pos.Y--;
461 if ( !::ReadConsoleOutputCharacterA(m_hStderr, buf, WXSIZEOF(buf),
462 pos, &ret) )
463 {
9a83f860 464 wxLogLastError(wxT("ReadConsoleOutputCharacterA"));
784ee7d5
VZ
465 return false;
466 }
467 } while ( wxStrncmp(" ", buf, WXSIZEOF(buf)) != 0 );
468
469 // calculate line offset and length of data
470 m_dataLine = csbi.dwCursorPosition.Y - pos.Y;
471 m_dataLen = m_dataLine*csbi.dwMaximumWindowSize.X + csbi.dwCursorPosition.X;
472
473 if ( m_dataLen > 0 )
474 {
475 m_data.extend(m_dataLen);
476 if ( !::ReadConsoleOutputCharacterA(m_hStderr, m_data.data(), m_dataLen,
477 pos, &ret) )
478 {
9a83f860 479 wxLogLastError(wxT("ReadConsoleOutputCharacterA"));
784ee7d5
VZ
480 return false;
481 }
482 }
483
484 return true;
485}
486
487int wxConsoleStderr::GetCommandHistory(wxWxCharBuffer& buf) const
488{
489 // these functions are internal and may only be called by cmd.exe
9a83f860 490 static const wxChar *CMD_EXE = wxT("cmd.exe");
784ee7d5
VZ
491
492 const int len = m_pfnGetConsoleCommandHistoryLength(CMD_EXE);
493 if ( len )
494 {
495 buf.extend(len);
1033a7cc
VZ
496
497 int len2 = m_pfnGetConsoleCommandHistory(buf.data(), len, CMD_EXE);
498
499#if !wxUSE_UNICODE
500 // there seems to be a bug in the GetConsoleCommandHistoryA(), it
501 // returns the length of Unicode string and not ANSI one
502 len2 /= 2;
503#endif // !wxUSE_UNICODE
504
575cabba
VZ
505 if ( len2 != len )
506 {
9a83f860 507 wxFAIL_MSG( wxT("failed getting history?") );
575cabba 508 }
784ee7d5
VZ
509 }
510
511 return len;
512}
513
514bool wxConsoleStderr::IsHistoryUnchanged() const
515{
9a83f860 516 wxASSERT_MSG( m_ok == 1, wxT("shouldn't be called if not initialized") );
784ee7d5
VZ
517
518 // get (possibly changed) command history
519 wxWxCharBuffer history;
520 const int historyLen = GetCommandHistory(history);
521
522 // and compare it with the original one
523 return historyLen == m_historyLen && history &&
524 memcmp(m_history, history, historyLen) == 0;
525}
526
527bool wxConsoleStderr::Write(const wxString& text)
528{
529 wxASSERT_MSG( m_hStderr != INVALID_HANDLE_VALUE,
9a83f860 530 wxT("should only be called if Init() returned true") );
784ee7d5
VZ
531
532 // get current position
533 CONSOLE_SCREEN_BUFFER_INFO csbi;
534 if ( !::GetConsoleScreenBufferInfo(m_hStderr, &csbi) )
535 {
9a83f860 536 wxLogLastError(wxT("GetConsoleScreenBufferInfo"));
784ee7d5
VZ
537 return false;
538 }
539
540 // and calculate new position (where is empty line)
541 csbi.dwCursorPosition.X = 0;
542 csbi.dwCursorPosition.Y -= m_dataLine;
543
544 if ( !::SetConsoleCursorPosition(m_hStderr, csbi.dwCursorPosition) )
545 {
9a83f860 546 wxLogLastError(wxT("SetConsoleCursorPosition"));
784ee7d5
VZ
547 return false;
548 }
549
550 DWORD ret;
9a83f860 551 if ( !::FillConsoleOutputCharacter(m_hStderr, wxT(' '), m_dataLen,
784ee7d5
VZ
552 csbi.dwCursorPosition, &ret) )
553 {
9a83f860 554 wxLogLastError(wxT("FillConsoleOutputCharacter"));
784ee7d5
VZ
555 return false;
556 }
557
558 if ( !::WriteConsole(m_hStderr, text.wx_str(), text.length(), &ret, NULL) )
559 {
9a83f860 560 wxLogLastError(wxT("WriteConsole"));
784ee7d5
VZ
561 return false;
562 }
563
564 WriteConsoleA(m_hStderr, m_data, m_dataLen, &ret, 0);
565
566 return true;
567}
568
569wxConsoleStderr s_consoleStderr;
570
571} // anonymous namespace
572
573bool wxGUIAppTraits::CanUseStderr()
574{
575 return s_consoleStderr.IsOkToUse();
576}
577
578bool wxGUIAppTraits::WriteToStderr(const wxString& text)
579{
580 return s_consoleStderr.IsOkToUse() && s_consoleStderr.Write(text);
581}
582
14ca3a3b
VZ
583#else // !wxUSE_DYNLIB_CLASS
584
585bool wxGUIAppTraits::CanUseStderr()
586{
587 return false;
588}
589
590bool wxGUIAppTraits::WriteToStderr(const wxString& WXUNUSED(text))
591{
592 return false;
593}
594
595#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
596
784ee7d5
VZ
597#endif // !__WXWINCE__
598
e2478fde
VZ
599// ===========================================================================
600// wxApp implementation
e5c0b16a 601// ===========================================================================
589f0e3e 602
94826170
VZ
603int wxApp::m_nCmdShow = SW_SHOWNORMAL;
604
e5c0b16a 605// ---------------------------------------------------------------------------
e2478fde 606// wxWin macros
e5c0b16a
VZ
607// ---------------------------------------------------------------------------
608
f6bcfd97 609IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
e5c0b16a 610
f6bcfd97
BP
611BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
612 EVT_IDLE(wxApp::OnIdle)
613 EVT_END_SESSION(wxApp::OnEndSession)
614 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
615END_EVENT_TABLE()
e5c0b16a 616
94826170
VZ
617// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
618// fails
619class wxCallBaseCleanup
620{
621public:
622 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
623 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
624
625 void Dismiss() { m_app = NULL; }
626
627private:
628 wxApp *m_app;
629};
630
e5c0b16a 631//// Initialize
05e2b077 632bool wxApp::Initialize(int& argc, wxChar **argv)
2bda0e17 633{
94826170
VZ
634 if ( !wxAppBase::Initialize(argc, argv) )
635 return false;
636
637 // ensure that base cleanup is done if we return too early
638 wxCallBaseCleanup callBaseCleanup(this);
639
a71d815b 640#if !defined(__WXMICROWIN__)
a5e0e655 641 InitCommonControls();
a71d815b 642#endif // !defined(__WXMICROWIN__)
2bda0e17 643
afafd942
JS
644#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
645 SHInitExtraControls();
646#endif
647
d5ea3919
JS
648#ifndef __WXWINCE__
649 // Don't show a message box if a function such as SHGetFileInfo
650 // fails to find a device.
651 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
652#endif
ad9835c9 653
360ae33f 654 wxOleInitialize();
2bda0e17 655
4676948b 656#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 657 wxSetKeyboardHook(true);
04ef50df 658#endif
2bda0e17 659
94826170
VZ
660 callBaseCleanup.Dismiss();
661
662 return true;
2bda0e17
KB
663}
664
42e69d6b 665// ---------------------------------------------------------------------------
d9698bd4 666// Win32 window class registration
42e69d6b 667// ---------------------------------------------------------------------------
589f0e3e 668
d9698bd4
VZ
669/* static */
670const wxChar *wxApp::GetRegisteredClassName(const wxChar *name,
671 int bgBrushCol,
672 int extraStyles)
bcbb1359 673{
d9698bd4
VZ
674 const size_t count = gs_regClassesInfo.size();
675 for ( size_t n = 0; n < count; n++ )
bcbb1359 676 {
563cf28f 677 if ( gs_regClassesInfo[n].regname == name )
64accea5 678 return gs_regClassesInfo[n].regname.c_str();
bcbb1359 679 }
bcbb1359 680
d9698bd4 681 // we need to register this class
42e69d6b 682 WNDCLASS wndclass;
03baf031 683 wxZeroMemory(wndclass);
e5c0b16a 684
e5c0b16a 685 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
5431e4a6 686 wndclass.hInstance = wxGetInstance();
d9698bd4
VZ
687 wndclass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
688 wndclass.hbrBackground = (HBRUSH)wxUIntToPtr(bgBrushCol + 1);
689 wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | extraStyles;
690
691
563cf28f 692 ClassRegInfo regClass(name);
d9698bd4
VZ
693 wndclass.lpszClassName = regClass.regname.wx_str();
694 if ( !::RegisterClass(&wndclass) )
9787a4b6 695 {
d9698bd4
VZ
696 wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
697 regClass.regname));
698 return NULL;
699 }
9787a4b6 700
d9698bd4
VZ
701 wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW);
702 wndclass.lpszClassName = regClass.regnameNR.wx_str();
703 if ( !::RegisterClass(&wndclass) )
704 {
705 wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
706 regClass.regname));
5431e4a6 707 ::UnregisterClass(regClass.regname.c_str(), wxGetInstance());
d9698bd4 708 return NULL;
9787a4b6
VZ
709 }
710
d9698bd4 711 gs_regClassesInfo.push_back(regClass);
9787a4b6 712
d9698bd4
VZ
713 // take care to return the pointer which will remain valid after the
714 // function returns (it could be invalidated later if new elements are
715 // added to the vector and it's reallocated but this shouldn't matter as
716 // this pointer should be used right now, not stored)
717 return gs_regClassesInfo.back().regname.wx_str();
bcbb1359 718}
9787a4b6 719
d9698bd4 720bool wxApp::IsRegisteredClassName(const wxString& name)
bcbb1359 721{
d9698bd4
VZ
722 const size_t count = gs_regClassesInfo.size();
723 for ( size_t n = 0; n < count; n++ )
724 {
725 if ( gs_regClassesInfo[n].regname == name ||
726 gs_regClassesInfo[n].regnameNR == name )
727 return true;
728 }
9787a4b6 729
d9698bd4
VZ
730 return false;
731}
9787a4b6 732
d9698bd4
VZ
733void wxApp::UnregisterWindowClasses()
734{
735 const size_t count = gs_regClassesInfo.size();
736 for ( size_t n = 0; n < count; n++ )
737 {
738 const ClassRegInfo& regClass = gs_regClassesInfo[n];
5431e4a6 739 if ( !::UnregisterClass(regClass.regname.c_str(), wxGetInstance()) )
d9698bd4
VZ
740 {
741 wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
742 regClass.regname));
743 }
9787a4b6 744
5431e4a6 745 if ( !::UnregisterClass(regClass.regnameNR.c_str(), wxGetInstance()) )
d9698bd4
VZ
746 {
747 wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
748 regClass.regnameNR));
749 }
750 }
03baf031 751
d9698bd4 752 gs_regClassesInfo.clear();
9787a4b6
VZ
753}
754
bb6290e3 755void wxApp::CleanUp()
2bda0e17 756{
dca0f651
VZ
757 // all objects pending for deletion must be deleted first, otherwise
758 // UnregisterWindowClasses() call wouldn't succeed (because windows
759 // using the classes being unregistered still exist), so call the base
760 // class method first and only then do our clean up
7a9dfa3c
VZ
761 wxAppBase::CleanUp();
762
4676948b 763#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
77c46f00 764 wxSetKeyboardHook(false);
04ef50df 765#endif
2bda0e17 766
360ae33f 767 wxOleUninitialize();
2bda0e17 768
9787a4b6
VZ
769 // for an EXE the classes are unregistered when it terminates but DLL may
770 // be loaded several times (load/unload/load) into the same process in
771 // which case the registration will fail after the first time if we don't
772 // unregister the classes now
773 UnregisterWindowClasses();
2bda0e17
KB
774}
775
94826170
VZ
776// ----------------------------------------------------------------------------
777// wxApp ctor/dtor
778// ----------------------------------------------------------------------------
589f0e3e 779
bb6290e3 780wxApp::wxApp()
2bda0e17 781{
e5c0b16a 782 m_printMode = wxPRINT_WINDOWS;
2bda0e17
KB
783}
784
589f0e3e
JS
785wxApp::~wxApp()
786{
589f0e3e
JS
787}
788
6046e57a
VZ
789// ----------------------------------------------------------------------------
790// wxApp idle handling
791// ----------------------------------------------------------------------------
792
cb3c7fdd 793void wxApp::OnIdle(wxIdleEvent& WXUNUSED(event))
2bda0e17 794{
aef94d68
JS
795#if wxUSE_DC_CACHEING
796 // automated DC cache management: clear the cached DCs and bitmap
797 // if it's likely that the app has finished with them, that is, we
798 // get an idle event and we're not dragging anything.
4624defa 799 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
888dde65 800 wxMSWDCImpl::ClearCache();
aef94d68 801#endif // wxUSE_DC_CACHEING
2bda0e17
KB
802}
803
e2478fde
VZ
804void wxApp::WakeUpIdle()
805{
806 // Send the top window a dummy message so idle handler processing will
807 // start up again. Doing it this way ensures that the idle handler
808 // wakes up in the right thread (see also wxWakeUpMainThread() which does
809 // the same for the main app thread only)
1a18f241 810 wxWindow * const topWindow = wxTheApp->GetTopWindow();
e2478fde
VZ
811 if ( topWindow )
812 {
1a18f241
VZ
813 HWND hwndTop = GetHwndOf(topWindow);
814
815 // Do not post WM_NULL if there's already a pending WM_NULL to avoid
816 // overflowing the message queue.
817 //
818 // Notice that due to a limitation of PeekMessage() API (which handles
819 // 0,0 range specially), we have to check the range from 0-1 instead.
820 // This still makes it possible to overflow the queue with WM_NULLs by
821 // interspersing the calles to WakeUpIdle() with windows creation but
822 // it should be rather hard to do it accidentally.
823 MSG msg;
824 if ( !::PeekMessage(&msg, hwndTop, 0, 1, PM_NOREMOVE) ||
825 ::PeekMessage(&msg, hwndTop, 1, 1, PM_NOREMOVE) )
e2478fde 826 {
1a18f241
VZ
827 if ( !::PostMessage(hwndTop, WM_NULL, 0, 0) )
828 {
829 // should never happen
830 wxLogLastError(wxT("PostMessage(WM_NULL)"));
831 }
e2478fde
VZ
832 }
833 }
4a00d37c
JS
834#if wxUSE_THREADS
835 else
836 wxWakeUpMainThread();
837#endif // wxUSE_THREADS
e2478fde
VZ
838}
839
6046e57a
VZ
840// ----------------------------------------------------------------------------
841// other wxApp event hanlders
842// ----------------------------------------------------------------------------
843
57c208c5 844void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
387a3b02 845{
9fb99466 846 // Windows will terminate the process soon after we return from
8c6dcbd0
VZ
847 // WM_ENDSESSION handler or when we delete our last window, so make sure we
848 // at least execute our cleanup code before
849
850 // prevent the window from being destroyed when the corresponding wxTLW is
851 // destroyed: this will result in a leak of a HWND, of course, but who
852 // cares when the process is being killed anyhow
853 if ( !wxTopLevelWindows.empty() )
854 wxTopLevelWindows[0]->SetHWND(0);
855
9fb99466
VZ
856 const int rc = OnExit();
857
858 wxEntryCleanup();
859
860 // calling exit() instead of ExitProcess() or not doing anything at all and
861 // being killed by Windows has the advantage of executing the dtors of
862 // global objects
863 exit(rc);
387a3b02
JS
864}
865
866// Default behaviour: close the application with prompts. The
867// user can veto the close, and therefore the end session.
868void wxApp::OnQueryEndSession(wxCloseEvent& event)
869{
870 if (GetTopWindow())
871 {
872 if (!GetTopWindow()->Close(!event.CanVeto()))
77c46f00 873 event.Veto(true);
387a3b02
JS
874 }
875}
876
6046e57a 877// ----------------------------------------------------------------------------
5e9b921d 878// system DLL versions
6046e57a
VZ
879// ----------------------------------------------------------------------------
880
6b4296f7
VZ
881// these functions have trivial inline implementations for CE
882#ifndef __WXWINCE__
883
5e9b921d
VZ
884#if wxUSE_DYNLIB_CLASS
885
886namespace
887{
888
889// helper function: retrieve the DLL version by using DllGetVersion(), returns
890// 0 if the DLL doesn't export such function
891int CallDllGetVersion(wxDynamicLibrary& dll)
892{
893 // now check if the function is available during run-time
894 wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dll );
895 if ( !pfnDllGetVersion )
896 return 0;
897
898 DLLVERSIONINFO dvi;
899 dvi.cbSize = sizeof(dvi);
900
901 HRESULT hr = (*pfnDllGetVersion)(&dvi);
902 if ( FAILED(hr) )
903 {
9a83f860 904 wxLogApiError(wxT("DllGetVersion"), hr);
5e9b921d
VZ
905
906 return 0;
907 }
908
909 return 100*dvi.dwMajorVersion + dvi.dwMinorVersion;
910}
911
912} // anonymous namespace
913
6d167489
VZ
914/* static */
915int wxApp::GetComCtl32Version()
916{
6d167489 917 // cache the result
9fc6c21c
VZ
918 //
919 // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
920 // but as its value should be the same both times it doesn't matter
bdc72a22
VZ
921 static int s_verComCtl32 = -1;
922
6d167489
VZ
923 if ( s_verComCtl32 == -1 )
924 {
9fc6c21c
VZ
925 // we're prepared to handle the errors
926 wxLogNull noLog;
ad9835c9 927
e2d4ce7d
VZ
928 // we don't want to load comctl32.dll, it should be already loaded but,
929 // depending on the OS version and the presence of the manifest, it can
930 // be either v5 or v6 and instead of trying to guess it just get the
931 // handle of the already loaded version
9a83f860 932 wxLoadedDLL dllComCtl32(wxT("comctl32.dll"));
5e9b921d
VZ
933 if ( !dllComCtl32.IsLoaded() )
934 {
935 s_verComCtl32 = 0;
936 return 0;
937 }
6d167489 938
5e9b921d
VZ
939 // try DllGetVersion() for recent DLLs
940 s_verComCtl32 = CallDllGetVersion(dllComCtl32);
941
942 // if DllGetVersion() is unavailable either during compile or
943 // run-time, try to guess the version otherwise
944 if ( !s_verComCtl32 )
bb6290e3 945 {
5e9b921d 946 // InitCommonControlsEx is unique to 4.70 and later
9a83f860 947 void *pfn = dllComCtl32.GetSymbol(wxT("InitCommonControlsEx"));
5e9b921d 948 if ( !pfn )
9fc6c21c 949 {
5e9b921d
VZ
950 // not found, must be 4.00
951 s_verComCtl32 = 400;
9fc6c21c 952 }
5e9b921d 953 else // 4.70+
9fc6c21c 954 {
5e9b921d
VZ
955 // many symbols appeared in comctl32 4.71, could use any of
956 // them except may be DllInstall()
9a83f860 957 pfn = dllComCtl32.GetSymbol(wxT("InitializeFlatSB"));
9fc6c21c
VZ
958 if ( !pfn )
959 {
5e9b921d
VZ
960 // not found, must be 4.70
961 s_verComCtl32 = 470;
6d167489 962 }
5e9b921d 963 else
bdc72a22 964 {
5e9b921d
VZ
965 // found, must be 4.71 or later
966 s_verComCtl32 = 471;
6d167489 967 }
9fc6c21c 968 }
ef094fa0 969 }
bb6290e3 970 }
6d167489
VZ
971
972 return s_verComCtl32;
bb6290e3
JS
973}
974
5e9b921d
VZ
975/* static */
976int wxApp::GetShell32Version()
977{
978 static int s_verShell32 = -1;
979 if ( s_verShell32 == -1 )
980 {
981 // we're prepared to handle the errors
982 wxLogNull noLog;
983
9a83f860 984 wxDynamicLibrary dllShell32(wxT("shell32.dll"), wxDL_VERBATIM);
5e9b921d
VZ
985 if ( dllShell32.IsLoaded() )
986 {
987 s_verShell32 = CallDllGetVersion(dllShell32);
988
989 if ( !s_verShell32 )
990 {
991 // there doesn't seem to be any way to distinguish between 4.00
992 // and 4.70 (starting from 4.71 we have DllGetVersion()) so
993 // just assume it is 4.0
994 s_verShell32 = 400;
995 }
996 }
997 else // failed load the DLL?
998 {
999 s_verShell32 = 0;
1000 }
1001 }
1002
1003 return s_verShell32;
1004}
1005
1006#else // !wxUSE_DYNLIB_CLASS
1007
1008/* static */
1009int wxApp::GetComCtl32Version()
1010{
1011 return 0;
1012}
1013
1014/* static */
1015int wxApp::GetShell32Version()
1016{
1017 return 0;
1018}
1019
1020#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
1021
6b4296f7
VZ
1022#endif // !__WXWINCE__
1023
6046e57a
VZ
1024#if wxUSE_EXCEPTIONS
1025
1026// ----------------------------------------------------------------------------
1027// exception handling
1028// ----------------------------------------------------------------------------
1029
1030bool wxApp::OnExceptionInMainLoop()
1031{
1032 // ask the user about what to do: use the Win32 API function here as it
77ffb593 1033 // could be dangerous to use any wxWidgets code in this state
6046e57a
VZ
1034 switch (
1035 ::MessageBox
1036 (
1037 NULL,
9a83f860 1038 wxT("An unhandled exception occurred. Press \"Abort\" to \
6046e57a
VZ
1039terminate the program,\r\n\
1040\"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
9a83f860 1041 wxT("Unhandled exception"),
6046e57a 1042 MB_ABORTRETRYIGNORE |
a71d815b 1043 MB_ICONERROR|
6046e57a
VZ
1044 MB_TASKMODAL
1045 )
1046 )
1047 {
1048 case IDABORT:
1049 throw;
1050
1051 default:
9a83f860 1052 wxFAIL_MSG( wxT("unexpected MessageBox() return code") );
6046e57a
VZ
1053 // fall through
1054
1055 case IDRETRY:
1056 return false;
1057
1058 case IDIGNORE:
1059 return true;
1060 }
1061}
1062
1063#endif // wxUSE_EXCEPTIONS