]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/dialup.cpp
fix for hot keys in menu items (patch 1013082)
[wxWidgets.git] / src / msw / dialup.cpp
index ad6e0e606192ce7308cd0a4b07e322f8cbfa8670..0fc8e9eb323b4669f7e2984f5435a6c6130cdc3f 100644 (file)
     #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
 
 #ifndef WX_PRECOMP
 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED)
 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED)
 
-// Doesn't yet compile under VC++ 4, BC++, Watcom C++: no wininet.h
-#if !defined(__BORLANDC__) && \
+// Doesn't yet compile under VC++ 4, BC++, Watcom C++,
+// Wine: no wininet.h
+#if (!defined(__BORLANDC__) || (__BORLANDC__>=0x550)) && \
     (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \
     !defined(__GNUWIN32_OLD__) && \
-    !defined(__WATCOMC__) && \
+    !defined(__WINE__) && \
     (!defined(__VISUALC__) || (__VISUALC__ >= 1020))
 
 #include <ras.h>
@@ -137,13 +132,26 @@ 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
 };
@@ -202,6 +210,10 @@ private:
     // 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
     {
@@ -213,6 +225,8 @@ private:
 
     private:
         wxDialUpManagerMSW *m_dialUpManager;
+
+        DECLARE_NO_COPY_CLASS(RasTimer)
     } m_timerStatusPolling;
 
     // thread handle for the thread sitting on connection change event
@@ -220,10 +234,10 @@ 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
-    wxPluginManager m_dllRas;
+    wxDynamicLibrary m_dllRas;
 
     // the hidden window we use for passing messages between threads
     static HWND ms_hwndRas;
@@ -231,12 +245,6 @@ private:
     // the handle of the connection we initiated or 0 if none
     static HRASCONN ms_hRasConnection;
 
-    // FIXME: There is probably no reason these really need to
-    //        be static anymore since the dll refcounting is
-    //        handled by wxPluginManager now.  Whether or not
-    //        we still _want_ them to be static is another
-    //        issue entirely..
-
     // the pointers to RAS functions
     static RASDIAL ms_pfnRasDial;
     static RASENUMCONNECTIONS ms_pfnRasEnumConnections;
@@ -266,12 +274,10 @@ private:
     // this flag tells us if we're online
     static int ms_isConnected;
 
-    // this flag is the result of the call to IsAlwaysOnline() (-1 if not
-    // called yet)
-    static int ms_isAlwaysOnline;
-
     // this flag tells us whether a call to RasDial() is in progress
     static wxDialUpManagerMSW *ms_dialer;
+
+    DECLARE_NO_COPY_CLASS(wxDialUpManagerMSW)
 };
 
 // ----------------------------------------------------------------------------
@@ -321,7 +327,6 @@ RASCONNECTIONNOTIFICATION wxDialUpManagerMSW::ms_pfnRasConnectionNotification =
 
 int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus = -1;
 int wxDialUpManagerMSW::ms_isConnected = -1;
-int wxDialUpManagerMSW::ms_isAlwaysOnline = -1;
 wxDialUpManagerMSW *wxDialUpManagerMSW::ms_dialer = NULL;
 
 // ----------------------------------------------------------------------------
@@ -340,11 +345,13 @@ wxDialUpManager *wxDialUpManager::Create()
 #endif // VC++
 
 wxDialUpManagerMSW::wxDialUpManagerMSW()
-                  : m_timerStatusPolling(this)
-                  , m_dllRas(_T("RASAPI32"))
+                  : m_timerStatusPolling(this),
+                    m_dllRas(_T("RASAPI32"))
 {
     // initialize our data
+    m_autoCheckLevel = 0;
     m_hThread = 0;
+    m_data = new wxRasThreadData;
 
     if ( !m_dllRas.IsLoaded() )
     {
@@ -537,35 +544,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 )
-    {
-        CloseHandle(m_data.hEventQuit);
-
-        m_data.hEventQuit = 0;
-    }
-
-    if ( m_data.hEventRas )
+    if ( m_data )
     {
-        CloseHandle(m_data.hEventRas);
-
-        m_data.hEventRas = 0;
+        delete m_data;
+        m_data = NULL;
     }
 }
 
@@ -926,20 +924,16 @@ bool wxDialUpManagerMSW::HangUp()
 
 bool wxDialUpManagerMSW::IsAlwaysOnline() const
 {
-    // we cache the result (presumably this won't change while the program is
-    // running!)
-    if ( ms_isAlwaysOnline != -1 )
-    {
-        return ms_isAlwaysOnline != 0;
-    }
+    // assume no permanent connection by default
+    bool isAlwaysOnline = FALSE;
 
-    // try to use WinInet function first
+    // try to use WinInet functions
 
     // NB: we could probably use wxDynamicLibrary here just as well,
     //     but we allow multiple instances of wxDialUpManagerMSW so
     //     we might as well use the ref counted version here too.
 
-    wxPluginManager hDll(_T("WININET"));
+    wxDynamicLibrary hDll(_T("WININET"));
     if ( hDll.IsLoaded() )
     {
         typedef BOOL (WINAPI *INTERNETGETCONNECTEDSTATE)(LPDWORD, DWORD);
@@ -956,45 +950,26 @@ bool wxDialUpManagerMSW::IsAlwaysOnline() const
             if ( pfnInternetGetConnectedState(&flags, 0 /* reserved */) )
             {
                 // there is some connection to the net, see of which type
-                ms_isAlwaysOnline = ((flags & INTERNET_CONNECTION_LAN) != 0)
-                                    || ((flags & INTERNET_CONNECTION_PROXY) != 0);
-            }
-            else
-            {
-                // no Internet connection at all
-                ms_isAlwaysOnline = FALSE;
+                isAlwaysOnline = (flags & (INTERNET_CONNECTION_LAN |
+                                           INTERNET_CONNECTION_PROXY)) != 0;
             }
+            //else: no Internet connection at all
         }
     }
 
-    // did we succeed with WinInet? if not, try something else
-    if ( ms_isAlwaysOnline == -1 )
-    {
-        if ( !IsOnline() )
-        {
-            // definitely no permanent connection because we are not connected
-            // now
-            ms_isAlwaysOnline = FALSE;
-        }
-        else
-        {
-            // of course, having a modem doesn't prevent us from having a
-            // permanent connection as well, but we have to guess somehow and
-            // it's probably more common that a system connected via a modem
-            // doesn't have any other net access, so:
-            ms_isAlwaysOnline = FALSE;
-        }
-    }
-
-    wxASSERT_MSG( ms_isAlwaysOnline != -1, wxT("logic error") );
-
-    return ms_isAlwaysOnline != 0;
+    return isAlwaysOnline;
 }
 
 bool wxDialUpManagerMSW::IsOnline() const
 {
     wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
 
+    if ( IsAlwaysOnline() )
+    {
+        // always => now
+        return true;
+    }
+
     if ( ms_userSpecifiedOnlineStatus != -1 )
     {
         // user specified flag overrides our logic
@@ -1018,6 +993,12 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
 {
     wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
 
+    if ( m_autoCheckLevel++ )
+    {
+        // already checking
+        return TRUE;
+    }
+
     bool ok = ms_pfnRasConnectionNotification != 0;
 
     if ( ok )
@@ -1028,22 +1009,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;
         }
     }
 
@@ -1053,14 +1025,14 @@ 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)"));
 
@@ -1070,9 +1042,18 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
 
     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)"));
 
@@ -1101,21 +1082,15 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
         }
 
         // and subclass it
-        FARPROC windowProc = MakeProcInstance
-                             (
-                              (FARPROC)wxRasStatusWindowProc,
-                              wxGetInstance()
-                             );
-
-        ::SetWindowLong(ms_hwndRas, GWL_WNDPROC, (LONG) windowProc);
+        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
@@ -1123,7 +1098,7 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
                      NULL,
                      0,
                      (LPTHREAD_START_ROUTINE)wxRasMonitorThread,
-                     (void *)&m_data,
+                     (void *)m_data,
                      0,
                      &tid
                     );
@@ -1142,7 +1117,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 */
                       );
 
@@ -1176,6 +1151,12 @@ void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
 {
     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
 
+    if ( --m_autoCheckLevel )
+    {
+        // still checking
+        return;
+    }
+
     if ( m_hThread )
     {
         // we have running secondary thread, it's just enough to suspend it
@@ -1238,34 +1219,64 @@ static DWORD wxRasMonitorThread(wxRasThreadData *data)
                 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().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;
 }
 
 static LRESULT APIENTRY wxRasStatusWindowProc(HWND hWnd, UINT message,
                                               WPARAM wParam, LPARAM lParam)
 {
-    if ( message == wxWM_RAS_STATUS_CHANGED )
+    switch ( message )
     {
-        wxRasThreadData *data = (wxRasThreadData *)lParam;
-        data->dialUpManager->OnConnectStatusChange();
-    }
-    else if ( message == wxWM_RAS_DIALING_PROGRESS )
-    {
-        wxDialUpManagerMSW *dialUpManager = wxDialUpManagerMSW::GetDialer();
+        case wxWM_RAS_STATUS_CHANGED:
+            {
+                wxRasThreadData *data = (wxRasThreadData *)lParam;
+                data->dialUpManager->OnConnectStatusChange();
+            }
+            break;
 
-        dialUpManager->OnDialProgress((RASCONNSTATE)wParam, lParam);
+        case wxWM_RAS_DIALING_PROGRESS:
+            {
+                wxDialUpManagerMSW *dialMan = wxDialUpManagerMSW::GetDialer();
+
+                dialMan->OnDialProgress((RASCONNSTATE)wParam, lParam);
+            }
+            break;
+
+        default:
+            return ::DefWindowProc(hWnd, message, wParam, lParam);
     }
 
     return 0;
 }
 
-static void WINAPI wxRasDialFunc(UINT unMsg,
+static void WINAPI wxRasDialFunc(UINT WXUNUSED(unMsg),
                                  RASCONNSTATE rasconnstate,
                                  DWORD dwError)
 {