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