]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/dialup.cpp
don't compile in wx hash code unless we really use it (#9532:12)
[wxWidgets.git] / src / msw / dialup.cpp
index 70035cfc7a6c5ccc897e5e8b0dddbfb839f3fcad..566c31c3353eb4d008f747e47e93dbb8d3a844ff 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        msw/dialup.cpp
+// Name:        src/msw/dialup.cpp
 // Purpose:     MSW implementation of network/dialup classes and functions
 // Author:      Vadim Zeitlin
 // Modified by:
     #pragma hdrstop
 #endif
 
-// these functions require Win32
-#if defined(__WIN16__) && wxUSE_DIALUP_MANAGER
-    #undef wxUSE_DIALUP_MANAGER
-    #define wxUSE_DIALUP_MANAGER 0
-#endif // wxUSE_DIALUP_MANAGER && Win16
-
 #if wxUSE_DIALUP_MANAGER
 
+#include "wx/dialup.h"
+
 #ifndef WX_PRECOMP
     #include "wx/log.h"
     #include "wx/intl.h"
     #include "wx/event.h"
+    #include "wx/app.h"
+    #include "wx/timer.h"
+    #include "wx/module.h"
 #endif
 
-#include "wx/timer.h"
-#include "wx/app.h"
 #include "wx/generic/choicdgg.h"
 
 #include "wx/dynlib.h"
-#include "wx/dialup.h"
 
 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED)
 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED)
@@ -53,7 +49,6 @@ DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED)
 #if (!defined(__BORLANDC__) || (__BORLANDC__>=0x550)) && \
     (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \
     !defined(__GNUWIN32_OLD__) && \
-    !defined(__WATCOMC__) && \
     !defined(__WINE__) && \
     (!defined(__VISUALC__) || (__VISUALC__ >= 1020))
 
@@ -70,6 +65,14 @@ DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED)
 #define INTERNET_CONNECTION_PROXY 4
 #endif
 
+// implemented in utils.cpp
+extern "C" WXDLLIMPEXP_BASE HWND
+wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
+
+static const wxChar *
+    wxMSWDIALUP_WNDCLASSNAME = wxT("_wxDialUpManager_Internal_Class");
+static const wxChar *gs_classForDialUpWindow = NULL;
+
 // ----------------------------------------------------------------------------
 // constants
 // ----------------------------------------------------------------------------
@@ -139,15 +142,28 @@ struct WXDLLEXPORT wxRasThreadData
     wxRasThreadData()
     {
         hWnd = 0;
-        hEventRas = hEventQuit = INVALID_HANDLE_VALUE;
+        hEventRas =
+        hEventQuit = 0;
         dialUpManager = NULL;
     }
 
+    ~wxRasThreadData()
+    {
+        if ( hWnd )
+            DestroyWindow(hWnd);
+
+        if ( hEventQuit )
+            CloseHandle(hEventQuit);
+
+        if ( hEventRas )
+            CloseHandle(hEventRas);
+    }
+
     HWND    hWnd;       // window to send notifications to
-    HANDLE  hEventRas,  // event which RAS signals when status changes
-            hEventQuit; // event which we signal when we terminate
+    HANDLE  hEventRas,  // automatic event which RAS signals when status changes
+            hEventQuit; // manual event which we signal when we terminate
 
-    class WXDLLEXPORT wxDialUpManagerMSW *dialUpManager;  // the owner
+    class WXDLLIMPEXP_FWD_CORE wxDialUpManagerMSW *dialUpManager;  // the owner
 };
 
 // ----------------------------------------------------------------------------
@@ -173,7 +189,7 @@ public:
     virtual bool HangUp();
     virtual bool IsAlwaysOnline() const;
     virtual bool IsOnline() const;
-    virtual void SetOnlineStatus(bool isOnline = TRUE);
+    virtual void SetOnlineStatus(bool isOnline = true);
     virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds);
     virtual void DisableAutoCheckOnlineStatus();
     virtual void SetWellKnownHost(const wxString& hostname, int port);
@@ -189,6 +205,7 @@ public:
 
     // for wxRasDialFunc
     static HWND GetRasWindow() { return ms_hwndRas; }
+    static void ResetRasWindow() { ms_hwndRas = NULL; }
     static wxDialUpManagerMSW *GetDialer() { return ms_dialer; }
 
 private:
@@ -199,11 +216,15 @@ private:
     static HRASCONN FindActiveConnection();
 
     // notify the application about status change
-    void NotifyApp(bool connected, bool fromOurselves = FALSE) const;
+    void NotifyApp(bool connected, bool fromOurselves = false) const;
 
     // destroy the thread data and the thread itself
     void CleanUpThreadData();
 
+    // number of times EnableAutoCheckOnlineStatus() had been called minus the
+    // number of times DisableAutoCheckOnlineStatus() had been called
+    int m_autoCheckLevel;
+
     // timer used for polling RAS status
     class WXDLLEXPORT RasTimer : public wxTimer
     {
@@ -224,7 +245,7 @@ private:
 
     // data used by this thread and our hidden window to send messages between
     // each other
-    wxRasThreadData m_data;
+    wxRasThreadData *m_data;
 
     // the handle of rasapi32.dll when it's loaded
     wxDynamicLibrary m_dllRas;
@@ -270,6 +291,33 @@ private:
     DECLARE_NO_COPY_CLASS(wxDialUpManagerMSW)
 };
 
+// module to destroy helper window created by wxDialUpManagerMSW
+class wxDialUpManagerModule : public wxModule
+{
+public:
+    bool OnInit() { return true; }
+    void OnExit()
+    {
+        HWND hwnd = wxDialUpManagerMSW::GetRasWindow();
+        if ( hwnd )
+        {
+            ::DestroyWindow(hwnd);
+            wxDialUpManagerMSW::ResetRasWindow();
+        }
+
+        if ( gs_classForDialUpWindow )
+        {
+            ::UnregisterClass(wxMSWDIALUP_WNDCLASSNAME, wxGetInstance());
+            gs_classForDialUpWindow = NULL;
+        }
+    }
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxDialUpManagerModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxDialUpManagerModule, wxModule)
+
 // ----------------------------------------------------------------------------
 // private functions
 // ----------------------------------------------------------------------------
@@ -339,7 +387,9 @@ wxDialUpManagerMSW::wxDialUpManagerMSW()
                     m_dllRas(_T("RASAPI32"))
 {
     // initialize our data
+    m_autoCheckLevel = 0;
     m_hThread = 0;
+    m_data = new wxRasThreadData;
 
     if ( !m_dllRas.IsLoaded() )
     {
@@ -402,12 +452,10 @@ wxDialUpManagerMSW::wxDialUpManagerMSW()
 exit:
         if ( funcName )
         {
-            static const wxChar *msg = wxTRANSLATE(
-"The version of remote access service (RAS) installed on this machine is too\
-old, please upgrade (the following required function is missing: %s)."
-                                                   );
-
-            wxLogError(wxGetTranslation(msg), funcName);
+            wxLogError(_("The version of remote access service (RAS) installed "
+                          "on this machine is too old, please upgrade (the "
+                          "following required function is missing: %s)."),
+                       funcName);
             m_dllRas.Unload();
             return;
         }
@@ -448,7 +496,7 @@ wxString wxDialUpManagerMSW::GetErrorString(DWORD error)
 
         case 0:
             // we want the error message to start from a lower case letter
-            buffer[0] = wxTolower(buffer[0]);
+            buffer[0] = (wxChar)wxTolower(buffer[0]);
 
             return wxString(buffer);
     }
@@ -493,7 +541,7 @@ HRASCONN wxDialUpManagerMSW::FindActiveConnection()
         }
         else
         {
-            // an error occured
+            // an error occurred
             wxLogError(_("Cannot find active dialup connection: %s"),
                        GetErrorString(dwRet).c_str());
             return 0;
@@ -532,35 +580,26 @@ void wxDialUpManagerMSW::CleanUpThreadData()
 {
     if ( m_hThread )
     {
-        if ( !SetEvent(m_data.hEventQuit) )
+        if ( !SetEvent(m_data->hEventQuit) )
         {
             wxLogLastError(_T("SetEvent(RasThreadQuit)"));
         }
+        else // sent quit request to the background thread
+        {
+            // the thread still needs m_data so we can't free it here, rather
+            // let the thread do it itself
+            m_data = NULL;
+        }
 
         CloseHandle(m_hThread);
 
         m_hThread = 0;
     }
 
-    if ( m_data.hWnd )
-    {
-        DestroyWindow(m_data.hWnd);
-
-        m_data.hWnd = 0;
-    }
-
-    if ( m_data.hEventQuit )
+    if ( m_data )
     {
-        CloseHandle(m_data.hEventQuit);
-
-        m_data.hEventQuit = 0;
-    }
-
-    if ( m_data.hEventRas )
-    {
-        CloseHandle(m_data.hEventRas);
-
-        m_data.hEventRas = 0;
+        delete m_data;
+        m_data = NULL;
     }
 }
 
@@ -627,14 +666,14 @@ void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate,
 
         ms_dialer = NULL;
 
-        NotifyApp(FALSE /* !connected */, TRUE /* we dialed ourselves */);
+        NotifyApp(false /* !connected */, true /* we dialed ourselves */);
     }
     else if ( rasconnstate == RASCS_Connected )
     {
-        ms_isConnected = TRUE;
+        ms_isConnected = true;
         ms_dialer = NULL;
 
-        NotifyApp(TRUE /* connected */, TRUE /* we dialed ourselves */);
+        NotifyApp(true /* connected */, true /* we dialed ourselves */);
     }
 }
 
@@ -670,7 +709,13 @@ size_t wxDialUpManagerMSW::GetISPNames(wxArrayString& names) const
         if ( dwRet == ERROR_BUFFER_TOO_SMALL )
         {
             // reallocate the buffer
-            rasEntries = (RASENTRYNAME *)realloc(rasEntries, size);
+            void *n  = realloc(rasEntries, size);
+            if (n == NULL)
+            {
+                free(rasEntries);
+                return 0;
+            }
+            rasEntries = (RASENTRYNAME *)n;
         }
         else if ( dwRet != 0 )
         {
@@ -704,13 +749,13 @@ bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
                               bool async)
 {
     // check preconditions
-    wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
+    wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
 
     if ( ms_hRasConnection )
     {
         wxFAIL_MSG(wxT("there is already an active connection"));
 
-        return TRUE;
+        return true;
     }
 
     // get the default ISP if none given
@@ -725,7 +770,7 @@ bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
                 // no known ISPs, abort
                 wxLogError(_("Failed to connect: no ISP to dial."));
 
-                return FALSE;
+                return false;
 
             case 1:
                 // only one ISP, choose it
@@ -754,7 +799,7 @@ bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
                     if ( !entryName )
                     {
                         // cancelled by user
-                        return FALSE;
+                        return false;
                     }
                 }
         }
@@ -779,7 +824,7 @@ bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
         {
             wxLogError(_("Failed to connect: missing username/password."));
 
-            return FALSE;
+            return false;
         }
     }
     else
@@ -837,9 +882,12 @@ bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
     if ( dwRet != 0 )
     {
         // can't pass a wxWCharBuffer through ( ... )
-        wxLogError(_("Failed to %s dialup connection: %s"),
-                   wxString(async ? _("initiate") : _("establish")).c_str(),
-                   GetErrorString(dwRet).c_str());
+        if ( async )
+            wxLogError(_("Failed to initiate dialup connection: %s"),
+                       GetErrorString(dwRet).c_str());
+        else
+            wxLogError(_("Failed to establish dialup connection: %s"),
+                       GetErrorString(dwRet).c_str());
 
         // we should still call RasHangUp() if we got a non 0 connection
         if ( ms_hRasConnection )
@@ -850,16 +898,16 @@ bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
 
         ms_dialer = NULL;
 
-        return FALSE;
+        return false;
     }
 
     // for async dialing, we're not yet connected
     if ( !async )
     {
-        ms_isConnected = TRUE;
+        ms_isConnected = true;
     }
 
-    return TRUE;
+    return true;
 }
 
 bool wxDialUpManagerMSW::IsDialing() const
@@ -872,7 +920,7 @@ bool wxDialUpManagerMSW::CancelDialing()
     if ( !GetDialer() )
     {
         // silently ignore
-        return FALSE;
+        return false;
     }
 
     wxASSERT_MSG( ms_hRasConnection, wxT("dialing but no connection?") );
@@ -884,7 +932,7 @@ bool wxDialUpManagerMSW::CancelDialing()
 
 bool wxDialUpManagerMSW::HangUp()
 {
-    wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
+    wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
 
     // we may terminate either the connection we initiated or another one which
     // is active now
@@ -904,25 +952,27 @@ bool wxDialUpManagerMSW::HangUp()
     {
         wxLogError(_("Cannot hang up - no active dialup connection."));
 
-        return FALSE;
+        return false;
     }
 
-    DWORD dwRet = ms_pfnRasHangUp(hRasConn);
-    if ( dwRet != 0 )
+    // note that it's not an error if the connection had been already
+    // terminated
+    const DWORD dwRet = ms_pfnRasHangUp(hRasConn);
+    if ( dwRet != 0 && dwRet != ERROR_NO_CONNECTION )
     {
         wxLogError(_("Failed to terminate the dialup connection: %s"),
                    GetErrorString(dwRet).c_str());
     }
 
-    ms_isConnected = FALSE;
+    ms_isConnected = false;
 
-    return TRUE;
+    return true;
 }
 
 bool wxDialUpManagerMSW::IsAlwaysOnline() const
 {
     // assume no permanent connection by default
-    bool isAlwaysOnline = FALSE;
+    bool isAlwaysOnline = false;
 
     // try to use WinInet functions
 
@@ -959,7 +1009,7 @@ bool wxDialUpManagerMSW::IsAlwaysOnline() const
 
 bool wxDialUpManagerMSW::IsOnline() const
 {
-    wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
+    wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
 
     if ( IsAlwaysOnline() )
     {
@@ -974,7 +1024,7 @@ bool wxDialUpManagerMSW::IsOnline() const
     }
     else
     {
-        // return TRUE if there is at least one active connection
+        // return true if there is at least one active connection
         return FindActiveConnection() != 0;
     }
 }
@@ -988,7 +1038,13 @@ void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline)
 
 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
 {
-    wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
+    wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
+
+    if ( m_autoCheckLevel++ )
+    {
+        // already checking
+        return true;
+    }
 
     bool ok = ms_pfnRasConnectionNotification != 0;
 
@@ -1000,22 +1056,13 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
         // first, see if we don't have this thread already running
         if ( m_hThread != 0 )
         {
-            DWORD dwSuspendCount = 2;
-            while ( dwSuspendCount > 1 )
-            {
-                dwSuspendCount = ResumeThread(m_hThread);
-                if ( dwSuspendCount == (DWORD)-1 )
-                {
-                    wxLogLastError(wxT("ResumeThread(RasThread)"));
+            if ( ::ResumeThread(m_hThread) != (DWORD)-1 )
+                return true;
 
-                    ok = FALSE;
-                }
-            }
+            // we're leaving a zombie thread... but what else can we do?
+            wxLogLastError(wxT("ResumeThread(RasThread)"));
 
-            if ( ok )
-            {
-                return TRUE;
-            }
+            ok = false;
         }
     }
 
@@ -1025,32 +1072,41 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
     if ( ok )
     {
         // first create an event to wait on
-        m_data.hEventRas = CreateEvent
-                           (
+        m_data->hEventRas = ::CreateEvent
+                            (
                              NULL,      // security attribute (default)
-                             FALSE,     // manual reset (not)
+                             FALSE,     // manual reset (no, it is automatic)
                              FALSE,     // initial state (not signaled)
                              NULL       // name (no)
-                           );
-        if ( !m_data.hEventRas )
+                            );
+        if ( !m_data->hEventRas )
         {
             wxLogLastError(wxT("CreateEvent(RasStatus)"));
 
-            ok = FALSE;
+            ok = false;
         }
     }
 
     if ( ok )
     {
-        // create the event we use to quit the thread
-        m_data.hEventQuit = CreateEvent(NULL, FALSE, FALSE, NULL);
-        if ( !m_data.hEventQuit )
+        // create the event we use to quit the thread: using a manual event
+        // here avoids problems with missing the event if wxDialUpManagerMSW
+        // is created and destroyed immediately, before wxRasStatusWindowProc
+        // starts waiting on the event
+        m_data->hEventQuit = ::CreateEvent
+                             (
+                                NULL,   // default security
+                                TRUE,   // manual event
+                                FALSE,  // initially non signalled
+                                NULL    // nameless
+                             );
+        if ( !m_data->hEventQuit )
         {
             wxLogLastError(wxT("CreateEvent(RasThreadQuit)"));
 
             CleanUpThreadData();
 
-            ok = FALSE;
+            ok = false;
         }
     }
 
@@ -1058,30 +1114,28 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
     {
         // create a hidden window to receive notification about connections
         // status change
-        extern const wxChar *wxCanvasClassName;
-        ms_hwndRas = ::CreateWindow(wxCanvasClassName, NULL,
-                                    0, 0, 0, 0,
-                                    0, NULL,
-                                    (HMENU)NULL, wxGetInstance(), 0);
+        ms_hwndRas = wxCreateHiddenWindow
+                     (
+                        &gs_classForDialUpWindow,
+                        wxMSWDIALUP_WNDCLASSNAME,
+                        wxRasStatusWindowProc
+                     );
         if ( !ms_hwndRas )
         {
             wxLogLastError(wxT("CreateWindow(RasHiddenWindow)"));
 
             CleanUpThreadData();
 
-            ok = FALSE;
+            ok = false;
         }
-
-        // and subclass it
-        wxSetWindowProc(ms_hwndRas, wxRasStatusWindowProc);
     }
 
-    m_data.hWnd = ms_hwndRas;
+    m_data->hWnd = ms_hwndRas;
 
     if ( ok )
     {
         // start the secondary thread
-        m_data.dialUpManager = this;
+        m_data->dialUpManager = this;
 
         DWORD tid;
         m_hThread = CreateThread
@@ -1089,7 +1143,7 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
                      NULL,
                      0,
                      (LPTHREAD_START_ROUTINE)wxRasMonitorThread,
-                     (void *)&m_data,
+                     (void *)m_data,
                      0,
                      &tid
                     );
@@ -1108,7 +1162,7 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
         DWORD dwRet = ms_pfnRasConnectionNotification
                       (
                         (HRASCONN)INVALID_HANDLE_VALUE,
-                        m_data.hEventRas,
+                        m_data->hEventRas,
                         3 /* RASCN_Connection | RASCN_Disconnection */
                       );
 
@@ -1121,7 +1175,7 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
         }
         else
         {
-            return TRUE;
+            return true;
         }
     }
 
@@ -1135,13 +1189,19 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
     }
     m_timerStatusPolling.Start(nSeconds * 1000);
 
-    return TRUE;
+    return true;
 }
 
 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
 {
     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
 
+    if ( --m_autoCheckLevel != 0 )
+    {
+        // still checking
+        return;
+    }
+
     if ( m_hThread )
     {
         // we have running secondary thread, it's just enough to suspend it
@@ -1187,10 +1247,10 @@ static DWORD wxRasMonitorThread(wxRasThreadData *data)
     handles[0] = data->hEventRas;
     handles[1] = data->hEventQuit;
 
-    bool cont = TRUE;
+    bool cont = true;
     while ( cont )
     {
-        DWORD dwRet = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+        DWORD dwRet = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
 
         switch ( dwRet )
         {
@@ -1201,15 +1261,37 @@ static DWORD wxRasMonitorThread(wxRasThreadData *data)
                 break;
 
             case WAIT_OBJECT_0 + 1:
-                cont = FALSE;
+                cont = false;
                 break;
 
+            default:
+                wxFAIL_MSG( _T("unexpected return of WaitForMultipleObjects()") );
+                // fall through
+
             case WAIT_FAILED:
-                wxLogLastError(wxT("WaitForMultipleObjects(RasMonitor)"));
-                break;
+#ifdef __WXDEBUG__
+                // using wxLogLastError() from here is dangerous: we risk to
+                // deadlock the main thread if wxLog sends output to GUI
+                DWORD err = GetLastError();
+                wxMessageOutputDebug dbg;
+                dbg.Printf
+                (
+                    wxT("WaitForMultipleObjects(RasMonitor) failed: 0x%08lx (%s)"),
+                    err,
+                    wxSysErrorMsg(err)
+                );
+#endif // __WXDEBUG__
+
+                // no sense in continuing, who knows if the handles we're
+                // waiting for even exist yet...
+                return (DWORD)-1;
         }
     }
 
+    // we don't need it any more now and if this thread ran, it is our
+    // responsability to free the data
+    delete data;
+
     return 0;
 }
 
@@ -1248,11 +1330,10 @@ static void WINAPI wxRasDialFunc(UINT WXUNUSED(unMsg),
 
     wxCHECK_RET( dialUpManager, wxT("who started to dial then?") );
 
-    SendMessage(dialUpManager->GetRasWindow(), wxWM_RAS_DIALING_PROGRESS,
+    SendMessage(wxDialUpManagerMSW::GetRasWindow(), wxWM_RAS_DIALING_PROGRESS,
                 rasconnstate, dwError);
 }
 
 #endif // __BORLANDC__
 
 #endif // wxUSE_DIALUP_MANAGER
-