]> git.saurik.com Git - wxWidgets.git/blob - src/msw/app.cpp
#9675: wxDataViewModel::Reset() and scrollbar problem (wxMac)
[wxWidgets.git] / src / msw / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/app.cpp
3 // Purpose: wxApp
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #if defined(__BORLANDC__)
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/msw/wrapcctl.h"
29 #include "wx/dynarray.h"
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"
43 #include "wx/crt.h"
44 #include "wx/log.h"
45 #include "wx/module.h"
46 #endif
47
48 #include "wx/apptrait.h"
49 #include "wx/filename.h"
50 #include "wx/dynlib.h"
51 #include "wx/evtloop.h"
52 #include "wx/thread.h"
53
54 #include "wx/msw/private.h"
55 #include "wx/msw/dc.h"
56 #include "wx/msw/ole/oleutils.h"
57 #include "wx/msw/private/timer.h"
58
59 #if wxUSE_TOOLTIPS
60 #include "wx/tooltip.h"
61 #endif // wxUSE_TOOLTIPS
62
63 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
64 // compilers don't support it (missing headers, libs, ...)
65 #if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__)
66 #undef wxUSE_OLE
67
68 #define wxUSE_OLE 0
69 #endif // broken compilers
70
71 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
72 #include <ole2.h>
73 #include <aygshell.h>
74 #endif
75
76 #if wxUSE_OLE
77 #include <ole2.h>
78 #endif
79
80 #include <string.h>
81 #include <ctype.h>
82
83 #include "wx/msw/missing.h"
84
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
106 #ifndef ATTACH_PARENT_PROCESS
107 #define ATTACH_PARENT_PROCESS ((DWORD)-1)
108 #endif
109
110 // ---------------------------------------------------------------------------
111 // global variables
112 // ---------------------------------------------------------------------------
113
114 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
115 extern void wxSetKeyboardHook(bool doIt);
116 #endif
117
118 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
119 // with NR suffix - wxWindow::MSWCreate() supposes this
120 #ifdef __WXWINCE__
121 WXDLLIMPEXP_CORE wxChar *wxCanvasClassName;
122 WXDLLIMPEXP_CORE wxChar *wxCanvasClassNameNR;
123 #else
124 WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName = NULL;
125 WXDLLIMPEXP_CORE const wxChar *wxCanvasClassNameNR = NULL;
126 #endif
127 WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassName = NULL;
128 WXDLLIMPEXP_CORE const wxChar *wxMDIFrameClassNameNoRedraw = NULL;
129 WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassName = NULL;
130 WXDLLIMPEXP_CORE const wxChar *wxMDIChildFrameClassNameNoRedraw = NULL;
131
132 // ----------------------------------------------------------------------------
133 // private functions
134 // ----------------------------------------------------------------------------
135
136 LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
137
138 // ===========================================================================
139 // wxGUIAppTraits implementation
140 // ===========================================================================
141
142 // private class which we use to pass parameters from BeforeChildWaitLoop() to
143 // AfterChildWaitLoop()
144 struct 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
156 void *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(),
184 wxID_ANY,
185 wxEmptyString,
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
195 void wxGUIAppTraits::AlwaysYield()
196 {
197 wxYield();
198 }
199
200 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
201 {
202 wxEndBusyCursor();
203
204 ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
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();
212
213 // also delete the temporary data object itself
214 delete data;
215 }
216
217 bool wxGUIAppTraits::DoMessageFromThreadWait()
218 {
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
221 wxEventLoopBase * const evtLoop = wxEventLoop::GetActive();
222 if ( !evtLoop || !evtLoop->Pending() )
223 {
224 // no events means no quit event
225 return true;
226 }
227
228 return evtLoop->Dispatch();
229 }
230
231 DWORD wxGUIAppTraits::WaitForThread(WXHANDLE hThread)
232 {
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
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
246 QS_ALLINPUT | // return as soon as there are any events
247 QS_ALLPOSTMESSAGE
248 );
249 }
250
251 wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const
252 {
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;
271 #endif
272 }
273
274 #if wxUSE_TIMER
275
276 wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
277 {
278 return new wxMSWTimerImpl(timer);
279 }
280
281 #endif // wxUSE_TIMER
282
283 wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
284 {
285 return new wxEventLoop;
286 }
287
288 // ---------------------------------------------------------------------------
289 // Stuff for using console from the GUI applications
290 // ---------------------------------------------------------------------------
291
292 #ifndef __WXWINCE__
293
294 #include <wx/dynlib.h>
295
296 namespace
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 */
312 class wxConsoleStderr
313 {
314 public:
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
358 private:
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
394 bool 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
474 int 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);
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
492 if ( len2 != len )
493 {
494 wxFAIL_MSG( _T("failed getting history?") );
495 }
496 }
497
498 return len;
499 }
500
501 bool 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
514 bool 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
556 wxConsoleStderr s_consoleStderr;
557
558 } // anonymous namespace
559
560 bool wxGUIAppTraits::CanUseStderr()
561 {
562 return s_consoleStderr.IsOkToUse();
563 }
564
565 bool wxGUIAppTraits::WriteToStderr(const wxString& text)
566 {
567 return s_consoleStderr.IsOkToUse() && s_consoleStderr.Write(text);
568 }
569
570 #endif // !__WXWINCE__
571
572 // ===========================================================================
573 // wxApp implementation
574 // ===========================================================================
575
576 int wxApp::m_nCmdShow = SW_SHOWNORMAL;
577
578 // ---------------------------------------------------------------------------
579 // wxWin macros
580 // ---------------------------------------------------------------------------
581
582 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
583
584 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
585 EVT_IDLE(wxApp::OnIdle)
586 EVT_END_SESSION(wxApp::OnEndSession)
587 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
588 END_EVENT_TABLE()
589
590 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
591 // fails
592 class wxCallBaseCleanup
593 {
594 public:
595 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
596 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
597
598 void Dismiss() { m_app = NULL; }
599
600 private:
601 wxApp *m_app;
602 };
603
604 //// Initialize
605 bool wxApp::Initialize(int& argc, wxChar **argv)
606 {
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
613 #ifdef __WXWINCE__
614 wxString tmp = GetAppName();
615 tmp += wxT("ClassName");
616 wxCanvasClassName = wxStrdup( tmp.wc_str() );
617 tmp += wxT("NR");
618 wxCanvasClassNameNR = wxStrdup( tmp.wc_str() );
619 HWND hWnd = FindWindow( wxCanvasClassNameNR, NULL );
620 if (hWnd)
621 {
622 SetForegroundWindow( (HWND)(((DWORD)hWnd)|0x01) );
623 return false;
624 }
625 #endif
626
627 #if !defined(__WXMICROWIN__)
628 InitCommonControls();
629 #endif // !defined(__WXMICROWIN__)
630
631 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
632 SHInitExtraControls();
633 #endif
634
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
640
641 wxOleInitialize();
642
643 RegisterWindowClasses();
644
645 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
646 wxSetKeyboardHook(true);
647 #endif
648
649 callBaseCleanup.Dismiss();
650
651 return true;
652 }
653
654 // ---------------------------------------------------------------------------
655 // RegisterWindowClasses
656 // ---------------------------------------------------------------------------
657
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.
661 static 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.
682 static 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
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.
709 bool wxApp::RegisterWindowClasses()
710 {
711 WNDCLASS wndclass;
712 wxZeroMemory(wndclass);
713
714 // the fields which are common to all classes
715 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
716 wndclass.hInstance = wxhInstance;
717 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
718
719 // register the class for all normal windows and "no redraw" frames
720 wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
721 RegisterClassWithUniqueNames(wxT("wxWindowClass"),
722 &wxCanvasClassName,
723 &wxCanvasClassNameNR,
724 &wndclass);
725
726 // Register the MDI frame window class and "no redraw" MDI frame
727 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
728 RegisterClassWithUniqueNames(wxT("wxMDIFrameClass"),
729 &wxMDIFrameClassName,
730 &wxMDIFrameClassNameNoRedraw,
731 &wndclass);
732
733 // Register the MDI child frame window class and "no redraw" MDI child frame
734 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
735 RegisterClassWithUniqueNames(wxT("wxMDIChildFrameClass"),
736 &wxMDIChildFrameClassName,
737 &wxMDIChildFrameClassNameNoRedraw,
738 &wndclass);
739
740 return true;
741 }
742
743 // ---------------------------------------------------------------------------
744 // UnregisterWindowClasses
745 // ---------------------------------------------------------------------------
746
747 // This function unregisters the class with the given name and frees memory
748 // allocated for it by RegisterAndStoreClassName().
749 static bool UnregisterAndFreeClassName(const wxChar **ppClassName)
750 {
751 bool retval = true;
752
753 if ( !::UnregisterClass(*ppClassName, wxhInstance) )
754 {
755 wxLogLastError(
756 wxString::Format(wxT("UnregisterClass(%s)"), *ppClassName));
757
758 retval = false;
759 }
760
761 delete [] (wxChar*) *ppClassName;
762 *ppClassName = NULL;
763
764 return retval;
765 }
766
767 bool wxApp::UnregisterWindowClasses()
768 {
769 bool retval = true;
770
771 #ifndef __WXMICROWIN__
772 if ( !UnregisterAndFreeClassName(&wxMDIFrameClassName) )
773 retval = false;
774
775 if ( !UnregisterAndFreeClassName(&wxMDIFrameClassNameNoRedraw) )
776 retval = false;
777
778 if ( !UnregisterAndFreeClassName(&wxMDIChildFrameClassName) )
779 retval = false;
780
781 if ( !UnregisterAndFreeClassName(&wxMDIChildFrameClassNameNoRedraw) )
782 retval = false;
783
784 if ( !UnregisterAndFreeClassName(&wxCanvasClassName) )
785 retval = false;
786
787 if ( !UnregisterAndFreeClassName(&wxCanvasClassNameNR) )
788 retval = false;
789 #endif // __WXMICROWIN__
790
791 return retval;
792 }
793
794 void wxApp::CleanUp()
795 {
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
800 wxAppBase::CleanUp();
801
802 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
803 wxSetKeyboardHook(false);
804 #endif
805
806 wxOleUninitialize();
807
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();
813
814 #ifdef __WXWINCE__
815 free( wxCanvasClassName );
816 free( wxCanvasClassNameNR );
817 #endif
818 }
819
820 // ----------------------------------------------------------------------------
821 // wxApp ctor/dtor
822 // ----------------------------------------------------------------------------
823
824 wxApp::wxApp()
825 {
826 m_printMode = wxPRINT_WINDOWS;
827 }
828
829 wxApp::~wxApp()
830 {
831 }
832
833 // ----------------------------------------------------------------------------
834 // wxApp idle handling
835 // ----------------------------------------------------------------------------
836
837 void wxApp::OnIdle(wxIdleEvent& WXUNUSED(event))
838 {
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.
843 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
844 wxMSWDCImpl::ClearCache();
845 #endif // wxUSE_DC_CACHEING
846 }
847
848 void 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)
854 wxWindow * const topWindow = wxTheApp->GetTopWindow();
855 if ( topWindow )
856 {
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) )
870 {
871 if ( !::PostMessage(hwndTop, WM_NULL, 0, 0) )
872 {
873 // should never happen
874 wxLogLastError(wxT("PostMessage(WM_NULL)"));
875 }
876 }
877 }
878 }
879
880 // ----------------------------------------------------------------------------
881 // other wxApp event hanlders
882 // ----------------------------------------------------------------------------
883
884 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
885 {
886 // Windows will terminate the process soon after we return from
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
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);
904 }
905
906 // Default behaviour: close the application with prompts. The
907 // user can veto the close, and therefore the end session.
908 void wxApp::OnQueryEndSession(wxCloseEvent& event)
909 {
910 if (GetTopWindow())
911 {
912 if (!GetTopWindow()->Close(!event.CanVeto()))
913 event.Veto(true);
914 }
915 }
916
917 // ----------------------------------------------------------------------------
918 // system DLL versions
919 // ----------------------------------------------------------------------------
920
921 // these functions have trivial inline implementations for CE
922 #ifndef __WXWINCE__
923
924 #if wxUSE_DYNLIB_CLASS
925
926 namespace
927 {
928
929 // helper function: retrieve the DLL version by using DllGetVersion(), returns
930 // 0 if the DLL doesn't export such function
931 int 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
954 /* static */
955 int wxApp::GetComCtl32Version()
956 {
957 // cache the result
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
961 static int s_verComCtl32 = -1;
962
963 if ( s_verComCtl32 == -1 )
964 {
965 // we're prepared to handle the errors
966 wxLogNull noLog;
967
968 // the DLL should really be available
969 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
970 if ( !dllComCtl32.IsLoaded() )
971 {
972 s_verComCtl32 = 0;
973 return 0;
974 }
975
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 )
982 {
983 // InitCommonControlsEx is unique to 4.70 and later
984 void *pfn = dllComCtl32.GetSymbol(_T("InitCommonControlsEx"));
985 if ( !pfn )
986 {
987 // not found, must be 4.00
988 s_verComCtl32 = 400;
989 }
990 else // 4.70+
991 {
992 // many symbols appeared in comctl32 4.71, could use any of
993 // them except may be DllInstall()
994 pfn = dllComCtl32.GetSymbol(_T("InitializeFlatSB"));
995 if ( !pfn )
996 {
997 // not found, must be 4.70
998 s_verComCtl32 = 470;
999 }
1000 else
1001 {
1002 // found, must be 4.71 or later
1003 s_verComCtl32 = 471;
1004 }
1005 }
1006 }
1007 }
1008
1009 return s_verComCtl32;
1010 }
1011
1012 /* static */
1013 int 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 */
1046 int wxApp::GetComCtl32Version()
1047 {
1048 return 0;
1049 }
1050
1051 /* static */
1052 int wxApp::GetShell32Version()
1053 {
1054 return 0;
1055 }
1056
1057 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
1058
1059 #endif // !__WXWINCE__
1060
1061 // ----------------------------------------------------------------------------
1062 // Yield to incoming messages
1063 // ----------------------------------------------------------------------------
1064
1065 bool wxApp::Yield(bool onlyIfNeeded)
1066 {
1067 // MT-FIXME
1068 static bool s_inYield = false;
1069
1070 #if wxUSE_LOG
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();
1074 #endif // wxUSE_LOG
1075
1076 if ( s_inYield )
1077 {
1078 if ( !onlyIfNeeded )
1079 {
1080 wxFAIL_MSG( wxT("wxYield called recursively" ) );
1081 }
1082
1083 return false;
1084 }
1085
1086 s_inYield = true;
1087
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
1090 wxEventLoopGuarantor dummyLoopIfNeeded;
1091 MSG msg;
1092 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
1093 msg.message != WM_QUIT )
1094 {
1095 #if wxUSE_THREADS
1096 wxMutexGuiLeaveOrEnter();
1097 #endif // wxUSE_THREADS
1098
1099 if ( !wxTheApp->Dispatch() )
1100 break;
1101 }
1102
1103 // if there are pending events, we must process them.
1104 ProcessPendingEvents();
1105
1106 #if wxUSE_LOG
1107 // let the logs be flashed again
1108 wxLog::Resume();
1109 #endif // wxUSE_LOG
1110
1111 s_inYield = false;
1112
1113 return true;
1114 }
1115
1116 #if wxUSE_EXCEPTIONS
1117
1118 // ----------------------------------------------------------------------------
1119 // exception handling
1120 // ----------------------------------------------------------------------------
1121
1122 bool wxApp::OnExceptionInMainLoop()
1123 {
1124 // ask the user about what to do: use the Win32 API function here as it
1125 // could be dangerous to use any wxWidgets code in this state
1126 switch (
1127 ::MessageBox
1128 (
1129 NULL,
1130 _T("An unhandled exception occurred. Press \"Abort\" to \
1131 terminate the program,\r\n\
1132 \"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
1133 _T("Unhandled exception"),
1134 MB_ABORTRETRYIGNORE |
1135 MB_ICONERROR|
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