]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/app.cpp
Compilation fir for VC6 after r73124.
[wxWidgets.git] / src / msw / app.cpp
index 904f0aaed73e3f20431bb33b1677012e29a464ef..633722e0167055e31feb9507d8f48ee6b6afdabb 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
-// Name:        app.cpp
+// Name:        src/msw/app.cpp
 // Purpose:     wxApp
 // Author:      Julian Smart
 // Modified by:
 // Purpose:     wxApp
 // Author:      Julian Smart
 // Modified by:
 // headers
 // ---------------------------------------------------------------------------
 
 // headers
 // ---------------------------------------------------------------------------
 
-#ifdef __GNUG__
-    #pragma implementation "app.h"
-#endif
-
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
@@ -29,6 +25,8 @@
 #endif
 
 #ifndef WX_PRECOMP
 #endif
 
 #ifndef WX_PRECOMP
+    #include "wx/msw/wrapcctl.h"
+    #include "wx/dynarray.h"
     #include "wx/frame.h"
     #include "wx/app.h"
     #include "wx/utils.h"
     #include "wx/frame.h"
     #include "wx/app.h"
     #include "wx/utils.h"
     #include "wx/dialog.h"
     #include "wx/msgdlg.h"
     #include "wx/intl.h"
     #include "wx/dialog.h"
     #include "wx/msgdlg.h"
     #include "wx/intl.h"
-    #include "wx/dynarray.h"
-    #include "wx/wxchar.h"
-    #include "wx/icon.h"
+    #include "wx/crt.h"
     #include "wx/log.h"
     #include "wx/log.h"
+    #include "wx/module.h"
 #endif
 
 #include "wx/apptrait.h"
 #include "wx/filename.h"
 #endif
 
 #include "wx/apptrait.h"
 #include "wx/filename.h"
-#include "wx/module.h"
+#include "wx/dynlib.h"
+#include "wx/evtloop.h"
+#include "wx/thread.h"
+#include "wx/scopeguard.h"
+#include "wx/vector.h"
 
 #include "wx/msw/private.h"
 
 #include "wx/msw/private.h"
-
-#if wxUSE_THREADS
-    #include "wx/thread.h"
-
-    // define the array of MSG strutures
-    WX_DECLARE_OBJARRAY(MSG, wxMsgArray);
-
-    #include "wx/arrimpl.cpp"
-
-    WX_DEFINE_OBJARRAY(wxMsgArray);
-#endif // wxUSE_THREADS
+#include "wx/msw/dc.h"
+#include "wx/msw/ole/oleutils.h"
+#include "wx/msw/private/timer.h"
 
 #if wxUSE_TOOLTIPS
     #include "wx/tooltip.h"
 
 #if wxUSE_TOOLTIPS
     #include "wx/tooltip.h"
 
 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
 // compilers don't support it (missing headers, libs, ...)
 
 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
 // compilers don't support it (missing headers, libs, ...)
-#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
+#if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__)
     #undef wxUSE_OLE
 
     #define  wxUSE_OLE 0
 #endif // broken compilers
 
     #undef wxUSE_OLE
 
     #define  wxUSE_OLE 0
 #endif // broken compilers
 
+#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
+    #include <ole2.h>
+    #include <aygshell.h>
+#endif
+
 #if wxUSE_OLE
     #include <ole2.h>
 #endif
 #if wxUSE_OLE
     #include <ole2.h>
 #endif
 #include <string.h>
 #include <ctype.h>
 
 #include <string.h>
 #include <ctype.h>
 
-#if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__WXMICROWIN__)) && !defined(__CYGWIN10__))
-    #include <commctrl.h>
-#endif
-
-// ----------------------------------------------------------------------------
-// conditional compilation
-// ----------------------------------------------------------------------------
+#include "wx/msw/missing.h"
 
 
-// The macro _WIN32_IE is defined by commctrl.h (unless it had already been
-// defined before) and shows us what common control features are available
-// during the compile time (it doesn't mean that they will be available during
-// the run-time, use GetComCtl32Version() to test for them!). The possible
-// values are:
+// instead of including <shlwapi.h> which is not part of the core SDK and not
+// shipped at all with other compilers, we always define the parts of it we
+// need here ourselves
 //
 //
-// 0x0200     for comctl32.dll 4.00 shipped with Win95/NT 4.0
-// 0x0300                      4.70              IE 3.x
-// 0x0400                      4.71              IE 4.0
-// 0x0401                      4.72              IE 4.01 and Win98
-// 0x0500                      5.00              IE 5.x and NT 5.0 (Win2000)
-
-#ifndef _WIN32_IE
-    // minimal set of features by default
-    #define _WIN32_IE 0x0200
-#endif
+// NB: DLLVER_PLATFORM_WINDOWS will be defined if shlwapi.h had been somehow
+//     included already
+#ifndef DLLVER_PLATFORM_WINDOWS
+    // hopefully we don't need to change packing as DWORDs should be already
+    // correctly aligned
+    struct DLLVERSIONINFO
+    {
+        DWORD cbSize;
+        DWORD dwMajorVersion;                   // Major version
+        DWORD dwMinorVersion;                   // Minor version
+        DWORD dwBuildNumber;                    // Build number
+        DWORD dwPlatformID;                     // DLLVER_PLATFORM_*
+    };
+
+    typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
+#endif // defined(DLLVERSIONINFO)
 
 
-#if _WIN32_IE >= 0x0300 && \
-    (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
-    !defined(__CYGWIN__)
-    #include <shlwapi.h>
+#ifndef ATTACH_PARENT_PROCESS
+    #define ATTACH_PARENT_PROCESS ((DWORD)-1)
 #endif
 
 // ---------------------------------------------------------------------------
 // global variables
 // ---------------------------------------------------------------------------
 
 #endif
 
 // ---------------------------------------------------------------------------
 // global variables
 // ---------------------------------------------------------------------------
 
-extern wxChar *wxBuffer;
-extern wxList WXDLLEXPORT wxPendingDelete;
-#ifndef __WXMICROWIN__
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
 extern void wxSetKeyboardHook(bool doIt);
 #endif
 
 extern void wxSetKeyboardHook(bool doIt);
 #endif
 
-MSG s_currentMsg;
+// because of mingw32 4.3 bug this struct can't be inside the namespace below:
+// see http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/110282
+struct ClassRegInfo
+{
+    ClassRegInfo(const wxChar *name)
+        : regname(name),
+          regnameNR(regname + wxApp::GetNoRedrawClassSuffix())
+    {
+    }
+
+    // the name of the registered class with and without CS_[HV]REDRAW styles
+    wxString regname;
+    wxString regnameNR;
+};
 
 
-// NB: all "NoRedraw" classes must have the same names as the "normal" classes
-//     with NR suffix - wxWindow::MSWCreate() supposes this
-const wxChar *wxCanvasClassName        = wxT("wxWindowClass");
-const wxChar *wxCanvasClassNameNR      = wxT("wxWindowClassNR");
-const wxChar *wxMDIFrameClassName      = wxT("wxMDIFrameClass");
-const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
-const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
-const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
+namespace
+{
+
+wxVector<ClassRegInfo> gs_regClassesInfo;
 
 
-HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
+} // anonymous namespace
 
 // ----------------------------------------------------------------------------
 // private functions
 
 // ----------------------------------------------------------------------------
 // private functions
@@ -171,12 +172,12 @@ void *wxGUIAppTraits::BeforeChildWaitLoop()
        focus/activation entirely when the child process terminates which would
        happen if we simply disabled everything using wxWindowDisabler. Indeed,
        remember that Windows will never activate a disabled window and when the
        focus/activation entirely when the child process terminates which would
        happen if we simply disabled everything using wxWindowDisabler. Indeed,
        remember that Windows will never activate a disabled window and when the
-       last childs window is closed and Windows looks for a window to activate
+       last child's window is closed and Windows looks for a window to activate
        all our windows are still disabled. There is no way to enable them in
        all our windows are still disabled. There is no way to enable them in
-       time because we don't know when the childs windows are going to be
-       closed, so the solution we use here is to keep one special tiny frame
+       time because we don't know when the child's windows are going to be
+       closed, so the solution we use here is to keep one special tiny dialog
        enabled all the time. Then when the child terminates it will get
        enabled all the time. Then when the child terminates it will get
-       activated and when we close it below -- after reenabling all the other
+       activated and when we close it below -- after re-enabling all the other
        windows! -- the previously active window becomes activated again and
        everything is ok.
      */
        windows! -- the previously active window becomes activated again and
        everything is ok.
      */
@@ -185,703 +186,621 @@ void *wxGUIAppTraits::BeforeChildWaitLoop()
     // first disable all existing windows
     wxWindowDisabler *wd = new wxWindowDisabler;
 
     // first disable all existing windows
     wxWindowDisabler *wd = new wxWindowDisabler;
 
-    // then create an "invisible" frame: it has minimal size, is positioned
-    // (hopefully) outside the screen and doesn't appear on the taskbar
-    wxWindow *winActive = new wxFrame
+    // then create an "invisible" dialog: it has minimal size, is positioned
+    // (hopefully) outside the screen and doesn't appear in the Alt-TAB list
+    // (unlike the frames, which is why we use a dialog here)
+    wxWindow *winActive = new wxDialog
                     (
                         wxTheApp->GetTopWindow(),
                     (
                         wxTheApp->GetTopWindow(),
-                        -1,
-                        _T(""),
+                        wxID_ANY,
+                        wxEmptyString,
                         wxPoint(32600, 32600),
                         wxPoint(32600, 32600),
-                        wxSize(1, 1),
-                        wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
+                        wxSize(1, 1)
                     );
     winActive->Show();
 
     return new ChildWaitLoopData(wd, winActive);
 }
 
                     );
     winActive->Show();
 
     return new ChildWaitLoopData(wd, winActive);
 }
 
-void wxGUIAppTraits::AlwaysYield()
-{
-    wxYield();
-}
-
 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
 {
     wxEndBusyCursor();
 
 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
 {
     wxEndBusyCursor();
 
-    const ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
+    ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
 
     delete data->wd;
 
 
     delete data->wd;
 
-    // finally delete the dummy frame and, as wd has been already destroyed and
-    // the other windows reenabled, the activation is going to return to the
-    // window which had had it before
+    // finally delete the dummy dialog and, as wd has been already destroyed
+    // and the other windows reenabled, the activation is going to return to
+    // the window which had had it before
     data->winActive->Destroy();
     data->winActive->Destroy();
+
+    // also delete the temporary data object itself
+    delete data;
 }
 
 }
 
+#if wxUSE_THREADS
 bool wxGUIAppTraits::DoMessageFromThreadWait()
 {
 bool wxGUIAppTraits::DoMessageFromThreadWait()
 {
-    return !wxTheApp || wxTheApp->DoMessage();
+    // we should return false only if the app should exit, i.e. only if
+    // Dispatch() determines that the main event loop should terminate
+    wxEventLoopBase * const evtLoop = wxEventLoop::GetActive();
+    if ( !evtLoop || !evtLoop->Pending() )
+    {
+        // no events means no quit event
+        return true;
+    }
+
+    return evtLoop->Dispatch();
 }
 
 }
 
-// ===========================================================================
-// wxApp implementation
-// ===========================================================================
+DWORD wxGUIAppTraits::WaitForThread(WXHANDLE hThread, int flags)
+{
+    // We only ever dispatch messages from the main thread and, additionally,
+    // even from the main thread we shouldn't wait for the message if we don't
+    // have a running event loop as we would never remove them from the message
+    // queue then and so we would enter an infinite loop as
+    // MsgWaitForMultipleObjects() keeps returning WAIT_OBJECT_0 + 1.
+    if ( flags == wxTHREAD_WAIT_BLOCK ||
+            !wxIsMainThread() ||
+                !wxEventLoop::GetActive() )
+    {
+        // Simple blocking wait.
+        return DoSimpleWaitForThread(hThread);
+    }
 
 
-int wxApp::m_nCmdShow = SW_SHOWNORMAL;
+    return ::MsgWaitForMultipleObjects
+             (
+               1,                   // number of objects to wait for
+               (HANDLE *)&hThread,  // the objects
+               false,               // wait for any objects, not all
+               INFINITE,            // no timeout
+               QS_ALLINPUT |        // return as soon as there are any events
+               QS_ALLPOSTMESSAGE
+             );
+}
+#endif // wxUSE_THREADS
+
+wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const
+{
+    OSVERSIONINFO info;
+    wxZeroMemory(info);
+
+    // on Windows, the toolkit version is the same of the OS version
+    // as Windows integrates the OS kernel with the GUI toolkit.
+    info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+    if ( ::GetVersionEx(&info) )
+    {
+        if ( majVer )
+            *majVer = info.dwMajorVersion;
+        if ( minVer )
+            *minVer = info.dwMinorVersion;
+    }
+
+#if defined(__WXHANDHELD__) || defined(__WXWINCE__)
+    return wxPORT_WINCE;
+#else
+    return wxPORT_MSW;
+#endif
+}
+
+#if wxUSE_TIMER
+
+wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
+{
+    return new wxMSWTimerImpl(timer);
+}
+
+#endif // wxUSE_TIMER
+
+wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
+{
+    return new wxEventLoop;
+}
 
 // ---------------------------------------------------------------------------
 
 // ---------------------------------------------------------------------------
-// wxWin macros
+// Stuff for using console from the GUI applications
 // ---------------------------------------------------------------------------
 
 // ---------------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
+#ifndef __WXWINCE__
 
 
-BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
-    EVT_IDLE(wxApp::OnIdle)
-    EVT_END_SESSION(wxApp::OnEndSession)
-    EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
-END_EVENT_TABLE()
+#if wxUSE_DYNLIB_CLASS
 
 
-// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
-// fails
-class wxCallBaseCleanup
+#include <wx/dynlib.h>
+
+namespace
 {
 {
-public:
-    wxCallBaseCleanup(wxApp *app) : m_app(app) { }
-    ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
 
 
-    void Dismiss() { m_app = NULL; }
+/*
+    Helper class to manipulate console from a GUI app.
 
 
-private:
-    wxApp *m_app;
-};
+    Notice that console output is available in the GUI app only if:
+    - AttachConsole() returns TRUE (which means it never works under pre-XP)
+    - we have a valid STD_ERROR_HANDLE
+    - command history hasn't been changed since our startup
 
 
-//// Initialize
-bool wxApp::Initialize(int& argc, wxChar **argv)
+    To check if all these conditions are verified, you need to simple call
+    IsOkToUse(). It will check the first two conditions above the first time it
+    is called (and if this fails, the subsequent calls will return immediately)
+    and also recheck the last one every time it is called.
+ */
+class wxConsoleStderr
 {
 {
-    if ( !wxAppBase::Initialize(argc, argv) )
-        return false;
+public:
+    // default ctor does nothing, call Init() before using this class
+    wxConsoleStderr()
+    {
+        m_hStderr = INVALID_HANDLE_VALUE;
+        m_historyLen =
+        m_dataLen =
+        m_dataLine = 0;
 
 
-    // ensure that base cleanup is done if we return too early
-    wxCallBaseCleanup callBaseCleanup(this);
+        m_ok = -1;
+    }
 
 
-    // the first thing to do is to check if we're trying to run an Unicode
-    // program under Win9x w/o MSLU emulation layer - if so, abort right now
-    // as it has no chance to work
-#if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
-    if ( wxGetOsVersion() != wxWINDOWS_NT )
+    ~wxConsoleStderr()
     {
     {
-        // note that we can use MessageBoxW() as it's implemented even under
-        // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
-        // used by wxLocale are not
-        ::MessageBox
-        (
-         NULL,
-         _T("This program uses Unicode and requires Windows NT/2000/XP.\nProgram aborted."),
-         _T("wxWindows Fatal Error"),
-         MB_ICONERROR | MB_OK
-        );
-
-        return FALSE;
+        if ( m_hStderr != INVALID_HANDLE_VALUE )
+        {
+            if ( !::FreeConsole() )
+            {
+                wxLogLastError(wxT("FreeConsole"));
+            }
+        }
     }
     }
-#endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
 
 
-    wxBuffer = new wxChar[1500]; // FIXME
+    // return true if we were successfully initialized and there had been no
+    // console activity which would interfere with our output since then
+    bool IsOkToUse() const
+    {
+        if ( m_ok == -1 )
+        {
+            wxConsoleStderr * const self = const_cast<wxConsoleStderr *>(this);
+            self->m_ok = self->DoInit();
 
 
-#if defined(__WIN95__) && !defined(__WXMICROWIN__)
-    InitCommonControls();
-#endif // __WIN95__
+            // no need to call IsHistoryUnchanged() as we just initialized
+            // m_history anyhow
+            return m_ok == 1;
+        }
+
+        return m_ok && IsHistoryUnchanged();
+    }
 
 
-#if wxUSE_OLE || wxUSE_DRAG_AND_DROP
 
 
-#ifdef __WIN16__
-    // for OLE, enlarge message queue to be as large as possible
-    int iMsg = 96;
-    while (!SetMessageQueue(iMsg) && (iMsg -= 8))
-        ;
-#endif // Win16
+    // output the provided text on the console, return true if ok
+    bool Write(const wxString& text);
 
 
-#if wxUSE_OLE
-    // we need to initialize OLE library
-    if ( FAILED(::OleInitialize(NULL)) )
-        wxLogError(_("Cannot initialize OLE"));
-#endif
+private:
+    // called by Init() once only to do the real initialization
+    bool DoInit();
 
 
-#endif // wxUSE_OLE
+    // retrieve the command line history into the provided buffer and return
+    // its length
+    int GetCommandHistory(wxWxCharBuffer& buf) const;
 
 
-#if wxUSE_CTL3D
-    if (!Ctl3dRegister(wxhInstance))
-        wxLogError(wxT("Cannot register CTL3D"));
+    // check if the console history has changed
+    bool IsHistoryUnchanged() const;
 
 
-    Ctl3dAutoSubclass(wxhInstance);
-#endif // wxUSE_CTL3D
+    int m_ok;                   // initially -1, set to true or false by Init()
 
 
-    RegisterWindowClasses();
+    wxDynamicLibrary m_dllKernel32;
 
 
-#ifndef __WXMICROWIN__
-    // Create the brush for disabling bitmap buttons
+    HANDLE m_hStderr;           // console handle, if it's valid we must call
+                                // FreeConsole() (even if m_ok != 1)
 
 
-    LOGBRUSH lb;
-    lb.lbStyle = BS_PATTERN;
-    lb.lbColor = 0;
-    lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
-    if ( lb.lbHatch )
-    {
-        wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
-        ::DeleteObject( (HGDIOBJ)lb.lbHatch );
-    }
-    //else: wxWindows resources are probably not linked in
-#endif
+    wxWxCharBuffer m_history;   // command history on startup
+    int m_historyLen;           // length command history buffer
 
 
-#if wxUSE_PENWINDOWS
-    wxRegisterPenWin();
-#endif
+    wxCharBuffer m_data;        // data between empty line and cursor position
+    int m_dataLen;              // length data buffer
+    int m_dataLine;             // line offset
 
 
-    wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
+    typedef DWORD (WINAPI *GetConsoleCommandHistory_t)(LPTSTR sCommands,
+                                                       DWORD nBufferLength,
+                                                       LPCTSTR sExeName);
+    typedef DWORD (WINAPI *GetConsoleCommandHistoryLength_t)(LPCTSTR sExeName);
 
 
-    // This is to foil optimizations in Visual C++ that throw out dummy.obj.
-    // PLEASE DO NOT ALTER THIS.
-#if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
-    extern char wxDummyChar;
-    if (wxDummyChar) wxDummyChar++;
-#endif
+    GetConsoleCommandHistory_t m_pfnGetConsoleCommandHistory;
+    GetConsoleCommandHistoryLength_t m_pfnGetConsoleCommandHistoryLength;
 
 
-#ifndef __WXMICROWIN__
-    wxSetKeyboardHook(TRUE);
-#endif
+    wxDECLARE_NO_COPY_CLASS(wxConsoleStderr);
+};
 
 
-    callBaseCleanup.Dismiss();
+bool wxConsoleStderr::DoInit()
+{
+    HANDLE hStderr = ::GetStdHandle(STD_ERROR_HANDLE);
 
 
-    return true;
-}
+    if ( hStderr == INVALID_HANDLE_VALUE || !hStderr )
+        return false;
 
 
-// ---------------------------------------------------------------------------
-// RegisterWindowClasses
-// ---------------------------------------------------------------------------
+    if ( !m_dllKernel32.Load(wxT("kernel32.dll")) )
+        return false;
 
 
-// TODO we should only register classes really used by the app. For this it
-//      would be enough to just delay the class registration until an attempt
-//      to create a window of this class is made.
-bool wxApp::RegisterWindowClasses()
-{
-    WNDCLASS wndclass;
-    wxZeroMemory(wndclass);
+    typedef BOOL (WINAPI *AttachConsole_t)(DWORD dwProcessId);
+    AttachConsole_t wxDL_INIT_FUNC(pfn, AttachConsole, m_dllKernel32);
 
 
-    // for each class we register one with CS_(V|H)REDRAW style and one
-    // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
-    static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
-    static const long styleNoRedraw = CS_DBLCLKS;
+    if ( !pfnAttachConsole || !pfnAttachConsole(ATTACH_PARENT_PROCESS) )
+        return false;
 
 
-    // the fields which are common to all classes
-    wndclass.lpfnWndProc   = (WNDPROC)wxWndProc;
-    wndclass.hInstance     = wxhInstance;
-    wndclass.hCursor       = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
+    // console attached, set m_hStderr now to ensure that we free it in the
+    // dtor
+    m_hStderr = hStderr;
 
 
-    // Register the frame window class.
-    wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
-    wndclass.lpszClassName = wxCanvasClassName;
-    wndclass.style         = styleNormal;
+    wxDL_INIT_FUNC_AW(m_pfn, GetConsoleCommandHistory, m_dllKernel32);
+    if ( !m_pfnGetConsoleCommandHistory )
+        return false;
 
 
-    if ( !RegisterClass(&wndclass) )
-    {
-        wxLogLastError(wxT("RegisterClass(frame)"));
-    }
+    wxDL_INIT_FUNC_AW(m_pfn, GetConsoleCommandHistoryLength, m_dllKernel32);
+    if ( !m_pfnGetConsoleCommandHistoryLength )
+        return false;
 
 
-    // "no redraw" frame
-    wndclass.lpszClassName = wxCanvasClassNameNR;
-    wndclass.style         = styleNoRedraw;
+    // remember the current command history to be able to compare with it later
+    // in IsHistoryUnchanged()
+    m_historyLen = GetCommandHistory(m_history);
+    if ( !m_history )
+        return false;
 
 
-    if ( !RegisterClass(&wndclass) )
-    {
-        wxLogLastError(wxT("RegisterClass(no redraw frame)"));
-    }
 
 
-    // Register the MDI frame window class.
-    wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
-    wndclass.lpszClassName = wxMDIFrameClassName;
-    wndclass.style         = styleNormal;
+    // now find the first blank line above the current position
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
 
 
-    if ( !RegisterClass(&wndclass) )
+    if ( !::GetConsoleScreenBufferInfo(m_hStderr, &csbi) )
     {
     {
-        wxLogLastError(wxT("RegisterClass(MDI parent)"));
+        wxLogLastError(wxT("GetConsoleScreenBufferInfo"));
+        return false;
     }
 
     }
 
-    // "no redraw" MDI frame
-    wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
-    wndclass.style         = styleNoRedraw;
+    COORD pos;
+    pos.X = 0;
+    pos.Y = csbi.dwCursorPosition.Y + 1;
 
 
-    if ( !RegisterClass(&wndclass) )
+    // we decide that a line is empty if first 4 characters are spaces
+    DWORD ret;
+    char buf[4];
+    do
     {
     {
-        wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
-    }
+        pos.Y--;
+        if ( !::ReadConsoleOutputCharacterA(m_hStderr, buf, WXSIZEOF(buf),
+                                            pos, &ret) )
+        {
+            wxLogLastError(wxT("ReadConsoleOutputCharacterA"));
+            return false;
+        }
+    } while ( wxStrncmp("    ", buf, WXSIZEOF(buf)) != 0 );
 
 
-    // Register the MDI child frame window class.
-    wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
-    wndclass.lpszClassName = wxMDIChildFrameClassName;
-    wndclass.style         = styleNormal;
+    // calculate line offset and length of data
+    m_dataLine = csbi.dwCursorPosition.Y - pos.Y;
+    m_dataLen = m_dataLine*csbi.dwMaximumWindowSize.X + csbi.dwCursorPosition.X;
 
 
-    if ( !RegisterClass(&wndclass) )
+    if ( m_dataLen > 0 )
     {
     {
-        wxLogLastError(wxT("RegisterClass(MDI child)"));
+        m_data.extend(m_dataLen);
+        if ( !::ReadConsoleOutputCharacterA(m_hStderr, m_data.data(), m_dataLen,
+                                            pos, &ret) )
+        {
+            wxLogLastError(wxT("ReadConsoleOutputCharacterA"));
+            return false;
+        }
     }
 
     }
 
-    // "no redraw" MDI child frame
-    wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
-    wndclass.style         = styleNoRedraw;
+    return true;
+}
+
+int wxConsoleStderr::GetCommandHistory(wxWxCharBuffer& buf) const
+{
+    // these functions are internal and may only be called by cmd.exe
+    static const wxChar *CMD_EXE = wxT("cmd.exe");
 
 
-    if ( !RegisterClass(&wndclass) )
+    const int len = m_pfnGetConsoleCommandHistoryLength(CMD_EXE);
+    if ( len )
     {
     {
-        wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
+        buf.extend(len);
+
+        int len2 = m_pfnGetConsoleCommandHistory(buf.data(), len, CMD_EXE);
+
+#if !wxUSE_UNICODE
+        // there seems to be a bug in the GetConsoleCommandHistoryA(), it
+        // returns the length of Unicode string and not ANSI one
+        len2 /= 2;
+#endif // !wxUSE_UNICODE
+
+        if ( len2 != len )
+        {
+            wxFAIL_MSG( wxT("failed getting history?") );
+        }
     }
 
     }
 
-    return TRUE;
+    return len;
 }
 
 }
 
-// ---------------------------------------------------------------------------
-// UnregisterWindowClasses
-// ---------------------------------------------------------------------------
+bool wxConsoleStderr::IsHistoryUnchanged() const
+{
+    wxASSERT_MSG( m_ok == 1, wxT("shouldn't be called if not initialized") );
+
+    // get (possibly changed) command history
+    wxWxCharBuffer history;
+    const int historyLen = GetCommandHistory(history);
 
 
-bool wxApp::UnregisterWindowClasses()
+    // and compare it with the original one
+    return historyLen == m_historyLen && history &&
+                memcmp(m_history, history, historyLen) == 0;
+}
+
+bool wxConsoleStderr::Write(const wxString& text)
 {
 {
-    bool retval = TRUE;
+    wxASSERT_MSG( m_hStderr != INVALID_HANDLE_VALUE,
+                    wxT("should only be called if Init() returned true") );
 
 
-#ifndef __WXMICROWIN__
-    // MDI frame window class.
-    if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
+    // get current position
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    if ( !::GetConsoleScreenBufferInfo(m_hStderr, &csbi) )
     {
     {
-        wxLogLastError(wxT("UnregisterClass(MDI parent)"));
-
-        retval = FALSE;
+        wxLogLastError(wxT("GetConsoleScreenBufferInfo"));
+        return false;
     }
 
     }
 
-    // "no redraw" MDI frame
-    if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
-    {
-        wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
+    // and calculate new position (where is empty line)
+    csbi.dwCursorPosition.X = 0;
+    csbi.dwCursorPosition.Y -= m_dataLine;
 
 
-        retval = FALSE;
+    if ( !::SetConsoleCursorPosition(m_hStderr, csbi.dwCursorPosition) )
+    {
+        wxLogLastError(wxT("SetConsoleCursorPosition"));
+        return false;
     }
 
     }
 
-    // MDI child frame window class.
-    if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
+    DWORD ret;
+    if ( !::FillConsoleOutputCharacter(m_hStderr, wxT(' '), m_dataLen,
+                                       csbi.dwCursorPosition, &ret) )
     {
     {
-        wxLogLastError(wxT("UnregisterClass(MDI child)"));
-
-        retval = FALSE;
+        wxLogLastError(wxT("FillConsoleOutputCharacter"));
+        return false;
     }
 
     }
 
-    // "no redraw" MDI child frame
-    if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
+    if ( !::WriteConsole(m_hStderr, text.t_str(), text.length(), &ret, NULL) )
     {
     {
-        wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
-
-        retval = FALSE;
+        wxLogLastError(wxT("WriteConsole"));
+        return false;
     }
 
     }
 
-    // canvas class name
-    if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
-    {
-        wxLogLastError(wxT("UnregisterClass(canvas)"));
+    WriteConsoleA(m_hStderr, m_data, m_dataLen, &ret, 0);
 
 
-        retval = FALSE;
-    }
+    return true;
+}
 
 
-    if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
-    {
-        wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
+wxConsoleStderr s_consoleStderr;
 
 
-        retval = FALSE;
-    }
-#endif // __WXMICROWIN__
+} // anonymous namespace
 
 
-    return retval;
+bool wxGUIAppTraits::CanUseStderr()
+{
+    return s_consoleStderr.IsOkToUse();
 }
 
 }
 
-void wxApp::CleanUp()
+bool wxGUIAppTraits::WriteToStderr(const wxString& text)
 {
 {
-    delete[] wxBuffer;
-    wxBuffer = NULL;
+    return s_consoleStderr.IsOkToUse() && s_consoleStderr.Write(text);
+}
 
 
-#ifndef __WXMICROWIN__
-    wxSetKeyboardHook(FALSE);
-#endif
+#else // !wxUSE_DYNLIB_CLASS
 
 
-#if wxUSE_PENWINDOWS
-    wxCleanUpPenWin();
-#endif
+bool wxGUIAppTraits::CanUseStderr()
+{
+    return false;
+}
 
 
-    if ( wxDisableButtonBrush )
-        ::DeleteObject( wxDisableButtonBrush );
+bool wxGUIAppTraits::WriteToStderr(const wxString& WXUNUSED(text))
+{
+    return false;
+}
 
 
-#if wxUSE_OLE
-    ::OleUninitialize();
-#endif
+#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
 
 
-    // for an EXE the classes are unregistered when it terminates but DLL may
-    // be loaded several times (load/unload/load) into the same process in
-    // which case the registration will fail after the first time if we don't
-    // unregister the classes now
-    UnregisterWindowClasses();
+#endif // !__WXWINCE__
 
 
-#if wxUSE_CTL3D
-    Ctl3dUnregister(wxhInstance);
-#endif
+// ===========================================================================
+// wxApp implementation
+// ===========================================================================
 
 
-    delete wxWinHandleHash;
-    wxWinHandleHash = NULL;
+int wxApp::m_nCmdShow = SW_SHOWNORMAL;
 
 
-    wxAppBase::CleanUp();
-}
+// ---------------------------------------------------------------------------
+// wxWin macros
+// ---------------------------------------------------------------------------
 
 
-// ----------------------------------------------------------------------------
-// wxApp ctor/dtor
-// ----------------------------------------------------------------------------
+IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
 
 
-wxApp::wxApp()
-{
-    m_printMode = wxPRINT_WINDOWS;
-}
+BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
+    EVT_IDLE(wxApp::OnIdle)
+    EVT_END_SESSION(wxApp::OnEndSession)
+    EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
+END_EVENT_TABLE()
 
 
-wxApp::~wxApp()
+// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
+// fails
+class wxCallBaseCleanup
 {
 {
-    // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
-    // don't come from main(), so we have to free them
-
-    while ( argc )
-    {
-        // m_argv elements were allocated by wxStrdup()
-        free(argv[--argc]);
-    }
+public:
+    wxCallBaseCleanup(wxApp *app) : m_app(app) { }
+    ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
 
 
-    // but m_argv itself -- using new[]
-    delete [] argv;
-}
+    void Dismiss() { m_app = NULL; }
 
 
-bool wxApp::Initialized()
-{
-#ifndef _WINDLL
-    if (GetTopWindow())
-        return TRUE;
-    else
-        return FALSE;
-#else // Assume initialized if DLL (no way of telling)
-    return TRUE;
-#endif
-}
+private:
+    wxApp *m_app;
+};
 
 
-/*
- * Get and process a message, returning FALSE if WM_QUIT
- * received (and also set the flag telling the app to exit the main loop)
- *
- */
-bool wxApp::DoMessage()
+//// Initialize
+bool wxApp::Initialize(int& argc, wxChar **argv)
 {
 {
-    BOOL rc = ::GetMessage(&s_currentMsg, (HWND) NULL, 0, 0);
-    if ( rc == 0 )
-    {
-        // got WM_QUIT
-        m_keepGoing = FALSE;
-
-        return FALSE;
-    }
-    else if ( rc == -1 )
-    {
-        // should never happen, but let's test for it nevertheless
-        wxLogLastError(wxT("GetMessage"));
-    }
-    else
-    {
-#if wxUSE_THREADS
-        wxASSERT_MSG( wxThread::IsMain(),
-                      wxT("only the main thread can process Windows messages") );
-
-        static bool s_hadGuiLock = TRUE;
-        static wxMsgArray s_aSavedMessages;
+    if ( !wxAppBase::Initialize(argc, argv) )
+        return false;
 
 
-        // if a secondary thread owns is doing GUI calls, save all messages for
-        // later processing - we can't process them right now because it will
-        // lead to recursive library calls (and we're not reentrant)
-        if ( !wxGuiOwnedByMainThread() )
-        {
-            s_hadGuiLock = FALSE;
+    // ensure that base cleanup is done if we return too early
+    wxCallBaseCleanup callBaseCleanup(this);
 
 
-            // leave out WM_COMMAND messages: too dangerous, sometimes
-            // the message will be processed twice
-            if ( !wxIsWaitingForThread() ||
-                    s_currentMsg.message != WM_COMMAND )
-            {
-                s_aSavedMessages.Add(s_currentMsg);
-            }
+#if !defined(__WXMICROWIN__)
+    InitCommonControls();
+#endif // !defined(__WXMICROWIN__)
 
 
-            return TRUE;
-        }
-        else
-        {
-            // have we just regained the GUI lock? if so, post all of the saved
-            // messages
-            //
-            // FIXME of course, it's not _exactly_ the same as processing the
-            //       messages normally - expect some things to break...
-            if ( !s_hadGuiLock )
-            {
-                s_hadGuiLock = TRUE;
+#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
+    SHInitExtraControls();
+#endif
 
 
-                size_t count = s_aSavedMessages.GetCount();
-                for ( size_t n = 0; n < count; n++ )
-                {
-                    MSG& msg = s_aSavedMessages[n];
+#ifndef __WXWINCE__
+    // Don't show a message box if a function such as SHGetFileInfo
+    // fails to find a device.
+    SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+#endif
 
 
-                    DoMessage((WXMSG *)&msg);
-                }
+    wxOleInitialize();
 
 
-                s_aSavedMessages.Empty();
-            }
-        }
-#endif // wxUSE_THREADS
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
+    wxSetKeyboardHook(true);
+#endif
 
 
-        // Process the message
-        DoMessage((WXMSG *)&s_currentMsg);
-    }
+    callBaseCleanup.Dismiss();
 
 
-    return TRUE;
+    return true;
 }
 
 }
 
-void wxApp::DoMessage(WXMSG *pMsg)
+// ---------------------------------------------------------------------------
+// Win32 window class registration
+// ---------------------------------------------------------------------------
+
+/* static */
+const wxChar *wxApp::GetRegisteredClassName(const wxChar *name,
+                                            int bgBrushCol,
+                                            int extraStyles)
 {
 {
-    if ( !ProcessMessage(pMsg) )
+    const size_t count = gs_regClassesInfo.size();
+    for ( size_t n = 0; n < count; n++ )
     {
     {
-        ::TranslateMessage((MSG *)pMsg);
-        ::DispatchMessage((MSG *)pMsg);
+        if ( gs_regClassesInfo[n].regname == name )
+            return gs_regClassesInfo[n].regname.c_str();
     }
     }
-}
-
-/*
- * Keep trying to process messages until WM_QUIT
- * received.
- *
- * If there are messages to be processed, they will all be
- * processed and OnIdle will not be called.
- * When there are no more messages, OnIdle is called.
- * If OnIdle requests more time,
- * it will be repeatedly called so long as there are no pending messages.
- * A 'feature' of this is that once OnIdle has decided that no more processing
- * is required, then it won't get processing time until further messages
- * are processed (it'll sit in DoMessage).
- */
 
 
-int wxApp::MainLoop()
-{
-    m_keepGoing = TRUE;
+    // we need to register this class
+    WNDCLASS wndclass;
+    wxZeroMemory(wndclass);
 
 
-    while ( m_keepGoing )
-    {
-#if wxUSE_THREADS
-        wxMutexGuiLeaveOrEnter();
-#endif // wxUSE_THREADS
+    wndclass.lpfnWndProc   = (WNDPROC)wxWndProc;
+    wndclass.hInstance     = wxGetInstance();
+    wndclass.hCursor       = ::LoadCursor(NULL, IDC_ARROW);
+    wndclass.hbrBackground = (HBRUSH)wxUIntToPtr(bgBrushCol + 1);
+    wndclass.style         = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | extraStyles;
 
 
-        while ( !Pending() && ProcessIdle() )
-            ;
 
 
-        // a message came or no more idle processing to do
-        DoMessage();
+    ClassRegInfo regClass(name);
+    wndclass.lpszClassName = regClass.regname.t_str();
+    if ( !::RegisterClass(&wndclass) )
+    {
+        wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
+                       regClass.regname));
+        return NULL;
     }
 
     }
 
-    return s_currentMsg.wParam;
-}
-
-// Returns TRUE if more time is needed.
-bool wxApp::ProcessIdle()
-{
-    wxIdleEvent event;
-    event.SetEventObject(this);
-    ProcessEvent(event);
+    wndclass.style &= ~(CS_HREDRAW | CS_VREDRAW);
+    wndclass.lpszClassName = regClass.regnameNR.t_str();
+    if ( !::RegisterClass(&wndclass) )
+    {
+        wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
+                       regClass.regname));
+        ::UnregisterClass(regClass.regname.c_str(), wxGetInstance());
+        return NULL;
+    }
 
 
-    return event.MoreRequested();
-}
+    gs_regClassesInfo.push_back(regClass);
 
 
-void wxApp::ExitMainLoop()
-{
-    // this will set m_keepGoing to FALSE a bit later
-    ::PostQuitMessage(0);
+    // take care to return the pointer which will remain valid after the
+    // function returns (it could be invalidated later if new elements are
+    // added to the vector and it's reallocated but this shouldn't matter as
+    // this pointer should be used right now, not stored)
+    return gs_regClassesInfo.back().regname.t_str();
 }
 
 }
 
-bool wxApp::Pending()
+bool wxApp::IsRegisteredClassName(const wxString& name)
 {
 {
-    return ::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0;
-}
+    const size_t count = gs_regClassesInfo.size();
+    for ( size_t n = 0; n < count; n++ )
+    {
+        if ( gs_regClassesInfo[n].regname == name ||
+                gs_regClassesInfo[n].regnameNR == name )
+            return true;
+    }
 
 
-void wxApp::Dispatch()
-{
-    DoMessage();
+    return false;
 }
 
 }
 
-/*
- * Give all windows a chance to preprocess
- * the message. Some may have accelerator tables, or have
- * MDI complications.
- */
-
-bool wxApp::ProcessMessage(WXMSG *wxmsg)
+void wxApp::UnregisterWindowClasses()
 {
 {
-    MSG *msg = (MSG *)wxmsg;
-    HWND hwnd = msg->hwnd;
-    wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd);
-
-    // this may happen if the event occured in a standard modeless dialog (the
-    // only example of which I know of is the find/replace dialog) - then call
-    // IsDialogMessage() to make TAB navigation in it work
-    if ( !wndThis )
+    const size_t count = gs_regClassesInfo.size();
+    for ( size_t n = 0; n < count; n++ )
     {
     {
-        // we need to find the dialog containing this control as
-        // IsDialogMessage() just eats all the messages (i.e. returns TRUE for
-        // them) if we call it for the control itself
-        while ( hwnd && ::GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD )
+        const ClassRegInfo& regClass = gs_regClassesInfo[n];
+        if ( !::UnregisterClass(regClass.regname.c_str(), wxGetInstance()) )
         {
         {
-            hwnd = ::GetParent(hwnd);
+            wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
+                           regClass.regname));
         }
 
         }
 
-        return hwnd && ::IsDialogMessage(hwnd, msg) != 0;
-    }
-
-#if wxUSE_TOOLTIPS
-    // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
-    // popup the tooltip bubbles
-    if ( (msg->message == WM_MOUSEMOVE) )
-    {
-        wxToolTip *tt = wndThis->GetToolTip();
-        if ( tt )
+        if ( !::UnregisterClass(regClass.regnameNR.c_str(), wxGetInstance()) )
         {
         {
-            tt->RelayEvent(wxmsg);
+            wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
+                           regClass.regnameNR));
         }
     }
         }
     }
-#endif // wxUSE_TOOLTIPS
 
 
-    // allow the window to prevent certain messages from being
-    // translated/processed (this is currently used by wxTextCtrl to always
-    // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
-    if ( !wndThis->MSWShouldPreProcessMessage(wxmsg) )
-    {
-        return FALSE;
-    }
+    gs_regClassesInfo.clear();
+}
 
 
-    // try translations first: the accelerators override everything
-    wxWindow *wnd;
+void wxApp::CleanUp()
+{
+    // all objects pending for deletion must be deleted first, otherwise
+    // UnregisterWindowClasses() call wouldn't succeed (because windows
+    // using the classes being unregistered still exist), so call the base
+    // class method first and only then do our clean up
+    wxAppBase::CleanUp();
 
 
-    for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
-    {
-        if ( wnd->MSWTranslateMessage(wxmsg))
-            return TRUE;
-
-        // stop at first top level window, i.e. don't try to process the key
-        // strokes originating in a dialog using the accelerators of the parent
-        // frame - this doesn't make much sense
-        if ( wnd->IsTopLevel() )
-            break;
-    }
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
+    wxSetKeyboardHook(false);
+#endif
 
 
-    // now try the other hooks (kbd navigation is handled here): we start from
-    // wndThis->GetParent() because wndThis->MSWProcessMessage() was already
-    // called above
-    for ( wnd = wndThis->GetParent(); wnd; wnd = wnd->GetParent() )
-    {
-        if ( wnd->MSWProcessMessage(wxmsg) )
-            return TRUE;
-    }
+    wxOleUninitialize();
 
 
-    // no special preprocessing for this message, dispatch it normally
-    return FALSE;
+    // for an EXE the classes are unregistered when it terminates but DLL may
+    // be loaded several times (load/unload/load) into the same process in
+    // which case the registration will fail after the first time if we don't
+    // unregister the classes now
+    UnregisterWindowClasses();
 }
 
 }
 
-// this is a temporary hack and will be replaced by using wxEventLoop in the
-// future
-//
-// it is needed to allow other event loops (currently only one: the modal
-// dialog one) to reset the OnIdle() semaphore because otherwise OnIdle()
-// wouldn't do anything while a modal dialog shown from OnIdle() call is shown.
-bool wxIsInOnIdleFlag = FALSE;
+// ----------------------------------------------------------------------------
+// wxApp ctor/dtor
+// ----------------------------------------------------------------------------
 
 
-void wxApp::OnIdle(wxIdleEvent& event)
+wxApp::wxApp()
 {
 {
-    // Avoid recursion (via ProcessEvent default case)
-    if ( wxIsInOnIdleFlag )
-        return;
-
-    wxIsInOnIdleFlag = TRUE;
-
-    // If there are pending events, we must process them: pending events
-    // are either events to the threads other than main or events posted
-    // with wxPostEvent() functions
-    // GRG: I have moved this here so that all pending events are processed
-    //   before starting to delete any objects. This behaves better (in
-    //   particular, wrt wxPostEvent) and is coherent with wxGTK's current
-    //   behaviour. Changed Feb/2000 before 2.1.14
-    ProcessPendingEvents();
+    m_printMode = wxPRINT_WINDOWS;
+}
 
 
-    // 'Garbage' collection of windows deleted with Close().
-    DeletePendingObjects();
+wxApp::~wxApp()
+{
+}
 
 
-#if wxUSE_LOG
-    // flush the logged messages if any
-    wxLog::FlushActive();
-#endif // wxUSE_LOG
+// ----------------------------------------------------------------------------
+// wxApp idle handling
+// ----------------------------------------------------------------------------
 
 
+void wxApp::OnIdle(wxIdleEvent& WXUNUSED(event))
+{
 #if wxUSE_DC_CACHEING
     // automated DC cache management: clear the cached DCs and bitmap
     // if it's likely that the app has finished with them, that is, we
     // get an idle event and we're not dragging anything.
     if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
 #if wxUSE_DC_CACHEING
     // automated DC cache management: clear the cached DCs and bitmap
     // if it's likely that the app has finished with them, that is, we
     // get an idle event and we're not dragging anything.
     if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
-        wxDC::ClearCache();
+        wxMSWDCImpl::ClearCache();
 #endif // wxUSE_DC_CACHEING
 #endif // wxUSE_DC_CACHEING
-
-    // Send OnIdle events to all windows
-    if ( SendIdleEvents() )
-    {
-        // SendIdleEvents() returns TRUE if at least one window requested more
-        // idle events
-        event.RequestMore(TRUE);
-    }
-
-    wxIsInOnIdleFlag = FALSE;
-}
-
-// Send idle event to all top-level windows
-bool wxApp::SendIdleEvents()
-{
-    bool needMore = FALSE;
-
-    wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
-    while (node)
-    {
-        wxWindow* win = node->GetData();
-        if (SendIdleEvents(win))
-            needMore = TRUE;
-        node = node->GetNext();
-    }
-
-    return needMore;
-}
-
-// Send idle event to window and all subwindows
-bool wxApp::SendIdleEvents(wxWindow* win)
-{
-    wxIdleEvent event;
-    event.SetEventObject(win);
-    win->GetEventHandler()->ProcessEvent(event);
-
-    bool needMore = event.MoreRequested();
-
-    wxWindowList::Node *node = win->GetChildren().GetFirst();
-    while ( node )
-    {
-        wxWindow *win = node->GetData();
-        if (SendIdleEvents(win))
-            needMore = TRUE;
-
-        node = node->GetNext();
-    }
-
-    return needMore;
 }
 
 void wxApp::WakeUpIdle()
 }
 
 void wxApp::WakeUpIdle()
@@ -890,21 +809,60 @@ void wxApp::WakeUpIdle()
     // start up again.  Doing it this way ensures that the idle handler
     // wakes up in the right thread (see also wxWakeUpMainThread() which does
     // the same for the main app thread only)
     // start up again.  Doing it this way ensures that the idle handler
     // wakes up in the right thread (see also wxWakeUpMainThread() which does
     // the same for the main app thread only)
-    wxWindow *topWindow = wxTheApp->GetTopWindow();
+    wxWindow * const topWindow = wxTheApp->GetTopWindow();
     if ( topWindow )
     {
     if ( topWindow )
     {
-        if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
+        HWND hwndTop = GetHwndOf(topWindow);
+
+        // Do not post WM_NULL if there's already a pending WM_NULL to avoid
+        // overflowing the message queue.
+        //
+        // Notice that due to a limitation of PeekMessage() API (which handles
+        // 0,0 range specially), we have to check the range from 0-1 instead.
+        // This still makes it possible to overflow the queue with WM_NULLs by
+        // interspersing the calles to WakeUpIdle() with windows creation but
+        // it should be rather hard to do it accidentally.
+        MSG msg;
+        if ( !::PeekMessage(&msg, hwndTop, 0, 1, PM_NOREMOVE) ||
+              ::PeekMessage(&msg, hwndTop, 1, 1, PM_NOREMOVE) )
         {
         {
-            // should never happen
-            wxLogLastError(wxT("PostMessage(WM_NULL)"));
+            if ( !::PostMessage(hwndTop, WM_NULL, 0, 0) )
+            {
+                // should never happen
+                wxLogLastError(wxT("PostMessage(WM_NULL)"));
+            }
         }
     }
         }
     }
+#if wxUSE_THREADS
+    else
+        wxWakeUpMainThread();
+#endif // wxUSE_THREADS
 }
 
 }
 
+// ----------------------------------------------------------------------------
+// other wxApp event hanlders
+// ----------------------------------------------------------------------------
+
 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
 {
 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
 {
-    if (GetTopWindow())
-        GetTopWindow()->Close(TRUE);
+    // Windows will terminate the process soon after we return from
+    // WM_ENDSESSION handler or when we delete our last window, so make sure we
+    // at least execute our cleanup code before
+
+    // prevent the window from being destroyed when the corresponding wxTLW is
+    // destroyed: this will result in a leak of a HWND, of course, but who
+    // cares when the process is being killed anyhow
+    if ( !wxTopLevelWindows.empty() )
+        wxTopLevelWindows[0]->SetHWND(0);
+
+    const int rc = OnExit();
+
+    wxEntryCleanup();
+
+    // calling exit() instead of ExitProcess() or not doing anything at all and
+    // being killed by Windows has the advantage of executing the dtors of
+    // global objects
+    exit(rc);
 }
 
 // Default behaviour: close the application with prompts. The
 }
 
 // Default behaviour: close the application with prompts. The
@@ -914,173 +872,194 @@ void wxApp::OnQueryEndSession(wxCloseEvent& event)
     if (GetTopWindow())
     {
         if (!GetTopWindow()->Close(!event.CanVeto()))
     if (GetTopWindow())
     {
         if (!GetTopWindow()->Close(!event.CanVeto()))
-            event.Veto(TRUE);
+            event.Veto(true);
     }
 }
 
     }
 }
 
-typedef struct _WXADllVersionInfo
+// ----------------------------------------------------------------------------
+// system DLL versions
+// ----------------------------------------------------------------------------
+
+// these functions have trivial inline implementations for CE
+#ifndef __WXWINCE__
+
+#if wxUSE_DYNLIB_CLASS
+
+namespace
 {
 {
-        DWORD cbSize;
-        DWORD dwMajorVersion;                   // Major version
-        DWORD dwMinorVersion;                   // Minor version
-        DWORD dwBuildNumber;                    // Build number
-        DWORD dwPlatformID;                     // DLLVER_PLATFORM_*
-} WXADLLVERSIONINFO;
 
 
-typedef HRESULT (CALLBACK* WXADLLGETVERSIONPROC)(WXADLLVERSIONINFO *);
+// helper function: retrieve the DLL version by using DllGetVersion(), returns
+// 0 if the DLL doesn't export such function
+int CallDllGetVersion(wxDynamicLibrary& dll)
+{
+    // now check if the function is available during run-time
+    wxDYNLIB_FUNCTION( DLLGETVERSIONPROC, DllGetVersion, dll );
+    if ( !pfnDllGetVersion )
+        return 0;
+
+    DLLVERSIONINFO dvi;
+    dvi.cbSize = sizeof(dvi);
+
+    HRESULT hr = (*pfnDllGetVersion)(&dvi);
+    if ( FAILED(hr) )
+    {
+        wxLogApiError(wxT("DllGetVersion"), hr);
+
+        return 0;
+    }
+
+    return 100*dvi.dwMajorVersion + dvi.dwMinorVersion;
+}
+
+} // anonymous namespace
 
 /* static */
 int wxApp::GetComCtl32Version()
 {
 
 /* static */
 int wxApp::GetComCtl32Version()
 {
-#ifdef __WXMICROWIN__
-    return 0;
-#else
     // cache the result
     // cache the result
+    //
+    // NB: this is MT-ok as in the worst case we'd compute s_verComCtl32 twice,
+    //     but as its value should be the same both times it doesn't matter
     static int s_verComCtl32 = -1;
 
     static int s_verComCtl32 = -1;
 
-    wxCRIT_SECT_DECLARE(csComCtl32);
-    wxCRIT_SECT_LOCKER(lock, csComCtl32);
-
     if ( s_verComCtl32 == -1 )
     {
     if ( s_verComCtl32 == -1 )
     {
-        // initally assume no comctl32.dll at all
-        s_verComCtl32 = 0;
-
-        // do we have it?
-        HMODULE hModuleComCtl32 = ::GetModuleHandle(wxT("COMCTL32"));
-        BOOL bFreeComCtl32 = FALSE ;
-        if(!hModuleComCtl32)
+        // we're prepared to handle the errors
+        wxLogNull noLog;
+
+        // we don't want to load comctl32.dll, it should be already loaded but,
+        // depending on the OS version and the presence of the manifest, it can
+        // be either v5 or v6 and instead of trying to guess it just get the
+        // handle of the already loaded version
+        wxLoadedDLL dllComCtl32(wxT("comctl32.dll"));
+        if ( !dllComCtl32.IsLoaded() )
         {
         {
-            hModuleComCtl32 = ::LoadLibrary(wxT("COMCTL32.DLL")) ;
-            if(hModuleComCtl32)
-            {
-                bFreeComCtl32 = TRUE ;
-            }
+            s_verComCtl32 = 0;
+            return 0;
         }
 
         }
 
-        // if so, then we can check for the version
-        if ( hModuleComCtl32 )
+        // try DllGetVersion() for recent DLLs
+        s_verComCtl32 = CallDllGetVersion(dllComCtl32);
+
+        // if DllGetVersion() is unavailable either during compile or
+        // run-time, try to guess the version otherwise
+        if ( !s_verComCtl32 )
         {
         {
-            // try to use DllGetVersion() if available in _headers_
-                WXADLLGETVERSIONPROC pfnDllGetVersion = (WXADLLGETVERSIONPROC)
-                    ::GetProcAddress(hModuleComCtl32, "DllGetVersion");
-                if ( pfnDllGetVersion )
+            // InitCommonControlsEx is unique to 4.70 and later
+            void *pfn = dllComCtl32.GetSymbol(wxT("InitCommonControlsEx"));
+            if ( !pfn )
+            {
+                // not found, must be 4.00
+                s_verComCtl32 = 400;
+            }
+            else // 4.70+
+            {
+                // many symbols appeared in comctl32 4.71, could use any of
+                // them except may be DllInstall()
+                pfn = dllComCtl32.GetSymbol(wxT("InitializeFlatSB"));
+                if ( !pfn )
                 {
                 {
-                    WXADLLVERSIONINFO dvi;
-                    dvi.cbSize = sizeof(dvi);
-
-                    HRESULT hr = (*pfnDllGetVersion)(&dvi);
-                    if ( FAILED(hr) )
-                    {
-                        wxLogApiError(_T("DllGetVersion"), hr);
-                    }
-                    else
-                    {
-                        // this is incompatible with _WIN32_IE values, but
-                        // compatible with the other values returned by
-                        // GetComCtl32Version()
-                        s_verComCtl32 = 100*dvi.dwMajorVersion +
-                                            dvi.dwMinorVersion;
-                    }
+                    // not found, must be 4.70
+                    s_verComCtl32 = 470;
                 }
                 }
-                // DllGetVersion() unavailable either during compile or
-                // run-time, try to guess the version otherwise
-                if ( !s_verComCtl32 )
+                else
                 {
                 {
-                    // InitCommonControlsEx is unique to 4.70 and later
-                    FARPROC theProc = ::GetProcAddress
-                                        (
-                                         hModuleComCtl32,
-                                         "InitCommonControlsEx"
-                                        );
-
-                    if ( !theProc )
-                    {
-                        // not found, must be 4.00
-                        s_verComCtl32 = 400;
-                    }
-                    else
-                    {
-                        // many symbols appeared in comctl32 4.71, could use
-                        // any of them except may be DllInstall
-                        theProc = ::GetProcAddress
-                                    (
-                                     hModuleComCtl32,
-                                     "InitializeFlatSB"
-                                    );
-                        if ( !theProc )
-                        {
-                            // not found, must be 4.70
-                            s_verComCtl32 = 470;
-                        }
-                        else
-                        {
-                            // found, must be 4.71
-                            s_verComCtl32 = 471;
-                        }
-                    }
+                    // found, must be 4.71 or later
+                    s_verComCtl32 = 471;
                 }
                 }
-        }
-
-        if(bFreeComCtl32)
-        {
-            ::FreeLibrary(hModuleComCtl32) ;
+            }
         }
     }
 
     return s_verComCtl32;
         }
     }
 
     return s_verComCtl32;
-#endif
 }
 
 }
 
-// Yield to incoming messages
-
-bool wxApp::Yield(bool onlyIfNeeded)
+/* static */
+int wxApp::GetShell32Version()
 {
 {
-    // MT-FIXME
-    static bool s_inYield = FALSE;
+    static int s_verShell32 = -1;
+    if ( s_verShell32 == -1 )
+    {
+        // we're prepared to handle the errors
+        wxLogNull noLog;
 
 
-#if wxUSE_LOG
-    // disable log flushing from here because a call to wxYield() shouldn't
-    // normally result in message boxes popping up &c
-    wxLog::Suspend();
-#endif // wxUSE_LOG
+        wxDynamicLibrary dllShell32(wxT("shell32.dll"), wxDL_VERBATIM);
+        if ( dllShell32.IsLoaded() )
+        {
+            s_verShell32 = CallDllGetVersion(dllShell32);
 
 
-    if ( s_inYield )
-    {
-        if ( !onlyIfNeeded )
+            if ( !s_verShell32 )
+            {
+                // there doesn't seem to be any way to distinguish between 4.00
+                // and 4.70 (starting from 4.71 we have DllGetVersion()) so
+                // just assume it is 4.0
+                s_verShell32 = 400;
+            }
+        }
+        else // failed load the DLL?
         {
         {
-            wxFAIL_MSG( wxT("wxYield called recursively" ) );
+            s_verShell32 = 0;
         }
         }
-
-        return FALSE;
     }
 
     }
 
-    s_inYield = TRUE;
+    return s_verShell32;
+}
 
 
-    // we don't want to process WM_QUIT from here - it should be processed in
-    // the main event loop in order to stop it
-    MSG msg;
-    while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
-            msg.message != WM_QUIT )
-    {
-#if wxUSE_THREADS
-        wxMutexGuiLeaveOrEnter();
-#endif // wxUSE_THREADS
+#else // !wxUSE_DYNLIB_CLASS
 
 
-        if ( !wxTheApp->DoMessage() )
-            break;
-    }
+/* static */
+int wxApp::GetComCtl32Version()
+{
+    return 0;
+}
 
 
-    // if there are pending events, we must process them.
-    ProcessPendingEvents();
+/* static */
+int wxApp::GetShell32Version()
+{
+    return 0;
+}
+
+#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
 
 
-#if wxUSE_LOG
-    // let the logs be flashed again
-    wxLog::Resume();
-#endif // wxUSE_LOG
+#endif // !__WXWINCE__
 
 
-    s_inYield = FALSE;
+#if wxUSE_EXCEPTIONS
+
+// ----------------------------------------------------------------------------
+// exception handling
+// ----------------------------------------------------------------------------
 
 
-    return TRUE;
+bool wxApp::OnExceptionInMainLoop()
+{
+    // ask the user about what to do: use the Win32 API function here as it
+    // could be dangerous to use any wxWidgets code in this state
+    switch (
+            ::MessageBox
+              (
+                NULL,
+                wxT("An unhandled exception occurred. Press \"Abort\" to \
+terminate the program,\r\n\
+\"Retry\" to exit the program normally and \"Ignore\" to try to continue."),
+                wxT("Unhandled exception"),
+                MB_ABORTRETRYIGNORE |
+                MB_ICONERROR|
+                MB_TASKMODAL
+              )
+           )
+    {
+        case IDABORT:
+            throw;
+
+        default:
+            wxFAIL_MSG( wxT("unexpected MessageBox() return code") );
+            // fall through
+
+        case IDRETRY:
+            return false;
+
+        case IDIGNORE:
+            return true;
+    }
 }
 
 }
 
+#endif // wxUSE_EXCEPTIONS