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/dynlib.h"
46 #include "wx/dialup.h"
48 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED
)
49 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED
)
51 // Doesn't yet compile under VC++ 4, BC++, Watcom C++,
53 #if !defined(__BORLANDC__) && \
54 (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \
55 !defined(__GNUWIN32_OLD__) && \
56 !defined(__WATCOMC__) && \
57 !defined(__WXWINE__) && \
58 !defined(__WINE__) && \
59 (!defined(__VISUALC__) || (__VISUALC__ >= 1020))
67 #ifndef INTERNET_CONNECTION_LAN
68 #define INTERNET_CONNECTION_LAN 2
70 #ifndef INTERNET_CONNECTION_PROXY
71 #define INTERNET_CONNECTION_PROXY 4
74 // ----------------------------------------------------------------------------
76 // ----------------------------------------------------------------------------
78 // this message is sent by the secondary thread when RAS status changes
79 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010)
80 #define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011)
82 // ----------------------------------------------------------------------------
84 // ----------------------------------------------------------------------------
86 // the signatures of RAS functions: all this is quite heavy, but we must do it
87 // to allow running wxWin programs on machine which don't have RAS installed
88 // (this does exist) - if we link with rasapi32.lib, the program will fail on
89 // startup because of the missing DLL...
92 typedef DWORD (APIENTRY
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCSTR
, LPRASDIALPARAMSA
, DWORD
, LPVOID
, LPHRASCONN
);
93 typedef DWORD (APIENTRY
* RASENUMCONNECTIONS
)( LPRASCONNA
, LPDWORD
, LPDWORD
);
94 typedef DWORD (APIENTRY
* RASENUMENTRIES
)( LPCSTR
, LPCSTR
, LPRASENTRYNAMEA
, LPDWORD
, LPDWORD
);
95 typedef DWORD (APIENTRY
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSA
);
96 typedef DWORD (APIENTRY
* RASGETERRORSTRING
)( UINT
, LPSTR
, DWORD
);
97 typedef DWORD (APIENTRY
* RASHANGUP
)( HRASCONN
);
98 typedef DWORD (APIENTRY
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD
);
99 typedef DWORD (APIENTRY
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCSTR
);
100 typedef DWORD (APIENTRY
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCSTR
, LPCSTR
);
101 typedef DWORD (APIENTRY
* RASSETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, BOOL
);
102 typedef DWORD (APIENTRY
* RASGETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, LPBOOL
);
103 typedef DWORD (APIENTRY
* RASENUMDEVICES
)( LPRASDEVINFOA
, LPDWORD
, LPDWORD
);
104 typedef DWORD (APIENTRY
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOA
, LPDWORD
);
105 typedef DWORD (APIENTRY
* RASGETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, LPDWORD
, LPBYTE
, LPDWORD
);
106 typedef DWORD (APIENTRY
* RASSETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, DWORD
, LPBYTE
, DWORD
);
107 typedef DWORD (APIENTRY
* RASRENAMEENTRY
)( LPCSTR
, LPCSTR
, LPCSTR
);
108 typedef DWORD (APIENTRY
* RASDELETEENTRY
)( LPCSTR
, LPCSTR
);
109 typedef DWORD (APIENTRY
* RASVALIDATEENTRYNAME
)( LPCSTR
, LPCSTR
);
110 typedef DWORD (APIENTRY
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD
);
112 static const wxChar gs_funcSuffix
= _T('A');
114 typedef DWORD (APIENTRY
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCWSTR
, LPRASDIALPARAMSW
, DWORD
, LPVOID
, LPHRASCONN
);
115 typedef DWORD (APIENTRY
* RASENUMCONNECTIONS
)( LPRASCONNW
, LPDWORD
, LPDWORD
);
116 typedef DWORD (APIENTRY
* RASENUMENTRIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYNAMEW
, LPDWORD
, LPDWORD
);
117 typedef DWORD (APIENTRY
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSW
);
118 typedef DWORD (APIENTRY
* RASGETERRORSTRING
)( UINT
, LPWSTR
, DWORD
);
119 typedef DWORD (APIENTRY
* RASHANGUP
)( HRASCONN
);
120 typedef DWORD (APIENTRY
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD
);
121 typedef DWORD (APIENTRY
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCWSTR
);
122 typedef DWORD (APIENTRY
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCWSTR
, LPCWSTR
);
123 typedef DWORD (APIENTRY
* RASSETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, BOOL
);
124 typedef DWORD (APIENTRY
* RASGETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, LPBOOL
);
125 typedef DWORD (APIENTRY
* RASENUMDEVICES
)( LPRASDEVINFOW
, LPDWORD
, LPDWORD
);
126 typedef DWORD (APIENTRY
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOW
, LPDWORD
);
127 typedef DWORD (APIENTRY
* RASGETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, LPDWORD
, LPBYTE
, LPDWORD
);
128 typedef DWORD (APIENTRY
* RASSETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, DWORD
, LPBYTE
, DWORD
);
129 typedef DWORD (APIENTRY
* RASRENAMEENTRY
)( LPCWSTR
, LPCWSTR
, LPCWSTR
);
130 typedef DWORD (APIENTRY
* RASDELETEENTRY
)( LPCWSTR
, LPCWSTR
);
131 typedef DWORD (APIENTRY
* RASVALIDATEENTRYNAME
)( LPCWSTR
, LPCWSTR
);
132 typedef DWORD (APIENTRY
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD
);
134 static const wxChar gs_funcSuffix
= _T('W');
135 #endif // ASCII/Unicode
137 // structure passed to the secondary thread
138 struct WXDLLEXPORT wxRasThreadData
143 hEventRas
= hEventQuit
= INVALID_HANDLE_VALUE
;
144 dialUpManager
= NULL
;
147 HWND hWnd
; // window to send notifications to
148 HANDLE hEventRas
, // event which RAS signals when status changes
149 hEventQuit
; // event which we signal when we terminate
151 class WXDLLEXPORT wxDialUpManagerMSW
*dialUpManager
; // the owner
154 // ----------------------------------------------------------------------------
155 // wxDialUpManager class for MSW
156 // ----------------------------------------------------------------------------
158 class WXDLLEXPORT wxDialUpManagerMSW
: public wxDialUpManager
162 wxDialUpManagerMSW();
163 virtual ~wxDialUpManagerMSW();
165 // implement base class pure virtuals
166 virtual bool IsOk() const;
167 virtual size_t GetISPNames(wxArrayString
& names
) const;
168 virtual bool Dial(const wxString
& nameOfISP
,
169 const wxString
& username
,
170 const wxString
& password
,
172 virtual bool IsDialing() const;
173 virtual bool CancelDialing();
174 virtual bool HangUp();
175 virtual bool IsAlwaysOnline() const;
176 virtual bool IsOnline() const;
177 virtual void SetOnlineStatus(bool isOnline
= TRUE
);
178 virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
);
179 virtual void DisableAutoCheckOnlineStatus();
180 virtual void SetWellKnownHost(const wxString
& hostname
, int port
);
181 virtual void SetConnectCommand(const wxString
& commandDial
,
182 const wxString
& commandHangup
);
185 void CheckRasStatus();
187 // for wxRasStatusWindowProc
188 void OnConnectStatusChange();
189 void OnDialProgress(RASCONNSTATE rasconnstate
, DWORD dwError
);
192 static HWND
GetRasWindow() { return ms_hwndRas
; }
193 static wxDialUpManagerMSW
*GetDialer() { return ms_dialer
; }
196 // return the error string for the given RAS error code
197 static wxString
GetErrorString(DWORD error
);
199 // find the (first) handle of the active connection
200 static HRASCONN
FindActiveConnection();
202 // notify the application about status change
203 void NotifyApp(bool connected
, bool fromOurselves
= FALSE
) const;
205 // destroy the thread data and the thread itself
206 void CleanUpThreadData();
208 // timer used for polling RAS status
209 class WXDLLEXPORT RasTimer
: public wxTimer
212 RasTimer(wxDialUpManagerMSW
*dialUpManager
)
213 { m_dialUpManager
= dialUpManager
; }
215 virtual void Notify() { m_dialUpManager
->CheckRasStatus(); }
218 wxDialUpManagerMSW
*m_dialUpManager
;
219 } m_timerStatusPolling
;
221 // thread handle for the thread sitting on connection change event
224 // data used by this thread and our hidden window to send messages between
226 wxRasThreadData m_data
;
228 // the handle of rasapi32.dll when it's loaded
229 wxPluginManager m_dllRas
;
231 // the hidden window we use for passing messages between threads
232 static HWND ms_hwndRas
;
234 // the handle of the connection we initiated or 0 if none
235 static HRASCONN ms_hRasConnection
;
237 // FIXME: There is probably no reason these really need to
238 // be static anymore since the dll refcounting is
239 // handled by wxPluginManager now. Whether or not
240 // we still _want_ them to be static is another
243 // the pointers to RAS functions
244 static RASDIAL ms_pfnRasDial
;
245 static RASENUMCONNECTIONS ms_pfnRasEnumConnections
;
246 static RASENUMENTRIES ms_pfnRasEnumEntries
;
247 static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus
;
248 static RASGETERRORSTRING ms_pfnRasGetErrorString
;
249 static RASHANGUP ms_pfnRasHangUp
;
250 static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo
;
251 static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry
;
252 static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry
;
253 static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams
;
254 static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams
;
255 static RASENUMDEVICES ms_pfnRasEnumDevices
;
256 static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo
;
257 static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties
;
258 static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties
;
259 static RASRENAMEENTRY ms_pfnRasRenameEntry
;
260 static RASDELETEENTRY ms_pfnRasDeleteEntry
;
261 static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName
;
263 // this function is not supported by Win95
264 static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification
;
266 // if this flag is different from -1, it overrides IsOnline()
267 static int ms_userSpecifiedOnlineStatus
;
269 // this flag tells us if we're online
270 static int ms_isConnected
;
272 // this flag tells us whether a call to RasDial() is in progress
273 static wxDialUpManagerMSW
*ms_dialer
;
276 // ----------------------------------------------------------------------------
278 // ----------------------------------------------------------------------------
280 static LRESULT WINAPI
wxRasStatusWindowProc(HWND hWnd
, UINT message
,
281 WPARAM wParam
, LPARAM lParam
);
283 static DWORD
wxRasMonitorThread(wxRasThreadData
*data
);
285 static void WINAPI
wxRasDialFunc(UINT unMsg
,
286 RASCONNSTATE rasconnstate
,
289 // ============================================================================
291 // ============================================================================
293 // ----------------------------------------------------------------------------
294 // init the static variables
295 // ----------------------------------------------------------------------------
297 HRASCONN wxDialUpManagerMSW
::ms_hRasConnection
= 0;
299 HWND wxDialUpManagerMSW
::ms_hwndRas
= 0;
301 RASDIAL wxDialUpManagerMSW
::ms_pfnRasDial
= 0;
302 RASENUMCONNECTIONS wxDialUpManagerMSW
::ms_pfnRasEnumConnections
= 0;
303 RASENUMENTRIES wxDialUpManagerMSW
::ms_pfnRasEnumEntries
= 0;
304 RASGETCONNECTSTATUS wxDialUpManagerMSW
::ms_pfnRasGetConnectStatus
= 0;
305 RASGETERRORSTRING wxDialUpManagerMSW
::ms_pfnRasGetErrorString
= 0;
306 RASHANGUP wxDialUpManagerMSW
::ms_pfnRasHangUp
= 0;
307 RASGETPROJECTIONINFO wxDialUpManagerMSW
::ms_pfnRasGetProjectionInfo
= 0;
308 RASCREATEPHONEBOOKENTRY wxDialUpManagerMSW
::ms_pfnRasCreatePhonebookEntry
= 0;
309 RASEDITPHONEBOOKENTRY wxDialUpManagerMSW
::ms_pfnRasEditPhonebookEntry
= 0;
310 RASSETENTRYDIALPARAMS wxDialUpManagerMSW
::ms_pfnRasSetEntryDialParams
= 0;
311 RASGETENTRYDIALPARAMS wxDialUpManagerMSW
::ms_pfnRasGetEntryDialParams
= 0;
312 RASENUMDEVICES wxDialUpManagerMSW
::ms_pfnRasEnumDevices
= 0;
313 RASGETCOUNTRYINFO wxDialUpManagerMSW
::ms_pfnRasGetCountryInfo
= 0;
314 RASGETENTRYPROPERTIES wxDialUpManagerMSW
::ms_pfnRasGetEntryProperties
= 0;
315 RASSETENTRYPROPERTIES wxDialUpManagerMSW
::ms_pfnRasSetEntryProperties
= 0;
316 RASRENAMEENTRY wxDialUpManagerMSW
::ms_pfnRasRenameEntry
= 0;
317 RASDELETEENTRY wxDialUpManagerMSW
::ms_pfnRasDeleteEntry
= 0;
318 RASVALIDATEENTRYNAME wxDialUpManagerMSW
::ms_pfnRasValidateEntryName
= 0;
319 RASCONNECTIONNOTIFICATION wxDialUpManagerMSW
::ms_pfnRasConnectionNotification
= 0;
321 int wxDialUpManagerMSW
::ms_userSpecifiedOnlineStatus
= -1;
322 int wxDialUpManagerMSW
::ms_isConnected
= -1;
323 wxDialUpManagerMSW
*wxDialUpManagerMSW
::ms_dialer
= NULL
;
325 // ----------------------------------------------------------------------------
326 // ctor and dtor: the dynamic linking happens here
327 // ----------------------------------------------------------------------------
329 // the static creator function is implemented here
330 wxDialUpManager
*wxDialUpManager
::Create()
332 return new wxDialUpManagerMSW
;
336 // warning about "'this' : used in base member initializer list" - so what?
337 #pragma warning(disable:4355)
340 wxDialUpManagerMSW
::wxDialUpManagerMSW()
341 : m_timerStatusPolling(this)
342 , m_dllRas(_T("RASAPI32"))
344 // initialize our data
347 if ( !m_dllRas
.IsLoaded() )
349 wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it."));
351 else if ( !ms_pfnRasDial
)
353 // resolve the functions we need
355 // this will contain the name of the function we failed to resolve
357 const char *funcName
= NULL
;
359 // get the function from rasapi32.dll and abort if it's not found
360 #define RESOLVE_RAS_FUNCTION(type, name) \
361 ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name)) \
363 if ( !ms_pfn##name ) \
369 // a variant of above macro which doesn't abort if the function is
370 // not found in the DLL
371 #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \
372 ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name)) \
375 RESOLVE_RAS_FUNCTION(RASDIAL
, RasDial
);
376 RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS
, RasEnumConnections
);
377 RESOLVE_RAS_FUNCTION(RASENUMENTRIES
, RasEnumEntries
);
378 RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS
, RasGetConnectStatus
);
379 RESOLVE_RAS_FUNCTION(RASGETERRORSTRING
, RasGetErrorString
);
380 RESOLVE_RAS_FUNCTION(RASHANGUP
, RasHangUp
);
381 RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS
, RasGetEntryDialParams
);
383 // suppress error messages about missing (non essential) functions
387 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO
, RasGetProjectionInfo
);
388 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY
, RasCreatePhonebookEntry
);
389 RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY
, RasEditPhonebookEntry
);
390 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS
, RasSetEntryDialParams
);
391 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES
, RasGetEntryProperties
);
392 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES
, RasSetEntryProperties
);
393 RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY
, RasRenameEntry
);
394 RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY
, RasDeleteEntry
);
395 RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME
, RasValidateEntryName
);
396 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO
, RasGetCountryInfo
);
397 RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES
, RasEnumDevices
);
398 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION
, RasConnectionNotification
);
401 // keep your preprocessor name space clean
402 #undef RESOLVE_RAS_FUNCTION
403 #undef RESOLVE_OPTIONAL_RAS_FUNCTION
408 static const wxChar
*msg
= wxTRANSLATE(
409 "The version of remote access service (RAS) installed on this machine is too\
410 old, please upgrade (the following required function is missing: %s)."
413 wxLogError(wxGetTranslation(msg
), funcName
);
419 // enable auto check by default
420 EnableAutoCheckOnlineStatus(0);
423 wxDialUpManagerMSW
::~wxDialUpManagerMSW()
428 // ----------------------------------------------------------------------------
430 // ----------------------------------------------------------------------------
432 wxString wxDialUpManagerMSW
::GetErrorString(DWORD error
)
434 wxChar buffer
[512]; // this should be more than enough according to MS docs
435 DWORD dwRet
= ms_pfnRasGetErrorString(error
, buffer
, WXSIZEOF(buffer
));
438 case ERROR_INVALID_PARAMETER
:
439 // this was a standard Win32 error probably
440 return wxString(wxSysErrorMsg(error
));
445 _("Failed to retrieve text of RAS error message"));
448 msg
.Printf(_("unknown error (error code %08x)."), error
);
453 // we want the error message to start from a lower case letter
454 buffer
[0] = wxTolower(buffer
[0]);
456 return wxString(buffer
);
460 HRASCONN wxDialUpManagerMSW
::FindActiveConnection()
462 // enumerate connections
463 DWORD cbBuf
= sizeof(RASCONN
);
464 LPRASCONN lpRasConn
= (LPRASCONN
)malloc(cbBuf
);
471 lpRasConn
->dwSize
= sizeof(RASCONN
);
473 DWORD nConnections
= 0;
474 DWORD dwRet
= ERROR_BUFFER_TOO_SMALL
;
476 while ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
478 dwRet
= ms_pfnRasEnumConnections(lpRasConn
, &cbBuf
, &nConnections
);
480 if ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
482 LPRASCONN lpRasConnOld
= lpRasConn
;
483 lpRasConn
= (LPRASCONN
)realloc(lpRasConn
, cbBuf
);
492 else if ( dwRet
== 0 )
500 wxLogError(_("Cannot find active dialup connection: %s"),
501 GetErrorString(dwRet
).c_str());
508 switch ( nConnections
)
516 // more than 1 connection - we don't know what to do with this
517 // case, so give a warning but continue (taking the first
518 // connection) - the warning is really needed because this function
519 // is used, for example, to select the connection to hang up and so
520 // we may hang up the wrong connection here...
521 wxLogWarning(_("Several active dialup connections found, choosing one randomly."));
525 // exactly 1 connection, great
526 hrasconn
= lpRasConn
->hrasconn
;
534 void wxDialUpManagerMSW
::CleanUpThreadData()
538 if ( !SetEvent(m_data
.hEventQuit
) )
540 wxLogLastError(_T("SetEvent(RasThreadQuit)"));
543 CloseHandle(m_hThread
);
550 DestroyWindow(m_data
.hWnd
);
555 if ( m_data
.hEventQuit
)
557 CloseHandle(m_data
.hEventQuit
);
559 m_data
.hEventQuit
= 0;
562 if ( m_data
.hEventRas
)
564 CloseHandle(m_data
.hEventRas
);
566 m_data
.hEventRas
= 0;
570 // ----------------------------------------------------------------------------
572 // ----------------------------------------------------------------------------
574 void wxDialUpManagerMSW
::CheckRasStatus()
576 // use int, not bool to compare with -1
577 int isConnected
= FindActiveConnection() != 0;
578 if ( isConnected
!= ms_isConnected
)
580 if ( ms_isConnected
!= -1 )
582 // notify the program
583 NotifyApp(isConnected
!= 0);
585 // else: it's the first time we're called, just update the flag
587 ms_isConnected
= isConnected
;
591 void wxDialUpManagerMSW
::NotifyApp(bool connected
, bool fromOurselves
) const
593 wxDialUpEvent
event(connected
, fromOurselves
);
594 (void)wxTheApp
->ProcessEvent(event
);
597 // this function is called whenever the status of any RAS connection on this
598 // machine changes by RAS itself
599 void wxDialUpManagerMSW
::OnConnectStatusChange()
601 // we know that status changed, but we don't know whether we're connected
602 // or not - so find it out
606 // this function is called by our callback which we give to RasDial() when
607 // calling it asynchronously
608 void wxDialUpManagerMSW
::OnDialProgress(RASCONNSTATE rasconnstate
,
613 // this probably means that CancelDialing() was called and we get
614 // "disconnected" notification
618 // we're only interested in 2 events: connected and disconnected
621 wxLogError(_("Failed to establish dialup connection: %s"),
622 GetErrorString(dwError
).c_str());
624 // we should still call RasHangUp() if we got a non 0 connection
625 if ( ms_hRasConnection
)
627 ms_pfnRasHangUp(ms_hRasConnection
);
628 ms_hRasConnection
= 0;
633 NotifyApp(FALSE
/* !connected */, TRUE
/* we dialed ourselves */);
635 else if ( rasconnstate
== RASCS_Connected
)
637 ms_isConnected
= TRUE
;
640 NotifyApp(TRUE
/* connected */, TRUE
/* we dialed ourselves */);
644 // ----------------------------------------------------------------------------
645 // implementation of wxDialUpManager functions
646 // ----------------------------------------------------------------------------
648 bool wxDialUpManagerMSW
::IsOk() const
650 return m_dllRas
.IsLoaded();
653 size_t wxDialUpManagerMSW
::GetISPNames(wxArrayString
& names
) const
656 DWORD size
= sizeof(RASENTRYNAME
);
657 RASENTRYNAME
*rasEntries
= (RASENTRYNAME
*)malloc(size
);
658 rasEntries
->dwSize
= sizeof(RASENTRYNAME
);
664 dwRet
= ms_pfnRasEnumEntries
667 NULL
, // default phone book (or all)
668 rasEntries
, // [out] buffer for the entries
669 &size
, // [in/out] size of the buffer
670 &nEntries
// [out] number of entries fetched
673 if ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
675 // reallocate the buffer
676 rasEntries
= (RASENTRYNAME
*)realloc(rasEntries
, size
);
678 else if ( dwRet
!= 0 )
680 // some other error - abort
681 wxLogError(_("Failed to get ISP names: %s"),
682 GetErrorString(dwRet
).c_str());
689 while ( dwRet
!= 0 );
693 for ( size_t n
= 0; n
< (size_t)nEntries
; n
++ )
695 names
.Add(rasEntries
[n
].szEntryName
);
700 // return the number of entries
701 return names
.GetCount();
704 bool wxDialUpManagerMSW
::Dial(const wxString
& nameOfISP
,
705 const wxString
& username
,
706 const wxString
& password
,
709 // check preconditions
710 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
712 if ( ms_hRasConnection
)
714 wxFAIL_MSG(wxT("there is already an active connection"));
719 // get the default ISP if none given
720 wxString
entryName(nameOfISP
);
724 size_t count
= GetISPNames(names
);
728 // no known ISPs, abort
729 wxLogError(_("Failed to connect: no ISP to dial."));
734 // only one ISP, choose it
735 entryName
= names
[0u];
739 // several ISPs, let the user choose
741 wxString
*strings
= new wxString
[count
];
742 for ( size_t i
= 0; i
< count
; i
++ )
744 strings
[i
] = names
[i
];
747 entryName
= wxGetSingleChoice
749 _("Choose ISP to dial"),
750 _("Please choose which ISP do you want to connect to"),
766 RASDIALPARAMS rasDialParams
;
767 rasDialParams
.dwSize
= sizeof(rasDialParams
);
768 wxStrncpy(rasDialParams
.szEntryName
, entryName
, RAS_MaxEntryName
);
770 // do we have the username and password?
771 if ( !username
|| !password
)
774 DWORD dwRet
= ms_pfnRasGetEntryDialParams
776 NULL
, // default phonebook
777 &rasDialParams
, // [in/out] the params of this entry
778 &gotPassword
// [out] did we get password?
783 wxLogError(_("Failed to connect: missing username/password."));
790 wxStrncpy(rasDialParams
.szUserName
, username
, UNLEN
);
791 wxStrncpy(rasDialParams
.szPassword
, password
, PWLEN
);
794 // default values for other fields
795 rasDialParams
.szPhoneNumber
[0] = '\0';
796 rasDialParams
.szCallbackNumber
[0] = '\0';
797 rasDialParams
.szCallbackNumber
[0] = '\0';
799 rasDialParams
.szDomain
[0] = '*';
800 rasDialParams
.szDomain
[1] = '\0';
802 // apparently, this is not really necessary - passing NULL instead of the
803 // phone book has the same effect
806 if ( wxGetOsVersion() == wxWINDOWS_NT
)
808 // first get the length
809 UINT nLen
= ::GetSystemDirectory(NULL
, 0);
812 if ( !::GetSystemDirectory(phoneBook
.GetWriteBuf(nLen
), nLen
) )
814 wxLogSysError(_("Cannot find the location of address book file"));
817 phoneBook
.UngetWriteBuf();
819 // this is the default phone book
820 phoneBook
<< "\\ras\\rasphone.pbk";
824 // TODO may be we should disable auto check while async dialing is in
829 DWORD dwRet
= ms_pfnRasDial
831 NULL
, // no extended features
832 NULL
, // default phone book file (NT only)
834 0, // use callback for notifications
835 async ?
(void *)wxRasDialFunc
// cast needed for gcc 3.1
836 : 0, // no notifications, sync operation
842 // can't pass a wxWCharBuffer through ( ... )
843 wxLogError(_("Failed to %s dialup connection: %s"),
844 wxString(async ?
_("initiate") : _("establish")).c_str(),
845 GetErrorString(dwRet
).c_str());
847 // we should still call RasHangUp() if we got a non 0 connection
848 if ( ms_hRasConnection
)
850 ms_pfnRasHangUp(ms_hRasConnection
);
851 ms_hRasConnection
= 0;
859 // for async dialing, we're not yet connected
862 ms_isConnected
= TRUE
;
868 bool wxDialUpManagerMSW
::IsDialing() const
870 return GetDialer() != NULL
;
873 bool wxDialUpManagerMSW
::CancelDialing()
881 wxASSERT_MSG( ms_hRasConnection
, wxT("dialing but no connection?") );
888 bool wxDialUpManagerMSW
::HangUp()
890 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
892 // we may terminate either the connection we initiated or another one which
895 if ( ms_hRasConnection
)
897 hRasConn
= ms_hRasConnection
;
899 ms_hRasConnection
= 0;
903 hRasConn
= FindActiveConnection();
908 wxLogError(_("Cannot hang up - no active dialup connection."));
913 DWORD dwRet
= ms_pfnRasHangUp(hRasConn
);
916 wxLogError(_("Failed to terminate the dialup connection: %s"),
917 GetErrorString(dwRet
).c_str());
920 ms_isConnected
= FALSE
;
925 bool wxDialUpManagerMSW
::IsAlwaysOnline() const
927 // assume no permanent connection by default
928 bool isAlwaysOnline
= FALSE
;
930 // try to use WinInet functions
932 // NB: we could probably use wxDynamicLibrary here just as well,
933 // but we allow multiple instances of wxDialUpManagerMSW so
934 // we might as well use the ref counted version here too.
936 wxPluginManager
hDll(_T("WININET"));
937 if ( hDll
.IsLoaded() )
939 typedef BOOL (WINAPI
*INTERNETGETCONNECTEDSTATE
)(LPDWORD
, DWORD
);
940 INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState
;
942 #define RESOLVE_FUNCTION(type, name) \
943 pfn##name = (type)hDll.GetSymbol(_T(#name))
945 RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE
, InternetGetConnectedState
);
947 if ( pfnInternetGetConnectedState
)
950 if ( pfnInternetGetConnectedState(&flags
, 0 /* reserved */) )
952 // there is some connection to the net, see of which type
953 isAlwaysOnline
= (flags
& (INTERNET_CONNECTION_LAN
|
954 INTERNET_CONNECTION_PROXY
)) != 0;
956 //else: no Internet connection at all
960 return isAlwaysOnline
;
963 bool wxDialUpManagerMSW
::IsOnline() const
965 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
967 if ( ms_userSpecifiedOnlineStatus
!= -1 )
969 // user specified flag overrides our logic
970 return ms_userSpecifiedOnlineStatus
!= 0;
974 // return TRUE if there is at least one active connection
975 return FindActiveConnection() != 0;
979 void wxDialUpManagerMSW
::SetOnlineStatus(bool isOnline
)
981 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
983 ms_userSpecifiedOnlineStatus
= isOnline
;
986 bool wxDialUpManagerMSW
::EnableAutoCheckOnlineStatus(size_t nSeconds
)
988 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
990 bool ok
= ms_pfnRasConnectionNotification
!= 0;
994 // we're running under NT 4.0, Windows 98 or later and can use
995 // RasConnectionNotification() to be notified by a secondary thread
997 // first, see if we don't have this thread already running
998 if ( m_hThread
!= 0 )
1000 DWORD dwSuspendCount
= 2;
1001 while ( dwSuspendCount
> 1 )
1003 dwSuspendCount
= ResumeThread(m_hThread
);
1004 if ( dwSuspendCount
== (DWORD
)-1 )
1006 wxLogLastError(wxT("ResumeThread(RasThread)"));
1019 // create all the stuff we need to be notified about RAS connection
1024 // first create an event to wait on
1025 m_data
.hEventRas
= CreateEvent
1027 NULL
, // security attribute (default)
1028 FALSE
, // manual reset (not)
1029 FALSE
, // initial state (not signaled)
1032 if ( !m_data
.hEventRas
)
1034 wxLogLastError(wxT("CreateEvent(RasStatus)"));
1042 // create the event we use to quit the thread
1043 m_data
.hEventQuit
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1044 if ( !m_data
.hEventQuit
)
1046 wxLogLastError(wxT("CreateEvent(RasThreadQuit)"));
1048 CleanUpThreadData();
1054 if ( ok
&& !ms_hwndRas
)
1056 // create a hidden window to receive notification about connections
1058 extern const wxChar
*wxCanvasClassName
;
1059 ms_hwndRas
= ::CreateWindow(wxCanvasClassName
, NULL
,
1062 (HMENU
)NULL
, wxGetInstance(), 0);
1065 wxLogLastError(wxT("CreateWindow(RasHiddenWindow)"));
1067 CleanUpThreadData();
1073 FARPROC windowProc
= MakeProcInstance
1075 (FARPROC
)wxRasStatusWindowProc
,
1079 ::SetWindowLong(ms_hwndRas
, GWL_WNDPROC
, (LONG
) windowProc
);
1082 m_data
.hWnd
= ms_hwndRas
;
1086 // start the secondary thread
1087 m_data
.dialUpManager
= this;
1090 m_hThread
= CreateThread
1094 (LPTHREAD_START_ROUTINE
)wxRasMonitorThread
,
1102 wxLogLastError(wxT("CreateThread(RasStatusThread)"));
1104 CleanUpThreadData();
1110 // start receiving RAS notifications
1111 DWORD dwRet
= ms_pfnRasConnectionNotification
1113 (HRASCONN
)INVALID_HANDLE_VALUE
,
1115 3 /* RASCN_Connection | RASCN_Disconnection */
1120 wxLogDebug(wxT("RasConnectionNotification() failed: %s"),
1121 GetErrorString(dwRet
).c_str());
1123 CleanUpThreadData();
1131 // we're running under Windows 95 and have to poll ourselves
1132 // (or, alternatively, the code above for NT/98 failed)
1133 m_timerStatusPolling
.Stop();
1134 if ( nSeconds
== 0 )
1139 m_timerStatusPolling
.Start(nSeconds
* 1000);
1144 void wxDialUpManagerMSW
::DisableAutoCheckOnlineStatus()
1146 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1150 // we have running secondary thread, it's just enough to suspend it
1151 if ( SuspendThread(m_hThread
) == (DWORD
)-1 )
1153 wxLogLastError(wxT("SuspendThread(RasThread)"));
1158 // even simpler - just stop the timer
1159 m_timerStatusPolling
.Stop();
1163 // ----------------------------------------------------------------------------
1164 // stubs which don't do anything in MSW version
1165 // ----------------------------------------------------------------------------
1167 void wxDialUpManagerMSW
::SetWellKnownHost(const wxString
& WXUNUSED(hostname
),
1170 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1172 // nothing to do - we don't use this
1175 void wxDialUpManagerMSW
::SetConnectCommand(const wxString
& WXUNUSED(dial
),
1176 const wxString
& WXUNUSED(hangup
))
1178 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1180 // nothing to do - we don't use this
1183 // ----------------------------------------------------------------------------
1185 // ----------------------------------------------------------------------------
1187 static DWORD
wxRasMonitorThread(wxRasThreadData
*data
)
1190 handles
[0] = data
->hEventRas
;
1191 handles
[1] = data
->hEventQuit
;
1196 DWORD dwRet
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1201 // RAS connection status changed
1202 SendMessage(data
->hWnd
, wxWM_RAS_STATUS_CHANGED
,
1206 case WAIT_OBJECT_0
+ 1:
1211 wxLogLastError(wxT("WaitForMultipleObjects(RasMonitor)"));
1219 static LRESULT APIENTRY
wxRasStatusWindowProc(HWND hWnd
, UINT message
,
1220 WPARAM wParam
, LPARAM lParam
)
1224 case wxWM_RAS_STATUS_CHANGED
:
1226 wxRasThreadData
*data
= (wxRasThreadData
*)lParam
;
1227 data
->dialUpManager
->OnConnectStatusChange();
1231 case wxWM_RAS_DIALING_PROGRESS
:
1233 wxDialUpManagerMSW
*dialMan
= wxDialUpManagerMSW
::GetDialer();
1235 dialMan
->OnDialProgress((RASCONNSTATE
)wParam
, lParam
);
1240 return ::DefWindowProc(hWnd
, message
, wParam
, lParam
);
1246 static void WINAPI
wxRasDialFunc(UINT unMsg
,
1247 RASCONNSTATE rasconnstate
,
1250 wxDialUpManagerMSW
*dialUpManager
= wxDialUpManagerMSW
::GetDialer();
1252 wxCHECK_RET( dialUpManager
, wxT("who started to dial then?") );
1254 SendMessage(dialUpManager
->GetRasWindow(), wxWM_RAS_DIALING_PROGRESS
,
1255 rasconnstate
, dwError
);
1258 #endif // __BORLANDC__
1260 #endif // wxUSE_DIALUP_MANAGER