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
39 #include "wx/dynlib.h"
41 #include "wx/dialup.h"
43 // Doesn't yet compile under BC++: no wininet.h
51 #include "wx/msw/private.h"
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 // this message is sent by the secondary thread when RAS status changes
58 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010)
59 #define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011)
61 // ----------------------------------------------------------------------------
63 // ----------------------------------------------------------------------------
65 // the signatures of RAS functions: all this is quite heavy, but we must do it
66 // to allow running wxWin programs on machine which don't have RAS installed
67 // (this does exist) - if we link with rasapi32.lib, the program will fail on
68 // startup because of the missing DLL...
71 typedef DWORD (APIENTRY
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCSTR
, LPRASDIALPARAMSA
, DWORD
, LPVOID
, LPHRASCONN
);
72 typedef DWORD (APIENTRY
* RASENUMCONNECTIONS
)( LPRASCONNA
, LPDWORD
, LPDWORD
);
73 typedef DWORD (APIENTRY
* RASENUMENTRIES
)( LPCSTR
, LPCSTR
, LPRASENTRYNAMEA
, LPDWORD
, LPDWORD
);
74 typedef DWORD (APIENTRY
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSA
);
75 typedef DWORD (APIENTRY
* RASGETERRORSTRING
)( UINT
, LPSTR
, DWORD
);
76 typedef DWORD (APIENTRY
* RASHANGUP
)( HRASCONN
);
77 typedef DWORD (APIENTRY
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD
);
78 typedef DWORD (APIENTRY
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCSTR
);
79 typedef DWORD (APIENTRY
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCSTR
, LPCSTR
);
80 typedef DWORD (APIENTRY
* RASSETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, BOOL
);
81 typedef DWORD (APIENTRY
* RASGETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, LPBOOL
);
82 typedef DWORD (APIENTRY
* RASENUMDEVICES
)( LPRASDEVINFOA
, LPDWORD
, LPDWORD
);
83 typedef DWORD (APIENTRY
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOA
, LPDWORD
);
84 typedef DWORD (APIENTRY
* RASGETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, LPDWORD
, LPBYTE
, LPDWORD
);
85 typedef DWORD (APIENTRY
* RASSETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, DWORD
, LPBYTE
, DWORD
);
86 typedef DWORD (APIENTRY
* RASRENAMEENTRY
)( LPCSTR
, LPCSTR
, LPCSTR
);
87 typedef DWORD (APIENTRY
* RASDELETEENTRY
)( LPCSTR
, LPCSTR
);
88 typedef DWORD (APIENTRY
* RASVALIDATEENTRYNAME
)( LPCSTR
, LPCSTR
);
89 typedef DWORD (APIENTRY
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD
);
91 static const char gs_funcSuffix
= 'A';
93 typedef DWORD (APIENTRY
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCWSTR
, LPRASDIALPARAMSW
, DWORD
, LPVOID
, LPHRASCONN
);
94 typedef DWORD (APIENTRY
* RASENUMCONNECTIONS
)( LPRASCONNW
, LPDWORD
, LPDWORD
);
95 typedef DWORD (APIENTRY
* RASENUMENTRIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYNAMEW
, LPDWORD
, LPDWORD
);
96 typedef DWORD (APIENTRY
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSW
);
97 typedef DWORD (APIENTRY
* RASGETERRORSTRING
)( UINT
, LPWSTR
, DWORD
);
98 typedef DWORD (APIENTRY
* RASHANGUP
)( HRASCONN
);
99 typedef DWORD (APIENTRY
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD
);
100 typedef DWORD (APIENTRY
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCWSTR
);
101 typedef DWORD (APIENTRY
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCWSTR
, LPCWSTR
);
102 typedef DWORD (APIENTRY
* RASSETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, BOOL
);
103 typedef DWORD (APIENTRY
* RASGETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, LPBOOL
);
104 typedef DWORD (APIENTRY
* RASENUMDEVICES
)( LPRASDEVINFOW
, LPDWORD
, LPDWORD
);
105 typedef DWORD (APIENTRY
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOW
, LPDWORD
);
106 typedef DWORD (APIENTRY
* RASGETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, LPDWORD
, LPBYTE
, LPDWORD
);
107 typedef DWORD (APIENTRY
* RASSETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, DWORD
, LPBYTE
, DWORD
);
108 typedef DWORD (APIENTRY
* RASRENAMEENTRY
)( LPCWSTR
, LPCWSTR
, LPCWSTR
);
109 typedef DWORD (APIENTRY
* RASDELETEENTRY
)( LPCWSTR
, LPCWSTR
);
110 typedef DWORD (APIENTRY
* RASVALIDATEENTRYNAME
)( LPCWSTR
, LPCWSTR
);
111 typedef DWORD (APIENTRY
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD
);
113 static const char gs_funcSuffix
= 'W';
114 #endif // ASCII/Unicode
116 // structure passed to the secondary thread
117 struct wxRasThreadData
122 hEventRas
= hEventQuit
= INVALID_HANDLE_VALUE
;
123 dialUpManager
= NULL
;
126 HWND hWnd
; // window to send notifications to
127 HANDLE hEventRas
, // event which RAS signals when status changes
128 hEventQuit
; // event which we signal when we terminate
130 class WXDLLEXPORT wxDialUpManagerMSW
*dialUpManager
; // the owner
133 // ----------------------------------------------------------------------------
134 // wxDialUpManager class for MSW
135 // ----------------------------------------------------------------------------
137 class WXDLLEXPORT wxDialUpManagerMSW
: public wxDialUpManager
141 wxDialUpManagerMSW();
142 virtual ~wxDialUpManagerMSW();
144 // implement base class pure virtuals
145 virtual bool IsOk() const;
146 virtual size_t GetISPNames(wxArrayString
& names
) const;
147 virtual bool Dial(const wxString
& nameOfISP
,
148 const wxString
& username
,
149 const wxString
& password
,
151 virtual bool IsDialing() const;
152 virtual bool CancelDialing();
153 virtual bool HangUp();
154 virtual bool IsAlwaysOnline() const;
155 virtual bool IsOnline() const;
156 virtual void SetOnlineStatus(bool isOnline
= TRUE
);
157 virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
);
158 virtual void DisableAutoCheckOnlineStatus();
159 virtual void SetWellKnownHost(const wxString
& hostname
, int port
);
160 virtual void SetConnectCommand(const wxString
& commandDial
,
161 const wxString
& commandHangup
);
164 void CheckRasStatus();
166 // for wxRasStatusWindowProc
167 void OnConnectStatusChange();
168 void OnDialProgress(RASCONNSTATE rasconnstate
, DWORD dwError
);
171 static HWND
GetRasWindow() { return ms_hwndRas
; }
172 static wxDialUpManagerMSW
*GetDialer() { return ms_dialer
; }
175 // return the error string for the given RAS error code
176 static wxString
GetErrorString(DWORD error
);
178 // find the (first) handle of the active connection
179 static HRASCONN
FindActiveConnection();
181 // notify the application about status change
182 void NotifyApp(bool connected
, bool fromOurselves
= FALSE
) const;
184 // destroy the thread data and the thread itself
185 void CleanUpThreadData();
187 // timer used for polling RAS status
188 class RasTimer
: public wxTimer
191 RasTimer(wxDialUpManagerMSW
*dialUpManager
)
192 { m_dialUpManager
= dialUpManager
; }
194 virtual void Notify() { m_dialUpManager
->CheckRasStatus(); }
197 wxDialUpManagerMSW
*m_dialUpManager
;
198 } m_timerStatusPolling
;
200 // thread handle for the thread sitting on connection change event
203 // data used by this thread and our hidden window to send messages between
205 wxRasThreadData m_data
;
207 // the hidden window we use for passing messages between threads
208 static HWND ms_hwndRas
;
210 // the handle of the connection we initiated or 0 if none
211 static HRASCONN ms_hRasConnection
;
213 // the use count of rasapi32.dll
214 static int ms_nDllCount
;
216 // the handle of rasapi32.dll when it's loaded
217 static wxDllType ms_dllRas
;
219 // the pointers to RAS functions
220 static RASDIAL ms_pfnRasDial
;
221 static RASENUMCONNECTIONS ms_pfnRasEnumConnections
;
222 static RASENUMENTRIES ms_pfnRasEnumEntries
;
223 static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus
;
224 static RASGETERRORSTRING ms_pfnRasGetErrorString
;
225 static RASHANGUP ms_pfnRasHangUp
;
226 static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo
;
227 static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry
;
228 static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry
;
229 static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams
;
230 static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams
;
231 static RASENUMDEVICES ms_pfnRasEnumDevices
;
232 static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo
;
233 static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties
;
234 static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties
;
235 static RASRENAMEENTRY ms_pfnRasRenameEntry
;
236 static RASDELETEENTRY ms_pfnRasDeleteEntry
;
237 static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName
;
239 // this function is not supported by Win95
240 static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification
;
242 // if this flag is different from -1, it overrides IsOnline()
243 static int ms_userSpecifiedOnlineStatus
;
245 // this flag tells us if we're online
246 static int ms_isConnected
;
248 // this flag is the result of the call to IsAlwaysOnline() (-1 if not
250 static int ms_isAlwaysOnline
;
252 // this flag tells us whether a call to RasDial() is in progress
253 static wxDialUpManagerMSW
*ms_dialer
;
256 // ----------------------------------------------------------------------------
258 // ----------------------------------------------------------------------------
260 static LRESULT WINAPI
wxRasStatusWindowProc(HWND hWnd
, UINT message
,
261 WPARAM wParam
, LPARAM lParam
);
263 static DWORD
wxRasMonitorThread(wxRasThreadData
*data
);
265 static void WINAPI
wxRasDialFunc(UINT unMsg
,
266 RASCONNSTATE rasconnstate
,
269 // ============================================================================
271 // ============================================================================
273 // ----------------------------------------------------------------------------
274 // init the static variables
275 // ----------------------------------------------------------------------------
277 HRASCONN
wxDialUpManagerMSW::ms_hRasConnection
= 0;
279 HWND
wxDialUpManagerMSW::ms_hwndRas
= 0;
281 int wxDialUpManagerMSW::ms_nDllCount
= 0;
282 wxDllType
wxDialUpManagerMSW::ms_dllRas
= 0;
284 RASDIAL
wxDialUpManagerMSW::ms_pfnRasDial
= 0;
285 RASENUMCONNECTIONS
wxDialUpManagerMSW::ms_pfnRasEnumConnections
= 0;
286 RASENUMENTRIES
wxDialUpManagerMSW::ms_pfnRasEnumEntries
= 0;
287 RASGETCONNECTSTATUS
wxDialUpManagerMSW::ms_pfnRasGetConnectStatus
= 0;
288 RASGETERRORSTRING
wxDialUpManagerMSW::ms_pfnRasGetErrorString
= 0;
289 RASHANGUP
wxDialUpManagerMSW::ms_pfnRasHangUp
= 0;
290 RASGETPROJECTIONINFO
wxDialUpManagerMSW::ms_pfnRasGetProjectionInfo
= 0;
291 RASCREATEPHONEBOOKENTRY
wxDialUpManagerMSW::ms_pfnRasCreatePhonebookEntry
= 0;
292 RASEDITPHONEBOOKENTRY
wxDialUpManagerMSW::ms_pfnRasEditPhonebookEntry
= 0;
293 RASSETENTRYDIALPARAMS
wxDialUpManagerMSW::ms_pfnRasSetEntryDialParams
= 0;
294 RASGETENTRYDIALPARAMS
wxDialUpManagerMSW::ms_pfnRasGetEntryDialParams
= 0;
295 RASENUMDEVICES
wxDialUpManagerMSW::ms_pfnRasEnumDevices
= 0;
296 RASGETCOUNTRYINFO
wxDialUpManagerMSW::ms_pfnRasGetCountryInfo
= 0;
297 RASGETENTRYPROPERTIES
wxDialUpManagerMSW::ms_pfnRasGetEntryProperties
= 0;
298 RASSETENTRYPROPERTIES
wxDialUpManagerMSW::ms_pfnRasSetEntryProperties
= 0;
299 RASRENAMEENTRY
wxDialUpManagerMSW::ms_pfnRasRenameEntry
= 0;
300 RASDELETEENTRY
wxDialUpManagerMSW::ms_pfnRasDeleteEntry
= 0;
301 RASVALIDATEENTRYNAME
wxDialUpManagerMSW::ms_pfnRasValidateEntryName
= 0;
302 RASCONNECTIONNOTIFICATION
wxDialUpManagerMSW::ms_pfnRasConnectionNotification
= 0;
304 int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus
= -1;
305 int wxDialUpManagerMSW::ms_isConnected
= -1;
306 int wxDialUpManagerMSW::ms_isAlwaysOnline
= -1;
307 wxDialUpManagerMSW
*wxDialUpManagerMSW::ms_dialer
= NULL
;
309 // ----------------------------------------------------------------------------
310 // ctor and dtor: the dynamic linking happens here
311 // ----------------------------------------------------------------------------
313 // the static creator function is implemented here
314 wxDialUpManager
*wxDialUpManager::Create()
316 return new wxDialUpManagerMSW
;
320 // warning about "'this' : used in base member initializer list" - so what?
321 #pragma warning(disable:4355)
324 wxDialUpManagerMSW::wxDialUpManagerMSW()
325 : m_timerStatusPolling(this)
327 // initialize our data
330 if ( !ms_nDllCount
++ )
332 // load the RAS library
333 ms_dllRas
= wxDllLoader::LoadLibrary("RASAPI32");
336 wxLogError(_("Dial up functions are unavailable because the "
337 "remote access service (RAS) is not installed "
338 "on this machine. Please install it."));
342 // resolve the functions we need
344 // this will contain the name of the function we failed to resolve
346 const char *funcName
= NULL
;
348 // get the function from rasapi32.dll and abort if it's not found
349 #define RESOLVE_RAS_FUNCTION(type, name) \
350 ms_pfn##name = (type)wxDllLoader::GetSymbol(ms_dllRas, \
351 wxString(_T(#name)) + gs_funcSuffix); \
352 if ( !ms_pfn##name ) \
358 // a variant of above macro which doesn't abort if the function is
359 // not found in the DLL
360 #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \
361 ms_pfn##name = (type)wxDllLoader::GetSymbol(ms_dllRas, \
362 wxString(_T(#name)) + gs_funcSuffix);
364 RESOLVE_RAS_FUNCTION(RASDIAL
, RasDial
);
365 RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS
, RasEnumConnections
);
366 RESOLVE_RAS_FUNCTION(RASENUMENTRIES
, RasEnumEntries
);
367 RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS
, RasGetConnectStatus
);
368 RESOLVE_RAS_FUNCTION(RASGETERRORSTRING
, RasGetErrorString
);
369 RESOLVE_RAS_FUNCTION(RASHANGUP
, RasHangUp
);
370 RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS
, RasGetEntryDialParams
);
372 // suppress wxDllLoader messages about missing (non essential)
377 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO
, RasGetProjectionInfo
);
378 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY
, RasCreatePhonebookEntry
);
379 RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY
, RasEditPhonebookEntry
);
380 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS
, RasSetEntryDialParams
);
381 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES
, RasGetEntryProperties
);
382 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES
, RasSetEntryProperties
);
383 RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY
, RasRenameEntry
);
384 RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY
, RasDeleteEntry
);
385 RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME
, RasValidateEntryName
);
386 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO
, RasGetCountryInfo
);
387 RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES
, RasEnumDevices
);
388 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION
, RasConnectionNotification
);
391 // keep your preprocessor name space clean
392 #undef RESOLVE_RAS_FUNCTION
393 #undef RESOLVE_OPTIONAL_RAS_FUNCTION
398 wxLogError(_("The version of remote access service (RAS) "
399 "installed on this machine is too old, please "
400 "upgrade (the following required function is "
401 "missing: %s)."), funcName
);
403 wxDllLoader::UnloadLibrary(ms_dllRas
);
412 // enable auto check by default
413 EnableAutoCheckOnlineStatus(0);
416 wxDialUpManagerMSW::~wxDialUpManagerMSW()
420 if ( !--ms_nDllCount
)
422 // unload the RAS library
423 wxDllLoader::UnloadLibrary(ms_dllRas
);
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
));
444 wxLogSysError(dwRet
, _("Failed to retrieve text of RAS "
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
));
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, "
522 "choosing one randomly."));
526 // exactly 1 connection, great
527 hrasconn
= lpRasConn
->hrasconn
;
535 void wxDialUpManagerMSW::CleanUpThreadData()
539 if ( !SetEvent(m_data
.hEventQuit
) )
541 wxLogLastError("SetEvent(RasThreadQuit)");
544 CloseHandle(m_hThread
);
551 DestroyWindow(m_data
.hWnd
);
556 if ( m_data
.hEventQuit
)
558 CloseHandle(m_data
.hEventQuit
);
560 m_data
.hEventQuit
= 0;
563 if ( m_data
.hEventRas
)
565 CloseHandle(m_data
.hEventRas
);
567 m_data
.hEventRas
= 0;
571 // ----------------------------------------------------------------------------
573 // ----------------------------------------------------------------------------
575 void wxDialUpManagerMSW::CheckRasStatus()
577 // use int, not bool to compare with -1
578 int isConnected
= FindActiveConnection() != 0;
579 if ( isConnected
!= ms_isConnected
)
581 if ( ms_isConnected
!= -1 )
583 // notify the program
584 NotifyApp(isConnected
!= 0);
586 // else: it's the first time we're called, just update the flag
588 ms_isConnected
= isConnected
;
592 void wxDialUpManagerMSW::NotifyApp(bool connected
, bool fromOurselves
) const
594 wxDialUpEvent
event(connected
, fromOurselves
);
595 (void)wxTheApp
->ProcessEvent(event
);
598 // this function is called whenever the status of any RAS connection on this
599 // machine changes by RAS itself
600 void wxDialUpManagerMSW::OnConnectStatusChange()
602 // we know that status changed, but we don't know whether we're connected
603 // or not - so find it out
607 // this function is called by our callback which we give to RasDial() when
608 // calling it asynchronously
609 void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate
,
614 // this probably means that CancelDialing() was called and we get
615 // "disconnected" notification
619 // we're only interested in 2 events: connected and disconnected
622 wxLogError(_("Failed to establish dialup connection: %s"),
623 GetErrorString(dwError
));
625 // we should still call RasHangUp() if we got a non 0 connection
626 if ( ms_hRasConnection
)
628 ms_pfnRasHangUp(ms_hRasConnection
);
629 ms_hRasConnection
= 0;
634 NotifyApp(FALSE
/* !connected */, TRUE
/* we dialed ourselves */);
636 else if ( rasconnstate
== RASCS_Connected
)
638 ms_isConnected
= TRUE
;
641 NotifyApp(TRUE
/* connected */, TRUE
/* we dialed ourselves */);
645 // ----------------------------------------------------------------------------
646 // implementation of wxDialUpManager functions
647 // ----------------------------------------------------------------------------
649 bool wxDialUpManagerMSW::IsOk() const
651 return ms_dllRas
!= 0;
654 size_t wxDialUpManagerMSW::GetISPNames(wxArrayString
& names
) const
657 DWORD size
= sizeof(RASENTRYNAME
);
658 RASENTRYNAME
*rasEntries
= (RASENTRYNAME
*)malloc(size
);
659 rasEntries
->dwSize
= sizeof(RASENTRYNAME
);
665 dwRet
= ms_pfnRasEnumEntries
668 NULL
, // default phone book (or all)
669 rasEntries
, // [out] buffer for the entries
670 &size
, // [in/out] size of the buffer
671 &nEntries
// [out] number of entries fetched
674 if ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
676 // reallocate the buffer
677 rasEntries
= (RASENTRYNAME
*)realloc(rasEntries
, size
);
679 else if ( dwRet
!= 0 )
681 // some other error - abort
682 wxLogError(_("Failed to get ISP names: %s"), GetErrorString(dwRet
));
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 "
767 RASDIALPARAMS rasDialParams
;
768 rasDialParams
.dwSize
= sizeof(rasDialParams
);
769 strncpy(rasDialParams
.szEntryName
, entryName
, RAS_MaxEntryName
);
771 // do we have the username and password?
772 if ( !username
|| !password
)
775 DWORD dwRet
= ms_pfnRasGetEntryDialParams
777 NULL
, // default phonebook
778 &rasDialParams
, // [in/out] the params of this entry
779 &gotPassword
// [out] did we get password?
784 wxLogError(_("Failed to connect: missing username/password."));
791 strncpy(rasDialParams
.szUserName
, username
, UNLEN
);
792 strncpy(rasDialParams
.szPassword
, password
, PWLEN
);
795 // default values for other fields
796 rasDialParams
.szPhoneNumber
[0] = '\0';
797 rasDialParams
.szCallbackNumber
[0] = '\0';
798 rasDialParams
.szCallbackNumber
[0] = '\0';
800 rasDialParams
.szDomain
[0] = '*';
801 rasDialParams
.szDomain
[1] = '\0';
803 // apparently, this is not really necessary - passing NULL instead of the
804 // phone book has the same effect
807 if ( wxGetOsVersion() == wxWINDOWS_NT
)
809 // first get the length
810 UINT nLen
= ::GetSystemDirectory(NULL
, 0);
813 if ( !::GetSystemDirectory(phoneBook
.GetWriteBuf(nLen
), nLen
) )
815 wxLogSysError(_("Cannot find the location of address book file"));
818 phoneBook
.UngetWriteBuf();
820 // this is the default phone book
821 phoneBook
<< "\\ras\\rasphone.pbk";
825 // TODO may be we should disable auto check while async dialing is in
830 DWORD dwRet
= ms_pfnRasDial
832 (LPRASDIALEXTENSIONS
)NULL
, // no extended features
833 NULL
, // default phone book file (NT only)
835 0, // use callback for notifications
836 async
? wxRasDialFunc
// the callback
837 : 0, // no notifications - sync operation
843 wxLogError(_("Failed to %s dialup connection: %s"),
844 async
? _("initiate") : _("establish"),
845 GetErrorString(dwRet
));
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
));
920 ms_isConnected
= FALSE
;
925 bool wxDialUpManagerMSW::IsAlwaysOnline() const
927 // we cache the result (presumably this won't change while the program is
929 if ( ms_isAlwaysOnline
!= -1 )
931 return ms_isAlwaysOnline
!= 0;
934 // try to use WinInet function first
936 wxDllType hDll
= wxDllLoader::LoadLibrary(_T("WININET"), &ok
);
939 typedef BOOL (*INTERNETGETCONNECTEDSTATE
)(LPDWORD
, DWORD
);
940 INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState
;
942 #define RESOLVE_FUNCTION(type, name) \
943 pfn##name = (type)wxDllLoader::GetSymbol(hDll, _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 ms_isAlwaysOnline
= (flags
& INTERNET_CONNECTION_LAN
!= 0) ||
954 (flags
& INTERNET_CONNECTION_PROXY
!= 0);
956 wxLogMessage("InternetGetConnectedState() returned TRUE, "
957 "flags = %08x", flags
);
961 // no Internet connection at all
962 ms_isAlwaysOnline
= FALSE
;
966 wxDllLoader::UnloadLibrary(hDll
);
969 // did we succeed with WinInet? if not, try something else
970 if ( ms_isAlwaysOnline
== -1 )
974 // definitely no permanent connection because we are not connected
976 ms_isAlwaysOnline
= FALSE
;
980 // of course, having a modem doesn't prevent us from having a
981 // permanent connection as well, but we have to guess somehow and
982 // it's probably more common that a system connected via a modem
983 // doesn't have any other net access, so:
984 ms_isAlwaysOnline
= FALSE
;
988 wxASSERT_MSG( ms_isAlwaysOnline
!= -1, wxT("logic error") );
990 return ms_isAlwaysOnline
!= 0;
993 bool wxDialUpManagerMSW::IsOnline() const
995 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
997 if ( ms_userSpecifiedOnlineStatus
!= -1 )
999 // user specified flag overrides our logic
1000 return ms_userSpecifiedOnlineStatus
!= 0;
1004 // return TRUE if there is at least one active connection
1005 return FindActiveConnection() != 0;
1009 void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline
)
1011 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1013 ms_userSpecifiedOnlineStatus
= isOnline
;
1016 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds
)
1018 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
1020 bool ok
= ms_pfnRasConnectionNotification
!= 0;
1024 // we're running under NT 4.0, Windows 98 or later and can use
1025 // RasConnectionNotification() to be notified by a secondary thread
1027 // first, see if we don't have this thread already running
1028 if ( m_hThread
!= 0 )
1030 DWORD dwSuspendCount
= 2;
1031 while ( dwSuspendCount
> 1 )
1033 dwSuspendCount
= ResumeThread(m_hThread
);
1034 if ( dwSuspendCount
== (DWORD
)-1 )
1036 wxLogLastError("ResumeThread(RasThread)");
1049 // create all the stuff we need to be notified about RAS connection
1054 // first create an event to wait on
1055 m_data
.hEventRas
= CreateEvent
1057 NULL
, // security attribute (default)
1058 FALSE
, // manual reset (not)
1059 FALSE
, // initial state (not signaled)
1062 if ( !m_data
.hEventRas
)
1064 wxLogLastError("CreateEvent(RasStatus)");
1072 // create the event we use to quit the thread
1073 m_data
.hEventQuit
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
1074 if ( !m_data
.hEventQuit
)
1076 wxLogLastError("CreateEvent(RasThreadQuit)");
1078 CleanUpThreadData();
1084 if ( ok
&& !ms_hwndRas
)
1086 // create a hidden window to receive notification about connections
1088 extern wxChar wxPanelClassName
[];
1089 ms_hwndRas
= ::CreateWindow(wxPanelClassName
, NULL
,
1092 (HMENU
)NULL
, wxGetInstance(), 0);
1095 wxLogLastError("CreateWindow(RasHiddenWindow)");
1097 CleanUpThreadData();
1103 FARPROC windowProc
= MakeProcInstance
1105 (FARPROC
)wxRasStatusWindowProc
,
1109 ::SetWindowLong(ms_hwndRas
, GWL_WNDPROC
, (LONG
) windowProc
);
1112 m_data
.hWnd
= ms_hwndRas
;
1116 // start the secondary thread
1117 m_data
.dialUpManager
= this;
1120 m_hThread
= CreateThread
1124 (LPTHREAD_START_ROUTINE
)wxRasMonitorThread
,
1132 wxLogLastError("CreateThread(RasStatusThread)");
1134 CleanUpThreadData();
1140 // start receiving RAS notifications
1141 DWORD dwRet
= ms_pfnRasConnectionNotification
1143 (HRASCONN
)INVALID_HANDLE_VALUE
,
1145 3 /* RASCN_Connection | RASCN_Disconnection */
1150 wxLogDebug(wxT("RasConnectionNotification() failed: %s"),
1151 GetErrorString(dwRet
));
1153 CleanUpThreadData();
1161 // we're running under Windows 95 and have to poll ourselves
1162 // (or, alternatively, the code above for NT/98 failed)
1163 m_timerStatusPolling
.Stop();
1164 if ( nSeconds
== 0 )
1169 m_timerStatusPolling
.Start(nSeconds
* 1000);
1174 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
1176 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1180 // we have running secondary thread, it's just enough to suspend it
1181 if ( SuspendThread(m_hThread
) == (DWORD
)-1 )
1183 wxLogLastError("SuspendThread(RasThread)");
1188 // even simpler - just stop the timer
1189 m_timerStatusPolling
.Stop();
1193 // ----------------------------------------------------------------------------
1194 // stubs which don't do anything in MSW version
1195 // ----------------------------------------------------------------------------
1197 void wxDialUpManagerMSW::SetWellKnownHost(const wxString
& WXUNUSED(hostname
),
1200 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1202 // nothing to do - we don't use this
1205 void wxDialUpManagerMSW::SetConnectCommand(const wxString
& WXUNUSED(dial
),
1206 const wxString
& WXUNUSED(hangup
))
1208 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1210 // nothing to do - we don't use this
1213 // ----------------------------------------------------------------------------
1215 // ----------------------------------------------------------------------------
1217 static DWORD
wxRasMonitorThread(wxRasThreadData
*data
)
1220 handles
[0] = data
->hEventRas
;
1221 handles
[1] = data
->hEventQuit
;
1226 DWORD dwRet
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1231 // RAS connection status changed
1232 SendMessage(data
->hWnd
, wxWM_RAS_STATUS_CHANGED
,
1236 case WAIT_OBJECT_0
+ 1:
1241 wxLogLastError("WaitForMultipleObjects(RasMonitor)");
1249 static LRESULT APIENTRY
wxRasStatusWindowProc(HWND hWnd
, UINT message
,
1250 WPARAM wParam
, LPARAM lParam
)
1252 if ( message
== wxWM_RAS_STATUS_CHANGED
)
1254 wxRasThreadData
*data
= (wxRasThreadData
*)lParam
;
1255 data
->dialUpManager
->OnConnectStatusChange();
1257 else if ( message
== wxWM_RAS_DIALING_PROGRESS
)
1259 wxDialUpManagerMSW
*dialUpManager
= wxDialUpManagerMSW::GetDialer();
1261 dialUpManager
->OnDialProgress((RASCONNSTATE
)wParam
, lParam
);
1267 static void WINAPI
wxRasDialFunc(UINT unMsg
,
1268 RASCONNSTATE rasconnstate
,
1271 wxDialUpManagerMSW
*dialUpManager
= wxDialUpManagerMSW::GetDialer();
1273 wxCHECK_RET( dialUpManager
, wxT("who started to dial then?") );
1275 SendMessage(dialUpManager
->GetRasWindow(), wxWM_RAS_DIALING_PROGRESS
,
1276 rasconnstate
, dwError
);
1281 #endif // wxUSE_DIALUP_MANAGER