]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/app.cpp
Add more checks for Intel compiler.
[wxWidgets.git] / src / msw / app.cpp
index 1b2e4f96baa9477b9c66afc60201dbc190dd4414..cadcdaaead1aca02b926492dd09a76d978341fdc 100644 (file)
@@ -1,10 +1,9 @@
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
-// Name:        app.cpp
+// Name:        src/msw/app.cpp
 // Purpose:     wxApp
 // Author:      Julian Smart
 // Modified by:
 // Created:     04/01/98
 // Purpose:     wxApp
 // Author:      Julian Smart
 // Modified by:
 // Created:     04/01/98
-// RCS-ID:      $Id$
 // Copyright:   (c) Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 // Copyright:   (c) Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 // 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 +24,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"
 #endif
 
 #include "wx/apptrait.h"
-#include "wx/cmdline.h"
 #include "wx/filename.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
+#include "wx/msw/missing.h"
 
 
-#ifndef __WXMICROWIN__
-#include "wx/msw/msvcrt.h"
-#endif
-
-// ----------------------------------------------------------------------------
-// conditional compilation
-// ----------------------------------------------------------------------------
-
-// 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
+{
 
 
-HICON wxSTD_FRAME_ICON = (HICON) NULL;
-HICON wxSTD_MDICHILDFRAME_ICON = (HICON) NULL;
-HICON wxSTD_MDIPARENTFRAME_ICON = (HICON) NULL;
+wxVector<ClassRegInfo> gs_regClassesInfo;
 
 
-HICON wxDEFAULT_FRAME_ICON = (HICON) NULL;
-HICON wxDEFAULT_MDICHILDFRAME_ICON = (HICON) NULL;
-HICON wxDEFAULT_MDIPARENTFRAME_ICON = (HICON) NULL;
+} // anonymous namespace
 
 
-HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
+// ----------------------------------------------------------------------------
+// private functions
+// ----------------------------------------------------------------------------
 
 LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
 
 
 LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
 
-// FIXME wxUSE_ON_FATAL_EXCEPTION is only supported for VC++ now because it
-//       needs compiler support for Win32 SEH. Others (especially Borland)
-//       probably have it too, but I'm not sure about how it works
-// JACS: get 'Cannot use __try in functions that require unwinding
-// in Unicode mode, so disabling.
-#if !defined(__VISUALC__) || defined(__WIN16__) || defined(UNICODE)
-    #undef wxUSE_ON_FATAL_EXCEPTION
-    #define wxUSE_ON_FATAL_EXCEPTION 0
-#endif // VC++
-
-#if wxUSE_ON_FATAL_EXCEPTION
-    static bool gs_handleExceptions = FALSE;
-#endif
-
 // ===========================================================================
 // wxGUIAppTraits implementation
 // ===========================================================================
 // ===========================================================================
 // wxGUIAppTraits implementation
 // ===========================================================================
@@ -194,12 +171,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.
      */
@@ -208,1021 +185,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();
-}
-
-// ===========================================================================
-// wxApp implementation
-// ===========================================================================
-
-// ---------------------------------------------------------------------------
-// wxWin macros
-// ---------------------------------------------------------------------------
-
-IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
+    // 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;
+    }
 
 
-BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
-    EVT_IDLE(wxApp::OnIdle)
-    EVT_END_SESSION(wxApp::OnEndSession)
-    EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
-END_EVENT_TABLE()
+    return evtLoop->Dispatch();
+}
 
 
-//// Initialize
-bool wxApp::Initialize()
+DWORD wxGUIAppTraits::WaitForThread(WXHANDLE hThread, int flags)
 {
 {
-    // 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 )
+    // 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() )
     {
     {
-        // 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;
+        // Simple blocking wait.
+        return DoSimpleWaitForThread(hThread);
     }
     }
-#endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
-
-    wxBuffer = new wxChar[1500]; // FIXME
-
-    wxClassInfo::InitializeClasses();
-
-#if wxUSE_THREADS
-    wxPendingEventsLocker = new wxCriticalSection;
-#endif
-
-    wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
-    wxTheColourDatabase->Initialize();
-
-    wxInitializeStockLists();
-    wxInitializeStockObjects();
-
-    wxBitmap::InitStandardHandlers();
-
-#if defined(__WIN95__) && !defined(__WXMICROWIN__)
-    InitCommonControls();
-#endif // __WIN95__
 
 
-#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
-
-#if wxUSE_OLE
-    // we need to initialize OLE library
-    if ( FAILED(::OleInitialize(NULL)) )
-        wxLogError(_("Cannot initialize OLE"));
-#endif
-
-#endif // wxUSE_OLE
-
-#if wxUSE_CTL3D
-    if (!Ctl3dRegister(wxhInstance))
-        wxLogError(wxT("Cannot register CTL3D"));
-
-    Ctl3dAutoSubclass(wxhInstance);
-#endif // wxUSE_CTL3D
-
-    // VZ: these icons are not in wx.rc anyhow (but should they?)!
-#if 0
-    wxSTD_FRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_FRAME"));
-    wxSTD_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_MDIPARENTFRAME"));
-    wxSTD_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_MDICHILDFRAME"));
-
-    wxDEFAULT_FRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_FRAME"));
-    wxDEFAULT_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_MDIPARENTFRAME"));
-    wxDEFAULT_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, wxT("wxDEFAULT_MDICHILDFRAME"));
-#endif // 0
-
-    RegisterWindowClasses();
+    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
 
 
-#ifndef __WXMICROWIN__
-    // Create the brush for disabling bitmap buttons
+wxPortId wxGUIAppTraits::GetToolkitVersion(int *majVer, int *minVer) const
+{
+    OSVERSIONINFO info;
+    wxZeroMemory(info);
 
 
-    LOGBRUSH lb;
-    lb.lbStyle = BS_PATTERN;
-    lb.lbColor = 0;
-    lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
-    if ( lb.lbHatch )
+    // 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) )
     {
     {
-        wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
-        ::DeleteObject( (HGDIOBJ)lb.lbHatch );
+        if ( majVer )
+            *majVer = info.dwMajorVersion;
+        if ( minVer )
+            *minVer = info.dwMinorVersion;
     }
     }
-    //else: wxWindows resources are probably not linked in
-#endif
 
 
-#if wxUSE_PENWINDOWS
-    wxRegisterPenWin();
+#if defined(__WXHANDHELD__) || defined(__WXWINCE__)
+    return wxPORT_WINCE;
+#else
+    return wxPORT_MSW;
 #endif
 #endif
+}
 
 
-    wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
+#if wxUSE_TIMER
 
 
-    // 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
+wxTimerImpl *wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
+{
+    return new wxMSWTimerImpl(timer);
+}
 
 
-#ifndef __WXMICROWIN__
-    wxSetKeyboardHook(TRUE);
-#endif
+#endif // wxUSE_TIMER
 
 
-    wxModule::RegisterModules();
-    if (!wxModule::InitializeModules())
-        return FALSE;
-    return TRUE;
+wxEventLoopBase* wxGUIAppTraits::CreateEventLoop()
+{
+    return new wxEventLoop;
 }
 
 // ---------------------------------------------------------------------------
 }
 
 // ---------------------------------------------------------------------------
-// RegisterWindowClasses
+// Stuff for using console from the GUI applications
 // ---------------------------------------------------------------------------
 
 // ---------------------------------------------------------------------------
 
-// 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);
+#ifndef __WXWINCE__
 
 
-    // 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 wxUSE_DYNLIB_CLASS
 
 
-    // the fields which are common to all classes
-    wndclass.lpfnWndProc   = (WNDPROC)wxWndProc;
-    wndclass.hInstance     = wxhInstance;
-    wndclass.hCursor       = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
+#include <wx/dynlib.h>
 
 
-    // Register the frame window class.
-    wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
-    wndclass.lpszClassName = wxCanvasClassName;
-    wndclass.style         = styleNormal;
+namespace
+{
 
 
-    if ( !RegisterClass(&wndclass) )
-    {
-        wxLogLastError(wxT("RegisterClass(frame)"));
-    }
+/*
+    Helper class to manipulate console from a GUI app.
 
 
-    // "no redraw" frame
-    wndclass.lpszClassName = wxCanvasClassNameNR;
-    wndclass.style         = styleNoRedraw;
+    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
 
 
-    if ( !RegisterClass(&wndclass) )
+    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
+{
+public:
+    // default ctor does nothing, call Init() before using this class
+    wxConsoleStderr()
     {
     {
-        wxLogLastError(wxT("RegisterClass(no redraw frame)"));
-    }
+        m_hStderr = INVALID_HANDLE_VALUE;
+        m_historyLen =
+        m_dataLen =
+        m_dataLine = 0;
 
 
-    // Register the MDI frame window class.
-    wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
-    wndclass.lpszClassName = wxMDIFrameClassName;
-    wndclass.style         = styleNormal;
-
-    if ( !RegisterClass(&wndclass) )
-    {
-        wxLogLastError(wxT("RegisterClass(MDI parent)"));
+        m_ok = -1;
     }
 
     }
 
-    // "no redraw" MDI frame
-    wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
-    wndclass.style         = styleNoRedraw;
-
-    if ( !RegisterClass(&wndclass) )
+    ~wxConsoleStderr()
     {
     {
-        wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
+        if ( m_hStderr != INVALID_HANDLE_VALUE )
+        {
+            if ( !::FreeConsole() )
+            {
+                wxLogLastError(wxT("FreeConsole"));
+            }
+        }
     }
 
     }
 
-    // Register the MDI child frame window class.
-    wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
-    wndclass.lpszClassName = wxMDIChildFrameClassName;
-    wndclass.style         = styleNormal;
-
-    if ( !RegisterClass(&wndclass) )
+    // 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
     {
     {
-        wxLogLastError(wxT("RegisterClass(MDI child)"));
-    }
+        if ( m_ok == -1 )
+        {
+            wxConsoleStderr * const self = const_cast<wxConsoleStderr *>(this);
+            self->m_ok = self->DoInit();
 
 
-    // "no redraw" MDI child frame
-    wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
-    wndclass.style         = styleNoRedraw;
+            // no need to call IsHistoryUnchanged() as we just initialized
+            // m_history anyhow
+            return m_ok == 1;
+        }
 
 
-    if ( !RegisterClass(&wndclass) )
-    {
-        wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
+        return m_ok && IsHistoryUnchanged();
     }
 
     }
 
-    return TRUE;
-}
 
 
-// ---------------------------------------------------------------------------
-// UnregisterWindowClasses
-// ---------------------------------------------------------------------------
+    // output the provided text on the console, return true if ok
+    bool Write(const wxString& text);
 
 
-bool wxApp::UnregisterWindowClasses()
-{
-    bool retval = TRUE;
+private:
+    // called by Init() once only to do the real initialization
+    bool DoInit();
 
 
-#ifndef __WXMICROWIN__
-    // MDI frame window class.
-    if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
-    {
-        wxLogLastError(wxT("UnregisterClass(MDI parent)"));
+    // retrieve the command line history into the provided buffer and return
+    // its length
+    int GetCommandHistory(wxWxCharBuffer& buf) const;
 
 
-        retval = FALSE;
-    }
+    // check if the console history has changed
+    bool IsHistoryUnchanged() const;
 
 
-    // "no redraw" MDI frame
-    if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
-    {
-        wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
+    int m_ok;                   // initially -1, set to true or false by Init()
 
 
-        retval = FALSE;
-    }
+    wxDynamicLibrary m_dllKernel32;
 
 
-    // MDI child frame window class.
-    if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
-    {
-        wxLogLastError(wxT("UnregisterClass(MDI child)"));
+    HANDLE m_hStderr;           // console handle, if it's valid we must call
+                                // FreeConsole() (even if m_ok != 1)
 
 
-        retval = FALSE;
-    }
+    wxWxCharBuffer m_history;   // command history on startup
+    int m_historyLen;           // length command history buffer
 
 
-    // "no redraw" MDI child frame
-    if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
-    {
-        wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
+    wxCharBuffer m_data;        // data between empty line and cursor position
+    int m_dataLen;              // length data buffer
+    int m_dataLine;             // line offset
 
 
-        retval = FALSE;
-    }
+    typedef DWORD (WINAPI *GetConsoleCommandHistory_t)(LPTSTR sCommands,
+                                                       DWORD nBufferLength,
+                                                       LPCTSTR sExeName);
+    typedef DWORD (WINAPI *GetConsoleCommandHistoryLength_t)(LPCTSTR sExeName);
 
 
-    // canvas class name
-    if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
-    {
-        wxLogLastError(wxT("UnregisterClass(canvas)"));
+    GetConsoleCommandHistory_t m_pfnGetConsoleCommandHistory;
+    GetConsoleCommandHistoryLength_t m_pfnGetConsoleCommandHistoryLength;
 
 
-        retval = FALSE;
-    }
-
-    if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
-    {
-        wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
-
-        retval = FALSE;
-    }
-#endif // __WXMICROWIN__
-
-    return retval;
-}
-
-// ---------------------------------------------------------------------------
-// Convert Windows to argc, argv style
-// ---------------------------------------------------------------------------
+    wxDECLARE_NO_COPY_CLASS(wxConsoleStderr);
+};
 
 
-void wxApp::ConvertToStandardCommandArgs(const char* lpCmdLine)
+bool wxConsoleStderr::DoInit()
 {
 {
-    // break the command line in words
-    wxArrayString args =
-        wxCmdLineParser::ConvertStringToArgs(wxConvertMB2WX(lpCmdLine));
+    HANDLE hStderr = ::GetStdHandle(STD_ERROR_HANDLE);
 
 
-    // +1 here for the program name
-    argc = args.GetCount() + 1;
+    if ( hStderr == INVALID_HANDLE_VALUE || !hStderr )
+        return false;
 
 
-    // and +1 here for the terminating NULL
-    argv = new wxChar *[argc + 1];
+    if ( !m_dllKernel32.Load(wxT("kernel32.dll")) )
+        return false;
 
 
-    argv[0] = new wxChar[260]; // 260 is MAX_PATH value from windef.h
-    ::GetModuleFileName(wxhInstance, argv[0], 260);
+    typedef BOOL (WINAPI *AttachConsole_t)(DWORD dwProcessId);
+    AttachConsole_t wxDL_INIT_FUNC(pfn, AttachConsole, m_dllKernel32);
 
 
-    // also set the app name from argv[0]
-    wxString name;
-    wxFileName::SplitPath(argv[0], NULL, &name, NULL);
+    if ( !pfnAttachConsole || !pfnAttachConsole(ATTACH_PARENT_PROCESS) )
+        return false;
 
 
-    // but don't override the name already set by the user code, if any
-    if ( GetAppName().empty() )
-        SetAppName(name);
+    // console attached, set m_hStderr now to ensure that we free it in the
+    // dtor
+    m_hStderr = hStderr;
 
 
-    // copy all the other arguments to wxApp::argv[]
-    for ( int i = 1; i < argc; i++ )
-    {
-        argv[i] = copystring(args[i - 1]);
-    }
+    wxDL_INIT_FUNC_AW(m_pfn, GetConsoleCommandHistory, m_dllKernel32);
+    if ( !m_pfnGetConsoleCommandHistory )
+        return false;
 
 
-    // argv[] must be NULL-terminated
-    argv[argc] = NULL;
-}
+    wxDL_INIT_FUNC_AW(m_pfn, GetConsoleCommandHistoryLength, m_dllKernel32);
+    if ( !m_pfnGetConsoleCommandHistoryLength )
+        return false;
 
 
-//// Cleans up any wxWindows internal structures left lying around
+    // 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;
 
 
-void wxApp::CleanUp()
-{
-    //// COMMON CLEANUP
-
-#if wxUSE_LOG
-    // flush the logged messages if any and install a 'safer' log target: the
-    // default one (wxLogGui) can't be used after the resources are freed just
-    // below and the user suppliedo ne might be even more unsafe (using any
-    // wxWindows GUI function is unsafe starting from now)
-    wxLog::DontCreateOnDemand();
-
-    // this will flush the old messages if any
-    delete wxLog::SetActiveTarget(new wxLogStderr);
-#endif // wxUSE_LOG
 
 
-    // One last chance for pending objects to be cleaned up
-    wxTheApp->DeletePendingObjects();
+    // now find the first blank line above the current position
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
 
 
-    wxModule::CleanUpModules();
+    if ( !::GetConsoleScreenBufferInfo(m_hStderr, &csbi) )
+    {
+        wxLogLastError(wxT("GetConsoleScreenBufferInfo"));
+        return false;
+    }
 
 
-    wxDeleteStockObjects();
+    COORD pos;
+    pos.X = 0;
+    pos.Y = csbi.dwCursorPosition.Y + 1;
 
 
-    // Destroy all GDI lists, etc.
-    wxDeleteStockLists();
+    // we decide that a line is empty if first 4 characters are spaces
+    DWORD ret;
+    char buf[4];
+    do
+    {
+        pos.Y--;
+        if ( !::ReadConsoleOutputCharacterA(m_hStderr, buf, WXSIZEOF(buf),
+                                            pos, &ret) )
+        {
+            wxLogLastError(wxT("ReadConsoleOutputCharacterA"));
+            return false;
+        }
+    } while ( wxStrncmp("    ", buf, WXSIZEOF(buf)) != 0 );
 
 
-    delete wxTheColourDatabase;
-    wxTheColourDatabase = NULL;
+    // calculate line offset and length of data
+    m_dataLine = csbi.dwCursorPosition.Y - pos.Y;
+    m_dataLen = m_dataLine*csbi.dwMaximumWindowSize.X + csbi.dwCursorPosition.X;
 
 
-    wxBitmap::CleanUpHandlers();
+    if ( m_dataLen > 0 )
+    {
+        m_data.extend(m_dataLen);
+        if ( !::ReadConsoleOutputCharacterA(m_hStderr, m_data.data(), m_dataLen,
+                                            pos, &ret) )
+        {
+            wxLogLastError(wxT("ReadConsoleOutputCharacterA"));
+            return false;
+        }
+    }
 
 
-    delete[] wxBuffer;
-    wxBuffer = NULL;
+    return true;
+}
 
 
-    //// WINDOWS-SPECIFIC CLEANUP
+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");
 
 
-#ifndef __WXMICROWIN__
-    wxSetKeyboardHook(FALSE);
-#endif
+    const int len = m_pfnGetConsoleCommandHistoryLength(CMD_EXE);
+    if ( len )
+    {
+        buf.extend(len);
 
 
-#if wxUSE_PENWINDOWS
-    wxCleanUpPenWin();
-#endif
+        int len2 = m_pfnGetConsoleCommandHistory(buf.data(), len, CMD_EXE);
 
 
-    if (wxSTD_FRAME_ICON)
-        DestroyIcon(wxSTD_FRAME_ICON);
-    if (wxSTD_MDICHILDFRAME_ICON)
-        DestroyIcon(wxSTD_MDICHILDFRAME_ICON);
-    if (wxSTD_MDIPARENTFRAME_ICON)
-        DestroyIcon(wxSTD_MDIPARENTFRAME_ICON);
+#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 (wxDEFAULT_FRAME_ICON)
-        DestroyIcon(wxDEFAULT_FRAME_ICON);
-    if (wxDEFAULT_MDICHILDFRAME_ICON)
-        DestroyIcon(wxDEFAULT_MDICHILDFRAME_ICON);
-    if (wxDEFAULT_MDIPARENTFRAME_ICON)
-        DestroyIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
+        if ( len2 != len )
+        {
+            wxFAIL_MSG( wxT("failed getting history?") );
+        }
+    }
 
 
-    if ( wxDisableButtonBrush )
-        ::DeleteObject( wxDisableButtonBrush );
+    return len;
+}
 
 
-#if wxUSE_OLE
-    ::OleUninitialize();
-#endif
+bool wxConsoleStderr::IsHistoryUnchanged() const
+{
+    wxASSERT_MSG( m_ok == 1, wxT("shouldn't be called if not initialized") );
 
 
-#ifdef WXMAKINGDLL
-    // 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 // WXMAKINGDLL
+    // get (possibly changed) command history
+    wxWxCharBuffer history;
+    const int historyLen = GetCommandHistory(history);
 
 
-#if wxUSE_CTL3D
-    Ctl3dUnregister(wxhInstance);
-#endif
+    // and compare it with the original one
+    return historyLen == m_historyLen && history &&
+                memcmp(m_history, history, historyLen) == 0;
+}
 
 
-    delete wxWinHandleHash;
-    wxWinHandleHash = NULL; // Set to null in case anything later tries to ref it.
+bool wxConsoleStderr::Write(const wxString& text)
+{
+    wxASSERT_MSG( m_hStderr != INVALID_HANDLE_VALUE,
+                    wxT("should only be called if Init() returned true") );
 
 
-    delete wxPendingEvents;
-    wxPendingEvents = NULL; // Set to null because wxAppBase::wxEvtHandler is destroyed later.
+    // get current position
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    if ( !::GetConsoleScreenBufferInfo(m_hStderr, &csbi) )
+    {
+        wxLogLastError(wxT("GetConsoleScreenBufferInfo"));
+        return false;
+    }
 
 
-#if wxUSE_THREADS
-    delete wxPendingEventsLocker;
-    wxPendingEventsLocker = NULL; // Set to null because wxAppBase::wxEvtHandler is destroyed later.
-    // If we don't do the following, we get an apparent memory leak
-#if wxUSE_VALIDATORS
-    ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
-#endif // wxUSE_VALIDATORS
-#endif // wxUSE_THREADS
+    // and calculate new position (where is empty line)
+    csbi.dwCursorPosition.X = 0;
+    csbi.dwCursorPosition.Y -= m_dataLine;
 
 
-    wxClassInfo::CleanUpClasses();
+    if ( !::SetConsoleCursorPosition(m_hStderr, csbi.dwCursorPosition) )
+    {
+        wxLogLastError(wxT("SetConsoleCursorPosition"));
+        return false;
+    }
 
 
-    delete wxTheApp;
-    wxTheApp = NULL;
+    DWORD ret;
+    if ( !::FillConsoleOutputCharacter(m_hStderr, wxT(' '), m_dataLen,
+                                       csbi.dwCursorPosition, &ret) )
+    {
+        wxLogLastError(wxT("FillConsoleOutputCharacter"));
+        return false;
+    }
 
 
-#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
-    // At this point we want to check if there are any memory
-    // blocks that aren't part of the wxDebugContext itself,
-    // as a special case. Then when dumping we need to ignore
-    // wxDebugContext, too.
-    if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
+    if ( !::WriteConsole(m_hStderr, text.t_str(), text.length(), &ret, NULL) )
     {
     {
-        wxLogMessage(wxT("There were memory leaks."));
-        wxDebugContext::Dump();
-        wxDebugContext::PrintStatistics();
+        wxLogLastError(wxT("WriteConsole"));
+        return false;
     }
     }
-    //  wxDebugContext::SetStream(NULL, NULL);
-#endif
 
 
-#if wxUSE_LOG
-    // do it as the very last thing because everything else can log messages
-    delete wxLog::SetActiveTarget(NULL);
-#endif // wxUSE_LOG
+    WriteConsoleA(m_hStderr, m_data, m_dataLen, &ret, 0);
+
+    return true;
 }
 
 }
 
-//----------------------------------------------------------------------
-// Entry point helpers, used by wxPython
-//----------------------------------------------------------------------
+wxConsoleStderr s_consoleStderr;
 
 
-int WXDLLEXPORT wxEntryStart( int WXUNUSED(argc), char** WXUNUSED(argv) )
-{
-    return wxApp::Initialize();
-}
+} // anonymous namespace
 
 
-int WXDLLEXPORT wxEntryInitGui()
+bool wxGUIAppTraits::CanUseStderr()
 {
 {
-    return wxTheApp->OnInitGui();
+    return s_consoleStderr.IsOkToUse();
 }
 
 }
 
-void WXDLLEXPORT wxEntryCleanup()
+bool wxGUIAppTraits::WriteToStderr(const wxString& text)
 {
 {
-    wxApp::CleanUp();
+    return s_consoleStderr.IsOkToUse() && s_consoleStderr.Write(text);
 }
 
 }
 
+#else // !wxUSE_DYNLIB_CLASS
 
 
-#if !defined(_WINDLL) || (defined(_WINDLL) && defined(WXMAKINGDLL))
-
-// temporarily disable this warning which would be generated in release builds
-// because of __try
-#ifdef __VISUALC__
-    #pragma warning(disable: 4715) // not all control paths return a value
-#endif // Visual C++
+bool wxGUIAppTraits::CanUseStderr()
+{
+    return false;
+}
 
 
-//----------------------------------------------------------------------
-// Main wxWindows entry point
-//----------------------------------------------------------------------
-int wxEntry(WXHINSTANCE hInstance,
-            WXHINSTANCE WXUNUSED(hPrevInstance),
-            char *lpCmdLine,
-            int nCmdShow,
-            bool enterLoop)
+bool wxGUIAppTraits::WriteToStderr(const wxString& WXUNUSED(text))
 {
 {
-    // do check for memory leaks on program exit
-    // (another useful flag is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free
-    //  deallocated memory which may be used to simulate low-memory condition)
-#ifndef __WXMICROWIN__
-    wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF);
-#endif
+    return false;
+}
 
 
-#ifdef __MWERKS__
-#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
-    // This seems to be necessary since there are 'rogue'
-    // objects present at this point (perhaps global objects?)
-    // Setting a checkpoint will ignore them as far as the
-    // memory checking facility is concerned.
-    // Of course you may argue that memory allocated in globals should be
-    // checked, but this is a reasonable compromise.
-    wxDebugContext::SetCheckpoint();
-#endif
-#endif
+#endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
 
 
-    // take everything into a try-except block to be able to call
-    // OnFatalException() if necessary
-#if wxUSE_ON_FATAL_EXCEPTION
-    __try {
-#endif
-        wxhInstance = (HINSTANCE) hInstance;
+#endif // !__WXWINCE__
 
 
-        if (!wxEntryStart(0,0))
-            return 0;
+// ===========================================================================
+// wxApp implementation
+// ===========================================================================
 
 
-        // create the application object or ensure that one already exists
-        if (!wxTheApp)
-        {
-            // The app may have declared a global application object, but we recommend
-            // the IMPLEMENT_APP macro is used instead, which sets an initializer
-            // function for delayed, dynamic app object construction.
-            wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
-                         wxT("No initializer - use IMPLEMENT_APP macro.") );
+int wxApp::m_nCmdShow = SW_SHOWNORMAL;
 
 
-            wxTheApp = (wxApp*) (*wxApp::GetInitializerFunction()) ();
-        }
+// ---------------------------------------------------------------------------
+// wxWin macros
+// ---------------------------------------------------------------------------
 
 
-        wxCHECK_MSG( wxTheApp, 0, wxT("You have to define an instance of wxApp!") );
+IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
 
 
-        // save the WinMain() parameters
-        if (lpCmdLine) // MicroWindows passes NULL
-            wxTheApp->ConvertToStandardCommandArgs(lpCmdLine);
-        wxTheApp->m_nCmdShow = nCmdShow;
+BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
+    EVT_IDLE(wxApp::OnIdle)
+    EVT_END_SESSION(wxApp::OnEndSession)
+    EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
+END_EVENT_TABLE()
 
 
-        // We really don't want timestamps by default, because it means
-        // we can't simply double-click on the error message and get to that
-        // line in the source. So VC++ at least, let's have a sensible default.
-#ifdef __VISUALC__
-#if wxUSE_LOG
-        wxLog::SetTimestamp(NULL);
-#endif // wxUSE_LOG
-#endif // __VISUALC__
+// class to ensure that wxAppBase::CleanUp() is called if our Initialize()
+// fails
+class wxCallBaseCleanup
+{
+public:
+    wxCallBaseCleanup(wxApp *app) : m_app(app) { }
+    ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
 
 
-        // init the app
-        int retValue = wxEntryInitGui() && wxTheApp->OnInit() ? 0 : -1;
+    void Dismiss() { m_app = NULL; }
 
 
-        if ( retValue == 0 )
-        {
-            if ( enterLoop )
-            {
-                // run the main loop
-                wxTheApp->OnRun();
-            }
-            else
-            {
-                // we want to initialize, but not run or exit immediately.
-                return 1;
-            }
-        }
-        //else: app initialization failed, so we skipped OnRun()
+private:
+    wxApp *m_app;
+};
 
 
-        wxWindow *topWindow = wxTheApp->GetTopWindow();
-        if ( topWindow )
-        {
-            // Forcibly delete the window.
-            if ( topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
-                    topWindow->IsKindOf(CLASSINFO(wxDialog)) )
-            {
-                topWindow->Close(TRUE);
-                wxTheApp->DeletePendingObjects();
-            }
-            else
-            {
-                delete topWindow;
-                wxTheApp->SetTopWindow(NULL);
-            }
-        }
+//// Initialize
+bool wxApp::Initialize(int& argc, wxChar **argv)
+{
+    if ( !wxAppBase::Initialize(argc, argv) )
+        return false;
 
 
-        retValue = wxTheApp->OnExit();
+    // ensure that base cleanup is done if we return too early
+    wxCallBaseCleanup callBaseCleanup(this);
 
 
-        wxEntryCleanup();
+#if !defined(__WXMICROWIN__)
+    InitCommonControls();
+#endif // !defined(__WXMICROWIN__)
 
 
-        return retValue;
+#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
+    SHInitExtraControls();
+#endif
 
 
-#if wxUSE_ON_FATAL_EXCEPTION
-    }
-    __except ( gs_handleExceptions ? EXCEPTION_EXECUTE_HANDLER
-                                   : EXCEPTION_CONTINUE_SEARCH ) {
-        if ( wxTheApp )
-        {
-           // give the user a chance to do something special about this
-           wxTheApp->OnFatalException();
-        }
+#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
 
 
-        ::ExitProcess(3); // the same exit code as abort()
+    wxOleInitialize();
 
 
-        // NOTREACHED
-    }
-#endif // wxUSE_ON_FATAL_EXCEPTION
-}
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
+    wxSetKeyboardHook(true);
+#endif
 
 
-// restore warning state
-#ifdef __VISUALC__
-    #pragma warning(default: 4715) // not all control paths return a value
-#endif // Visual C++
+    callBaseCleanup.Dismiss();
 
 
-#else /*  _WINDLL  */
+    return true;
+}
 
 
-//----------------------------------------------------------------------
-// Entry point for wxWindows + the App in a DLL
-//----------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+// Win32 window class registration
+// ---------------------------------------------------------------------------
 
 
-int wxEntry(WXHINSTANCE hInstance)
+/* static */
+const wxChar *wxApp::GetRegisteredClassName(const wxChar *name,
+                                            int bgBrushCol,
+                                            int extraStyles)
 {
 {
-    wxhInstance = (HINSTANCE) hInstance;
-    wxEntryStart(0, 0);
-
-    // The app may have declared a global application object, but we recommend
-    // the IMPLEMENT_APP macro is used instead, which sets an initializer function
-    // for delayed, dynamic app object construction.
-    if (!wxTheApp)
+    const size_t count = gs_regClassesInfo.size();
+    for ( size_t n = 0; n < count; n++ )
     {
     {
-        wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
-                     "No initializer - use IMPLEMENT_APP macro." );
-
-        wxTheApp = (* wxApp::GetInitializerFunction()) ();
+        if ( gs_regClassesInfo[n].regname == name )
+            return gs_regClassesInfo[n].regname.c_str();
     }
 
     }
 
-    wxCHECK_MSG( wxTheApp, 0, "You have to define an instance of wxApp!" );
-
-    wxTheApp->argc = 0;
-    wxTheApp->argv = NULL;
+    // we need to register this class
+    WNDCLASS wndclass;
+    wxZeroMemory(wndclass);
 
 
-    wxEntryInitGui();
+    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;
 
 
-    wxTheApp->OnInit();
 
 
-    wxWindow *topWindow = wxTheApp->GetTopWindow();
-    if ( topWindow && topWindow->GetHWND())
+    ClassRegInfo regClass(name);
+    wndclass.lpszClassName = regClass.regname.t_str();
+    if ( !::RegisterClass(&wndclass) )
     {
     {
-        topWindow->Show(TRUE);
+        wxLogLastError(wxString::Format(wxT("RegisterClass(%s)"),
+                       regClass.regname));
+        return NULL;
     }
 
     }
 
-    return 1;
-}
-#endif // _WINDLL
+    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;
+    }
 
 
-//// Static member initialization
+    gs_regClassesInfo.push_back(regClass);
 
 
-wxApp::wxApp()
-{
-    argc = 0;
-    argv = NULL;
-    m_printMode = wxPRINT_WINDOWS;
-    m_auto3D = TRUE;
+    // 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();
 }
 
 }
 
-wxApp::~wxApp()
+bool wxApp::IsRegisteredClassName(const wxString& name)
 {
 {
-    // Delete command-line args
-    int i;
-    for (i = 0; i < argc; i++)
+    const size_t count = gs_regClassesInfo.size();
+    for ( size_t n = 0; n < count; n++ )
     {
     {
-        delete[] argv[i];
+        if ( gs_regClassesInfo[n].regname == name ||
+                gs_regClassesInfo[n].regnameNR == name )
+            return true;
     }
     }
-    delete[] argv;
-}
 
 
-bool wxApp::Initialized()
-{
-#ifndef _WINDLL
-    if (GetTopWindow())
-        return TRUE;
-    else
-        return FALSE;
-#else // Assume initialized if DLL (no way of telling)
-    return TRUE;
-#endif
+    return false;
 }
 
 }
 
-/*
- * 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()
+void wxApp::UnregisterWindowClasses()
 {
 {
-    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
+    const size_t count = gs_regClassesInfo.size();
+    for ( size_t n = 0; n < count; n++ )
     {
     {
-#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 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() )
+        const ClassRegInfo& regClass = gs_regClassesInfo[n];
+        if ( !::UnregisterClass(regClass.regname.c_str(), wxGetInstance()) )
         {
         {
-            s_hadGuiLock = FALSE;
-
-            // 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);
-            }
-
-            return TRUE;
+            wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
+                           regClass.regname));
         }
         }
-        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;
-
-                size_t count = s_aSavedMessages.GetCount();
-                for ( size_t n = 0; n < count; n++ )
-                {
-                    MSG& msg = s_aSavedMessages[n];
-
-                    DoMessage((WXMSG *)&msg);
-                }
 
 
-                s_aSavedMessages.Empty();
-            }
+        if ( !::UnregisterClass(regClass.regnameNR.c_str(), wxGetInstance()) )
+        {
+            wxLogLastError(wxString::Format(wxT("UnregisterClass(%s)"),
+                           regClass.regnameNR));
         }
         }
-#endif // wxUSE_THREADS
-
-        // Process the message
-        DoMessage((WXMSG *)&s_currentMsg);
-    }
-
-    return TRUE;
-}
-
-void wxApp::DoMessage(WXMSG *pMsg)
-{
-    if ( !ProcessMessage(pMsg) )
-    {
-        ::TranslateMessage((MSG *)pMsg);
-        ::DispatchMessage((MSG *)pMsg);
     }
     }
-}
-
-/*
- * 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;
-
-    while ( m_keepGoing )
-    {
-#if wxUSE_THREADS
-        wxMutexGuiLeaveOrEnter();
-#endif // wxUSE_THREADS
-
-        while ( !Pending() && ProcessIdle() )
-            ;
 
 
-        // a message came or no more idle processing to do
-        DoMessage();
-    }
-
-    return s_currentMsg.wParam;
+    gs_regClassesInfo.clear();
 }
 
 }
 
-// Returns TRUE if more time is needed.
-bool wxApp::ProcessIdle()
+void wxApp::CleanUp()
 {
 {
-    wxIdleEvent event;
-    event.SetEventObject(this);
-    ProcessEvent(event);
+    // 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();
+
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
+    wxSetKeyboardHook(false);
+#endif
 
 
-    return event.MoreRequested();
-}
+    wxOleUninitialize();
 
 
-void wxApp::ExitMainLoop()
-{
-    // this will set m_keepGoing to FALSE a bit later
-    ::PostQuitMessage(0);
+    // 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();
 }
 
 }
 
-bool wxApp::Pending()
-{
-    return ::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0;
-}
+// ----------------------------------------------------------------------------
+// wxApp ctor/dtor
+// ----------------------------------------------------------------------------
 
 
-void wxApp::Dispatch()
+wxApp::wxApp()
 {
 {
-    DoMessage();
+    m_printMode = wxPRINT_WINDOWS;
 }
 
 }
 
-/*
- * Give all windows a chance to preprocess
- * the message. Some may have accelerator tables, or have
- * MDI complications.
- */
-
-bool wxApp::ProcessMessage(WXMSG *wxmsg)
+wxApp::~wxApp()
 {
 {
-    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 )
-    {
-        // 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 )
-        {
-            hwnd = ::GetParent(hwnd);
-        }
-
-        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 )
-        {
-            tt->RelayEvent(wxmsg);
-        }
-    }
-#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;
-    }
-
-    // try translations first: the accelerators override everything
-    wxWindow *wnd;
-
-    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;
-    }
-
-    // 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;
-    }
-
-    // no special preprocessing for this message, dispatch it normally
-    return FALSE;
 }
 
 }
 
-// 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 idle handling
+// ----------------------------------------------------------------------------
 
 
-void wxApp::OnIdle(wxIdleEvent& event)
+void wxApp::OnIdle(wxIdleEvent& WXUNUSED(event))
 {
 {
-    // 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();
-
-    // 'Garbage' collection of windows deleted with Close().
-    DeletePendingObjects();
-
-#if wxUSE_LOG
-    // flush the logged messages if any
-    wxLog::FlushActive();
-#endif // wxUSE_LOG
-
 #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()
@@ -1231,39 +808,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
 }
 
 }
 
-void wxApp::DeletePendingObjects()
+// ----------------------------------------------------------------------------
+// other wxApp event hanlders
+// ----------------------------------------------------------------------------
+
+void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
 {
 {
-    wxNode *node = wxPendingDelete.GetFirst();
-    while (node)
-    {
-        wxObject *obj = node->GetData();
+    // 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
 
 
-        delete obj;
+    // 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);
 
 
-        if (wxPendingDelete.Member(obj))
-            delete node;
+    const int rc = OnExit();
 
 
-        // Deleting one object may have deleted other pending
-        // objects, so start from beginning of list again.
-        node = wxPendingDelete.GetFirst();
-    }
-}
+    wxEntryCleanup();
 
 
-void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
-{
-    if (GetTopWindow())
-        GetTopWindow()->Close(TRUE);
+    // 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
@@ -1273,195 +871,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;
+}
+
+/* static */
+int wxApp::GetShell32Version()
+{
+    return 0;
+}
 
 
-    // if there are pending events, we must process them.
-    ProcessPendingEvents();
+#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
 
 
-    return TRUE;
-}
+// ----------------------------------------------------------------------------
+// exception handling
+// ----------------------------------------------------------------------------
 
 
-bool wxHandleFatalExceptions(bool doit)
+bool wxApp::OnExceptionInMainLoop()
 {
 {
-#if wxUSE_ON_FATAL_EXCEPTION
-    // assume this can only be called from the main thread
-    gs_handleExceptions = doit;
+    // 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;
 
 
-    return TRUE;
-#else
-    wxFAIL_MSG(_T("set wxUSE_ON_FATAL_EXCEPTION to 1 to use this function"));
+        default:
+            wxFAIL_MSG( wxT("unexpected MessageBox() return code") );
+            // fall through
 
 
-    (void)doit;
-    return FALSE;
-#endif
-}
+        case IDRETRY:
+            return false;
 
 
-//-----------------------------------------------------------------------------
+        case IDIGNORE:
+            return true;
+    }
+}
 
 
-// For some reason, with MSVC++ 1.5, WinMain isn't linked in properly
-// if in a separate file. So include it here to ensure it's linked.
-#if (defined(__VISUALC__) && !defined(__WIN32__)) || (defined(__GNUWIN32__) && !defined(__WINE__) && !defined(WXMAKINGDLL))
-#include "main.cpp"
-#endif
+#endif // wxUSE_EXCEPTIONS