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