X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5283098e1316b4a811fbccaabbda71f676e86c93..665b71b17c8eb8f2586a8c84f8d9cf0d8559bf35:/src/msw/dialup.cpp?ds=sidebyside diff --git a/src/msw/dialup.cpp b/src/msw/dialup.cpp index 595563115d..0fc8e9eb32 100644 --- a/src/msw/dialup.cpp +++ b/src/msw/dialup.cpp @@ -24,12 +24,6 @@ #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 @@ -50,11 +44,9 @@ DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED) // Doesn't yet compile under VC++ 4, BC++, Watcom C++, // Wine: no wininet.h -#if !defined(__BORLANDC__) && \ +#if (!defined(__BORLANDC__) || (__BORLANDC__>=0x550)) && \ (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \ !defined(__GNUWIN32_OLD__) && \ - !defined(__WATCOMC__) && \ - !defined(__WXWINE__) && \ !defined(__WINE__) && \ (!defined(__VISUALC__) || (__VISUALC__ >= 1020)) @@ -140,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 }; @@ -205,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 { @@ -216,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 @@ -223,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; @@ -234,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; @@ -271,6 +276,8 @@ private: // this flag tells us whether a call to RasDial() is in progress static wxDialUpManagerMSW *ms_dialer; + + DECLARE_NO_COPY_CLASS(wxDialUpManagerMSW) }; // ---------------------------------------------------------------------------- @@ -338,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() ) { @@ -535,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 ) + 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; } } @@ -933,7 +933,7 @@ bool wxDialUpManagerMSW::IsAlwaysOnline() const // 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); @@ -964,6 +964,12 @@ 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 @@ -987,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 ) @@ -997,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; } } @@ -1022,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)")); @@ -1039,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)")); @@ -1070,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 @@ -1092,7 +1098,7 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds) NULL, 0, (LPTHREAD_START_ROUTINE)wxRasMonitorThread, - (void *)&m_data, + (void *)m_data, 0, &tid ); @@ -1111,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 */ ); @@ -1145,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 @@ -1207,12 +1219,33 @@ 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; } @@ -1243,7 +1276,7 @@ static LRESULT APIENTRY wxRasStatusWindowProc(HWND hWnd, UINT message, return 0; } -static void WINAPI wxRasDialFunc(UINT unMsg, +static void WINAPI wxRasDialFunc(UINT WXUNUSED(unMsg), RASCONNSTATE rasconnstate, DWORD dwError) {