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