X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7d6727528886073e462499f8084504eccf8234b7..37c2a8dab05154b396e20a9de1de7a10adb2b88a:/src/msw/dialup.cpp diff --git a/src/msw/dialup.cpp b/src/msw/dialup.cpp index aad7149867..3ef963a5f5 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 @@ -38,23 +32,37 @@ #include "wx/event.h" #endif -#if !wxUSE_DYNLIB_CLASS - #error You need wxUSE_DYNLIB_CLASS to be 1 to compile dialup.cpp. -#endif +#include "wx/timer.h" +#include "wx/app.h" +#include "wx/generic/choicdgg.h" #include "wx/dynlib.h" - #include "wx/dialup.h" -// Doesn't yet compile under BC++, mingw, Watcom C++: no wininet.h -#if !defined(__BORLANDC__) && !defined(__GNUWIN32_OLD__) && !defined(__GNUWIN32__) && !defined(__WATCOMC__) +DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED) +DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED) + +// 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 #include #include -#include "wx/msw/private.h" +// Not in VC++ 5 +#ifndef INTERNET_CONNECTION_LAN +#define INTERNET_CONNECTION_LAN 2 +#endif +#ifndef INTERNET_CONNECTION_PROXY +#define INTERNET_CONNECTION_PROXY 4 +#endif // ---------------------------------------------------------------------------- // constants @@ -94,7 +102,7 @@ typedef DWORD (APIENTRY * RASVALIDATEENTRYNAME)( LPCSTR, LPCSTR ); typedef DWORD (APIENTRY * RASCONNECTIONNOTIFICATION)( HRASCONN, HANDLE, DWORD ); - static const char gs_funcSuffix = 'A'; + static const wxChar gs_funcSuffix = _T('A'); #else // Unicode typedef DWORD (APIENTRY * RASDIAL)( LPRASDIALEXTENSIONS, LPCWSTR, LPRASDIALPARAMSW, DWORD, LPVOID, LPHRASCONN ); typedef DWORD (APIENTRY * RASENUMCONNECTIONS)( LPRASCONNW, LPDWORD, LPDWORD ); @@ -116,22 +124,35 @@ typedef DWORD (APIENTRY * RASVALIDATEENTRYNAME)( LPCWSTR, LPCWSTR ); typedef DWORD (APIENTRY * RASCONNECTIONNOTIFICATION)( HRASCONN, HANDLE, DWORD ); - static const char gs_funcSuffix = 'W'; + static const wxChar gs_funcSuffix = _T('W'); #endif // ASCII/Unicode // structure passed to the secondary thread -struct wxRasThreadData +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 }; @@ -190,8 +211,12 @@ 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 RasTimer : public wxTimer + class WXDLLEXPORT RasTimer : public wxTimer { public: RasTimer(wxDialUpManagerMSW *dialUpManager) @@ -201,6 +226,8 @@ private: private: wxDialUpManagerMSW *m_dialUpManager; + + DECLARE_NO_COPY_CLASS(RasTimer) } m_timerStatusPolling; // thread handle for the thread sitting on connection change event @@ -208,7 +235,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 + wxDynamicLibrary m_dllRas; // the hidden window we use for passing messages between threads static HWND ms_hwndRas; @@ -216,12 +246,6 @@ private: // the handle of the connection we initiated or 0 if none static HRASCONN ms_hRasConnection; - // the use count of rasapi32.dll - static int ms_nDllCount; - - // the handle of rasapi32.dll when it's loaded - static wxDllType ms_dllRas; - // the pointers to RAS functions static RASDIAL ms_pfnRasDial; static RASENUMCONNECTIONS ms_pfnRasEnumConnections; @@ -251,12 +275,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) }; // ---------------------------------------------------------------------------- @@ -284,9 +306,6 @@ HRASCONN wxDialUpManagerMSW::ms_hRasConnection = 0; HWND wxDialUpManagerMSW::ms_hwndRas = 0; -int wxDialUpManagerMSW::ms_nDllCount = 0; -wxDllType wxDialUpManagerMSW::ms_dllRas = 0; - RASDIAL wxDialUpManagerMSW::ms_pfnRasDial = 0; RASENUMCONNECTIONS wxDialUpManagerMSW::ms_pfnRasEnumConnections = 0; RASENUMENTRIES wxDialUpManagerMSW::ms_pfnRasEnumEntries = 0; @@ -309,7 +328,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; // ---------------------------------------------------------------------------- @@ -328,90 +346,83 @@ wxDialUpManager *wxDialUpManager::Create() #endif // VC++ wxDialUpManagerMSW::wxDialUpManagerMSW() - : m_timerStatusPolling(this) + : m_timerStatusPolling(this), + m_dllRas(_T("RASAPI32")) { // initialize our data + m_autoCheckLevel = 0; m_hThread = 0; + m_data = new wxRasThreadData; - if ( !ms_nDllCount++ ) + if ( !m_dllRas.IsLoaded() ) + { + wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it.")); + } + else if ( !ms_pfnRasDial ) { - // load the RAS library - ms_dllRas = wxDllLoader::LoadLibrary("RASAPI32"); - if ( !ms_dllRas ) + // resolve the functions we need + + // this will contain the name of the function we failed to resolve + // if any at the end + const char *funcName = NULL; + + // get the function from rasapi32.dll and abort if it's not found + #define RESOLVE_RAS_FUNCTION(type, name) \ + ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name)) \ + + gs_funcSuffix); \ + if ( !ms_pfn##name ) \ + { \ + funcName = #name; \ + goto exit; \ + } + + // a variant of above macro which doesn't abort if the function is + // not found in the DLL + #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \ + ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name)) \ + + gs_funcSuffix); + + RESOLVE_RAS_FUNCTION(RASDIAL, RasDial); + RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS, RasEnumConnections); + RESOLVE_RAS_FUNCTION(RASENUMENTRIES, RasEnumEntries); + RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS, RasGetConnectStatus); + RESOLVE_RAS_FUNCTION(RASGETERRORSTRING, RasGetErrorString); + RESOLVE_RAS_FUNCTION(RASHANGUP, RasHangUp); + RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS, RasGetEntryDialParams); + + // suppress error messages about missing (non essential) functions { - wxLogError(_("Dial up functions are unavailable because the " - "remote access service (RAS) is not installed " - "on this machine. Please install it.")); + wxLogNull noLog; + + RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO, RasGetProjectionInfo); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY, RasCreatePhonebookEntry); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY, RasEditPhonebookEntry); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS, RasSetEntryDialParams); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES, RasGetEntryProperties); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES, RasSetEntryProperties); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY, RasRenameEntry); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY, RasDeleteEntry); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME, RasValidateEntryName); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO, RasGetCountryInfo); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES, RasEnumDevices); + RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION, RasConnectionNotification); } - else - { - // resolve the functions we need - - // this will contain the name of the function we failed to resolve - // if any at the end - const char *funcName = NULL; - - // get the function from rasapi32.dll and abort if it's not found - #define RESOLVE_RAS_FUNCTION(type, name) \ - ms_pfn##name = (type)wxDllLoader::GetSymbol(ms_dllRas, \ - wxString(_T(#name)) + gs_funcSuffix); \ - if ( !ms_pfn##name ) \ - { \ - funcName = #name; \ - goto exit; \ - } - - // a variant of above macro which doesn't abort if the function is - // not found in the DLL - #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \ - ms_pfn##name = (type)wxDllLoader::GetSymbol(ms_dllRas, \ - wxString(_T(#name)) + gs_funcSuffix); - - RESOLVE_RAS_FUNCTION(RASDIAL, RasDial); - RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS, RasEnumConnections); - RESOLVE_RAS_FUNCTION(RASENUMENTRIES, RasEnumEntries); - RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS, RasGetConnectStatus); - RESOLVE_RAS_FUNCTION(RASGETERRORSTRING, RasGetErrorString); - RESOLVE_RAS_FUNCTION(RASHANGUP, RasHangUp); - RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS, RasGetEntryDialParams); - - // suppress wxDllLoader messages about missing (non essential) - // functions - { - wxLogNull noLog; - - RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO, RasGetProjectionInfo); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY, RasCreatePhonebookEntry); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY, RasEditPhonebookEntry); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS, RasSetEntryDialParams); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES, RasGetEntryProperties); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES, RasSetEntryProperties); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY, RasRenameEntry); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY, RasDeleteEntry); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME, RasValidateEntryName); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO, RasGetCountryInfo); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES, RasEnumDevices); - RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION, RasConnectionNotification); - } - // keep your preprocessor name space clean - #undef RESOLVE_RAS_FUNCTION - #undef RESOLVE_OPTIONAL_RAS_FUNCTION + // keep your preprocessor name space clean + #undef RESOLVE_RAS_FUNCTION + #undef RESOLVE_OPTIONAL_RAS_FUNCTION exit: - if ( 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); - - wxDllLoader::UnloadLibrary(ms_dllRas); - ms_dllRas = 0; - ms_nDllCount = 0; - - return; - } + 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); + m_dllRas.Unload(); + return; } } @@ -422,13 +433,6 @@ exit: wxDialUpManagerMSW::~wxDialUpManagerMSW() { CleanUpThreadData(); - - if ( !--ms_nDllCount ) - { - // unload the RAS library - wxDllLoader::UnloadLibrary(ms_dllRas); - ms_dllRas = 0; - } } // ---------------------------------------------------------------------------- @@ -447,8 +451,8 @@ wxString wxDialUpManagerMSW::GetErrorString(DWORD error) default: { - wxLogSysError(dwRet, _("Failed to retrieve text of RAS " - "error message")); + wxLogSysError(dwRet, + _("Failed to retrieve text of RAS error message")); wxString msg; msg.Printf(_("unknown error (error code %08x)."), error); @@ -504,7 +508,7 @@ HRASCONN wxDialUpManagerMSW::FindActiveConnection() { // an error occured wxLogError(_("Cannot find active dialup connection: %s"), - GetErrorString(dwRet)); + GetErrorString(dwRet).c_str()); return 0; } } @@ -524,8 +528,7 @@ HRASCONN wxDialUpManagerMSW::FindActiveConnection() // connection) - the warning is really needed because this function // is used, for example, to select the connection to hang up and so // we may hang up the wrong connection here... - wxLogWarning(_("Several active dialup connections found, " - "choosing one randomly.")); + wxLogWarning(_("Several active dialup connections found, choosing one randomly.")); // fall through case 1: @@ -542,9 +545,15 @@ 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 { - wxLogLastError("SetEvent(RasThreadQuit)"); + // 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); @@ -552,25 +561,10 @@ void wxDialUpManagerMSW::CleanUpThreadData() m_hThread = 0; } - if ( m_data.hWnd ) + if ( m_data ) { - DestroyWindow(m_data.hWnd); - - m_data.hWnd = 0; - } - - if ( m_data.hEventQuit ) - { - 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; } } @@ -626,7 +620,7 @@ void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate, if ( dwError ) { wxLogError(_("Failed to establish dialup connection: %s"), - GetErrorString(dwError)); + GetErrorString(dwError).c_str()); // we should still call RasHangUp() if we got a non 0 connection if ( ms_hRasConnection ) @@ -654,7 +648,7 @@ void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate, bool wxDialUpManagerMSW::IsOk() const { - return ms_dllRas != 0; + return m_dllRas.IsLoaded(); } size_t wxDialUpManagerMSW::GetISPNames(wxArrayString& names) const @@ -685,7 +679,8 @@ size_t wxDialUpManagerMSW::GetISPNames(wxArrayString& names) const else if ( dwRet != 0 ) { // some other error - abort - wxLogError(_("Failed to get ISP names: %s"), GetErrorString(dwRet)); + wxLogError(_("Failed to get ISP names: %s"), + GetErrorString(dwRet).c_str()); free(rasEntries); @@ -753,8 +748,7 @@ bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP, entryName = wxGetSingleChoice ( _("Choose ISP to dial"), - _("Please choose which ISP do you want to " - "connect to"), + _("Please choose which ISP do you want to connect to"), count, strings ); @@ -772,7 +766,7 @@ bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP, RASDIALPARAMS rasDialParams; rasDialParams.dwSize = sizeof(rasDialParams); - strncpy(rasDialParams.szEntryName, entryName, RAS_MaxEntryName); + wxStrncpy(rasDialParams.szEntryName, entryName, RAS_MaxEntryName); // do we have the username and password? if ( !username || !password ) @@ -792,13 +786,13 @@ bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP, return FALSE; } } - else - { - strncpy(rasDialParams.szUserName, username, UNLEN); - strncpy(rasDialParams.szPassword, password, PWLEN); - } + else + { + wxStrncpy(rasDialParams.szUserName, username, UNLEN); + wxStrncpy(rasDialParams.szPassword, password, PWLEN); + } - // default values for other fields + // default values for other fields rasDialParams.szPhoneNumber[0] = '\0'; rasDialParams.szCallbackNumber[0] = '\0'; rasDialParams.szCallbackNumber[0] = '\0'; @@ -835,20 +829,21 @@ bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP, DWORD dwRet = ms_pfnRasDial ( - (LPRASDIALEXTENSIONS)NULL, // no extended features - NULL, // default phone book file (NT only) + NULL, // no extended features + NULL, // default phone book file (NT only) &rasDialParams, - 0, // use callback for notifications - async ? wxRasDialFunc // the callback - : 0, // no notifications - sync operation + 0, // use callback for notifications + async ? (void *)wxRasDialFunc // cast needed for gcc 3.1 + : 0, // no notifications, sync operation &ms_hRasConnection ); if ( dwRet != 0 ) { + // can't pass a wxWCharBuffer through ( ... ) wxLogError(_("Failed to %s dialup connection: %s"), - async ? _("initiate") : _("establish"), - GetErrorString(dwRet)); + wxString(async ? _("initiate") : _("establish")).c_str(), + GetErrorString(dwRet).c_str()); // we should still call RasHangUp() if we got a non 0 connection if ( ms_hRasConnection ) @@ -920,7 +915,7 @@ bool wxDialUpManagerMSW::HangUp() if ( dwRet != 0 ) { wxLogError(_("Failed to terminate the dialup connection: %s"), - GetErrorString(dwRet)); + GetErrorString(dwRet).c_str()); } ms_isConnected = FALSE; @@ -930,23 +925,23 @@ 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 - bool ok; - wxDllType hDll = wxDllLoader::LoadLibrary(_T("WININET"), &ok); - if ( ok ) + // 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. + + wxDynamicLibrary hDll(_T("WININET")); + if ( hDll.IsLoaded() ) { - typedef BOOL (*INTERNETGETCONNECTEDSTATE)(LPDWORD, DWORD); + typedef BOOL (WINAPI *INTERNETGETCONNECTEDSTATE)(LPDWORD, DWORD); INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState; #define RESOLVE_FUNCTION(type, name) \ - pfn##name = (type)wxDllLoader::GetSymbol(hDll, _T(#name)) + pfn##name = (type)hDll.GetSymbol(_T(#name)) RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE, InternetGetConnectedState); @@ -956,50 +951,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); - - wxLogMessage("InternetGetConnectedState() returned TRUE, " - "flags = %08x", flags); - } - else - { - // no Internet connection at all - ms_isAlwaysOnline = FALSE; + isAlwaysOnline = (flags & (INTERNET_CONNECTION_LAN | + INTERNET_CONNECTION_PROXY)) != 0; } + //else: no Internet connection at all } - - wxDllLoader::UnloadLibrary(hDll); } - // 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 @@ -1023,6 +994,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 ) @@ -1033,22 +1010,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("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; } } @@ -1058,16 +1026,16 @@ 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("CreateEvent(RasStatus)"); + wxLogLastError(wxT("CreateEvent(RasStatus)")); ok = FALSE; } @@ -1075,11 +1043,20 @@ 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("CreateEvent(RasThreadQuit)"); + wxLogLastError(wxT("CreateEvent(RasThreadQuit)")); CleanUpThreadData(); @@ -1091,14 +1068,14 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds) { // create a hidden window to receive notification about connections // status change - extern const wxChar *wxPanelClassName; - ms_hwndRas = ::CreateWindow(wxPanelClassName, NULL, + extern const wxChar *wxCanvasClassName; + ms_hwndRas = ::CreateWindow(wxCanvasClassName, NULL, 0, 0, 0, 0, 0, NULL, (HMENU)NULL, wxGetInstance(), 0); if ( !ms_hwndRas ) { - wxLogLastError("CreateWindow(RasHiddenWindow)"); + wxLogLastError(wxT("CreateWindow(RasHiddenWindow)")); CleanUpThreadData(); @@ -1106,21 +1083,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 @@ -1128,14 +1099,14 @@ bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds) NULL, 0, (LPTHREAD_START_ROUTINE)wxRasMonitorThread, - (void *)&m_data, + (void *)m_data, 0, &tid ); if ( !m_hThread ) { - wxLogLastError("CreateThread(RasStatusThread)"); + wxLogLastError(wxT("CreateThread(RasStatusThread)")); CleanUpThreadData(); } @@ -1147,14 +1118,14 @@ 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 */ ); if ( dwRet != 0 ) { wxLogDebug(wxT("RasConnectionNotification() failed: %s"), - GetErrorString(dwRet)); + GetErrorString(dwRet).c_str()); CleanUpThreadData(); } @@ -1181,12 +1152,18 @@ 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 if ( SuspendThread(m_hThread) == (DWORD)-1 ) { - wxLogLastError("SuspendThread(RasThread)"); + wxLogLastError(wxT("SuspendThread(RasThread)")); } } else @@ -1243,34 +1220,64 @@ static DWORD wxRasMonitorThread(wxRasThreadData *data) cont = FALSE; break; + default: + wxFAIL_MSG( _T("unexpected return of WaitForMultipleObjects()") ); + // fall through + case WAIT_FAILED: - wxLogLastError("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 ) - { - wxRasThreadData *data = (wxRasThreadData *)lParam; - data->dialUpManager->OnConnectStatusChange(); - } - else if ( message == wxWM_RAS_DIALING_PROGRESS ) + switch ( message ) { - wxDialUpManagerMSW *dialUpManager = wxDialUpManagerMSW::GetDialer(); + case wxWM_RAS_STATUS_CHANGED: + { + wxRasThreadData *data = (wxRasThreadData *)lParam; + data->dialUpManager->OnConnectStatusChange(); + } + break; + + case wxWM_RAS_DIALING_PROGRESS: + { + wxDialUpManagerMSW *dialMan = wxDialUpManagerMSW::GetDialer(); + + dialMan->OnDialProgress((RASCONNSTATE)wParam, lParam); + } + break; - dialUpManager->OnDialProgress((RASCONNSTATE)wParam, lParam); + 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) { @@ -1282,6 +1289,7 @@ static void WINAPI wxRasDialFunc(UINT unMsg, rasconnstate, dwError); } -#endif - // __BORLANDC__ +#endif // __BORLANDC__ + #endif // wxUSE_DIALUP_MANAGER +