1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/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 
  29 #include "wx/dialup.h" 
  37     #include "wx/module.h" 
  40 #include "wx/generic/choicdgg.h" 
  42 #include "wx/dynlib.h" 
  44 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED
) 
  45 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED
) 
  47 // Doesn't yet compile under VC++ 4, BC++, Watcom C++, 
  49 #if (!defined(__BORLANDC__) || (__BORLANDC__>=0x550)) && \ 
  50     (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \ 
  51     !defined(__GNUWIN32_OLD__) && \ 
  52     !defined(__WINE__) && \ 
  53     (!defined(__VISUALC__) || (__VISUALC__ >= 1020)) 
  61 #ifndef INTERNET_CONNECTION_LAN 
  62 #define INTERNET_CONNECTION_LAN 2 
  64 #ifndef INTERNET_CONNECTION_PROXY 
  65 #define INTERNET_CONNECTION_PROXY 4 
  68 // implemented in utils.cpp 
  69 extern "C" WXDLLIMPEXP_BASE HWND
 
  70 wxCreateHiddenWindow(LPCTSTR 
*pclassname
, LPCTSTR classname
, WNDPROC wndproc
); 
  73     wxMSWDIALUP_WNDCLASSNAME 
= wxT("_wxDialUpManager_Internal_Class"); 
  74 static const wxChar 
*gs_classForDialUpWindow 
= NULL
; 
  76 // ---------------------------------------------------------------------------- 
  78 // ---------------------------------------------------------------------------- 
  80 // this message is sent by the secondary thread when RAS status changes 
  81 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010) 
  82 #define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011) 
  84 // ---------------------------------------------------------------------------- 
  86 // ---------------------------------------------------------------------------- 
  88 // the signatures of RAS functions: all this is quite heavy, but we must do it 
  89 // to allow running wxWin programs on machine which don't have RAS installed 
  90 // (this does exist) - if we link with rasapi32.lib, the program will fail on 
  91 // startup because of the missing DLL... 
  94     typedef DWORD (APIENTRY 
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCSTR
, LPRASDIALPARAMSA
, DWORD
, LPVOID
, LPHRASCONN 
); 
  95     typedef DWORD (APIENTRY 
* RASENUMCONNECTIONS
)( LPRASCONNA
, LPDWORD
, LPDWORD 
); 
  96     typedef DWORD (APIENTRY 
* RASENUMENTRIES
)( LPCSTR
, LPCSTR
, LPRASENTRYNAMEA
, LPDWORD
, LPDWORD 
); 
  97     typedef DWORD (APIENTRY 
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSA 
); 
  98     typedef DWORD (APIENTRY 
* RASGETERRORSTRING
)( UINT
, LPSTR
, DWORD 
); 
  99     typedef DWORD (APIENTRY 
* RASHANGUP
)( HRASCONN 
); 
 100     typedef DWORD (APIENTRY 
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD 
); 
 101     typedef DWORD (APIENTRY 
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCSTR 
); 
 102     typedef DWORD (APIENTRY 
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCSTR
, LPCSTR 
); 
 103     typedef DWORD (APIENTRY 
* RASSETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, BOOL 
); 
 104     typedef DWORD (APIENTRY 
* RASGETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, LPBOOL 
); 
 105     typedef DWORD (APIENTRY 
* RASENUMDEVICES
)( LPRASDEVINFOA
, LPDWORD
, LPDWORD 
); 
 106     typedef DWORD (APIENTRY 
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOA
, LPDWORD 
); 
 107     typedef DWORD (APIENTRY 
* RASGETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, LPDWORD
, LPBYTE
, LPDWORD 
); 
 108     typedef DWORD (APIENTRY 
* RASSETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, DWORD
, LPBYTE
, DWORD 
); 
 109     typedef DWORD (APIENTRY 
* RASRENAMEENTRY
)( LPCSTR
, LPCSTR
, LPCSTR 
); 
 110     typedef DWORD (APIENTRY 
* RASDELETEENTRY
)( LPCSTR
, LPCSTR 
); 
 111     typedef DWORD (APIENTRY 
* RASVALIDATEENTRYNAME
)( LPCSTR
, LPCSTR 
); 
 112     typedef DWORD (APIENTRY 
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD 
); 
 114     static const wxChar gs_funcSuffix 
= _T('A'); 
 116     typedef DWORD (APIENTRY 
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCWSTR
, LPRASDIALPARAMSW
, DWORD
, LPVOID
, LPHRASCONN 
); 
 117     typedef DWORD (APIENTRY 
* RASENUMCONNECTIONS
)( LPRASCONNW
, LPDWORD
, LPDWORD 
); 
 118     typedef DWORD (APIENTRY 
* RASENUMENTRIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYNAMEW
, LPDWORD
, LPDWORD 
); 
 119     typedef DWORD (APIENTRY 
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSW 
); 
 120     typedef DWORD (APIENTRY 
* RASGETERRORSTRING
)( UINT
, LPWSTR
, DWORD 
); 
 121     typedef DWORD (APIENTRY 
* RASHANGUP
)( HRASCONN 
); 
 122     typedef DWORD (APIENTRY 
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD 
); 
 123     typedef DWORD (APIENTRY 
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCWSTR 
); 
 124     typedef DWORD (APIENTRY 
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCWSTR
, LPCWSTR 
); 
 125     typedef DWORD (APIENTRY 
* RASSETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, BOOL 
); 
 126     typedef DWORD (APIENTRY 
* RASGETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, LPBOOL 
); 
 127     typedef DWORD (APIENTRY 
* RASENUMDEVICES
)( LPRASDEVINFOW
, LPDWORD
, LPDWORD 
); 
 128     typedef DWORD (APIENTRY 
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOW
, LPDWORD 
); 
 129     typedef DWORD (APIENTRY 
* RASGETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, LPDWORD
, LPBYTE
, LPDWORD 
); 
 130     typedef DWORD (APIENTRY 
* RASSETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, DWORD
, LPBYTE
, DWORD 
); 
 131     typedef DWORD (APIENTRY 
* RASRENAMEENTRY
)( LPCWSTR
, LPCWSTR
, LPCWSTR 
); 
 132     typedef DWORD (APIENTRY 
* RASDELETEENTRY
)( LPCWSTR
, LPCWSTR 
); 
 133     typedef DWORD (APIENTRY 
* RASVALIDATEENTRYNAME
)( LPCWSTR
, LPCWSTR 
); 
 134     typedef DWORD (APIENTRY 
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD 
); 
 136     static const wxChar gs_funcSuffix 
= _T('W'); 
 137 #endif // ASCII/Unicode 
 139 // structure passed to the secondary thread 
 140 struct WXDLLEXPORT wxRasThreadData
 
 147         dialUpManager 
= NULL
; 
 156             CloseHandle(hEventQuit
); 
 159             CloseHandle(hEventRas
); 
 162     HWND    hWnd
;       // window to send notifications to 
 163     HANDLE  hEventRas
,  // automatic event which RAS signals when status changes 
 164             hEventQuit
; // manual event which we signal when we terminate 
 166     class WXDLLEXPORT wxDialUpManagerMSW 
*dialUpManager
;  // the owner 
 169 // ---------------------------------------------------------------------------- 
 170 // wxDialUpManager class for MSW 
 171 // ---------------------------------------------------------------------------- 
 173 class WXDLLEXPORT wxDialUpManagerMSW 
: public wxDialUpManager
 
 177     wxDialUpManagerMSW(); 
 178     virtual ~wxDialUpManagerMSW(); 
 180     // implement base class pure virtuals 
 181     virtual bool IsOk() const; 
 182     virtual size_t GetISPNames(wxArrayString
& names
) const; 
 183     virtual bool Dial(const wxString
& nameOfISP
, 
 184                       const wxString
& username
, 
 185                       const wxString
& password
, 
 187     virtual bool IsDialing() const; 
 188     virtual bool CancelDialing(); 
 189     virtual bool HangUp(); 
 190     virtual bool IsAlwaysOnline() const; 
 191     virtual bool IsOnline() const; 
 192     virtual void SetOnlineStatus(bool isOnline 
= true); 
 193     virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
); 
 194     virtual void DisableAutoCheckOnlineStatus(); 
 195     virtual void SetWellKnownHost(const wxString
& hostname
, int port
); 
 196     virtual void SetConnectCommand(const wxString
& commandDial
, 
 197                                    const wxString
& commandHangup
); 
 200     void CheckRasStatus(); 
 202     // for wxRasStatusWindowProc 
 203     void OnConnectStatusChange(); 
 204     void OnDialProgress(RASCONNSTATE rasconnstate
, DWORD dwError
); 
 207     static HWND 
GetRasWindow() { return ms_hwndRas
; } 
 208     static void ResetRasWindow() { ms_hwndRas 
= NULL
; } 
 209     static wxDialUpManagerMSW 
*GetDialer() { return ms_dialer
; } 
 212     // return the error string for the given RAS error code 
 213     static wxString 
GetErrorString(DWORD error
); 
 215     // find the (first) handle of the active connection 
 216     static HRASCONN 
FindActiveConnection(); 
 218     // notify the application about status change 
 219     void NotifyApp(bool connected
, bool fromOurselves 
= false) const; 
 221     // destroy the thread data and the thread itself 
 222     void CleanUpThreadData(); 
 224     // number of times EnableAutoCheckOnlineStatus() had been called minus the 
 225     // number of times DisableAutoCheckOnlineStatus() had been called 
 226     int m_autoCheckLevel
; 
 228     // timer used for polling RAS status 
 229     class WXDLLEXPORT RasTimer 
: public wxTimer
 
 232         RasTimer(wxDialUpManagerMSW 
*dialUpManager
) 
 233             { m_dialUpManager 
= dialUpManager
; } 
 235         virtual void Notify() { m_dialUpManager
->CheckRasStatus(); } 
 238         wxDialUpManagerMSW 
*m_dialUpManager
; 
 240         DECLARE_NO_COPY_CLASS(RasTimer
) 
 241     } m_timerStatusPolling
; 
 243     // thread handle for the thread sitting on connection change event 
 246     // data used by this thread and our hidden window to send messages between 
 248     wxRasThreadData 
*m_data
; 
 250     // the handle of rasapi32.dll when it's loaded 
 251     wxDynamicLibrary m_dllRas
; 
 253     // the hidden window we use for passing messages between threads 
 254     static HWND ms_hwndRas
; 
 256     // the handle of the connection we initiated or 0 if none 
 257     static HRASCONN ms_hRasConnection
; 
 259     // the pointers to RAS functions 
 260     static RASDIAL ms_pfnRasDial
; 
 261     static RASENUMCONNECTIONS ms_pfnRasEnumConnections
; 
 262     static RASENUMENTRIES ms_pfnRasEnumEntries
; 
 263     static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus
; 
 264     static RASGETERRORSTRING ms_pfnRasGetErrorString
; 
 265     static RASHANGUP ms_pfnRasHangUp
; 
 266     static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo
; 
 267     static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry
; 
 268     static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry
; 
 269     static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams
; 
 270     static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams
; 
 271     static RASENUMDEVICES ms_pfnRasEnumDevices
; 
 272     static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo
; 
 273     static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties
; 
 274     static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties
; 
 275     static RASRENAMEENTRY ms_pfnRasRenameEntry
; 
 276     static RASDELETEENTRY ms_pfnRasDeleteEntry
; 
 277     static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName
; 
 279     // this function is not supported by Win95 
 280     static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification
; 
 282     // if this flag is different from -1, it overrides IsOnline() 
 283     static int ms_userSpecifiedOnlineStatus
; 
 285     // this flag tells us if we're online 
 286     static int ms_isConnected
; 
 288     // this flag tells us whether a call to RasDial() is in progress 
 289     static wxDialUpManagerMSW 
*ms_dialer
; 
 291     DECLARE_NO_COPY_CLASS(wxDialUpManagerMSW
) 
 294 // module to destroy helper window created by wxDialUpManagerMSW 
 295 class wxDialUpManagerModule 
: public wxModule
 
 298     bool OnInit() { return true; } 
 301         HWND hwnd 
= wxDialUpManagerMSW::GetRasWindow(); 
 304             ::DestroyWindow(hwnd
); 
 305             wxDialUpManagerMSW::ResetRasWindow(); 
 308         if ( gs_classForDialUpWindow 
) 
 310             ::UnregisterClass(wxMSWDIALUP_WNDCLASSNAME
, wxGetInstance()); 
 311             gs_classForDialUpWindow 
= NULL
; 
 316     DECLARE_DYNAMIC_CLASS(wxDialUpManagerModule
) 
 319 IMPLEMENT_DYNAMIC_CLASS(wxDialUpManagerModule
, wxModule
) 
 321 // ---------------------------------------------------------------------------- 
 323 // ---------------------------------------------------------------------------- 
 325 static LRESULT WINAPI 
wxRasStatusWindowProc(HWND hWnd
, UINT message
, 
 326                                             WPARAM wParam
, LPARAM lParam
); 
 328 static DWORD 
wxRasMonitorThread(wxRasThreadData 
*data
); 
 330 static void WINAPI 
wxRasDialFunc(UINT unMsg
, 
 331                                  RASCONNSTATE rasconnstate
, 
 334 // ============================================================================ 
 336 // ============================================================================ 
 338 // ---------------------------------------------------------------------------- 
 339 // init the static variables 
 340 // ---------------------------------------------------------------------------- 
 342 HRASCONN 
wxDialUpManagerMSW::ms_hRasConnection 
= 0; 
 344 HWND 
wxDialUpManagerMSW::ms_hwndRas 
= 0; 
 346 RASDIAL 
wxDialUpManagerMSW::ms_pfnRasDial 
= 0; 
 347 RASENUMCONNECTIONS 
wxDialUpManagerMSW::ms_pfnRasEnumConnections 
= 0; 
 348 RASENUMENTRIES 
wxDialUpManagerMSW::ms_pfnRasEnumEntries 
= 0; 
 349 RASGETCONNECTSTATUS 
wxDialUpManagerMSW::ms_pfnRasGetConnectStatus 
= 0; 
 350 RASGETERRORSTRING 
wxDialUpManagerMSW::ms_pfnRasGetErrorString 
= 0; 
 351 RASHANGUP 
wxDialUpManagerMSW::ms_pfnRasHangUp 
= 0; 
 352 RASGETPROJECTIONINFO 
wxDialUpManagerMSW::ms_pfnRasGetProjectionInfo 
= 0; 
 353 RASCREATEPHONEBOOKENTRY 
wxDialUpManagerMSW::ms_pfnRasCreatePhonebookEntry 
= 0; 
 354 RASEDITPHONEBOOKENTRY 
wxDialUpManagerMSW::ms_pfnRasEditPhonebookEntry 
= 0; 
 355 RASSETENTRYDIALPARAMS 
wxDialUpManagerMSW::ms_pfnRasSetEntryDialParams 
= 0; 
 356 RASGETENTRYDIALPARAMS 
wxDialUpManagerMSW::ms_pfnRasGetEntryDialParams 
= 0; 
 357 RASENUMDEVICES 
wxDialUpManagerMSW::ms_pfnRasEnumDevices 
= 0; 
 358 RASGETCOUNTRYINFO 
wxDialUpManagerMSW::ms_pfnRasGetCountryInfo 
= 0; 
 359 RASGETENTRYPROPERTIES 
wxDialUpManagerMSW::ms_pfnRasGetEntryProperties 
= 0; 
 360 RASSETENTRYPROPERTIES 
wxDialUpManagerMSW::ms_pfnRasSetEntryProperties 
= 0; 
 361 RASRENAMEENTRY 
wxDialUpManagerMSW::ms_pfnRasRenameEntry 
= 0; 
 362 RASDELETEENTRY 
wxDialUpManagerMSW::ms_pfnRasDeleteEntry 
= 0; 
 363 RASVALIDATEENTRYNAME 
wxDialUpManagerMSW::ms_pfnRasValidateEntryName 
= 0; 
 364 RASCONNECTIONNOTIFICATION 
wxDialUpManagerMSW::ms_pfnRasConnectionNotification 
= 0; 
 366 int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus 
= -1; 
 367 int wxDialUpManagerMSW::ms_isConnected 
= -1; 
 368 wxDialUpManagerMSW 
*wxDialUpManagerMSW::ms_dialer 
= NULL
; 
 370 // ---------------------------------------------------------------------------- 
 371 // ctor and dtor: the dynamic linking happens here 
 372 // ---------------------------------------------------------------------------- 
 374 // the static creator function is implemented here 
 375 wxDialUpManager 
*wxDialUpManager::Create() 
 377     return new wxDialUpManagerMSW
; 
 381     // warning about "'this' : used in base member initializer list" - so what? 
 382     #pragma warning(disable:4355) 
 385 wxDialUpManagerMSW::wxDialUpManagerMSW() 
 386                   : m_timerStatusPolling(this), 
 387                     m_dllRas(_T("RASAPI32")) 
 389     // initialize our data 
 390     m_autoCheckLevel 
= 0; 
 392     m_data 
= new wxRasThreadData
; 
 394     if ( !m_dllRas
.IsLoaded() ) 
 396         wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it.")); 
 398     else if ( !ms_pfnRasDial 
) 
 400         // resolve the functions we need 
 402         // this will contain the name of the function we failed to resolve 
 404         const char *funcName 
= NULL
; 
 406         // get the function from rasapi32.dll and abort if it's not found 
 407         #define RESOLVE_RAS_FUNCTION(type, name)                          \ 
 408             ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name))  \ 
 410             if ( !ms_pfn##name )                                          \ 
 416         // a variant of above macro which doesn't abort if the function is 
 417         // not found in the DLL 
 418         #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name)                 \ 
 419             ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name))  \ 
 422         RESOLVE_RAS_FUNCTION(RASDIAL
, RasDial
); 
 423         RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS
, RasEnumConnections
); 
 424         RESOLVE_RAS_FUNCTION(RASENUMENTRIES
, RasEnumEntries
); 
 425         RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS
, RasGetConnectStatus
); 
 426         RESOLVE_RAS_FUNCTION(RASGETERRORSTRING
, RasGetErrorString
); 
 427         RESOLVE_RAS_FUNCTION(RASHANGUP
, RasHangUp
); 
 428         RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS
, RasGetEntryDialParams
); 
 430         // suppress error messages about missing (non essential) functions 
 434             RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO
, RasGetProjectionInfo
); 
 435             RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY
, RasCreatePhonebookEntry
); 
 436             RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY
, RasEditPhonebookEntry
); 
 437             RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS
, RasSetEntryDialParams
); 
 438             RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES
, RasGetEntryProperties
); 
 439             RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES
, RasSetEntryProperties
); 
 440             RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY
, RasRenameEntry
); 
 441             RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY
, RasDeleteEntry
); 
 442             RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME
, RasValidateEntryName
); 
 443             RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO
, RasGetCountryInfo
); 
 444             RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES
, RasEnumDevices
); 
 445             RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION
, RasConnectionNotification
); 
 448         // keep your preprocessor name space clean 
 449         #undef RESOLVE_RAS_FUNCTION 
 450         #undef RESOLVE_OPTIONAL_RAS_FUNCTION 
 455             static const wxChar 
*msg 
= wxTRANSLATE( 
 456 "The version of remote access service (RAS) installed on this machine is too\ 
 457 old, please upgrade (the following required function is missing: %s)." 
 460             wxLogError(wxGetTranslation(msg
), funcName
); 
 466     // enable auto check by default 
 467     EnableAutoCheckOnlineStatus(0); 
 470 wxDialUpManagerMSW::~wxDialUpManagerMSW() 
 475 // ---------------------------------------------------------------------------- 
 477 // ---------------------------------------------------------------------------- 
 479 wxString 
wxDialUpManagerMSW::GetErrorString(DWORD error
) 
 481     wxChar buffer
[512]; // this should be more than enough according to MS docs 
 482     DWORD dwRet 
= ms_pfnRasGetErrorString(error
, buffer
, WXSIZEOF(buffer
)); 
 485         case ERROR_INVALID_PARAMETER
: 
 486             // this was a standard Win32 error probably 
 487             return wxString(wxSysErrorMsg(error
)); 
 492                       _("Failed to retrieve text of RAS error message")); 
 495                 msg
.Printf(_("unknown error (error code %08x)."), error
); 
 500             // we want the error message to start from a lower case letter 
 501             buffer
[0] = (wxChar
)wxTolower(buffer
[0]); 
 503             return wxString(buffer
); 
 507 HRASCONN 
wxDialUpManagerMSW::FindActiveConnection() 
 509     // enumerate connections 
 510     DWORD cbBuf 
= sizeof(RASCONN
); 
 511     LPRASCONN lpRasConn 
= (LPRASCONN
)malloc(cbBuf
); 
 518     lpRasConn
->dwSize 
= sizeof(RASCONN
); 
 520     DWORD nConnections 
= 0; 
 521     DWORD dwRet 
= ERROR_BUFFER_TOO_SMALL
; 
 523     while ( dwRet 
== ERROR_BUFFER_TOO_SMALL 
) 
 525         dwRet 
= ms_pfnRasEnumConnections(lpRasConn
, &cbBuf
, &nConnections
); 
 527         if ( dwRet 
== ERROR_BUFFER_TOO_SMALL 
) 
 529             LPRASCONN lpRasConnOld 
= lpRasConn
; 
 530             lpRasConn 
= (LPRASCONN
)realloc(lpRasConn
, cbBuf
); 
 539         else if ( dwRet 
== 0 ) 
 547             wxLogError(_("Cannot find active dialup connection: %s"), 
 548                        GetErrorString(dwRet
).c_str()); 
 555     switch ( nConnections 
) 
 563             // more than 1 connection - we don't know what to do with this 
 564             // case, so give a warning but continue (taking the first 
 565             // connection) - the warning is really needed because this function 
 566             // is used, for example, to select the connection to hang up and so 
 567             // we may hang up the wrong connection here... 
 568             wxLogWarning(_("Several active dialup connections found, choosing one randomly.")); 
 572             // exactly 1 connection, great 
 573             hrasconn 
= lpRasConn
->hrasconn
; 
 581 void wxDialUpManagerMSW::CleanUpThreadData() 
 585         if ( !SetEvent(m_data
->hEventQuit
) ) 
 587             wxLogLastError(_T("SetEvent(RasThreadQuit)")); 
 589         else // sent quit request to the background thread 
 591             // the thread still needs m_data so we can't free it here, rather 
 592             // let the thread do it itself 
 596         CloseHandle(m_hThread
); 
 608 // ---------------------------------------------------------------------------- 
 610 // ---------------------------------------------------------------------------- 
 612 void wxDialUpManagerMSW::CheckRasStatus() 
 614     // use int, not bool to compare with -1 
 615     int isConnected 
= FindActiveConnection() != 0; 
 616     if ( isConnected 
!= ms_isConnected 
) 
 618         if ( ms_isConnected 
!= -1 ) 
 620             // notify the program 
 621             NotifyApp(isConnected 
!= 0); 
 623         // else: it's the first time we're called, just update the flag 
 625         ms_isConnected 
= isConnected
; 
 629 void wxDialUpManagerMSW::NotifyApp(bool connected
, bool fromOurselves
) const 
 631     wxDialUpEvent 
event(connected
, fromOurselves
); 
 632     (void)wxTheApp
->ProcessEvent(event
); 
 635 // this function is called whenever the status of any RAS connection on this 
 636 // machine changes by RAS itself 
 637 void wxDialUpManagerMSW::OnConnectStatusChange() 
 639     // we know that status changed, but we don't know whether we're connected 
 640     // or not - so find it out 
 644 // this function is called by our callback which we give to RasDial() when 
 645 // calling it asynchronously 
 646 void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate
, 
 651         // this probably means that CancelDialing() was called and we get 
 652         // "disconnected" notification 
 656     // we're only interested in 2 events: connected and disconnected 
 659         wxLogError(_("Failed to establish dialup connection: %s"), 
 660                    GetErrorString(dwError
).c_str()); 
 662         // we should still call RasHangUp() if we got a non 0 connection 
 663         if ( ms_hRasConnection 
) 
 665             ms_pfnRasHangUp(ms_hRasConnection
); 
 666             ms_hRasConnection 
= 0; 
 671         NotifyApp(false /* !connected */, true /* we dialed ourselves */); 
 673     else if ( rasconnstate 
== RASCS_Connected 
) 
 675         ms_isConnected 
= true; 
 678         NotifyApp(true /* connected */, true /* we dialed ourselves */); 
 682 // ---------------------------------------------------------------------------- 
 683 // implementation of wxDialUpManager functions 
 684 // ---------------------------------------------------------------------------- 
 686 bool wxDialUpManagerMSW::IsOk() const 
 688     return m_dllRas
.IsLoaded(); 
 691 size_t wxDialUpManagerMSW::GetISPNames(wxArrayString
& names
) const 
 694     DWORD size 
= sizeof(RASENTRYNAME
); 
 695     RASENTRYNAME 
*rasEntries 
= (RASENTRYNAME 
*)malloc(size
); 
 696     rasEntries
->dwSize 
= sizeof(RASENTRYNAME
); 
 702         dwRet 
= ms_pfnRasEnumEntries
 
 705                    NULL
,                // default phone book (or all) 
 706                    rasEntries
,          // [out] buffer for the entries 
 707                    &size
,               // [in/out] size of the buffer 
 708                    &nEntries            
// [out] number of entries fetched 
 711         if ( dwRet 
== ERROR_BUFFER_TOO_SMALL 
) 
 713             // reallocate the buffer 
 714             rasEntries 
= (RASENTRYNAME 
*)realloc(rasEntries
, size
); 
 716         else if ( dwRet 
!= 0 ) 
 718             // some other error - abort 
 719             wxLogError(_("Failed to get ISP names: %s"), 
 720                        GetErrorString(dwRet
).c_str()); 
 727     while ( dwRet 
!= 0 ); 
 731     for ( size_t n 
= 0; n 
< (size_t)nEntries
; n
++ ) 
 733         names
.Add(rasEntries
[n
].szEntryName
); 
 738     // return the number of entries 
 739     return names
.GetCount(); 
 742 bool wxDialUpManagerMSW::Dial(const wxString
& nameOfISP
, 
 743                               const wxString
& username
, 
 744                               const wxString
& password
, 
 747     // check preconditions 
 748     wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") ); 
 750     if ( ms_hRasConnection 
) 
 752         wxFAIL_MSG(wxT("there is already an active connection")); 
 757     // get the default ISP if none given 
 758     wxString 
entryName(nameOfISP
); 
 762         size_t count 
= GetISPNames(names
); 
 766                 // no known ISPs, abort 
 767                 wxLogError(_("Failed to connect: no ISP to dial.")); 
 772                 // only one ISP, choose it 
 773                 entryName 
= names
[0u]; 
 777                 // several ISPs, let the user choose 
 779                     wxString 
*strings 
= new wxString
[count
]; 
 780                     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 782                         strings
[i
] = names
[i
]; 
 785                     entryName 
= wxGetSingleChoice
 
 787                                  _("Choose ISP to dial"), 
 788                                  _("Please choose which ISP do you want to connect to"), 
 804     RASDIALPARAMS rasDialParams
; 
 805     rasDialParams
.dwSize 
= sizeof(rasDialParams
); 
 806     wxStrncpy(rasDialParams
.szEntryName
, entryName
, RAS_MaxEntryName
); 
 808     // do we have the username and password? 
 809     if ( !username 
|| !password 
) 
 812         DWORD dwRet 
= ms_pfnRasGetEntryDialParams
 
 814                        NULL
,            // default phonebook 
 815                        &rasDialParams
,  // [in/out] the params of this entry 
 816                        &gotPassword     
// [out] did we get password? 
 821             wxLogError(_("Failed to connect: missing username/password.")); 
 828         wxStrncpy(rasDialParams
.szUserName
, username
, UNLEN
); 
 829         wxStrncpy(rasDialParams
.szPassword
, password
, PWLEN
); 
 832     // default values for other fields 
 833     rasDialParams
.szPhoneNumber
[0] = '\0'; 
 834     rasDialParams
.szCallbackNumber
[0] = '\0'; 
 835     rasDialParams
.szCallbackNumber
[0] = '\0'; 
 837     rasDialParams
.szDomain
[0] = '*'; 
 838     rasDialParams
.szDomain
[1] = '\0'; 
 840     // apparently, this is not really necessary - passing NULL instead of the 
 841     // phone book has the same effect 
 844     if ( wxGetOsVersion() == wxWINDOWS_NT 
) 
 846         // first get the length 
 847         UINT nLen 
= ::GetSystemDirectory(NULL
, 0); 
 850         if ( !::GetSystemDirectory(phoneBook
.GetWriteBuf(nLen
), nLen
) ) 
 852             wxLogSysError(_("Cannot find the location of address book file")); 
 855         phoneBook
.UngetWriteBuf(); 
 857         // this is the default phone book 
 858         phoneBook 
<< "\\ras\\rasphone.pbk"; 
 862     // TODO may be we should disable auto check while async dialing is in 
 867     DWORD dwRet 
= ms_pfnRasDial
 
 869                    NULL
,                    // no extended features 
 870                    NULL
,                    // default phone book file (NT only) 
 872                    0,                       // use callback for notifications 
 873                    async 
? (void *)wxRasDialFunc  
// cast needed for gcc 3.1 
 874                          : 0,               // no notifications, sync operation 
 880         // can't pass a wxWCharBuffer through ( ... ) 
 882             wxLogError(_("Failed to initiate dialup connection: %s"), 
 883                        GetErrorString(dwRet
).c_str()); 
 885             wxLogError(_("Failed to establish dialup connection: %s"), 
 886                        GetErrorString(dwRet
).c_str()); 
 888         // we should still call RasHangUp() if we got a non 0 connection 
 889         if ( ms_hRasConnection 
) 
 891             ms_pfnRasHangUp(ms_hRasConnection
); 
 892             ms_hRasConnection 
= 0; 
 900     // for async dialing, we're not yet connected 
 903         ms_isConnected 
= true; 
 909 bool wxDialUpManagerMSW::IsDialing() const 
 911     return GetDialer() != NULL
; 
 914 bool wxDialUpManagerMSW::CancelDialing() 
 922     wxASSERT_MSG( ms_hRasConnection
, wxT("dialing but no connection?") ); 
 929 bool wxDialUpManagerMSW::HangUp() 
 931     wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") ); 
 933     // we may terminate either the connection we initiated or another one which 
 936     if ( ms_hRasConnection 
) 
 938         hRasConn 
= ms_hRasConnection
; 
 940         ms_hRasConnection 
= 0; 
 944         hRasConn 
= FindActiveConnection(); 
 949         wxLogError(_("Cannot hang up - no active dialup connection.")); 
 954     // note that it's not an error if the connection had been already 
 956     const DWORD dwRet 
= ms_pfnRasHangUp(hRasConn
); 
 957     if ( dwRet 
!= 0 && dwRet 
!= ERROR_NO_CONNECTION 
) 
 959         wxLogError(_("Failed to terminate the dialup connection: %s"), 
 960                    GetErrorString(dwRet
).c_str()); 
 963     ms_isConnected 
= false; 
 968 bool wxDialUpManagerMSW::IsAlwaysOnline() const 
 970     // assume no permanent connection by default 
 971     bool isAlwaysOnline 
= false; 
 973     // try to use WinInet functions 
 975     // NB: we could probably use wxDynamicLibrary here just as well, 
 976     //     but we allow multiple instances of wxDialUpManagerMSW so 
 977     //     we might as well use the ref counted version here too. 
 979     wxDynamicLibrary 
hDll(_T("WININET")); 
 980     if ( hDll
.IsLoaded() ) 
 982         typedef BOOL (WINAPI 
*INTERNETGETCONNECTEDSTATE
)(LPDWORD
, DWORD
); 
 983         INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState
; 
 985         #define RESOLVE_FUNCTION(type, name) \ 
 986             pfn##name = (type)hDll.GetSymbol(_T(#name)) 
 988         RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE
, InternetGetConnectedState
); 
 990         if ( pfnInternetGetConnectedState 
) 
 993             if ( pfnInternetGetConnectedState(&flags
, 0 /* reserved */) ) 
 995                 // there is some connection to the net, see of which type 
 996                 isAlwaysOnline 
= (flags 
& (INTERNET_CONNECTION_LAN 
| 
 997                                            INTERNET_CONNECTION_PROXY
)) != 0; 
 999             //else: no Internet connection at all 
1003     return isAlwaysOnline
; 
1006 bool wxDialUpManagerMSW::IsOnline() const 
1008     wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") ); 
1010     if ( IsAlwaysOnline() ) 
1016     if ( ms_userSpecifiedOnlineStatus 
!= -1 ) 
1018         // user specified flag overrides our logic 
1019         return ms_userSpecifiedOnlineStatus 
!= 0; 
1023         // return true if there is at least one active connection 
1024         return FindActiveConnection() != 0; 
1028 void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline
) 
1030     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1032     ms_userSpecifiedOnlineStatus 
= isOnline
; 
1035 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds
) 
1037     wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") ); 
1039     if ( m_autoCheckLevel
++ ) 
1045     bool ok 
= ms_pfnRasConnectionNotification 
!= 0; 
1049         // we're running under NT 4.0, Windows 98 or later and can use 
1050         // RasConnectionNotification() to be notified by a secondary thread 
1052         // first, see if we don't have this thread already running 
1053         if ( m_hThread 
!= 0 ) 
1055             if ( ::ResumeThread(m_hThread
) != (DWORD
)-1 ) 
1058             // we're leaving a zombie thread... but what else can we do? 
1059             wxLogLastError(wxT("ResumeThread(RasThread)")); 
1065     // create all the stuff we need to be notified about RAS connection 
1070         // first create an event to wait on 
1071         m_data
->hEventRas 
= ::CreateEvent
 
1073                              NULL
,      // security attribute (default) 
1074                              FALSE
,     // manual reset (no, it is automatic) 
1075                              FALSE
,     // initial state (not signaled) 
1078         if ( !m_data
->hEventRas 
) 
1080             wxLogLastError(wxT("CreateEvent(RasStatus)")); 
1088         // create the event we use to quit the thread: using a manual event 
1089         // here avoids problems with missing the event if wxDialUpManagerMSW 
1090         // is created and destroyed immediately, before wxRasStatusWindowProc 
1091         // starts waiting on the event 
1092         m_data
->hEventQuit 
= ::CreateEvent
 
1094                                 NULL
,   // default security 
1095                                 TRUE
,   // manual event 
1096                                 FALSE
,  // initially non signalled 
1099         if ( !m_data
->hEventQuit 
) 
1101             wxLogLastError(wxT("CreateEvent(RasThreadQuit)")); 
1103             CleanUpThreadData(); 
1109     if ( ok 
&& !ms_hwndRas 
) 
1111         // create a hidden window to receive notification about connections 
1113         ms_hwndRas 
= wxCreateHiddenWindow
 
1115                         &gs_classForDialUpWindow
, 
1116                         wxMSWDIALUP_WNDCLASSNAME
, 
1117                         wxRasStatusWindowProc
 
1121             wxLogLastError(wxT("CreateWindow(RasHiddenWindow)")); 
1123             CleanUpThreadData(); 
1129     m_data
->hWnd 
= ms_hwndRas
; 
1133         // start the secondary thread 
1134         m_data
->dialUpManager 
= this; 
1137         m_hThread 
= CreateThread
 
1141                      (LPTHREAD_START_ROUTINE
)wxRasMonitorThread
, 
1149             wxLogLastError(wxT("CreateThread(RasStatusThread)")); 
1151             CleanUpThreadData(); 
1157         // start receiving RAS notifications 
1158         DWORD dwRet 
= ms_pfnRasConnectionNotification
 
1160                         (HRASCONN
)INVALID_HANDLE_VALUE
, 
1162                         3 /* RASCN_Connection | RASCN_Disconnection */ 
1167             wxLogDebug(wxT("RasConnectionNotification() failed: %s"), 
1168                        GetErrorString(dwRet
).c_str()); 
1170             CleanUpThreadData(); 
1178     // we're running under Windows 95 and have to poll ourselves 
1179     // (or, alternatively, the code above for NT/98 failed) 
1180     m_timerStatusPolling
.Stop(); 
1181     if ( nSeconds 
== 0 ) 
1186     m_timerStatusPolling
.Start(nSeconds 
* 1000); 
1191 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus() 
1193     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1195     if ( --m_autoCheckLevel 
!= 0 ) 
1203         // we have running secondary thread, it's just enough to suspend it 
1204         if ( SuspendThread(m_hThread
) == (DWORD
)-1 ) 
1206             wxLogLastError(wxT("SuspendThread(RasThread)")); 
1211         // even simpler - just stop the timer 
1212         m_timerStatusPolling
.Stop(); 
1216 // ---------------------------------------------------------------------------- 
1217 // stubs which don't do anything in MSW version 
1218 // ---------------------------------------------------------------------------- 
1220 void wxDialUpManagerMSW::SetWellKnownHost(const wxString
& WXUNUSED(hostname
), 
1223     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1225     // nothing to do - we don't use this 
1228 void wxDialUpManagerMSW::SetConnectCommand(const wxString
& WXUNUSED(dial
), 
1229                                            const wxString
& WXUNUSED(hangup
)) 
1231     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1233     // nothing to do - we don't use this 
1236 // ---------------------------------------------------------------------------- 
1238 // ---------------------------------------------------------------------------- 
1240 static DWORD 
wxRasMonitorThread(wxRasThreadData 
*data
) 
1243     handles
[0] = data
->hEventRas
; 
1244     handles
[1] = data
->hEventQuit
; 
1249         DWORD dwRet 
= ::WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
); 
1254                 // RAS connection status changed 
1255                 SendMessage(data
->hWnd
, wxWM_RAS_STATUS_CHANGED
, 
1259             case WAIT_OBJECT_0 
+ 1: 
1264                 wxFAIL_MSG( _T("unexpected return of WaitForMultipleObjects()") ); 
1269                 // using wxLogLastError() from here is dangerous: we risk to 
1270                 // deadlock the main thread if wxLog sends output to GUI 
1271                 DWORD err 
= GetLastError(); 
1272                 wxMessageOutputDebug dbg
; 
1275                     wxT("WaitForMultipleObjects(RasMonitor) failed: 0x%08lx (%s)"), 
1279 #endif // __WXDEBUG__ 
1281                 // no sense in continuing, who knows if the handles we're 
1282                 // waiting for even exist yet... 
1287     // we don't need it any more now and if this thread ran, it is our 
1288     // responsability to free the data 
1294 static LRESULT APIENTRY 
wxRasStatusWindowProc(HWND hWnd
, UINT message
, 
1295                                               WPARAM wParam
, LPARAM lParam
) 
1299         case wxWM_RAS_STATUS_CHANGED
: 
1301                 wxRasThreadData 
*data 
= (wxRasThreadData 
*)lParam
; 
1302                 data
->dialUpManager
->OnConnectStatusChange(); 
1306         case wxWM_RAS_DIALING_PROGRESS
: 
1308                 wxDialUpManagerMSW 
*dialMan 
= wxDialUpManagerMSW::GetDialer(); 
1310                 dialMan
->OnDialProgress((RASCONNSTATE
)wParam
, lParam
); 
1315             return ::DefWindowProc(hWnd
, message
, wParam
, lParam
); 
1321 static void WINAPI 
wxRasDialFunc(UINT 
WXUNUSED(unMsg
), 
1322                                  RASCONNSTATE rasconnstate
, 
1325     wxDialUpManagerMSW 
*dialUpManager 
= wxDialUpManagerMSW::GetDialer(); 
1327     wxCHECK_RET( dialUpManager
, wxT("who started to dial then?") ); 
1329     SendMessage(wxDialUpManagerMSW::GetRasWindow(), wxWM_RAS_DIALING_PROGRESS
, 
1330                 rasconnstate
, dwError
); 
1333 #endif // __BORLANDC__ 
1335 #endif // wxUSE_DIALUP_MANAGER