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" 
  41 #include "wx/module.h" 
  43 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED
) 
  44 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED
) 
  46 // Doesn't yet compile under VC++ 4, BC++, Watcom C++, 
  48 #if (!defined(__BORLANDC__) || (__BORLANDC__>=0x550)) && \ 
  49     (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \ 
  50     !defined(__GNUWIN32_OLD__) && \ 
  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 // implemented in utils.cpp 
  68 extern "C" WXDLLIMPEXP_BASE HWND
 
  69 wxCreateHiddenWindow(LPCTSTR 
*pclassname
, LPCTSTR classname
, WNDPROC wndproc
); 
  72     wxMSWDIALUP_WNDCLASSNAME 
= wxT("_wxDialUpManager_Internal_Class"); 
  73 static const wxChar 
*gs_classForDialUpWindow 
= NULL
; 
  75 // ---------------------------------------------------------------------------- 
  77 // ---------------------------------------------------------------------------- 
  79 // this message is sent by the secondary thread when RAS status changes 
  80 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010) 
  81 #define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011) 
  83 // ---------------------------------------------------------------------------- 
  85 // ---------------------------------------------------------------------------- 
  87 // the signatures of RAS functions: all this is quite heavy, but we must do it 
  88 // to allow running wxWin programs on machine which don't have RAS installed 
  89 // (this does exist) - if we link with rasapi32.lib, the program will fail on 
  90 // startup because of the missing DLL... 
  93     typedef DWORD (APIENTRY 
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCSTR
, LPRASDIALPARAMSA
, DWORD
, LPVOID
, LPHRASCONN 
); 
  94     typedef DWORD (APIENTRY 
* RASENUMCONNECTIONS
)( LPRASCONNA
, LPDWORD
, LPDWORD 
); 
  95     typedef DWORD (APIENTRY 
* RASENUMENTRIES
)( LPCSTR
, LPCSTR
, LPRASENTRYNAMEA
, LPDWORD
, LPDWORD 
); 
  96     typedef DWORD (APIENTRY 
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSA 
); 
  97     typedef DWORD (APIENTRY 
* RASGETERRORSTRING
)( UINT
, LPSTR
, DWORD 
); 
  98     typedef DWORD (APIENTRY 
* RASHANGUP
)( HRASCONN 
); 
  99     typedef DWORD (APIENTRY 
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD 
); 
 100     typedef DWORD (APIENTRY 
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCSTR 
); 
 101     typedef DWORD (APIENTRY 
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCSTR
, LPCSTR 
); 
 102     typedef DWORD (APIENTRY 
* RASSETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, BOOL 
); 
 103     typedef DWORD (APIENTRY 
* RASGETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, LPBOOL 
); 
 104     typedef DWORD (APIENTRY 
* RASENUMDEVICES
)( LPRASDEVINFOA
, LPDWORD
, LPDWORD 
); 
 105     typedef DWORD (APIENTRY 
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOA
, LPDWORD 
); 
 106     typedef DWORD (APIENTRY 
* RASGETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, LPDWORD
, LPBYTE
, LPDWORD 
); 
 107     typedef DWORD (APIENTRY 
* RASSETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, DWORD
, LPBYTE
, DWORD 
); 
 108     typedef DWORD (APIENTRY 
* RASRENAMEENTRY
)( LPCSTR
, LPCSTR
, LPCSTR 
); 
 109     typedef DWORD (APIENTRY 
* RASDELETEENTRY
)( LPCSTR
, LPCSTR 
); 
 110     typedef DWORD (APIENTRY 
* RASVALIDATEENTRYNAME
)( LPCSTR
, LPCSTR 
); 
 111     typedef DWORD (APIENTRY 
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD 
); 
 113     static const wxChar gs_funcSuffix 
= _T('A'); 
 115     typedef DWORD (APIENTRY 
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCWSTR
, LPRASDIALPARAMSW
, DWORD
, LPVOID
, LPHRASCONN 
); 
 116     typedef DWORD (APIENTRY 
* RASENUMCONNECTIONS
)( LPRASCONNW
, LPDWORD
, LPDWORD 
); 
 117     typedef DWORD (APIENTRY 
* RASENUMENTRIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYNAMEW
, LPDWORD
, LPDWORD 
); 
 118     typedef DWORD (APIENTRY 
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSW 
); 
 119     typedef DWORD (APIENTRY 
* RASGETERRORSTRING
)( UINT
, LPWSTR
, DWORD 
); 
 120     typedef DWORD (APIENTRY 
* RASHANGUP
)( HRASCONN 
); 
 121     typedef DWORD (APIENTRY 
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD 
); 
 122     typedef DWORD (APIENTRY 
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCWSTR 
); 
 123     typedef DWORD (APIENTRY 
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCWSTR
, LPCWSTR 
); 
 124     typedef DWORD (APIENTRY 
* RASSETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, BOOL 
); 
 125     typedef DWORD (APIENTRY 
* RASGETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, LPBOOL 
); 
 126     typedef DWORD (APIENTRY 
* RASENUMDEVICES
)( LPRASDEVINFOW
, LPDWORD
, LPDWORD 
); 
 127     typedef DWORD (APIENTRY 
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOW
, LPDWORD 
); 
 128     typedef DWORD (APIENTRY 
* RASGETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, LPDWORD
, LPBYTE
, LPDWORD 
); 
 129     typedef DWORD (APIENTRY 
* RASSETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, DWORD
, LPBYTE
, DWORD 
); 
 130     typedef DWORD (APIENTRY 
* RASRENAMEENTRY
)( LPCWSTR
, LPCWSTR
, LPCWSTR 
); 
 131     typedef DWORD (APIENTRY 
* RASDELETEENTRY
)( LPCWSTR
, LPCWSTR 
); 
 132     typedef DWORD (APIENTRY 
* RASVALIDATEENTRYNAME
)( LPCWSTR
, LPCWSTR 
); 
 133     typedef DWORD (APIENTRY 
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD 
); 
 135     static const wxChar gs_funcSuffix 
= _T('W'); 
 136 #endif // ASCII/Unicode 
 138 // structure passed to the secondary thread 
 139 struct WXDLLEXPORT wxRasThreadData
 
 146         dialUpManager 
= NULL
; 
 155             CloseHandle(hEventQuit
); 
 158             CloseHandle(hEventRas
); 
 161     HWND    hWnd
;       // window to send notifications to 
 162     HANDLE  hEventRas
,  // automatic event which RAS signals when status changes 
 163             hEventQuit
; // manual event which we signal when we terminate 
 165     class WXDLLEXPORT wxDialUpManagerMSW 
*dialUpManager
;  // the owner 
 168 // ---------------------------------------------------------------------------- 
 169 // wxDialUpManager class for MSW 
 170 // ---------------------------------------------------------------------------- 
 172 class WXDLLEXPORT wxDialUpManagerMSW 
: public wxDialUpManager
 
 176     wxDialUpManagerMSW(); 
 177     virtual ~wxDialUpManagerMSW(); 
 179     // implement base class pure virtuals 
 180     virtual bool IsOk() const; 
 181     virtual size_t GetISPNames(wxArrayString
& names
) const; 
 182     virtual bool Dial(const wxString
& nameOfISP
, 
 183                       const wxString
& username
, 
 184                       const wxString
& password
, 
 186     virtual bool IsDialing() const; 
 187     virtual bool CancelDialing(); 
 188     virtual bool HangUp(); 
 189     virtual bool IsAlwaysOnline() const; 
 190     virtual bool IsOnline() const; 
 191     virtual void SetOnlineStatus(bool isOnline 
= true); 
 192     virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
); 
 193     virtual void DisableAutoCheckOnlineStatus(); 
 194     virtual void SetWellKnownHost(const wxString
& hostname
, int port
); 
 195     virtual void SetConnectCommand(const wxString
& commandDial
, 
 196                                    const wxString
& commandHangup
); 
 199     void CheckRasStatus(); 
 201     // for wxRasStatusWindowProc 
 202     void OnConnectStatusChange(); 
 203     void OnDialProgress(RASCONNSTATE rasconnstate
, DWORD dwError
); 
 206     static HWND 
GetRasWindow() { return ms_hwndRas
; } 
 207     static void ResetRasWindow() { ms_hwndRas 
= NULL
; } 
 208     static wxDialUpManagerMSW 
*GetDialer() { return ms_dialer
; } 
 211     // return the error string for the given RAS error code 
 212     static wxString 
GetErrorString(DWORD error
); 
 214     // find the (first) handle of the active connection 
 215     static HRASCONN 
FindActiveConnection(); 
 217     // notify the application about status change 
 218     void NotifyApp(bool connected
, bool fromOurselves 
= false) const; 
 220     // destroy the thread data and the thread itself 
 221     void CleanUpThreadData(); 
 223     // number of times EnableAutoCheckOnlineStatus() had been called minus the 
 224     // number of times DisableAutoCheckOnlineStatus() had been called 
 225     int m_autoCheckLevel
; 
 227     // timer used for polling RAS status 
 228     class WXDLLEXPORT RasTimer 
: public wxTimer
 
 231         RasTimer(wxDialUpManagerMSW 
*dialUpManager
) 
 232             { m_dialUpManager 
= dialUpManager
; } 
 234         virtual void Notify() { m_dialUpManager
->CheckRasStatus(); } 
 237         wxDialUpManagerMSW 
*m_dialUpManager
; 
 239         DECLARE_NO_COPY_CLASS(RasTimer
) 
 240     } m_timerStatusPolling
; 
 242     // thread handle for the thread sitting on connection change event 
 245     // data used by this thread and our hidden window to send messages between 
 247     wxRasThreadData 
*m_data
; 
 249     // the handle of rasapi32.dll when it's loaded 
 250     wxDynamicLibrary m_dllRas
; 
 252     // the hidden window we use for passing messages between threads 
 253     static HWND ms_hwndRas
; 
 255     // the handle of the connection we initiated or 0 if none 
 256     static HRASCONN ms_hRasConnection
; 
 258     // the pointers to RAS functions 
 259     static RASDIAL ms_pfnRasDial
; 
 260     static RASENUMCONNECTIONS ms_pfnRasEnumConnections
; 
 261     static RASENUMENTRIES ms_pfnRasEnumEntries
; 
 262     static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus
; 
 263     static RASGETERRORSTRING ms_pfnRasGetErrorString
; 
 264     static RASHANGUP ms_pfnRasHangUp
; 
 265     static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo
; 
 266     static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry
; 
 267     static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry
; 
 268     static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams
; 
 269     static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams
; 
 270     static RASENUMDEVICES ms_pfnRasEnumDevices
; 
 271     static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo
; 
 272     static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties
; 
 273     static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties
; 
 274     static RASRENAMEENTRY ms_pfnRasRenameEntry
; 
 275     static RASDELETEENTRY ms_pfnRasDeleteEntry
; 
 276     static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName
; 
 278     // this function is not supported by Win95 
 279     static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification
; 
 281     // if this flag is different from -1, it overrides IsOnline() 
 282     static int ms_userSpecifiedOnlineStatus
; 
 284     // this flag tells us if we're online 
 285     static int ms_isConnected
; 
 287     // this flag tells us whether a call to RasDial() is in progress 
 288     static wxDialUpManagerMSW 
*ms_dialer
; 
 290     DECLARE_NO_COPY_CLASS(wxDialUpManagerMSW
) 
 293 // module to destroy helper window created by wxDialUpManagerMSW 
 294 class wxDialUpManagerModule 
: public wxModule
 
 297     bool OnInit() { return true; } 
 300         HWND hwnd 
= wxDialUpManagerMSW::GetRasWindow(); 
 303             ::DestroyWindow(hwnd
); 
 304             wxDialUpManagerMSW::ResetRasWindow(); 
 307         if ( gs_classForDialUpWindow 
) 
 309             ::UnregisterClass(wxMSWDIALUP_WNDCLASSNAME
, wxGetInstance()); 
 310             gs_classForDialUpWindow 
= NULL
; 
 315     DECLARE_DYNAMIC_CLASS(wxDialUpManagerModule
) 
 318 IMPLEMENT_DYNAMIC_CLASS(wxDialUpManagerModule
, wxModule
) 
 320 // ---------------------------------------------------------------------------- 
 322 // ---------------------------------------------------------------------------- 
 324 static LRESULT WINAPI 
wxRasStatusWindowProc(HWND hWnd
, UINT message
, 
 325                                             WPARAM wParam
, LPARAM lParam
); 
 327 static DWORD 
wxRasMonitorThread(wxRasThreadData 
*data
); 
 329 static void WINAPI 
wxRasDialFunc(UINT unMsg
, 
 330                                  RASCONNSTATE rasconnstate
, 
 333 // ============================================================================ 
 335 // ============================================================================ 
 337 // ---------------------------------------------------------------------------- 
 338 // init the static variables 
 339 // ---------------------------------------------------------------------------- 
 341 HRASCONN 
wxDialUpManagerMSW::ms_hRasConnection 
= 0; 
 343 HWND 
wxDialUpManagerMSW::ms_hwndRas 
= 0; 
 345 RASDIAL 
wxDialUpManagerMSW::ms_pfnRasDial 
= 0; 
 346 RASENUMCONNECTIONS 
wxDialUpManagerMSW::ms_pfnRasEnumConnections 
= 0; 
 347 RASENUMENTRIES 
wxDialUpManagerMSW::ms_pfnRasEnumEntries 
= 0; 
 348 RASGETCONNECTSTATUS 
wxDialUpManagerMSW::ms_pfnRasGetConnectStatus 
= 0; 
 349 RASGETERRORSTRING 
wxDialUpManagerMSW::ms_pfnRasGetErrorString 
= 0; 
 350 RASHANGUP 
wxDialUpManagerMSW::ms_pfnRasHangUp 
= 0; 
 351 RASGETPROJECTIONINFO 
wxDialUpManagerMSW::ms_pfnRasGetProjectionInfo 
= 0; 
 352 RASCREATEPHONEBOOKENTRY 
wxDialUpManagerMSW::ms_pfnRasCreatePhonebookEntry 
= 0; 
 353 RASEDITPHONEBOOKENTRY 
wxDialUpManagerMSW::ms_pfnRasEditPhonebookEntry 
= 0; 
 354 RASSETENTRYDIALPARAMS 
wxDialUpManagerMSW::ms_pfnRasSetEntryDialParams 
= 0; 
 355 RASGETENTRYDIALPARAMS 
wxDialUpManagerMSW::ms_pfnRasGetEntryDialParams 
= 0; 
 356 RASENUMDEVICES 
wxDialUpManagerMSW::ms_pfnRasEnumDevices 
= 0; 
 357 RASGETCOUNTRYINFO 
wxDialUpManagerMSW::ms_pfnRasGetCountryInfo 
= 0; 
 358 RASGETENTRYPROPERTIES 
wxDialUpManagerMSW::ms_pfnRasGetEntryProperties 
= 0; 
 359 RASSETENTRYPROPERTIES 
wxDialUpManagerMSW::ms_pfnRasSetEntryProperties 
= 0; 
 360 RASRENAMEENTRY 
wxDialUpManagerMSW::ms_pfnRasRenameEntry 
= 0; 
 361 RASDELETEENTRY 
wxDialUpManagerMSW::ms_pfnRasDeleteEntry 
= 0; 
 362 RASVALIDATEENTRYNAME 
wxDialUpManagerMSW::ms_pfnRasValidateEntryName 
= 0; 
 363 RASCONNECTIONNOTIFICATION 
wxDialUpManagerMSW::ms_pfnRasConnectionNotification 
= 0; 
 365 int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus 
= -1; 
 366 int wxDialUpManagerMSW::ms_isConnected 
= -1; 
 367 wxDialUpManagerMSW 
*wxDialUpManagerMSW::ms_dialer 
= NULL
; 
 369 // ---------------------------------------------------------------------------- 
 370 // ctor and dtor: the dynamic linking happens here 
 371 // ---------------------------------------------------------------------------- 
 373 // the static creator function is implemented here 
 374 wxDialUpManager 
*wxDialUpManager::Create() 
 376     return new wxDialUpManagerMSW
; 
 380     // warning about "'this' : used in base member initializer list" - so what? 
 381     #pragma warning(disable:4355) 
 384 wxDialUpManagerMSW::wxDialUpManagerMSW() 
 385                   : m_timerStatusPolling(this), 
 386                     m_dllRas(_T("RASAPI32")) 
 388     // initialize our data 
 389     m_autoCheckLevel 
= 0; 
 391     m_data 
= new wxRasThreadData
; 
 393     if ( !m_dllRas
.IsLoaded() ) 
 395         wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it.")); 
 397     else if ( !ms_pfnRasDial 
) 
 399         // resolve the functions we need 
 401         // this will contain the name of the function we failed to resolve 
 403         const char *funcName 
= NULL
; 
 405         // get the function from rasapi32.dll and abort if it's not found 
 406         #define RESOLVE_RAS_FUNCTION(type, name)                          \ 
 407             ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name))  \ 
 409             if ( !ms_pfn##name )                                          \ 
 415         // a variant of above macro which doesn't abort if the function is 
 416         // not found in the DLL 
 417         #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name)                 \ 
 418             ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name))  \ 
 421         RESOLVE_RAS_FUNCTION(RASDIAL
, RasDial
); 
 422         RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS
, RasEnumConnections
); 
 423         RESOLVE_RAS_FUNCTION(RASENUMENTRIES
, RasEnumEntries
); 
 424         RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS
, RasGetConnectStatus
); 
 425         RESOLVE_RAS_FUNCTION(RASGETERRORSTRING
, RasGetErrorString
); 
 426         RESOLVE_RAS_FUNCTION(RASHANGUP
, RasHangUp
); 
 427         RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS
, RasGetEntryDialParams
); 
 429         // suppress error messages about missing (non essential) functions 
 433             RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO
, RasGetProjectionInfo
); 
 434             RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY
, RasCreatePhonebookEntry
); 
 435             RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY
, RasEditPhonebookEntry
); 
 436             RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS
, RasSetEntryDialParams
); 
 437             RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES
, RasGetEntryProperties
); 
 438             RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES
, RasSetEntryProperties
); 
 439             RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY
, RasRenameEntry
); 
 440             RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY
, RasDeleteEntry
); 
 441             RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME
, RasValidateEntryName
); 
 442             RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO
, RasGetCountryInfo
); 
 443             RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES
, RasEnumDevices
); 
 444             RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION
, RasConnectionNotification
); 
 447         // keep your preprocessor name space clean 
 448         #undef RESOLVE_RAS_FUNCTION 
 449         #undef RESOLVE_OPTIONAL_RAS_FUNCTION 
 454             static const wxChar 
*msg 
= wxTRANSLATE( 
 455 "The version of remote access service (RAS) installed on this machine is too\ 
 456 old, please upgrade (the following required function is missing: %s)." 
 459             wxLogError(wxGetTranslation(msg
), funcName
); 
 465     // enable auto check by default 
 466     EnableAutoCheckOnlineStatus(0); 
 469 wxDialUpManagerMSW::~wxDialUpManagerMSW() 
 474 // ---------------------------------------------------------------------------- 
 476 // ---------------------------------------------------------------------------- 
 478 wxString 
wxDialUpManagerMSW::GetErrorString(DWORD error
) 
 480     wxChar buffer
[512]; // this should be more than enough according to MS docs 
 481     DWORD dwRet 
= ms_pfnRasGetErrorString(error
, buffer
, WXSIZEOF(buffer
)); 
 484         case ERROR_INVALID_PARAMETER
: 
 485             // this was a standard Win32 error probably 
 486             return wxString(wxSysErrorMsg(error
)); 
 491                       _("Failed to retrieve text of RAS error message")); 
 494                 msg
.Printf(_("unknown error (error code %08x)."), error
); 
 499             // we want the error message to start from a lower case letter 
 500             buffer
[0] = (wxChar
)wxTolower(buffer
[0]); 
 502             return wxString(buffer
); 
 506 HRASCONN 
wxDialUpManagerMSW::FindActiveConnection() 
 508     // enumerate connections 
 509     DWORD cbBuf 
= sizeof(RASCONN
); 
 510     LPRASCONN lpRasConn 
= (LPRASCONN
)malloc(cbBuf
); 
 517     lpRasConn
->dwSize 
= sizeof(RASCONN
); 
 519     DWORD nConnections 
= 0; 
 520     DWORD dwRet 
= ERROR_BUFFER_TOO_SMALL
; 
 522     while ( dwRet 
== ERROR_BUFFER_TOO_SMALL 
) 
 524         dwRet 
= ms_pfnRasEnumConnections(lpRasConn
, &cbBuf
, &nConnections
); 
 526         if ( dwRet 
== ERROR_BUFFER_TOO_SMALL 
) 
 528             LPRASCONN lpRasConnOld 
= lpRasConn
; 
 529             lpRasConn 
= (LPRASCONN
)realloc(lpRasConn
, cbBuf
); 
 538         else if ( dwRet 
== 0 ) 
 546             wxLogError(_("Cannot find active dialup connection: %s"), 
 547                        GetErrorString(dwRet
).c_str()); 
 554     switch ( nConnections 
) 
 562             // more than 1 connection - we don't know what to do with this 
 563             // case, so give a warning but continue (taking the first 
 564             // connection) - the warning is really needed because this function 
 565             // is used, for example, to select the connection to hang up and so 
 566             // we may hang up the wrong connection here... 
 567             wxLogWarning(_("Several active dialup connections found, choosing one randomly.")); 
 571             // exactly 1 connection, great 
 572             hrasconn 
= lpRasConn
->hrasconn
; 
 580 void wxDialUpManagerMSW::CleanUpThreadData() 
 584         if ( !SetEvent(m_data
->hEventQuit
) ) 
 586             wxLogLastError(_T("SetEvent(RasThreadQuit)")); 
 588         else // sent quit request to the background thread 
 590             // the thread still needs m_data so we can't free it here, rather 
 591             // let the thread do it itself 
 595         CloseHandle(m_hThread
); 
 607 // ---------------------------------------------------------------------------- 
 609 // ---------------------------------------------------------------------------- 
 611 void wxDialUpManagerMSW::CheckRasStatus() 
 613     // use int, not bool to compare with -1 
 614     int isConnected 
= FindActiveConnection() != 0; 
 615     if ( isConnected 
!= ms_isConnected 
) 
 617         if ( ms_isConnected 
!= -1 ) 
 619             // notify the program 
 620             NotifyApp(isConnected 
!= 0); 
 622         // else: it's the first time we're called, just update the flag 
 624         ms_isConnected 
= isConnected
; 
 628 void wxDialUpManagerMSW::NotifyApp(bool connected
, bool fromOurselves
) const 
 630     wxDialUpEvent 
event(connected
, fromOurselves
); 
 631     (void)wxTheApp
->ProcessEvent(event
); 
 634 // this function is called whenever the status of any RAS connection on this 
 635 // machine changes by RAS itself 
 636 void wxDialUpManagerMSW::OnConnectStatusChange() 
 638     // we know that status changed, but we don't know whether we're connected 
 639     // or not - so find it out 
 643 // this function is called by our callback which we give to RasDial() when 
 644 // calling it asynchronously 
 645 void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate
, 
 650         // this probably means that CancelDialing() was called and we get 
 651         // "disconnected" notification 
 655     // we're only interested in 2 events: connected and disconnected 
 658         wxLogError(_("Failed to establish dialup connection: %s"), 
 659                    GetErrorString(dwError
).c_str()); 
 661         // we should still call RasHangUp() if we got a non 0 connection 
 662         if ( ms_hRasConnection 
) 
 664             ms_pfnRasHangUp(ms_hRasConnection
); 
 665             ms_hRasConnection 
= 0; 
 670         NotifyApp(false /* !connected */, true /* we dialed ourselves */); 
 672     else if ( rasconnstate 
== RASCS_Connected 
) 
 674         ms_isConnected 
= true; 
 677         NotifyApp(true /* connected */, true /* we dialed ourselves */); 
 681 // ---------------------------------------------------------------------------- 
 682 // implementation of wxDialUpManager functions 
 683 // ---------------------------------------------------------------------------- 
 685 bool wxDialUpManagerMSW::IsOk() const 
 687     return m_dllRas
.IsLoaded(); 
 690 size_t wxDialUpManagerMSW::GetISPNames(wxArrayString
& names
) const 
 693     DWORD size 
= sizeof(RASENTRYNAME
); 
 694     RASENTRYNAME 
*rasEntries 
= (RASENTRYNAME 
*)malloc(size
); 
 695     rasEntries
->dwSize 
= sizeof(RASENTRYNAME
); 
 701         dwRet 
= ms_pfnRasEnumEntries
 
 704                    NULL
,                // default phone book (or all) 
 705                    rasEntries
,          // [out] buffer for the entries 
 706                    &size
,               // [in/out] size of the buffer 
 707                    &nEntries            
// [out] number of entries fetched 
 710         if ( dwRet 
== ERROR_BUFFER_TOO_SMALL 
) 
 712             // reallocate the buffer 
 713             rasEntries 
= (RASENTRYNAME 
*)realloc(rasEntries
, size
); 
 715         else if ( dwRet 
!= 0 ) 
 717             // some other error - abort 
 718             wxLogError(_("Failed to get ISP names: %s"), 
 719                        GetErrorString(dwRet
).c_str()); 
 726     while ( dwRet 
!= 0 ); 
 730     for ( size_t n 
= 0; n 
< (size_t)nEntries
; n
++ ) 
 732         names
.Add(rasEntries
[n
].szEntryName
); 
 737     // return the number of entries 
 738     return names
.GetCount(); 
 741 bool wxDialUpManagerMSW::Dial(const wxString
& nameOfISP
, 
 742                               const wxString
& username
, 
 743                               const wxString
& password
, 
 746     // check preconditions 
 747     wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") ); 
 749     if ( ms_hRasConnection 
) 
 751         wxFAIL_MSG(wxT("there is already an active connection")); 
 756     // get the default ISP if none given 
 757     wxString 
entryName(nameOfISP
); 
 761         size_t count 
= GetISPNames(names
); 
 765                 // no known ISPs, abort 
 766                 wxLogError(_("Failed to connect: no ISP to dial.")); 
 771                 // only one ISP, choose it 
 772                 entryName 
= names
[0u]; 
 776                 // several ISPs, let the user choose 
 778                     wxString 
*strings 
= new wxString
[count
]; 
 779                     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 781                         strings
[i
] = names
[i
]; 
 784                     entryName 
= wxGetSingleChoice
 
 786                                  _("Choose ISP to dial"), 
 787                                  _("Please choose which ISP do you want to connect to"), 
 803     RASDIALPARAMS rasDialParams
; 
 804     rasDialParams
.dwSize 
= sizeof(rasDialParams
); 
 805     wxStrncpy(rasDialParams
.szEntryName
, entryName
, RAS_MaxEntryName
); 
 807     // do we have the username and password? 
 808     if ( !username 
|| !password 
) 
 811         DWORD dwRet 
= ms_pfnRasGetEntryDialParams
 
 813                        NULL
,            // default phonebook 
 814                        &rasDialParams
,  // [in/out] the params of this entry 
 815                        &gotPassword     
// [out] did we get password? 
 820             wxLogError(_("Failed to connect: missing username/password.")); 
 827         wxStrncpy(rasDialParams
.szUserName
, username
, UNLEN
); 
 828         wxStrncpy(rasDialParams
.szPassword
, password
, PWLEN
); 
 831     // default values for other fields 
 832     rasDialParams
.szPhoneNumber
[0] = '\0'; 
 833     rasDialParams
.szCallbackNumber
[0] = '\0'; 
 834     rasDialParams
.szCallbackNumber
[0] = '\0'; 
 836     rasDialParams
.szDomain
[0] = '*'; 
 837     rasDialParams
.szDomain
[1] = '\0'; 
 839     // apparently, this is not really necessary - passing NULL instead of the 
 840     // phone book has the same effect 
 843     if ( wxGetOsVersion() == wxWINDOWS_NT 
) 
 845         // first get the length 
 846         UINT nLen 
= ::GetSystemDirectory(NULL
, 0); 
 849         if ( !::GetSystemDirectory(phoneBook
.GetWriteBuf(nLen
), nLen
) ) 
 851             wxLogSysError(_("Cannot find the location of address book file")); 
 854         phoneBook
.UngetWriteBuf(); 
 856         // this is the default phone book 
 857         phoneBook 
<< "\\ras\\rasphone.pbk"; 
 861     // TODO may be we should disable auto check while async dialing is in 
 866     DWORD dwRet 
= ms_pfnRasDial
 
 868                    NULL
,                    // no extended features 
 869                    NULL
,                    // default phone book file (NT only) 
 871                    0,                       // use callback for notifications 
 872                    async 
? (void *)wxRasDialFunc  
// cast needed for gcc 3.1 
 873                          : 0,               // no notifications, sync operation 
 879         // can't pass a wxWCharBuffer through ( ... ) 
 880         wxLogError(_("Failed to %s dialup connection: %s"), 
 881                    wxString(async 
? _("initiate") : _("establish")).c_str(), 
 882                    GetErrorString(dwRet
).c_str()); 
 884         // we should still call RasHangUp() if we got a non 0 connection 
 885         if ( ms_hRasConnection 
) 
 887             ms_pfnRasHangUp(ms_hRasConnection
); 
 888             ms_hRasConnection 
= 0; 
 896     // for async dialing, we're not yet connected 
 899         ms_isConnected 
= true; 
 905 bool wxDialUpManagerMSW::IsDialing() const 
 907     return GetDialer() != NULL
; 
 910 bool wxDialUpManagerMSW::CancelDialing() 
 918     wxASSERT_MSG( ms_hRasConnection
, wxT("dialing but no connection?") ); 
 925 bool wxDialUpManagerMSW::HangUp() 
 927     wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") ); 
 929     // we may terminate either the connection we initiated or another one which 
 932     if ( ms_hRasConnection 
) 
 934         hRasConn 
= ms_hRasConnection
; 
 936         ms_hRasConnection 
= 0; 
 940         hRasConn 
= FindActiveConnection(); 
 945         wxLogError(_("Cannot hang up - no active dialup connection.")); 
 950     // note that it's not an error if the connection had been already 
 952     const DWORD dwRet 
= ms_pfnRasHangUp(hRasConn
); 
 953     if ( dwRet 
!= 0 && dwRet 
!= ERROR_NO_CONNECTION 
) 
 955         wxLogError(_("Failed to terminate the dialup connection: %s"), 
 956                    GetErrorString(dwRet
).c_str()); 
 959     ms_isConnected 
= false; 
 964 bool wxDialUpManagerMSW::IsAlwaysOnline() const 
 966     // assume no permanent connection by default 
 967     bool isAlwaysOnline 
= false; 
 969     // try to use WinInet functions 
 971     // NB: we could probably use wxDynamicLibrary here just as well, 
 972     //     but we allow multiple instances of wxDialUpManagerMSW so 
 973     //     we might as well use the ref counted version here too. 
 975     wxDynamicLibrary 
hDll(_T("WININET")); 
 976     if ( hDll
.IsLoaded() ) 
 978         typedef BOOL (WINAPI 
*INTERNETGETCONNECTEDSTATE
)(LPDWORD
, DWORD
); 
 979         INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState
; 
 981         #define RESOLVE_FUNCTION(type, name) \ 
 982             pfn##name = (type)hDll.GetSymbol(_T(#name)) 
 984         RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE
, InternetGetConnectedState
); 
 986         if ( pfnInternetGetConnectedState 
) 
 989             if ( pfnInternetGetConnectedState(&flags
, 0 /* reserved */) ) 
 991                 // there is some connection to the net, see of which type 
 992                 isAlwaysOnline 
= (flags 
& (INTERNET_CONNECTION_LAN 
| 
 993                                            INTERNET_CONNECTION_PROXY
)) != 0; 
 995             //else: no Internet connection at all 
 999     return isAlwaysOnline
; 
1002 bool wxDialUpManagerMSW::IsOnline() const 
1004     wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") ); 
1006     if ( IsAlwaysOnline() ) 
1012     if ( ms_userSpecifiedOnlineStatus 
!= -1 ) 
1014         // user specified flag overrides our logic 
1015         return ms_userSpecifiedOnlineStatus 
!= 0; 
1019         // return true if there is at least one active connection 
1020         return FindActiveConnection() != 0; 
1024 void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline
) 
1026     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1028     ms_userSpecifiedOnlineStatus 
= isOnline
; 
1031 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds
) 
1033     wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") ); 
1035     if ( m_autoCheckLevel
++ ) 
1041     bool ok 
= ms_pfnRasConnectionNotification 
!= 0; 
1045         // we're running under NT 4.0, Windows 98 or later and can use 
1046         // RasConnectionNotification() to be notified by a secondary thread 
1048         // first, see if we don't have this thread already running 
1049         if ( m_hThread 
!= 0 ) 
1051             if ( ::ResumeThread(m_hThread
) != (DWORD
)-1 ) 
1054             // we're leaving a zombie thread... but what else can we do? 
1055             wxLogLastError(wxT("ResumeThread(RasThread)")); 
1061     // create all the stuff we need to be notified about RAS connection 
1066         // first create an event to wait on 
1067         m_data
->hEventRas 
= ::CreateEvent
 
1069                              NULL
,      // security attribute (default) 
1070                              FALSE
,     // manual reset (no, it is automatic) 
1071                              FALSE
,     // initial state (not signaled) 
1074         if ( !m_data
->hEventRas 
) 
1076             wxLogLastError(wxT("CreateEvent(RasStatus)")); 
1084         // create the event we use to quit the thread: using a manual event 
1085         // here avoids problems with missing the event if wxDialUpManagerMSW 
1086         // is created and destroyed immediately, before wxRasStatusWindowProc 
1087         // starts waiting on the event 
1088         m_data
->hEventQuit 
= ::CreateEvent
 
1090                                 NULL
,   // default security 
1091                                 TRUE
,   // manual event 
1092                                 FALSE
,  // initially non signalled 
1095         if ( !m_data
->hEventQuit 
) 
1097             wxLogLastError(wxT("CreateEvent(RasThreadQuit)")); 
1099             CleanUpThreadData(); 
1105     if ( ok 
&& !ms_hwndRas 
) 
1107         // create a hidden window to receive notification about connections 
1109         ms_hwndRas 
= wxCreateHiddenWindow
 
1111                         &gs_classForDialUpWindow
, 
1112                         wxMSWDIALUP_WNDCLASSNAME
, 
1113                         wxRasStatusWindowProc
 
1117             wxLogLastError(wxT("CreateWindow(RasHiddenWindow)")); 
1119             CleanUpThreadData(); 
1125     m_data
->hWnd 
= ms_hwndRas
; 
1129         // start the secondary thread 
1130         m_data
->dialUpManager 
= this; 
1133         m_hThread 
= CreateThread
 
1137                      (LPTHREAD_START_ROUTINE
)wxRasMonitorThread
, 
1145             wxLogLastError(wxT("CreateThread(RasStatusThread)")); 
1147             CleanUpThreadData(); 
1153         // start receiving RAS notifications 
1154         DWORD dwRet 
= ms_pfnRasConnectionNotification
 
1156                         (HRASCONN
)INVALID_HANDLE_VALUE
, 
1158                         3 /* RASCN_Connection | RASCN_Disconnection */ 
1163             wxLogDebug(wxT("RasConnectionNotification() failed: %s"), 
1164                        GetErrorString(dwRet
).c_str()); 
1166             CleanUpThreadData(); 
1174     // we're running under Windows 95 and have to poll ourselves 
1175     // (or, alternatively, the code above for NT/98 failed) 
1176     m_timerStatusPolling
.Stop(); 
1177     if ( nSeconds 
== 0 ) 
1182     m_timerStatusPolling
.Start(nSeconds 
* 1000); 
1187 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus() 
1189     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1191     if ( --m_autoCheckLevel 
!= 0 ) 
1199         // we have running secondary thread, it's just enough to suspend it 
1200         if ( SuspendThread(m_hThread
) == (DWORD
)-1 ) 
1202             wxLogLastError(wxT("SuspendThread(RasThread)")); 
1207         // even simpler - just stop the timer 
1208         m_timerStatusPolling
.Stop(); 
1212 // ---------------------------------------------------------------------------- 
1213 // stubs which don't do anything in MSW version 
1214 // ---------------------------------------------------------------------------- 
1216 void wxDialUpManagerMSW::SetWellKnownHost(const wxString
& WXUNUSED(hostname
), 
1219     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1221     // nothing to do - we don't use this 
1224 void wxDialUpManagerMSW::SetConnectCommand(const wxString
& WXUNUSED(dial
), 
1225                                            const wxString
& WXUNUSED(hangup
)) 
1227     wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") ); 
1229     // nothing to do - we don't use this 
1232 // ---------------------------------------------------------------------------- 
1234 // ---------------------------------------------------------------------------- 
1236 static DWORD 
wxRasMonitorThread(wxRasThreadData 
*data
) 
1239     handles
[0] = data
->hEventRas
; 
1240     handles
[1] = data
->hEventQuit
; 
1245         DWORD dwRet 
= ::WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
); 
1250                 // RAS connection status changed 
1251                 SendMessage(data
->hWnd
, wxWM_RAS_STATUS_CHANGED
, 
1255             case WAIT_OBJECT_0 
+ 1: 
1260                 wxFAIL_MSG( _T("unexpected return of WaitForMultipleObjects()") ); 
1265                 // using wxLogLastError() from here is dangerous: we risk to 
1266                 // deadlock the main thread if wxLog sends output to GUI 
1267                 DWORD err 
= GetLastError(); 
1268                 wxMessageOutputDebug dbg
; 
1271                     wxT("WaitForMultipleObjects(RasMonitor) failed: 0x%08lx (%s)"), 
1275 #endif // __WXDEBUG__ 
1277                 // no sense in continuing, who knows if the handles we're 
1278                 // waiting for even exist yet... 
1283     // we don't need it any more now and if this thread ran, it is our 
1284     // responsability to free the data 
1290 static LRESULT APIENTRY 
wxRasStatusWindowProc(HWND hWnd
, UINT message
, 
1291                                               WPARAM wParam
, LPARAM lParam
) 
1295         case wxWM_RAS_STATUS_CHANGED
: 
1297                 wxRasThreadData 
*data 
= (wxRasThreadData 
*)lParam
; 
1298                 data
->dialUpManager
->OnConnectStatusChange(); 
1302         case wxWM_RAS_DIALING_PROGRESS
: 
1304                 wxDialUpManagerMSW 
*dialMan 
= wxDialUpManagerMSW::GetDialer(); 
1306                 dialMan
->OnDialProgress((RASCONNSTATE
)wParam
, lParam
); 
1311             return ::DefWindowProc(hWnd
, message
, wParam
, lParam
); 
1317 static void WINAPI 
wxRasDialFunc(UINT 
WXUNUSED(unMsg
), 
1318                                  RASCONNSTATE rasconnstate
, 
1321     wxDialUpManagerMSW 
*dialUpManager 
= wxDialUpManagerMSW::GetDialer(); 
1323     wxCHECK_RET( dialUpManager
, wxT("who started to dial then?") ); 
1325     SendMessage(wxDialUpManagerMSW::GetRasWindow(), wxWM_RAS_DIALING_PROGRESS
, 
1326                 rasconnstate
, dwError
); 
1329 #endif // __BORLANDC__ 
1331 #endif // wxUSE_DIALUP_MANAGER