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 // these functions require Win32
28 #if defined(__WIN16__) && wxUSE_DIALUP_MANAGER
29 #undef wxUSE_DIALUP_MANAGER
30 #define wxUSE_DIALUP_MANAGER 0
31 #endif // wxUSE_DIALUP_MANAGER && Win16
33 #if wxUSE_DIALUP_MANAGER
43 #include "wx/generic/choicdgg.h"
45 #include "wx/msw/private.h" // must be before #include "dynlib.h"
47 #if !wxUSE_DYNLIB_CLASS
48 #error You need wxUSE_DYNLIB_CLASS to be 1 to compile dialup.cpp.
51 #include "wx/dynlib.h"
53 #include "wx/dialup.h"
55 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED
)
56 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED
)
58 // Doesn't yet compile under VC++ 4, BC++, Watcom C++: no wininet.h
59 #if !defined(__BORLANDC__) && \
60 (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \
61 !defined(__GNUWIN32_OLD__) && \
62 !defined(__WATCOMC__) && \
63 (!defined(__VISUALC__) || (__VISUALC__ >= 1020))
71 #ifndef INTERNET_CONNECTION_LAN
72 #define INTERNET_CONNECTION_LAN 2
74 #ifndef INTERNET_CONNECTION_PROXY
75 #define INTERNET_CONNECTION_PROXY 4
78 // ----------------------------------------------------------------------------
80 // ----------------------------------------------------------------------------
82 // this message is sent by the secondary thread when RAS status changes
83 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010)
84 #define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011)
86 // ----------------------------------------------------------------------------
88 // ----------------------------------------------------------------------------
90 // the signatures of RAS functions: all this is quite heavy, but we must do it
91 // to allow running wxWin programs on machine which don't have RAS installed
92 // (this does exist) - if we link with rasapi32.lib, the program will fail on
93 // startup because of the missing DLL...
96 typedef DWORD (APIENTRY
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCSTR
, LPRASDIALPARAMSA
, DWORD
, LPVOID
, LPHRASCONN
);
97 typedef DWORD (APIENTRY
* RASENUMCONNECTIONS
)( LPRASCONNA
, LPDWORD
, LPDWORD
);
98 typedef DWORD (APIENTRY
* RASENUMENTRIES
)( LPCSTR
, LPCSTR
, LPRASENTRYNAMEA
, LPDWORD
, LPDWORD
);
99 typedef DWORD (APIENTRY
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSA
);
100 typedef DWORD (APIENTRY
* RASGETERRORSTRING
)( UINT
, LPSTR
, DWORD
);
101 typedef DWORD (APIENTRY
* RASHANGUP
)( HRASCONN
);
102 typedef DWORD (APIENTRY
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD
);
103 typedef DWORD (APIENTRY
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCSTR
);
104 typedef DWORD (APIENTRY
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCSTR
, LPCSTR
);
105 typedef DWORD (APIENTRY
* RASSETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, BOOL
);
106 typedef DWORD (APIENTRY
* RASGETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, LPBOOL
);
107 typedef DWORD (APIENTRY
* RASENUMDEVICES
)( LPRASDEVINFOA
, LPDWORD
, LPDWORD
);
108 typedef DWORD (APIENTRY
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOA
, LPDWORD
);
109 typedef DWORD (APIENTRY
* RASGETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, LPDWORD
, LPBYTE
, LPDWORD
);
110 typedef DWORD (APIENTRY
* RASSETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, DWORD
, LPBYTE
, DWORD
);
111 typedef DWORD (APIENTRY
* RASRENAMEENTRY
)( LPCSTR
, LPCSTR
, LPCSTR
);
112 typedef DWORD (APIENTRY
* RASDELETEENTRY
)( LPCSTR
, LPCSTR
);
113 typedef DWORD (APIENTRY
* RASVALIDATEENTRYNAME
)( LPCSTR
, LPCSTR
);
114 typedef DWORD (APIENTRY
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD
);
116 static const wxChar gs_funcSuffix
= _T('A');
118 typedef DWORD (APIENTRY
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCWSTR
, LPRASDIALPARAMSW
, DWORD
, LPVOID
, LPHRASCONN
);
119 typedef DWORD (APIENTRY
* RASENUMCONNECTIONS
)( LPRASCONNW
, LPDWORD
, LPDWORD
);
120 typedef DWORD (APIENTRY
* RASENUMENTRIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYNAMEW
, LPDWORD
, LPDWORD
);
121 typedef DWORD (APIENTRY
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSW
);
122 typedef DWORD (APIENTRY
* RASGETERRORSTRING
)( UINT
, LPWSTR
, DWORD
);
123 typedef DWORD (APIENTRY
* RASHANGUP
)( HRASCONN
);
124 typedef DWORD (APIENTRY
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD
);
125 typedef DWORD (APIENTRY
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCWSTR
);
126 typedef DWORD (APIENTRY
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCWSTR
, LPCWSTR
);
127 typedef DWORD (APIENTRY
* RASSETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, BOOL
);
128 typedef DWORD (APIENTRY
* RASGETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, LPBOOL
);
129 typedef DWORD (APIENTRY
* RASENUMDEVICES
)( LPRASDEVINFOW
, LPDWORD
, LPDWORD
);
130 typedef DWORD (APIENTRY
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOW
, LPDWORD
);
131 typedef DWORD (APIENTRY
* RASGETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, LPDWORD
, LPBYTE
, LPDWORD
);
132 typedef DWORD (APIENTRY
* RASSETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, DWORD
, LPBYTE
, DWORD
);
133 typedef DWORD (APIENTRY
* RASRENAMEENTRY
)( LPCWSTR
, LPCWSTR
, LPCWSTR
);
134 typedef DWORD (APIENTRY
* RASDELETEENTRY
)( LPCWSTR
, LPCWSTR
);
135 typedef DWORD (APIENTRY
* RASVALIDATEENTRYNAME
)( LPCWSTR
, LPCWSTR
);
136 typedef DWORD (APIENTRY
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD
);
138 static const wxChar gs_funcSuffix
= _T('W');
139 #endif // ASCII/Unicode
141 // structure passed to the secondary thread
142 struct WXDLLEXPORT wxRasThreadData
147 hEventRas
= hEventQuit
= INVALID_HANDLE_VALUE
;
148 dialUpManager
= NULL
;
151 HWND hWnd
; // window to send notifications to
152 HANDLE hEventRas
, // event which RAS signals when status changes
153 hEventQuit
; // event which we signal when we terminate
155 class WXDLLEXPORT wxDialUpManagerMSW
*dialUpManager
; // the owner
158 // ----------------------------------------------------------------------------
159 // wxDialUpManager class for MSW
160 // ----------------------------------------------------------------------------
162 class WXDLLEXPORT wxDialUpManagerMSW
: public wxDialUpManager
166 wxDialUpManagerMSW();
167 virtual ~wxDialUpManagerMSW();
169 // implement base class pure virtuals
170 virtual bool IsOk() const;
171 virtual size_t GetISPNames(wxArrayString
& names
) const;
172 virtual bool Dial(const wxString
& nameOfISP
,
173 const wxString
& username
,
174 const wxString
& password
,
176 virtual bool IsDialing() const;
177 virtual bool CancelDialing();
178 virtual bool HangUp();
179 virtual bool IsAlwaysOnline() const;
180 virtual bool IsOnline() const;
181 virtual void SetOnlineStatus(bool isOnline
= TRUE
);
182 virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
);
183 virtual void DisableAutoCheckOnlineStatus();
184 virtual void SetWellKnownHost(const wxString
& hostname
, int port
);
185 virtual void SetConnectCommand(const wxString
& commandDial
,
186 const wxString
& commandHangup
);
189 void CheckRasStatus();
191 // for wxRasStatusWindowProc
192 void OnConnectStatusChange();
193 void OnDialProgress(RASCONNSTATE rasconnstate
, DWORD dwError
);
196 static HWND
GetRasWindow() { return ms_hwndRas
; }
197 static wxDialUpManagerMSW
*GetDialer() { return ms_dialer
; }
200 // return the error string for the given RAS error code
201 static wxString
GetErrorString(DWORD error
);
203 // find the (first) handle of the active connection
204 static HRASCONN
FindActiveConnection();
206 // notify the application about status change
207 void NotifyApp(bool connected
, bool fromOurselves
= FALSE
) const;
209 // destroy the thread data and the thread itself
210 void CleanUpThreadData();
212 // timer used for polling RAS status
213 class WXDLLEXPORT RasTimer
: public wxTimer
216 RasTimer(wxDialUpManagerMSW
*dialUpManager
)
217 { m_dialUpManager
= dialUpManager
; }
219 virtual void Notify() { m_dialUpManager
->CheckRasStatus(); }
222 wxDialUpManagerMSW
*m_dialUpManager
;
223 } m_timerStatusPolling
;
225 // thread handle for the thread sitting on connection change event
228 // data used by this thread and our hidden window to send messages between
230 wxRasThreadData m_data
;
232 // the hidden window we use for passing messages between threads
233 static HWND ms_hwndRas
;
235 // the handle of the connection we initiated or 0 if none
236 static HRASCONN ms_hRasConnection
;
238 // the use count of rasapi32.dll
239 static int ms_nDllCount
;
241 // the handle of rasapi32.dll when it's loaded
242 static wxDllType ms_dllRas
;
244 // the pointers to RAS functions
245 static RASDIAL ms_pfnRasDial
;
246 static RASENUMCONNECTIONS ms_pfnRasEnumConnections
;
247 static RASENUMENTRIES ms_pfnRasEnumEntries
;
248 static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus
;
249 static RASGETERRORSTRING ms_pfnRasGetErrorString
;
250 static RASHANGUP ms_pfnRasHangUp
;
251 static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo
;
252 static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry
;
253 static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry
;
254 static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams
;
255 static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams
;
256 static RASENUMDEVICES ms_pfnRasEnumDevices
;
257 static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo
;
258 static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties
;
259 static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties
;
260 static RASRENAMEENTRY ms_pfnRasRenameEntry
;
261 static RASDELETEENTRY ms_pfnRasDeleteEntry
;
262 static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName
;
264 // this function is not supported by Win95
265 static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification
;
267 // if this flag is different from -1, it overrides IsOnline()
268 static int ms_userSpecifiedOnlineStatus
;
270 // this flag tells us if we're online
271 static int ms_isConnected
;
273 // this flag is the result of the call to IsAlwaysOnline() (-1 if not
275 static int ms_isAlwaysOnline
;
277 // this flag tells us whether a call to RasDial() is in progress
278 static wxDialUpManagerMSW
*ms_dialer
;
281 // ----------------------------------------------------------------------------
283 // ----------------------------------------------------------------------------
285 static LRESULT WINAPI
wxRasStatusWindowProc(HWND hWnd
, UINT message
,
286 WPARAM wParam
, LPARAM lParam
);
288 static DWORD
wxRasMonitorThread(wxRasThreadData
*data
);
290 static void WINAPI
wxRasDialFunc(UINT unMsg
,
291 RASCONNSTATE rasconnstate
,
294 // ============================================================================
296 // ============================================================================
298 // ----------------------------------------------------------------------------
299 // init the static variables
300 // ----------------------------------------------------------------------------
302 HRASCONN
wxDialUpManagerMSW::ms_hRasConnection
= 0;
304 HWND
wxDialUpManagerMSW::ms_hwndRas
= 0;
306 int wxDialUpManagerMSW::ms_nDllCount
= 0;
307 wxDllType
wxDialUpManagerMSW::ms_dllRas
= 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 int wxDialUpManagerMSW::ms_isAlwaysOnline
= -1;
332 wxDialUpManagerMSW
*wxDialUpManagerMSW::ms_dialer
= NULL
;
334 // ----------------------------------------------------------------------------
335 // ctor and dtor: the dynamic linking happens here
336 // ----------------------------------------------------------------------------
338 // the static creator function is implemented here
339 wxDialUpManager
*wxDialUpManager::Create()
341 return new wxDialUpManagerMSW
;
345 // warning about "'this' : used in base member initializer list" - so what?
346 #pragma warning(disable:4355)
349 wxDialUpManagerMSW::wxDialUpManagerMSW()
350 : m_timerStatusPolling(this)
352 // initialize our data
355 if ( !ms_nDllCount
++ )
357 // load the RAS library
358 ms_dllRas
= wxDllLoader::LoadLibrary("RASAPI32");
361 wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it."));
365 // resolve the functions we need
367 // this will contain the name of the function we failed to resolve
369 const char *funcName
= NULL
;
371 // get the function from rasapi32.dll and abort if it's not found
372 #define RESOLVE_RAS_FUNCTION(type, name) \
373 ms_pfn##name = (type)wxDllLoader::GetSymbol(ms_dllRas, \
374 wxString(_T(#name)) + gs_funcSuffix); \
375 if ( !ms_pfn##name ) \
381 // a variant of above macro which doesn't abort if the function is
382 // not found in the DLL
383 #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \
384 ms_pfn##name = (type)wxDllLoader::GetSymbol(ms_dllRas, \
385 wxString(_T(#name)) + gs_funcSuffix);
387 RESOLVE_RAS_FUNCTION(RASDIAL
, RasDial
);
388 RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS
, RasEnumConnections
);
389 RESOLVE_RAS_FUNCTION(RASENUMENTRIES
, RasEnumEntries
);
390 RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS
, RasGetConnectStatus
);
391 RESOLVE_RAS_FUNCTION(RASGETERRORSTRING
, RasGetErrorString
);
392 RESOLVE_RAS_FUNCTION(RASHANGUP
, RasHangUp
);
393 RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS
, RasGetEntryDialParams
);
395 // suppress wxDllLoader messages about missing (non essential)
400 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO
, RasGetProjectionInfo
);
401 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY
, RasCreatePhonebookEntry
);
402 RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY
, RasEditPhonebookEntry
);
403 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS
, RasSetEntryDialParams
);
404 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES
, RasGetEntryProperties
);
405 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES
, RasSetEntryProperties
);
406 RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY
, RasRenameEntry
);
407 RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY
, RasDeleteEntry
);
408 RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME
, RasValidateEntryName
);
409 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO
, RasGetCountryInfo
);
410 RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES
, RasEnumDevices
);
411 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION
, RasConnectionNotification
);
414 // keep your preprocessor name space clean
415 #undef RESOLVE_RAS_FUNCTION
416 #undef RESOLVE_OPTIONAL_RAS_FUNCTION
421 static const wxChar
*msg
= wxTRANSLATE(
422 "The version of remote access service (RAS) installed on this machine is too\
423 old, please upgrade (the following required function is missing: %s)."
426 wxLogError(wxGetTranslation(msg
), funcName
);
428 wxDllLoader::UnloadLibrary(ms_dllRas
);
437 // enable auto check by default
438 EnableAutoCheckOnlineStatus(0);
441 wxDialUpManagerMSW::~wxDialUpManagerMSW()
445 if ( !--ms_nDllCount
)
447 // unload the RAS library
448 wxDllLoader::UnloadLibrary(ms_dllRas
);
453 // ----------------------------------------------------------------------------
455 // ----------------------------------------------------------------------------
457 wxString
wxDialUpManagerMSW::GetErrorString(DWORD error
)
459 wxChar buffer
[512]; // this should be more than enough according to MS docs
460 DWORD dwRet
= ms_pfnRasGetErrorString(error
, buffer
, WXSIZEOF(buffer
));
463 case ERROR_INVALID_PARAMETER
:
464 // this was a standard Win32 error probably
465 return wxString(wxSysErrorMsg(error
));
470 _("Failed to retrieve text of RAS error message"));
473 msg
.Printf(_("unknown error (error code %08x)."), error
);
478 // we want the error message to start from a lower case letter
479 buffer
[0] = wxTolower(buffer
[0]);
481 return wxString(buffer
);
485 HRASCONN
wxDialUpManagerMSW::FindActiveConnection()
487 // enumerate connections
488 DWORD cbBuf
= sizeof(RASCONN
);
489 LPRASCONN lpRasConn
= (LPRASCONN
)malloc(cbBuf
);
496 lpRasConn
->dwSize
= sizeof(RASCONN
);
498 DWORD nConnections
= 0;
499 DWORD dwRet
= ERROR_BUFFER_TOO_SMALL
;
501 while ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
503 dwRet
= ms_pfnRasEnumConnections(lpRasConn
, &cbBuf
, &nConnections
);
505 if ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
507 LPRASCONN lpRasConnOld
= lpRasConn
;
508 lpRasConn
= (LPRASCONN
)realloc(lpRasConn
, cbBuf
);
517 else if ( dwRet
== 0 )
525 wxLogError(_("Cannot find active dialup connection: %s"),
526 GetErrorString(dwRet
).c_str());
533 switch ( nConnections
)
541 // more than 1 connection - we don't know what to do with this
542 // case, so give a warning but continue (taking the first
543 // connection) - the warning is really needed because this function
544 // is used, for example, to select the connection to hang up and so
545 // we may hang up the wrong connection here...
546 wxLogWarning(_("Several active dialup connections found, choosing one randomly."));
550 // exactly 1 connection, great
551 hrasconn
= lpRasConn
->hrasconn
;
559 void wxDialUpManagerMSW::CleanUpThreadData()
563 if ( !SetEvent(m_data
.hEventQuit
) )
565 wxLogLastError(_T("SetEvent(RasThreadQuit)"));
568 CloseHandle(m_hThread
);
575 DestroyWindow(m_data
.hWnd
);
580 if ( m_data
.hEventQuit
)
582 CloseHandle(m_data
.hEventQuit
);
584 m_data
.hEventQuit
= 0;
587 if ( m_data
.hEventRas
)
589 CloseHandle(m_data
.hEventRas
);
591 m_data
.hEventRas
= 0;
595 // ----------------------------------------------------------------------------
597 // ----------------------------------------------------------------------------
599 void wxDialUpManagerMSW::CheckRasStatus()
601 // use int, not bool to compare with -1
602 int isConnected
= FindActiveConnection() != 0;
603 if ( isConnected
!= ms_isConnected
)
605 if ( ms_isConnected
!= -1 )
607 // notify the program
608 NotifyApp(isConnected
!= 0);
610 // else: it's the first time we're called, just update the flag
612 ms_isConnected
= isConnected
;
616 void wxDialUpManagerMSW::NotifyApp(bool connected
, bool fromOurselves
) const
618 wxDialUpEvent
event(connected
, fromOurselves
);
619 (void)wxTheApp
->ProcessEvent(event
);
622 // this function is called whenever the status of any RAS connection on this
623 // machine changes by RAS itself
624 void wxDialUpManagerMSW::OnConnectStatusChange()
626 // we know that status changed, but we don't know whether we're connected
627 // or not - so find it out
631 // this function is called by our callback which we give to RasDial() when
632 // calling it asynchronously
633 void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate
,
638 // this probably means that CancelDialing() was called and we get
639 // "disconnected" notification
643 // we're only interested in 2 events: connected and disconnected
646 wxLogError(_("Failed to establish dialup connection: %s"),
647 GetErrorString(dwError
).c_str());
649 // we should still call RasHangUp() if we got a non 0 connection
650 if ( ms_hRasConnection
)
652 ms_pfnRasHangUp(ms_hRasConnection
);
653 ms_hRasConnection
= 0;
658 NotifyApp(FALSE
/* !connected */, TRUE
/* we dialed ourselves */);
660 else if ( rasconnstate
== RASCS_Connected
)
662 ms_isConnected
= TRUE
;
665 NotifyApp(TRUE
/* connected */, TRUE
/* we dialed ourselves */);
669 // ----------------------------------------------------------------------------
670 // implementation of wxDialUpManager functions
671 // ----------------------------------------------------------------------------
673 bool wxDialUpManagerMSW::IsOk() const
675 return ms_dllRas
!= 0;
678 size_t wxDialUpManagerMSW::GetISPNames(wxArrayString
& names
) const
681 DWORD size
= sizeof(RASENTRYNAME
);
682 RASENTRYNAME
*rasEntries
= (RASENTRYNAME
*)malloc(size
);
683 rasEntries
->dwSize
= sizeof(RASENTRYNAME
);
689 dwRet
= ms_pfnRasEnumEntries
692 NULL
, // default phone book (or all)
693 rasEntries
, // [out] buffer for the entries
694 &size
, // [in/out] size of the buffer
695 &nEntries
// [out] number of entries fetched
698 if ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
700 // reallocate the buffer
701 rasEntries
= (RASENTRYNAME
*)realloc(rasEntries
, size
);
703 else if ( dwRet
!= 0 )
705 // some other error - abort
706 wxLogError(_("Failed to get ISP names: %s"),
707 GetErrorString(dwRet
).c_str());
714 while ( dwRet
!= 0 );
718 for ( size_t n
= 0; n
< (size_t)nEntries
; n
++ )
720 names
.Add(rasEntries
[n
].szEntryName
);
725 // return the number of entries
726 return names
.GetCount();
729 bool wxDialUpManagerMSW::Dial(const wxString
& nameOfISP
,
730 const wxString
& username
,
731 const wxString
& password
,
734 // check preconditions
735 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
737 if ( ms_hRasConnection
)
739 wxFAIL_MSG(wxT("there is already an active connection"));
744 // get the default ISP if none given
745 wxString
entryName(nameOfISP
);
749 size_t count
= GetISPNames(names
);
753 // no known ISPs, abort
754 wxLogError(_("Failed to connect: no ISP to dial."));
759 // only one ISP, choose it
760 entryName
= names
[0u];
764 // several ISPs, let the user choose
766 wxString
*strings
= new wxString
[count
];
767 for ( size_t i
= 0; i
< count
; i
++ )
769 strings
[i
] = names
[i
];
772 entryName
= wxGetSingleChoice
774 _("Choose ISP to dial"),
775 _("Please choose which ISP do you want to connect to"),
791 RASDIALPARAMS rasDialParams
;
792 rasDialParams
.dwSize
= sizeof(rasDialParams
);
793 wxStrncpy(rasDialParams
.szEntryName
, entryName
, RAS_MaxEntryName
);
795 // do we have the username and password?
796 if ( !username
|| !password
)
799 DWORD dwRet
= ms_pfnRasGetEntryDialParams
801 NULL
, // default phonebook
802 &rasDialParams
, // [in/out] the params of this entry
803 &gotPassword
// [out] did we get password?
808 wxLogError(_("Failed to connect: missing username/password."));
815 wxStrncpy(rasDialParams
.szUserName
, username
, UNLEN
);
816 wxStrncpy(rasDialParams
.szPassword
, password
, PWLEN
);
819 // default values for other fields
820 rasDialParams
.szPhoneNumber
[0] = '\0';
821 rasDialParams
.szCallbackNumber
[0] = '\0';
822 rasDialParams
.szCallbackNumber
[0] = '\0';
824 rasDialParams
.szDomain
[0] = '*';
825 rasDialParams
.szDomain
[1] = '\0';
827 // apparently, this is not really necessary - passing NULL instead of the
828 // phone book has the same effect
831 if ( wxGetOsVersion() == wxWINDOWS_NT
)
833 // first get the length
834 UINT nLen
= ::GetSystemDirectory(NULL
, 0);
837 if ( !::GetSystemDirectory(phoneBook
.GetWriteBuf(nLen
), nLen
) )
839 wxLogSysError(_("Cannot find the location of address book file"));
842 phoneBook
.UngetWriteBuf();
844 // this is the default phone book
845 phoneBook
<< "\\ras\\rasphone.pbk";
849 // TODO may be we should disable auto check while async dialing is in
854 DWORD dwRet
= ms_pfnRasDial
856 (LPRASDIALEXTENSIONS
)NULL
, // no extended features
857 NULL
, // default phone book file (NT only)
859 0, // use callback for notifications
860 async
? wxRasDialFunc
// the callback
861 : 0, // no notifications - sync operation
868 // can't pass a wxWCharBuffer through ( ... )
869 wxLogError(_("Failed to %s dialup connection: %s").data(),
870 async
? _("initiate").data() : _("establish").data(),
871 GetErrorString(dwRet
).c_str());
873 // can't pass a wxWCharBuffer through ( ... )
874 wxLogError(_("Failed to %s dialup connection: %s"),
875 wxString(async
? _("initiate") : _("establish")).c_str(),
876 GetErrorString(dwRet
).c_str());
879 // we should still call RasHangUp() if we got a non 0 connection
880 if ( ms_hRasConnection
)
882 ms_pfnRasHangUp(ms_hRasConnection
);
883 ms_hRasConnection
= 0;
891 // for async dialing, we're not yet connected
894 ms_isConnected
= TRUE
;
900 bool wxDialUpManagerMSW::IsDialing() const
902 return GetDialer() != NULL
;
905 bool wxDialUpManagerMSW::CancelDialing()
913 wxASSERT_MSG( ms_hRasConnection
, wxT("dialing but no connection?") );
920 bool wxDialUpManagerMSW::HangUp()
922 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
924 // we may terminate either the connection we initiated or another one which
927 if ( ms_hRasConnection
)
929 hRasConn
= ms_hRasConnection
;
931 ms_hRasConnection
= 0;
935 hRasConn
= FindActiveConnection();
940 wxLogError(_("Cannot hang up - no active dialup connection."));
945 DWORD dwRet
= ms_pfnRasHangUp(hRasConn
);
948 wxLogError(_("Failed to terminate the dialup connection: %s"),
949 GetErrorString(dwRet
).c_str());
952 ms_isConnected
= FALSE
;
957 bool wxDialUpManagerMSW::IsAlwaysOnline() const
959 // we cache the result (presumably this won't change while the program is
961 if ( ms_isAlwaysOnline
!= -1 )
963 return ms_isAlwaysOnline
!= 0;
966 // try to use WinInet function first
968 wxDllType hDll
= wxDllLoader::LoadLibrary(_T("WININET"), &ok
);
971 typedef BOOL (WINAPI
*INTERNETGETCONNECTEDSTATE
)(LPDWORD
, DWORD
);
972 INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState
;
974 #define RESOLVE_FUNCTION(type, name) \
975 pfn##name = (type)wxDllLoader::GetSymbol(hDll, _T(#name))
977 RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE
, InternetGetConnectedState
);
979 if ( pfnInternetGetConnectedState
)
982 if ( pfnInternetGetConnectedState(&flags
, 0 /* reserved */) )
984 // there is some connection to the net, see of which type
985 ms_isAlwaysOnline
= (flags
& INTERNET_CONNECTION_LAN
!= 0) ||
986 (flags
& INTERNET_CONNECTION_PROXY
!= 0);
990 // no Internet connection at all
991 ms_isAlwaysOnline
= FALSE
;
995 wxDllLoader::UnloadLibrary(hDll
);
998 // did we succeed with WinInet? if not, try something else
999 if ( ms_isAlwaysOnline
== -1 )
1003 // definitely no permanent connection because we are not connected
1005 ms_isAlwaysOnline
= FALSE
;
1009 // of course, having a modem doesn't prevent us from having a
1010 // permanent connection as well, but we have to guess somehow and
1011 // it's probably more common that a system connected via a modem
1012 // doesn't have any other net access, so:
1013 ms_isAlwaysOnline
= FALSE
;
1017 wxASSERT_MSG( ms_isAlwaysOnline
!= -1, wxT("logic error") );
1019 return ms_isAlwaysOnline
!= 0;
1022 bool wxDialUpManagerMSW::IsOnline() const
1024 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
1026 if ( ms_userSpecifiedOnlineStatus
!= -1 )
1028 // user specified flag overrides our logic
1029 return ms_userSpecifiedOnlineStatus
!= 0;
1033 // return TRUE if there is at least one active connection
1034 return FindActiveConnection() != 0;
1038 void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline
)
1040 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1042 ms_userSpecifiedOnlineStatus
= isOnline
;
1045 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds
)
1047 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
1049 bool ok
= ms_pfnRasConnectionNotification
!= 0;
1053 // we're running under NT 4.0, Windows 98 or later and can use
1054 // RasConnectionNotification() to be notified by a secondary thread
1056 // first, see if we don't have this thread already running
1057 if ( m_hThread
!= 0 )
1059 DWORD dwSuspendCount
= 2;
1060 while ( dwSuspendCount
> 1 )
1062 dwSuspendCount
= ResumeThread(m_hThread
);
1063 if ( dwSuspendCount
== (DWORD
)-1 )
1065 wxLogLastError(wxT("ResumeThread(RasThread)"));
1078 // create all the stuff we need to be notified about RAS connection
1083 // first create an event to wait on
1084 m_data
.hEventRas
= CreateEvent
1086 NULL
, // security attribute (default)
1087 FALSE
, // manual reset (not)
1088 FALSE
, // initial state (not signaled)
1091 if ( !m_data
.hEventRas
)
1093 wxLogLastError(wxT("CreateEvent(RasStatus)"));
1101 // create the event we use to quit the thread
1102 m_data
.hEventQuit
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1103 if ( !m_data
.hEventQuit
)
1105 wxLogLastError(wxT("CreateEvent(RasThreadQuit)"));
1107 CleanUpThreadData();
1113 if ( ok
&& !ms_hwndRas
)
1115 // create a hidden window to receive notification about connections
1117 extern const wxChar
*wxPanelClassName
;
1118 ms_hwndRas
= ::CreateWindow(wxPanelClassName
, NULL
,
1121 (HMENU
)NULL
, wxGetInstance(), 0);
1124 wxLogLastError(wxT("CreateWindow(RasHiddenWindow)"));
1126 CleanUpThreadData();
1132 FARPROC windowProc
= MakeProcInstance
1134 (FARPROC
)wxRasStatusWindowProc
,
1138 ::SetWindowLong(ms_hwndRas
, GWL_WNDPROC
, (LONG
) windowProc
);
1141 m_data
.hWnd
= ms_hwndRas
;
1145 // start the secondary thread
1146 m_data
.dialUpManager
= this;
1149 m_hThread
= CreateThread
1153 (LPTHREAD_START_ROUTINE
)wxRasMonitorThread
,
1161 wxLogLastError(wxT("CreateThread(RasStatusThread)"));
1163 CleanUpThreadData();
1169 // start receiving RAS notifications
1170 DWORD dwRet
= ms_pfnRasConnectionNotification
1172 (HRASCONN
)INVALID_HANDLE_VALUE
,
1174 3 /* RASCN_Connection | RASCN_Disconnection */
1179 wxLogDebug(wxT("RasConnectionNotification() failed: %s"),
1180 GetErrorString(dwRet
).c_str());
1182 CleanUpThreadData();
1190 // we're running under Windows 95 and have to poll ourselves
1191 // (or, alternatively, the code above for NT/98 failed)
1192 m_timerStatusPolling
.Stop();
1193 if ( nSeconds
== 0 )
1198 m_timerStatusPolling
.Start(nSeconds
* 1000);
1203 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
1205 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1209 // we have running secondary thread, it's just enough to suspend it
1210 if ( SuspendThread(m_hThread
) == (DWORD
)-1 )
1212 wxLogLastError(wxT("SuspendThread(RasThread)"));
1217 // even simpler - just stop the timer
1218 m_timerStatusPolling
.Stop();
1222 // ----------------------------------------------------------------------------
1223 // stubs which don't do anything in MSW version
1224 // ----------------------------------------------------------------------------
1226 void wxDialUpManagerMSW::SetWellKnownHost(const wxString
& WXUNUSED(hostname
),
1229 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1231 // nothing to do - we don't use this
1234 void wxDialUpManagerMSW::SetConnectCommand(const wxString
& WXUNUSED(dial
),
1235 const wxString
& WXUNUSED(hangup
))
1237 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1239 // nothing to do - we don't use this
1242 // ----------------------------------------------------------------------------
1244 // ----------------------------------------------------------------------------
1246 static DWORD
wxRasMonitorThread(wxRasThreadData
*data
)
1249 handles
[0] = data
->hEventRas
;
1250 handles
[1] = data
->hEventQuit
;
1255 DWORD dwRet
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1260 // RAS connection status changed
1261 SendMessage(data
->hWnd
, wxWM_RAS_STATUS_CHANGED
,
1265 case WAIT_OBJECT_0
+ 1:
1270 wxLogLastError(wxT("WaitForMultipleObjects(RasMonitor)"));
1278 static LRESULT APIENTRY
wxRasStatusWindowProc(HWND hWnd
, UINT message
,
1279 WPARAM wParam
, LPARAM lParam
)
1281 if ( message
== wxWM_RAS_STATUS_CHANGED
)
1283 wxRasThreadData
*data
= (wxRasThreadData
*)lParam
;
1284 data
->dialUpManager
->OnConnectStatusChange();
1286 else if ( message
== wxWM_RAS_DIALING_PROGRESS
)
1288 wxDialUpManagerMSW
*dialUpManager
= wxDialUpManagerMSW::GetDialer();
1290 dialUpManager
->OnDialProgress((RASCONNSTATE
)wParam
, lParam
);
1296 static void WINAPI
wxRasDialFunc(UINT unMsg
,
1297 RASCONNSTATE rasconnstate
,
1300 wxDialUpManagerMSW
*dialUpManager
= wxDialUpManagerMSW::GetDialer();
1302 wxCHECK_RET( dialUpManager
, wxT("who started to dial then?") );
1304 SendMessage(dialUpManager
->GetRasWindow(), wxWM_RAS_DIALING_PROGRESS
,
1305 rasconnstate
, dwError
);
1310 #endif // wxUSE_DIALUP_MANAGER