1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        msw/dialup.cpp 
   3 // Purpose:     MSW implementation of network/dialup classes and functions 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) Vadim Zeitlin 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // for compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 #if wxUSE_DIALUP_MANAGER 
  37 #include "wx/generic/choicdgg.h" 
  39 #include "wx/dynlib.h" 
  40 #include "wx/dialup.h" 
  42 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED
) 
  43 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED
) 
  45 // Doesn't yet compile under VC++ 4, BC++, Watcom C++, 
  47 #if (!defined(__BORLANDC__) || (__BORLANDC__>=0x550)) && \ 
  48     (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \ 
  49     !defined(__GNUWIN32_OLD__) && \ 
  50     !defined(__WATCOMC__) && \ 
  51     !defined(__WINE__) && \ 
  52     (!defined(__VISUALC__) || (__VISUALC__ >= 1020)) 
  60 #ifndef INTERNET_CONNECTION_LAN 
  61 #define INTERNET_CONNECTION_LAN 2 
  63 #ifndef INTERNET_CONNECTION_PROXY 
  64 #define INTERNET_CONNECTION_PROXY 4 
  67 // ---------------------------------------------------------------------------- 
  69 // ---------------------------------------------------------------------------- 
  71 // this message is sent by the secondary thread when RAS status changes 
  72 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010) 
  73 #define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011) 
  75 // ---------------------------------------------------------------------------- 
  77 // ---------------------------------------------------------------------------- 
  79 // the signatures of RAS functions: all this is quite heavy, but we must do it 
  80 // to allow running wxWin programs on machine which don't have RAS installed 
  81 // (this does exist) - if we link with rasapi32.lib, the program will fail on 
  82 // startup because of the missing DLL... 
  85     typedef DWORD (APIENTRY 
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCSTR
, LPRASDIALPARAMSA
, DWORD
, LPVOID
, LPHRASCONN 
); 
  86     typedef DWORD (APIENTRY 
* RASENUMCONNECTIONS
)( LPRASCONNA
, LPDWORD
, LPDWORD 
); 
  87     typedef DWORD (APIENTRY 
* RASENUMENTRIES
)( LPCSTR
, LPCSTR
, LPRASENTRYNAMEA
, LPDWORD
, LPDWORD 
); 
  88     typedef DWORD (APIENTRY 
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSA 
); 
  89     typedef DWORD (APIENTRY 
* RASGETERRORSTRING
)( UINT
, LPSTR
, DWORD 
); 
  90     typedef DWORD (APIENTRY 
* RASHANGUP
)( HRASCONN 
); 
  91     typedef DWORD (APIENTRY 
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD 
); 
  92     typedef DWORD (APIENTRY 
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCSTR 
); 
  93     typedef DWORD (APIENTRY 
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCSTR
, LPCSTR 
); 
  94     typedef DWORD (APIENTRY 
* RASSETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, BOOL 
); 
  95     typedef DWORD (APIENTRY 
* RASGETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, LPBOOL 
); 
  96     typedef DWORD (APIENTRY 
* RASENUMDEVICES
)( LPRASDEVINFOA
, LPDWORD
, LPDWORD 
); 
  97     typedef DWORD (APIENTRY 
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOA
, LPDWORD 
); 
  98     typedef DWORD (APIENTRY 
* RASGETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, LPDWORD
, LPBYTE
, LPDWORD 
); 
  99     typedef DWORD (APIENTRY 
* RASSETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, DWORD
, LPBYTE
, DWORD 
); 
 100     typedef DWORD (APIENTRY 
* RASRENAMEENTRY
)( LPCSTR
, LPCSTR
, LPCSTR 
); 
 101     typedef DWORD (APIENTRY 
* RASDELETEENTRY
)( LPCSTR
, LPCSTR 
); 
 102     typedef DWORD (APIENTRY 
* RASVALIDATEENTRYNAME
)( LPCSTR
, LPCSTR 
); 
 103     typedef DWORD (APIENTRY 
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD 
); 
 105     static const wxChar gs_funcSuffix 
= _T('A'); 
 107     typedef DWORD (APIENTRY 
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCWSTR
, LPRASDIALPARAMSW
, DWORD
, LPVOID
, LPHRASCONN 
); 
 108     typedef DWORD (APIENTRY 
* RASENUMCONNECTIONS
)( LPRASCONNW
, LPDWORD
, LPDWORD 
); 
 109     typedef DWORD (APIENTRY 
* RASENUMENTRIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYNAMEW
, LPDWORD
, LPDWORD 
); 
 110     typedef DWORD (APIENTRY 
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSW 
); 
 111     typedef DWORD (APIENTRY 
* RASGETERRORSTRING
)( UINT
, LPWSTR
, DWORD 
); 
 112     typedef DWORD (APIENTRY 
* RASHANGUP
)( HRASCONN 
); 
 113     typedef DWORD (APIENTRY 
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD 
); 
 114     typedef DWORD (APIENTRY 
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCWSTR 
); 
 115     typedef DWORD (APIENTRY 
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCWSTR
, LPCWSTR 
); 
 116     typedef DWORD (APIENTRY 
* RASSETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, BOOL 
); 
 117     typedef DWORD (APIENTRY 
* RASGETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, LPBOOL 
); 
 118     typedef DWORD (APIENTRY 
* RASENUMDEVICES
)( LPRASDEVINFOW
, LPDWORD
, LPDWORD 
); 
 119     typedef DWORD (APIENTRY 
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOW
, LPDWORD 
); 
 120     typedef DWORD (APIENTRY 
* RASGETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, LPDWORD
, LPBYTE
, LPDWORD 
); 
 121     typedef DWORD (APIENTRY 
* RASSETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, DWORD
, LPBYTE
, DWORD 
); 
 122     typedef DWORD (APIENTRY 
* RASRENAMEENTRY
)( LPCWSTR
, LPCWSTR
, LPCWSTR 
); 
 123     typedef DWORD (APIENTRY 
* RASDELETEENTRY
)( LPCWSTR
, LPCWSTR 
); 
 124     typedef DWORD (APIENTRY 
* RASVALIDATEENTRYNAME
)( LPCWSTR
, LPCWSTR 
); 
 125     typedef DWORD (APIENTRY 
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD 
); 
 127     static const wxChar gs_funcSuffix 
= _T('W'); 
 128 #endif // ASCII/Unicode 
 130 // structure passed to the secondary thread 
 131 struct WXDLLEXPORT wxRasThreadData
 
 138         dialUpManager 
= NULL
; 
 147             CloseHandle(hEventQuit
); 
 150             CloseHandle(hEventRas
); 
 153     HWND    hWnd
;       // window to send notifications to 
 154     HANDLE  hEventRas
,  // automatic event which RAS signals when status changes 
 155             hEventQuit
; // manual event which we signal when we terminate 
 157     class WXDLLEXPORT wxDialUpManagerMSW 
*dialUpManager
;  // the owner 
 160 // ---------------------------------------------------------------------------- 
 161 // wxDialUpManager class for MSW 
 162 // ---------------------------------------------------------------------------- 
 164 class WXDLLEXPORT wxDialUpManagerMSW 
: public wxDialUpManager
 
 168     wxDialUpManagerMSW(); 
 169     virtual ~wxDialUpManagerMSW(); 
 171     // implement base class pure virtuals 
 172     virtual bool IsOk() const; 
 173     virtual size_t GetISPNames(wxArrayString
& names
) const; 
 174     virtual bool Dial(const wxString
& nameOfISP
, 
 175                       const wxString
& username
, 
 176                       const wxString
& password
, 
 178     virtual bool IsDialing() const; 
 179     virtual bool CancelDialing(); 
 180     virtual bool HangUp(); 
 181     virtual bool IsAlwaysOnline() const; 
 182     virtual bool IsOnline() const; 
 183     virtual void SetOnlineStatus(bool isOnline 
= TRUE
); 
 184     virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
); 
 185     virtual void DisableAutoCheckOnlineStatus(); 
 186     virtual void SetWellKnownHost(const wxString
& hostname
, int port
); 
 187     virtual void SetConnectCommand(const wxString
& commandDial
, 
 188                                    const wxString
& commandHangup
); 
 191     void CheckRasStatus(); 
 193     // for wxRasStatusWindowProc 
 194     void OnConnectStatusChange(); 
 195     void OnDialProgress(RASCONNSTATE rasconnstate
, DWORD dwError
); 
 198     static HWND 
GetRasWindow() { return ms_hwndRas
; } 
 199     static wxDialUpManagerMSW 
*GetDialer() { return ms_dialer
; } 
 202     // return the error string for the given RAS error code 
 203     static wxString 
GetErrorString(DWORD error
); 
 205     // find the (first) handle of the active connection 
 206     static HRASCONN 
FindActiveConnection(); 
 208     // notify the application about status change 
 209     void NotifyApp(bool connected
, bool fromOurselves 
= FALSE
) const; 
 211     // destroy the thread data and the thread itself 
 212     void CleanUpThreadData(); 
 214     // number of times EnableAutoCheckOnlineStatus() had been called minus the 
 215     // number of times DisableAutoCheckOnlineStatus() had been called 
 216     int m_autoCheckLevel
; 
 218     // timer used for polling RAS status 
 219     class WXDLLEXPORT RasTimer 
: public wxTimer
 
 222         RasTimer(wxDialUpManagerMSW 
*dialUpManager
) 
 223             { m_dialUpManager 
= dialUpManager
; } 
 225         virtual void Notify() { m_dialUpManager
->CheckRasStatus(); } 
 228         wxDialUpManagerMSW 
*m_dialUpManager
; 
 230         DECLARE_NO_COPY_CLASS(RasTimer
) 
 231     } m_timerStatusPolling
; 
 233     // thread handle for the thread sitting on connection change event 
 236     // data used by this thread and our hidden window to send messages between 
 238     wxRasThreadData 
*m_data
; 
 240     // the handle of rasapi32.dll when it's loaded 
 241     wxDynamicLibrary m_dllRas
; 
 243     // the hidden window we use for passing messages between threads 
 244     static HWND ms_hwndRas
; 
 246     // the handle of the connection we initiated or 0 if none 
 247     static HRASCONN ms_hRasConnection
; 
 249     // the pointers to RAS functions 
 250     static RASDIAL ms_pfnRasDial
; 
 251     static RASENUMCONNECTIONS ms_pfnRasEnumConnections
; 
 252     static RASENUMENTRIES ms_pfnRasEnumEntries
; 
 253     static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus
; 
 254     static RASGETERRORSTRING ms_pfnRasGetErrorString
; 
 255     static RASHANGUP ms_pfnRasHangUp
; 
 256     static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo
; 
 257     static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry
; 
 258     static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry
; 
 259     static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams
; 
 260     static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams
; 
 261     static RASENUMDEVICES ms_pfnRasEnumDevices
; 
 262     static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo
; 
 263     static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties
; 
 264     static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties
; 
 265     static RASRENAMEENTRY ms_pfnRasRenameEntry
; 
 266     static RASDELETEENTRY ms_pfnRasDeleteEntry
; 
 267     static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName
; 
 269     // this function is not supported by Win95 
 270     static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification
; 
 272     // if this flag is different from -1, it overrides IsOnline() 
 273     static int ms_userSpecifiedOnlineStatus
; 
 275     // this flag tells us if we're online 
 276     static int ms_isConnected
; 
 278     // this flag tells us whether a call to RasDial() is in progress 
 279     static wxDialUpManagerMSW 
*ms_dialer
; 
 281     DECLARE_NO_COPY_CLASS(wxDialUpManagerMSW
) 
 284 // ---------------------------------------------------------------------------- 
 286 // ---------------------------------------------------------------------------- 
 288 static LRESULT WINAPI 
wxRasStatusWindowProc(HWND hWnd
, UINT message
, 
 289                                             WPARAM wParam
, LPARAM lParam
); 
 291 static DWORD 
wxRasMonitorThread(wxRasThreadData 
*data
); 
 293 static void WINAPI 
wxRasDialFunc(UINT unMsg
, 
 294                                  RASCONNSTATE rasconnstate
, 
 297 // ============================================================================ 
 299 // ============================================================================ 
 301 // ---------------------------------------------------------------------------- 
 302 // init the static variables 
 303 // ---------------------------------------------------------------------------- 
 305 HRASCONN 
wxDialUpManagerMSW::ms_hRasConnection 
= 0; 
 307 HWND 
wxDialUpManagerMSW::ms_hwndRas 
= 0; 
 309 RASDIAL 
wxDialUpManagerMSW::ms_pfnRasDial 
= 0; 
 310 RASENUMCONNECTIONS 
wxDialUpManagerMSW::ms_pfnRasEnumConnections 
= 0; 
 311 RASENUMENTRIES 
wxDialUpManagerMSW::ms_pfnRasEnumEntries 
= 0; 
 312 RASGETCONNECTSTATUS 
wxDialUpManagerMSW::ms_pfnRasGetConnectStatus 
= 0; 
 313 RASGETERRORSTRING 
wxDialUpManagerMSW::ms_pfnRasGetErrorString 
= 0; 
 314 RASHANGUP 
wxDialUpManagerMSW::ms_pfnRasHangUp 
= 0; 
 315 RASGETPROJECTIONINFO 
wxDialUpManagerMSW::ms_pfnRasGetProjectionInfo 
= 0; 
 316 RASCREATEPHONEBOOKENTRY 
wxDialUpManagerMSW::ms_pfnRasCreatePhonebookEntry 
= 0; 
 317 RASEDITPHONEBOOKENTRY 
wxDialUpManagerMSW::ms_pfnRasEditPhonebookEntry 
= 0; 
 318 RASSETENTRYDIALPARAMS 
wxDialUpManagerMSW::ms_pfnRasSetEntryDialParams 
= 0; 
 319 RASGETENTRYDIALPARAMS 
wxDialUpManagerMSW::ms_pfnRasGetEntryDialParams 
= 0; 
 320 RASENUMDEVICES 
wxDialUpManagerMSW::ms_pfnRasEnumDevices 
= 0; 
 321 RASGETCOUNTRYINFO 
wxDialUpManagerMSW::ms_pfnRasGetCountryInfo 
= 0; 
 322 RASGETENTRYPROPERTIES 
wxDialUpManagerMSW::ms_pfnRasGetEntryProperties 
= 0; 
 323 RASSETENTRYPROPERTIES 
wxDialUpManagerMSW::ms_pfnRasSetEntryProperties 
= 0; 
 324 RASRENAMEENTRY 
wxDialUpManagerMSW::ms_pfnRasRenameEntry 
= 0; 
 325 RASDELETEENTRY 
wxDialUpManagerMSW::ms_pfnRasDeleteEntry 
= 0; 
 326 RASVALIDATEENTRYNAME 
wxDialUpManagerMSW::ms_pfnRasValidateEntryName 
= 0; 
 327 RASCONNECTIONNOTIFICATION 
wxDialUpManagerMSW::ms_pfnRasConnectionNotification 
= 0; 
 329 int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus 
= -1; 
 330 int wxDialUpManagerMSW::ms_isConnected 
= -1; 
 331 wxDialUpManagerMSW 
*wxDialUpManagerMSW::ms_dialer 
= NULL
; 
 333 // ---------------------------------------------------------------------------- 
 334 // ctor and dtor: the dynamic linking happens here 
 335 // ---------------------------------------------------------------------------- 
 337 // the static creator function is implemented here 
 338 wxDialUpManager 
*wxDialUpManager::Create() 
 340     return new wxDialUpManagerMSW
; 
 344     // warning about "'this' : used in base member initializer list" - so what? 
 345     #pragma warning(disable:4355) 
 348 wxDialUpManagerMSW::wxDialUpManagerMSW() 
 349                   : m_timerStatusPolling(this), 
 350                     m_dllRas(_T("RASAPI32")) 
 352     // initialize our data 
 353     m_autoCheckLevel 
= 0; 
 355     m_data 
= new wxRasThreadData
; 
 357     if ( !m_dllRas
.IsLoaded() ) 
 359         wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it.")); 
 361     else if ( !ms_pfnRasDial 
) 
 363         // resolve the functions we need 
 365         // this will contain the name of the function we failed to resolve 
 367         const char *funcName 
= NULL
; 
 369         // get the function from rasapi32.dll and abort if it's not found 
 370         #define RESOLVE_RAS_FUNCTION(type, name)                          \ 
 371             ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name))  \ 
 373             if ( !ms_pfn##name )                                          \ 
 379         // a variant of above macro which doesn't abort if the function is 
 380         // not found in the DLL 
 381         #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name)                 \ 
 382             ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name))  \ 
 385         RESOLVE_RAS_FUNCTION(RASDIAL
, RasDial
); 
 386         RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS
, RasEnumConnections
); 
 387         RESOLVE_RAS_FUNCTION(RASENUMENTRIES
, RasEnumEntries
); 
 388         RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS
, RasGetConnectStatus
); 
 389         RESOLVE_RAS_FUNCTION(RASGETERRORSTRING
, RasGetErrorString
); 
 390         RESOLVE_RAS_FUNCTION(RASHANGUP
, RasHangUp
); 
 391         RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS
, RasGetEntryDialParams
); 
 393         // suppress error messages about missing (non essential) functions 
 397             RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO
, RasGetProjectionInfo
); 
 398             RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY
, RasCreatePhonebookEntry
); 
 399             RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY
, RasEditPhonebookEntry
); 
 400             RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS
, RasSetEntryDialParams
); 
 401             RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES
, RasGetEntryProperties
); 
 402             RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES
, RasSetEntryProperties
); 
 403             RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY
, RasRenameEntry
); 
 404             RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY
, RasDeleteEntry
); 
 405             RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME
, RasValidateEntryName
); 
 406             RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO
, RasGetCountryInfo
); 
 407             RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES
, RasEnumDevices
); 
 408             RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION
, RasConnectionNotification
); 
 411         // keep your preprocessor name space clean 
 412         #undef RESOLVE_RAS_FUNCTION 
 413         #undef RESOLVE_OPTIONAL_RAS_FUNCTION 
 418             static const wxChar 
*msg 
= wxTRANSLATE( 
 419 "The version of remote access service (RAS) installed on this machine is too\ 
 420 old, please upgrade (the following required function is missing: %s)." 
 423             wxLogError(wxGetTranslation(msg
), funcName
); 
 429     // enable auto check by default 
 430     EnableAutoCheckOnlineStatus(0); 
 433 wxDialUpManagerMSW::~wxDialUpManagerMSW() 
 438 // ---------------------------------------------------------------------------- 
 440 // ---------------------------------------------------------------------------- 
 442 wxString 
wxDialUpManagerMSW::GetErrorString(DWORD error
) 
 444     wxChar buffer
[512]; // this should be more than enough according to MS docs 
 445     DWORD dwRet 
= ms_pfnRasGetErrorString(error
, buffer
, WXSIZEOF(buffer
)); 
 448         case ERROR_INVALID_PARAMETER
: 
 449             // this was a standard Win32 error probably 
 450             return wxString(wxSysErrorMsg(error
)); 
 455                       _("Failed to retrieve text of RAS error message")); 
 458                 msg
.Printf(_("unknown error (error code %08x)."), error
); 
 463             // we want the error message to start from a lower case letter 
 464             buffer
[0] = wxTolower(buffer
[0]); 
 466             return wxString(buffer
); 
 470 HRASCONN 
wxDialUpManagerMSW::FindActiveConnection() 
 472     // enumerate connections 
 473     DWORD cbBuf 
= sizeof(RASCONN
); 
 474     LPRASCONN lpRasConn 
= (LPRASCONN
)malloc(cbBuf
); 
 481     lpRasConn
->dwSize 
= sizeof(RASCONN
); 
 483     DWORD nConnections 
= 0; 
 484     DWORD dwRet 
= ERROR_BUFFER_TOO_SMALL
; 
 486     while ( dwRet 
== ERROR_BUFFER_TOO_SMALL 
) 
 488         dwRet 
= ms_pfnRasEnumConnections(lpRasConn
, &cbBuf
, &nConnections
); 
 490         if ( dwRet 
== ERROR_BUFFER_TOO_SMALL 
) 
 492             LPRASCONN lpRasConnOld 
= lpRasConn
; 
 493             lpRasConn 
= (LPRASCONN
)realloc(lpRasConn
, cbBuf
); 
 502         else if ( dwRet 
== 0 ) 
 510             wxLogError(_("Cannot find active dialup connection: %s"), 
 511                        GetErrorString(dwRet
).c_str()); 
 518     switch ( nConnections 
) 
 526             // more than 1 connection - we don't know what to do with this 
 527             // case, so give a warning but continue (taking the first 
 528             // connection) - the warning is really needed because this function 
 529             // is used, for example, to select the connection to hang up and so 
 530             // we may hang up the wrong connection here... 
 531             wxLogWarning(_("Several active dialup connections found, choosing one randomly.")); 
 535             // exactly 1 connection, great 
 536             hrasconn 
= lpRasConn
->hrasconn
; 
 544 void wxDialUpManagerMSW::CleanUpThreadData() 
 548         if ( !SetEvent(m_data
->hEventQuit
) ) 
 550             wxLogLastError(_T("SetEvent(RasThreadQuit)")); 
 552         else // sent quit request to the background thread 
 554             // the thread still needs m_data so we can't free it here, rather 
 555             // let the thread do it itself 
 559         CloseHandle(m_hThread
); 
 571 // ---------------------------------------------------------------------------- 
 573 // ---------------------------------------------------------------------------- 
 575 void wxDialUpManagerMSW::CheckRasStatus() 
 577     // use int, not bool to compare with -1 
 578     int isConnected 
= FindActiveConnection() != 0; 
 579     if ( isConnected 
!= ms_isConnected 
) 
 581         if ( ms_isConnected 
!= -1 ) 
 583             // notify the program 
 584             NotifyApp(isConnected 
!= 0); 
 586         // else: it's the first time we're called, just update the flag 
 588         ms_isConnected 
= isConnected
; 
 592 void wxDialUpManagerMSW::NotifyApp(bool connected
, bool fromOurselves
) const 
 594     wxDialUpEvent 
event(connected
, fromOurselves
); 
 595     (void)wxTheApp
->ProcessEvent(event
); 
 598 // this function is called whenever the status of any RAS connection on this 
 599 // machine changes by RAS itself 
 600 void wxDialUpManagerMSW::OnConnectStatusChange() 
 602     // we know that status changed, but we don't know whether we're connected 
 603     // or not - so find it out 
 607 // this function is called by our callback which we give to RasDial() when 
 608 // calling it asynchronously 
 609 void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate
, 
 614         // this probably means that CancelDialing() was called and we get 
 615         // "disconnected" notification 
 619     // we're only interested in 2 events: connected and disconnected 
 622         wxLogError(_("Failed to establish dialup connection: %s"), 
 623                    GetErrorString(dwError
).c_str()); 
 625         // we should still call RasHangUp() if we got a non 0 connection 
 626         if ( ms_hRasConnection 
) 
 628             ms_pfnRasHangUp(ms_hRasConnection
); 
 629             ms_hRasConnection 
= 0; 
 634         NotifyApp(FALSE 
/* !connected */, TRUE 
/* we dialed ourselves */); 
 636     else if ( rasconnstate 
== RASCS_Connected 
) 
 638         ms_isConnected 
= TRUE
; 
 641         NotifyApp(TRUE 
/* connected */, TRUE 
/* we dialed ourselves */); 
 645 // ---------------------------------------------------------------------------- 
 646 // implementation of wxDialUpManager functions 
 647 // ---------------------------------------------------------------------------- 
 649 bool wxDialUpManagerMSW::IsOk() const 
 651     return m_dllRas
.IsLoaded(); 
 654 size_t wxDialUpManagerMSW::GetISPNames(wxArrayString
& names
) const 
 657     DWORD size 
= sizeof(RASENTRYNAME
); 
 658     RASENTRYNAME 
*rasEntries 
= (RASENTRYNAME 
*)malloc(size
); 
 659     rasEntries
->dwSize 
= sizeof(RASENTRYNAME
); 
 665         dwRet 
= ms_pfnRasEnumEntries
 
 668                    NULL
,                // default phone book (or all) 
 669                    rasEntries
,          // [out] buffer for the entries 
 670                    &size
,               // [in/out] size of the buffer 
 671                    &nEntries            
// [out] number of entries fetched 
 674         if ( dwRet 
== ERROR_BUFFER_TOO_SMALL 
) 
 676             // reallocate the buffer 
 677             rasEntries 
= (RASENTRYNAME 
*)realloc(rasEntries
, size
); 
 679         else if ( dwRet 
!= 0 ) 
 681             // some other error - abort 
 682             wxLogError(_("Failed to get ISP names: %s"), 
 683                        GetErrorString(dwRet
).c_str()); 
 690     while ( dwRet 
!= 0 ); 
 694     for ( size_t n 
= 0; n 
< (size_t)nEntries
; n
++ ) 
 696         names
.Add(rasEntries
[n
].szEntryName
); 
 701     // return the number of entries 
 702     return names
.GetCount(); 
 705 bool wxDialUpManagerMSW::Dial(const wxString
& nameOfISP
, 
 706                               const wxString
& username
, 
 707                               const wxString
& password
, 
 710     // check preconditions 
 711     wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") ); 
 713     if ( ms_hRasConnection 
) 
 715         wxFAIL_MSG(wxT("there is already an active connection")); 
 720     // get the default ISP if none given 
 721     wxString 
entryName(nameOfISP
); 
 725         size_t count 
= GetISPNames(names
); 
 729                 // no known ISPs, abort 
 730                 wxLogError(_("Failed to connect: no ISP to dial.")); 
 735                 // only one ISP, choose it 
 736                 entryName 
= names
[0u]; 
 740                 // several ISPs, let the user choose 
 742                     wxString 
*strings 
= new wxString
[count
]; 
 743                     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 745                         strings
[i
] = names
[i
]; 
 748                     entryName 
= wxGetSingleChoice
 
 750                                  _("Choose ISP to dial"), 
 751                                  _("Please choose which ISP do you want to connect to"), 
 767     RASDIALPARAMS rasDialParams
; 
 768     rasDialParams
.dwSize 
= sizeof(rasDialParams
); 
 769     wxStrncpy(rasDialParams
.szEntryName
, entryName
, RAS_MaxEntryName
); 
 771     // do we have the username and password? 
 772     if ( !username 
|| !password 
) 
 775         DWORD dwRet 
= ms_pfnRasGetEntryDialParams
 
 777                        NULL
,            // default phonebook 
 778                        &rasDialParams
,  // [in/out] the params of this entry 
 779                        &gotPassword     
// [out] did we get password? 
 784             wxLogError(_("Failed to connect: missing username/password.")); 
 791         wxStrncpy(rasDialParams
.szUserName
, username
, UNLEN
); 
 792         wxStrncpy(rasDialParams
.szPassword
, password
, PWLEN
); 
 795     // default values for other fields 
 796     rasDialParams
.szPhoneNumber
[0] = '\0'; 
 797     rasDialParams
.szCallbackNumber
[0] = '\0'; 
 798     rasDialParams
.szCallbackNumber
[0] = '\0'; 
 800     rasDialParams
.szDomain
[0] = '*'; 
 801     rasDialParams
.szDomain
[1] = '\0'; 
 803     // apparently, this is not really necessary - passing NULL instead of the 
 804     // phone book has the same effect 
 807     if ( wxGetOsVersion() == wxWINDOWS_NT 
) 
 809         // first get the length 
 810         UINT nLen 
= ::GetSystemDirectory(NULL
, 0); 
 813         if ( !::GetSystemDirectory(phoneBook
.GetWriteBuf(nLen
), nLen
) ) 
 815             wxLogSysError(_("Cannot find the location of address book file")); 
 818         phoneBook
.UngetWriteBuf(); 
 820         // this is the default phone book 
 821         phoneBook 
<< "\\ras\\rasphone.pbk"; 
 825     // TODO may be we should disable auto check while async dialing is in 
 830     DWORD dwRet 
= ms_pfnRasDial
 
 832                    NULL
,                    // no extended features 
 833                    NULL
,                    // default phone book file (NT only) 
 835                    0,                       // use callback for notifications 
 836                    async 
? (void *)wxRasDialFunc  
// cast needed for gcc 3.1 
 837                          : 0,               // no notifications, sync operation 
 843         // can't pass a wxWCharBuffer through ( ... ) 
 844         wxLogError(_("Failed to %s dialup connection: %s"), 
 845                    wxString(async 
? _("initiate") : _("establish")).c_str(), 
 846                    GetErrorString(dwRet
).c_str()); 
 848         // we should still call RasHangUp() if we got a non 0 connection 
 849         if ( ms_hRasConnection 
) 
 851             ms_pfnRasHangUp(ms_hRasConnection
); 
 852             ms_hRasConnection 
= 0; 
 860     // for async dialing, we're not yet connected 
 863         ms_isConnected 
= TRUE
; 
 869 bool wxDialUpManagerMSW::IsDialing() const 
 871     return GetDialer() != NULL
; 
 874 bool wxDialUpManagerMSW::CancelDialing() 
 882     wxASSERT_MSG( ms_hRasConnection
, wxT("dialing but no connection?") ); 
 889 bool wxDialUpManagerMSW::HangUp() 
 891     wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") ); 
 893     // we may terminate either the connection we initiated or another one which 
 896     if ( ms_hRasConnection 
) 
 898         hRasConn 
= ms_hRasConnection
; 
 900         ms_hRasConnection 
= 0; 
 904         hRasConn 
= FindActiveConnection(); 
 909         wxLogError(_("Cannot hang up - no active dialup connection.")); 
 914     DWORD dwRet 
= ms_pfnRasHangUp(hRasConn
); 
 917         wxLogError(_("Failed to terminate the dialup connection: %s"), 
 918                    GetErrorString(dwRet
).c_str()); 
 921     ms_isConnected 
= FALSE
; 
 926 bool wxDialUpManagerMSW::IsAlwaysOnline() const 
 928     // assume no permanent connection by default 
 929     bool isAlwaysOnline 
= FALSE
; 
 931     // try to use WinInet functions 
 933     // NB: we could probably use wxDynamicLibrary here just as well, 
 934     //     but we allow multiple instances of wxDialUpManagerMSW so 
 935     //     we might as well use the ref counted version here too. 
 937     wxDynamicLibrary 
hDll(_T("WININET")); 
 938     if ( hDll
.IsLoaded() ) 
 940         typedef BOOL (WINAPI 
*INTERNETGETCONNECTEDSTATE
)(LPDWORD
, DWORD
); 
 941         INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState
; 
 943         #define RESOLVE_FUNCTION(type, name) \ 
 944             pfn##name = (type)hDll.GetSymbol(_T(#name)) 
 946         RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE
, InternetGetConnectedState
); 
 948         if ( pfnInternetGetConnectedState 
) 
 951             if ( pfnInternetGetConnectedState(&flags
, 0 /* reserved */) ) 
 953                 // there is some connection to the net, see of which type 
 954                 isAlwaysOnline 
= (flags 
& (INTERNET_CONNECTION_LAN 
| 
 955                                            INTERNET_CONNECTION_PROXY
)) != 0; 
 957             //else: no Internet connection at all 
 961     return isAlwaysOnline
; 
 964 bool wxDialUpManagerMSW::IsOnline() const 
 966     wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") ); 
 968     if ( IsAlwaysOnline() ) 
 974     if ( ms_userSpecifiedOnlineStatus 
!= -1 ) 
 976         // user specified flag overrides our logic 
 977         return ms_userSpecifiedOnlineStatus 
!= 0; 
 981         // return TRUE if there is at least one active connection 
 982         return FindActiveConnection() != 0; 
 986 void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline
) 
 988     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
 990     ms_userSpecifiedOnlineStatus 
= isOnline
; 
 993 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds
) 
 995     wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") ); 
 997     if ( m_autoCheckLevel
++ ) 
1003     bool ok 
= ms_pfnRasConnectionNotification 
!= 0; 
1007         // we're running under NT 4.0, Windows 98 or later and can use 
1008         // RasConnectionNotification() to be notified by a secondary thread 
1010         // first, see if we don't have this thread already running 
1011         if ( m_hThread 
!= 0 ) 
1013             if ( ::ResumeThread(m_hThread
) != (DWORD
)-1 ) 
1016             // we're leaving a zombie thread... but what else can we do? 
1017             wxLogLastError(wxT("ResumeThread(RasThread)")); 
1023     // create all the stuff we need to be notified about RAS connection 
1028         // first create an event to wait on 
1029         m_data
->hEventRas 
= CreateEvent
 
1031                              NULL
,      // security attribute (default) 
1032                              FALSE
,     // manual reset (no, it is automatic) 
1033                              FALSE
,     // initial state (not signaled) 
1036         if ( !m_data
->hEventRas 
) 
1038             wxLogLastError(wxT("CreateEvent(RasStatus)")); 
1046         // create the event we use to quit the thread: using a manual event 
1047         // here avoids problems with missing the event if wxDialUpManagerMSW 
1048         // is created and destroyed immediately, before wxRasStatusWindowProc 
1049         // starts waiting on the event 
1050         m_data
->hEventQuit 
= CreateEvent
 
1052                                 NULL
,   // default security 
1053                                 TRUE
,   // manual event 
1054                                 FALSE
,  // initially non signalled 
1057         if ( !m_data
->hEventQuit 
) 
1059             wxLogLastError(wxT("CreateEvent(RasThreadQuit)")); 
1061             CleanUpThreadData(); 
1067     if ( ok 
&& !ms_hwndRas 
) 
1069         // create a hidden window to receive notification about connections 
1071         extern const wxChar 
*wxCanvasClassName
; 
1072         ms_hwndRas 
= ::CreateWindow(wxCanvasClassName
, NULL
, 
1075                                     (HMENU
)NULL
, wxGetInstance(), 0); 
1078             wxLogLastError(wxT("CreateWindow(RasHiddenWindow)")); 
1080             CleanUpThreadData(); 
1086         wxSetWindowProc(ms_hwndRas
, wxRasStatusWindowProc
); 
1089     m_data
->hWnd 
= ms_hwndRas
; 
1093         // start the secondary thread 
1094         m_data
->dialUpManager 
= this; 
1097         m_hThread 
= CreateThread
 
1101                      (LPTHREAD_START_ROUTINE
)wxRasMonitorThread
, 
1109             wxLogLastError(wxT("CreateThread(RasStatusThread)")); 
1111             CleanUpThreadData(); 
1117         // start receiving RAS notifications 
1118         DWORD dwRet 
= ms_pfnRasConnectionNotification
 
1120                         (HRASCONN
)INVALID_HANDLE_VALUE
, 
1122                         3 /* RASCN_Connection | RASCN_Disconnection */ 
1127             wxLogDebug(wxT("RasConnectionNotification() failed: %s"), 
1128                        GetErrorString(dwRet
).c_str()); 
1130             CleanUpThreadData(); 
1138     // we're running under Windows 95 and have to poll ourselves 
1139     // (or, alternatively, the code above for NT/98 failed) 
1140     m_timerStatusPolling
.Stop(); 
1141     if ( nSeconds 
== 0 ) 
1146     m_timerStatusPolling
.Start(nSeconds 
* 1000); 
1151 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus() 
1153     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1155     if ( --m_autoCheckLevel 
) 
1163         // we have running secondary thread, it's just enough to suspend it 
1164         if ( SuspendThread(m_hThread
) == (DWORD
)-1 ) 
1166             wxLogLastError(wxT("SuspendThread(RasThread)")); 
1171         // even simpler - just stop the timer 
1172         m_timerStatusPolling
.Stop(); 
1176 // ---------------------------------------------------------------------------- 
1177 // stubs which don't do anything in MSW version 
1178 // ---------------------------------------------------------------------------- 
1180 void wxDialUpManagerMSW::SetWellKnownHost(const wxString
& WXUNUSED(hostname
), 
1183     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1185     // nothing to do - we don't use this 
1188 void wxDialUpManagerMSW::SetConnectCommand(const wxString
& WXUNUSED(dial
), 
1189                                            const wxString
& WXUNUSED(hangup
)) 
1191     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1193     // nothing to do - we don't use this 
1196 // ---------------------------------------------------------------------------- 
1198 // ---------------------------------------------------------------------------- 
1200 static DWORD 
wxRasMonitorThread(wxRasThreadData 
*data
) 
1203     handles
[0] = data
->hEventRas
; 
1204     handles
[1] = data
->hEventQuit
; 
1209         DWORD dwRet 
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
); 
1214                 // RAS connection status changed 
1215                 SendMessage(data
->hWnd
, wxWM_RAS_STATUS_CHANGED
, 
1219             case WAIT_OBJECT_0 
+ 1: 
1224                 wxFAIL_MSG( _T("unexpected return of WaitForMultipleObjects()") ); 
1229                 // using wxLogLastError() from here is dangerous: we risk to 
1230                 // deadlock the main thread if wxLog sends output to GUI 
1231                 DWORD err 
= GetLastError(); 
1232                 wxMessageOutputDebug().Printf
 
1234                     wxT("WaitForMultipleObjects(RasMonitor) failed: 0x%08lx (%s)"), 
1238 #endif // __WXDEBUG__ 
1240                 // no sense in continuing, who knows if the handles we're 
1241                 // waiting for even exist yet... 
1246     // we don't need it any more now and if this thread ran, it is our 
1247     // responsability to free the data 
1253 static LRESULT APIENTRY 
wxRasStatusWindowProc(HWND hWnd
, UINT message
, 
1254                                               WPARAM wParam
, LPARAM lParam
) 
1258         case wxWM_RAS_STATUS_CHANGED
: 
1260                 wxRasThreadData 
*data 
= (wxRasThreadData 
*)lParam
; 
1261                 data
->dialUpManager
->OnConnectStatusChange(); 
1265         case wxWM_RAS_DIALING_PROGRESS
: 
1267                 wxDialUpManagerMSW 
*dialMan 
= wxDialUpManagerMSW::GetDialer(); 
1269                 dialMan
->OnDialProgress((RASCONNSTATE
)wParam
, lParam
); 
1274             return ::DefWindowProc(hWnd
, message
, wParam
, lParam
); 
1280 static void WINAPI 
wxRasDialFunc(UINT 
WXUNUSED(unMsg
), 
1281                                  RASCONNSTATE rasconnstate
, 
1284     wxDialUpManagerMSW 
*dialUpManager 
= wxDialUpManagerMSW::GetDialer(); 
1286     wxCHECK_RET( dialUpManager
, wxT("who started to dial then?") ); 
1288     SendMessage(dialUpManager
->GetRasWindow(), wxWM_RAS_DIALING_PROGRESS
, 
1289                 rasconnstate
, dwError
); 
1292 #endif // __BORLANDC__ 
1294 #endif // wxUSE_DIALUP_MANAGER