#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>
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
};
// 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
{
private:
wxDialUpManagerMSW *m_dialUpManager;
+
+ DECLARE_NO_COPY_CLASS(RasTimer)
} m_timerStatusPolling;
// thread handle for the thread sitting on connection change event
// 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;
// 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;
// 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)
};
// ----------------------------------------------------------------------------
int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus = -1;
int wxDialUpManagerMSW::ms_isConnected = -1;
-int wxDialUpManagerMSW::ms_isAlwaysOnline = -1;
wxDialUpManagerMSW *wxDialUpManagerMSW::ms_dialer = NULL;
// ----------------------------------------------------------------------------
#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() )
{
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 == 0 )
+ else if ( !ms_pfnRasDial )
{
// resolve the functions we need
{
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;
}
}
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
);
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);
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
{
wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
+ if ( m_autoCheckLevel++ )
+ {
+ // already checking
+ return TRUE;
+ }
+
bool ok = ms_pfnRasConnectionNotification != 0;
if ( ok )
// 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;
}
}
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)"));
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)"));
}
// 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
NULL,
0,
(LPTHREAD_START_ROUTINE)wxRasMonitorThread,
- (void *)&m_data,
+ (void *)m_data,
0,
&tid
);
DWORD dwRet = ms_pfnRasConnectionNotification
(
(HRASCONN)INVALID_HANDLE_VALUE,
- m_data.hEventRas,
+ m_data->hEventRas,
3 /* RASCN_Connection | RASCN_Disconnection */
);
{
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
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)
{
rasconnstate, dwError);
}
-#endif
- // __BORLANDC__
+#endif // __BORLANDC__
+
#endif // wxUSE_DIALUP_MANAGER
-// vi:sts=4:sw=4:et