1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/dialup.cpp
3 // Purpose: MSW implementation of network/dialup classes and functions
4 // Author: Vadim Zeitlin
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #if wxUSE_DIALUP_MANAGER
29 #include "wx/dialup.h"
37 #include "wx/module.h"
40 #include "wx/generic/choicdgg.h"
42 #include "wx/msw/private.h"
43 #include "wx/dynlib.h"
45 wxDEFINE_EVENT( wxEVT_DIALUP_CONNECTED
, wxDialUpEvent
);
46 wxDEFINE_EVENT( wxEVT_DIALUP_DISCONNECTED
, wxDialUpEvent
);
48 // Doesn't yet compile under VC++ 4, BC++, Watcom C++,
50 #if (!defined(__BORLANDC__) || (__BORLANDC__>=0x550)) && \
51 (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \
52 !defined(__GNUWIN32_OLD__) && \
53 !defined(__WINE__) && \
54 (!defined(__VISUALC__) || (__VISUALC__ >= 1020))
62 #ifndef INTERNET_CONNECTION_LAN
63 #define INTERNET_CONNECTION_LAN 2
65 #ifndef INTERNET_CONNECTION_PROXY
66 #define INTERNET_CONNECTION_PROXY 4
69 // implemented in utils.cpp
70 extern "C" WXDLLIMPEXP_BASE HWND
71 wxCreateHiddenWindow(LPCTSTR
*pclassname
, LPCTSTR classname
, WNDPROC wndproc
);
74 wxMSWDIALUP_WNDCLASSNAME
= wxT("_wxDialUpManager_Internal_Class");
75 static const wxChar
*gs_classForDialUpWindow
= NULL
;
77 // ----------------------------------------------------------------------------
79 // ----------------------------------------------------------------------------
81 // this message is sent by the secondary thread when RAS status changes
82 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010)
83 #define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011)
85 // ----------------------------------------------------------------------------
87 // ----------------------------------------------------------------------------
89 // the signatures of RAS functions: all this is quite heavy, but we must do it
90 // to allow running wxWin programs on machine which don't have RAS installed
91 // (this does exist) - if we link with rasapi32.lib, the program will fail on
92 // startup because of the missing DLL...
95 typedef DWORD (APIENTRY
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCSTR
, LPRASDIALPARAMSA
, DWORD
, LPVOID
, LPHRASCONN
);
96 typedef DWORD (APIENTRY
* RASENUMCONNECTIONS
)( LPRASCONNA
, LPDWORD
, LPDWORD
);
97 typedef DWORD (APIENTRY
* RASENUMENTRIES
)( LPCSTR
, LPCSTR
, LPRASENTRYNAMEA
, LPDWORD
, LPDWORD
);
98 typedef DWORD (APIENTRY
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSA
);
99 typedef DWORD (APIENTRY
* RASGETERRORSTRING
)( UINT
, LPSTR
, DWORD
);
100 typedef DWORD (APIENTRY
* RASHANGUP
)( HRASCONN
);
101 typedef DWORD (APIENTRY
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD
);
102 typedef DWORD (APIENTRY
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCSTR
);
103 typedef DWORD (APIENTRY
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCSTR
, LPCSTR
);
104 typedef DWORD (APIENTRY
* RASSETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, BOOL
);
105 typedef DWORD (APIENTRY
* RASGETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, LPBOOL
);
106 typedef DWORD (APIENTRY
* RASENUMDEVICES
)( LPRASDEVINFOA
, LPDWORD
, LPDWORD
);
107 typedef DWORD (APIENTRY
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOA
, LPDWORD
);
108 typedef DWORD (APIENTRY
* RASGETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, LPDWORD
, LPBYTE
, LPDWORD
);
109 typedef DWORD (APIENTRY
* RASSETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, DWORD
, LPBYTE
, DWORD
);
110 typedef DWORD (APIENTRY
* RASRENAMEENTRY
)( LPCSTR
, LPCSTR
, LPCSTR
);
111 typedef DWORD (APIENTRY
* RASDELETEENTRY
)( LPCSTR
, LPCSTR
);
112 typedef DWORD (APIENTRY
* RASVALIDATEENTRYNAME
)( LPCSTR
, LPCSTR
);
113 typedef DWORD (APIENTRY
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD
);
115 static const wxChar gs_funcSuffix
= wxT('A');
117 typedef DWORD (APIENTRY
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCWSTR
, LPRASDIALPARAMSW
, DWORD
, LPVOID
, LPHRASCONN
);
118 typedef DWORD (APIENTRY
* RASENUMCONNECTIONS
)( LPRASCONNW
, LPDWORD
, LPDWORD
);
119 typedef DWORD (APIENTRY
* RASENUMENTRIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYNAMEW
, LPDWORD
, LPDWORD
);
120 typedef DWORD (APIENTRY
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSW
);
121 typedef DWORD (APIENTRY
* RASGETERRORSTRING
)( UINT
, LPWSTR
, DWORD
);
122 typedef DWORD (APIENTRY
* RASHANGUP
)( HRASCONN
);
123 typedef DWORD (APIENTRY
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD
);
124 typedef DWORD (APIENTRY
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCWSTR
);
125 typedef DWORD (APIENTRY
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCWSTR
, LPCWSTR
);
126 typedef DWORD (APIENTRY
* RASSETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, BOOL
);
127 typedef DWORD (APIENTRY
* RASGETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, LPBOOL
);
128 typedef DWORD (APIENTRY
* RASENUMDEVICES
)( LPRASDEVINFOW
, LPDWORD
, LPDWORD
);
129 typedef DWORD (APIENTRY
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOW
, LPDWORD
);
130 typedef DWORD (APIENTRY
* RASGETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, LPDWORD
, LPBYTE
, LPDWORD
);
131 typedef DWORD (APIENTRY
* RASSETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, DWORD
, LPBYTE
, DWORD
);
132 typedef DWORD (APIENTRY
* RASRENAMEENTRY
)( LPCWSTR
, LPCWSTR
, LPCWSTR
);
133 typedef DWORD (APIENTRY
* RASDELETEENTRY
)( LPCWSTR
, LPCWSTR
);
134 typedef DWORD (APIENTRY
* RASVALIDATEENTRYNAME
)( LPCWSTR
, LPCWSTR
);
135 typedef DWORD (APIENTRY
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD
);
137 static const wxChar gs_funcSuffix
= wxT('W');
138 #endif // ASCII/Unicode
140 // structure passed to the secondary thread
141 struct WXDLLEXPORT wxRasThreadData
148 dialUpManager
= NULL
;
157 CloseHandle(hEventQuit
);
160 CloseHandle(hEventRas
);
163 HWND hWnd
; // window to send notifications to
164 HANDLE hEventRas
, // automatic event which RAS signals when status changes
165 hEventQuit
; // manual event which we signal when we terminate
167 class WXDLLIMPEXP_FWD_CORE wxDialUpManagerMSW
*dialUpManager
; // the owner
170 // ----------------------------------------------------------------------------
171 // wxDialUpManager class for MSW
172 // ----------------------------------------------------------------------------
174 class WXDLLEXPORT wxDialUpManagerMSW
: public wxDialUpManager
178 wxDialUpManagerMSW();
179 virtual ~wxDialUpManagerMSW();
181 // implement base class pure virtuals
182 virtual bool IsOk() const;
183 virtual size_t GetISPNames(wxArrayString
& names
) const;
184 virtual bool Dial(const wxString
& nameOfISP
,
185 const wxString
& username
,
186 const wxString
& password
,
188 virtual bool IsDialing() const;
189 virtual bool CancelDialing();
190 virtual bool HangUp();
191 virtual bool IsAlwaysOnline() const;
192 virtual bool IsOnline() const;
193 virtual void SetOnlineStatus(bool isOnline
= true);
194 virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
);
195 virtual void DisableAutoCheckOnlineStatus();
196 virtual void SetWellKnownHost(const wxString
& hostname
, int port
);
197 virtual void SetConnectCommand(const wxString
& commandDial
,
198 const wxString
& commandHangup
);
201 void CheckRasStatus();
203 // for wxRasStatusWindowProc
204 void OnConnectStatusChange();
205 void OnDialProgress(RASCONNSTATE rasconnstate
, DWORD dwError
);
208 static HWND
GetRasWindow() { return ms_hwndRas
; }
209 static void ResetRasWindow() { ms_hwndRas
= NULL
; }
210 static wxDialUpManagerMSW
*GetDialer() { return ms_dialer
; }
213 // return the error string for the given RAS error code
214 static wxString
GetErrorString(DWORD error
);
216 // find the (first) handle of the active connection
217 static HRASCONN
FindActiveConnection();
219 // notify the application about status change
220 void NotifyApp(bool connected
, bool fromOurselves
= false) const;
222 // destroy the thread data and the thread itself
223 void CleanUpThreadData();
225 // number of times EnableAutoCheckOnlineStatus() had been called minus the
226 // number of times DisableAutoCheckOnlineStatus() had been called
227 int m_autoCheckLevel
;
229 // timer used for polling RAS status
230 class WXDLLEXPORT RasTimer
: public wxTimer
233 RasTimer(wxDialUpManagerMSW
*dialUpManager
)
234 { m_dialUpManager
= dialUpManager
; }
236 virtual void Notify() { m_dialUpManager
->CheckRasStatus(); }
239 wxDialUpManagerMSW
*m_dialUpManager
;
241 wxDECLARE_NO_COPY_CLASS(RasTimer
);
242 } m_timerStatusPolling
;
244 // thread handle for the thread sitting on connection change event
247 // data used by this thread and our hidden window to send messages between
249 wxRasThreadData
*m_data
;
251 // the handle of rasapi32.dll when it's loaded
252 wxDynamicLibrary m_dllRas
;
254 // the hidden window we use for passing messages between threads
255 static HWND ms_hwndRas
;
257 // the handle of the connection we initiated or 0 if none
258 static HRASCONN ms_hRasConnection
;
260 // the pointers to RAS functions
261 static RASDIAL ms_pfnRasDial
;
262 static RASENUMCONNECTIONS ms_pfnRasEnumConnections
;
263 static RASENUMENTRIES ms_pfnRasEnumEntries
;
264 static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus
;
265 static RASGETERRORSTRING ms_pfnRasGetErrorString
;
266 static RASHANGUP ms_pfnRasHangUp
;
267 static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo
;
268 static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry
;
269 static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry
;
270 static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams
;
271 static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams
;
272 static RASENUMDEVICES ms_pfnRasEnumDevices
;
273 static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo
;
274 static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties
;
275 static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties
;
276 static RASRENAMEENTRY ms_pfnRasRenameEntry
;
277 static RASDELETEENTRY ms_pfnRasDeleteEntry
;
278 static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName
;
280 // this function is not supported by Win95
281 static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification
;
283 // if this flag is different from -1, it overrides IsOnline()
284 static int ms_userSpecifiedOnlineStatus
;
286 // this flag tells us if we're online
287 static int ms_isConnected
;
289 // this flag tells us whether a call to RasDial() is in progress
290 static wxDialUpManagerMSW
*ms_dialer
;
292 wxDECLARE_NO_COPY_CLASS(wxDialUpManagerMSW
);
295 // module to destroy helper window created by wxDialUpManagerMSW
296 class wxDialUpManagerModule
: public wxModule
299 bool OnInit() { return true; }
302 HWND hwnd
= wxDialUpManagerMSW::GetRasWindow();
305 ::DestroyWindow(hwnd
);
306 wxDialUpManagerMSW::ResetRasWindow();
309 if ( gs_classForDialUpWindow
)
311 ::UnregisterClass(wxMSWDIALUP_WNDCLASSNAME
, wxGetInstance());
312 gs_classForDialUpWindow
= NULL
;
317 DECLARE_DYNAMIC_CLASS(wxDialUpManagerModule
)
320 IMPLEMENT_DYNAMIC_CLASS(wxDialUpManagerModule
, wxModule
)
322 // ----------------------------------------------------------------------------
324 // ----------------------------------------------------------------------------
326 static LRESULT WINAPI
wxRasStatusWindowProc(HWND hWnd
, UINT message
,
327 WPARAM wParam
, LPARAM lParam
);
329 static DWORD
wxRasMonitorThread(wxRasThreadData
*data
);
331 static void WINAPI
wxRasDialFunc(UINT unMsg
,
332 RASCONNSTATE rasconnstate
,
335 // ============================================================================
337 // ============================================================================
339 // ----------------------------------------------------------------------------
340 // init the static variables
341 // ----------------------------------------------------------------------------
343 HRASCONN
wxDialUpManagerMSW::ms_hRasConnection
= 0;
345 HWND
wxDialUpManagerMSW::ms_hwndRas
= 0;
347 RASDIAL
wxDialUpManagerMSW::ms_pfnRasDial
= 0;
348 RASENUMCONNECTIONS
wxDialUpManagerMSW::ms_pfnRasEnumConnections
= 0;
349 RASENUMENTRIES
wxDialUpManagerMSW::ms_pfnRasEnumEntries
= 0;
350 RASGETCONNECTSTATUS
wxDialUpManagerMSW::ms_pfnRasGetConnectStatus
= 0;
351 RASGETERRORSTRING
wxDialUpManagerMSW::ms_pfnRasGetErrorString
= 0;
352 RASHANGUP
wxDialUpManagerMSW::ms_pfnRasHangUp
= 0;
353 RASGETPROJECTIONINFO
wxDialUpManagerMSW::ms_pfnRasGetProjectionInfo
= 0;
354 RASCREATEPHONEBOOKENTRY
wxDialUpManagerMSW::ms_pfnRasCreatePhonebookEntry
= 0;
355 RASEDITPHONEBOOKENTRY
wxDialUpManagerMSW::ms_pfnRasEditPhonebookEntry
= 0;
356 RASSETENTRYDIALPARAMS
wxDialUpManagerMSW::ms_pfnRasSetEntryDialParams
= 0;
357 RASGETENTRYDIALPARAMS
wxDialUpManagerMSW::ms_pfnRasGetEntryDialParams
= 0;
358 RASENUMDEVICES
wxDialUpManagerMSW::ms_pfnRasEnumDevices
= 0;
359 RASGETCOUNTRYINFO
wxDialUpManagerMSW::ms_pfnRasGetCountryInfo
= 0;
360 RASGETENTRYPROPERTIES
wxDialUpManagerMSW::ms_pfnRasGetEntryProperties
= 0;
361 RASSETENTRYPROPERTIES
wxDialUpManagerMSW::ms_pfnRasSetEntryProperties
= 0;
362 RASRENAMEENTRY
wxDialUpManagerMSW::ms_pfnRasRenameEntry
= 0;
363 RASDELETEENTRY
wxDialUpManagerMSW::ms_pfnRasDeleteEntry
= 0;
364 RASVALIDATEENTRYNAME
wxDialUpManagerMSW::ms_pfnRasValidateEntryName
= 0;
365 RASCONNECTIONNOTIFICATION
wxDialUpManagerMSW::ms_pfnRasConnectionNotification
= 0;
367 int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus
= -1;
368 int wxDialUpManagerMSW::ms_isConnected
= -1;
369 wxDialUpManagerMSW
*wxDialUpManagerMSW::ms_dialer
= NULL
;
371 // ----------------------------------------------------------------------------
372 // ctor and dtor: the dynamic linking happens here
373 // ----------------------------------------------------------------------------
375 // the static creator function is implemented here
376 wxDialUpManager
*wxDialUpManager::Create()
378 return new wxDialUpManagerMSW
;
382 // warning about "'this' : used in base member initializer list" - so what?
383 #pragma warning(disable:4355)
386 wxDialUpManagerMSW::wxDialUpManagerMSW()
387 : m_timerStatusPolling(this),
388 m_dllRas(wxT("RASAPI32"))
390 // initialize our data
391 m_autoCheckLevel
= 0;
393 m_data
= new wxRasThreadData
;
395 if ( !m_dllRas
.IsLoaded() )
397 wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it."));
399 else if ( !ms_pfnRasDial
)
401 // resolve the functions we need
403 // this will contain the name of the function we failed to resolve
405 const char *funcName
= NULL
;
407 // get the function from rasapi32.dll and abort if it's not found
408 #define RESOLVE_RAS_FUNCTION(type, name) \
409 ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(wxT(#name)) \
411 if ( !ms_pfn##name ) \
417 // a variant of above macro which doesn't abort if the function is
418 // not found in the DLL
419 #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \
420 ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(wxT(#name)) \
423 RESOLVE_RAS_FUNCTION(RASDIAL
, RasDial
);
424 RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS
, RasEnumConnections
);
425 RESOLVE_RAS_FUNCTION(RASENUMENTRIES
, RasEnumEntries
);
426 RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS
, RasGetConnectStatus
);
427 RESOLVE_RAS_FUNCTION(RASGETERRORSTRING
, RasGetErrorString
);
428 RESOLVE_RAS_FUNCTION(RASHANGUP
, RasHangUp
);
429 RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS
, RasGetEntryDialParams
);
431 // suppress error messages about missing (non essential) functions
435 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO
, RasGetProjectionInfo
);
436 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY
, RasCreatePhonebookEntry
);
437 RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY
, RasEditPhonebookEntry
);
438 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS
, RasSetEntryDialParams
);
439 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES
, RasGetEntryProperties
);
440 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES
, RasSetEntryProperties
);
441 RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY
, RasRenameEntry
);
442 RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY
, RasDeleteEntry
);
443 RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME
, RasValidateEntryName
);
444 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO
, RasGetCountryInfo
);
445 RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES
, RasEnumDevices
);
446 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION
, RasConnectionNotification
);
449 // keep your preprocessor name space clean
450 #undef RESOLVE_RAS_FUNCTION
451 #undef RESOLVE_OPTIONAL_RAS_FUNCTION
456 wxLogError(_("The version of remote access service (RAS) installed "
457 "on this machine is too old, please upgrade (the "
458 "following required function is missing: %s)."),
465 // enable auto check by default
466 EnableAutoCheckOnlineStatus(0);
469 wxDialUpManagerMSW::~wxDialUpManagerMSW()
474 // ----------------------------------------------------------------------------
476 // ----------------------------------------------------------------------------
478 wxString
wxDialUpManagerMSW::GetErrorString(DWORD error
)
480 wxChar buffer
[512]; // this should be more than enough according to MS docs
481 DWORD dwRet
= ms_pfnRasGetErrorString(error
, buffer
, WXSIZEOF(buffer
));
484 case ERROR_INVALID_PARAMETER
:
485 // this was a standard Win32 error probably
486 return wxString(wxSysErrorMsg(error
));
491 _("Failed to retrieve text of RAS error message"));
494 msg
.Printf(_("unknown error (error code %08x)."), error
);
499 // we want the error message to start from a lower case letter
500 buffer
[0] = (wxChar
)wxTolower(buffer
[0]);
502 return wxString(buffer
);
506 HRASCONN
wxDialUpManagerMSW::FindActiveConnection()
508 // enumerate connections
509 DWORD cbBuf
= sizeof(RASCONN
);
510 LPRASCONN lpRasConn
= (LPRASCONN
)malloc(cbBuf
);
517 lpRasConn
->dwSize
= sizeof(RASCONN
);
519 DWORD nConnections
= 0;
520 DWORD dwRet
= ERROR_BUFFER_TOO_SMALL
;
522 while ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
524 dwRet
= ms_pfnRasEnumConnections(lpRasConn
, &cbBuf
, &nConnections
);
526 if ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
528 LPRASCONN lpRasConnOld
= lpRasConn
;
529 lpRasConn
= (LPRASCONN
)realloc(lpRasConn
, cbBuf
);
538 else if ( dwRet
== 0 )
546 wxLogError(_("Cannot find active dialup connection: %s"),
547 GetErrorString(dwRet
).c_str());
554 switch ( nConnections
)
562 // more than 1 connection - we don't know what to do with this
563 // case, so give a warning but continue (taking the first
564 // connection) - the warning is really needed because this function
565 // is used, for example, to select the connection to hang up and so
566 // we may hang up the wrong connection here...
567 wxLogWarning(_("Several active dialup connections found, choosing one randomly."));
571 // exactly 1 connection, great
572 hrasconn
= lpRasConn
->hrasconn
;
580 void wxDialUpManagerMSW::CleanUpThreadData()
584 if ( !SetEvent(m_data
->hEventQuit
) )
586 wxLogLastError(wxT("SetEvent(RasThreadQuit)"));
588 else // sent quit request to the background thread
590 // the thread still needs m_data so we can't free it here, rather
591 // let the thread do it itself
595 CloseHandle(m_hThread
);
607 // ----------------------------------------------------------------------------
609 // ----------------------------------------------------------------------------
611 void wxDialUpManagerMSW::CheckRasStatus()
613 // use int, not bool to compare with -1
614 int isConnected
= FindActiveConnection() != 0;
615 if ( isConnected
!= ms_isConnected
)
617 if ( ms_isConnected
!= -1 )
619 // notify the program
620 NotifyApp(isConnected
!= 0);
622 // else: it's the first time we're called, just update the flag
624 ms_isConnected
= isConnected
;
628 void wxDialUpManagerMSW::NotifyApp(bool connected
, bool fromOurselves
) const
630 wxDialUpEvent
event(connected
, fromOurselves
);
631 (void)wxTheApp
->ProcessEvent(event
);
634 // this function is called whenever the status of any RAS connection on this
635 // machine changes by RAS itself
636 void wxDialUpManagerMSW::OnConnectStatusChange()
638 // we know that status changed, but we don't know whether we're connected
639 // or not - so find it out
643 // this function is called by our callback which we give to RasDial() when
644 // calling it asynchronously
645 void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate
,
650 // this probably means that CancelDialing() was called and we get
651 // "disconnected" notification
655 // we're only interested in 2 events: connected and disconnected
658 wxLogError(_("Failed to establish dialup connection: %s"),
659 GetErrorString(dwError
).c_str());
661 // we should still call RasHangUp() if we got a non 0 connection
662 if ( ms_hRasConnection
)
664 ms_pfnRasHangUp(ms_hRasConnection
);
665 ms_hRasConnection
= 0;
670 NotifyApp(false /* !connected */, true /* we dialed ourselves */);
672 else if ( rasconnstate
== RASCS_Connected
)
674 ms_isConnected
= true;
677 NotifyApp(true /* connected */, true /* we dialed ourselves */);
681 // ----------------------------------------------------------------------------
682 // implementation of wxDialUpManager functions
683 // ----------------------------------------------------------------------------
685 bool wxDialUpManagerMSW::IsOk() const
687 return m_dllRas
.IsLoaded();
690 size_t wxDialUpManagerMSW::GetISPNames(wxArrayString
& names
) const
693 DWORD size
= sizeof(RASENTRYNAME
);
694 RASENTRYNAME
*rasEntries
= (RASENTRYNAME
*)malloc(size
);
695 rasEntries
->dwSize
= sizeof(RASENTRYNAME
);
701 dwRet
= ms_pfnRasEnumEntries
704 NULL
, // default phone book (or all)
705 rasEntries
, // [out] buffer for the entries
706 &size
, // [in/out] size of the buffer
707 &nEntries
// [out] number of entries fetched
710 if ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
712 // reallocate the buffer
713 void *n
= realloc(rasEntries
, size
);
719 rasEntries
= (RASENTRYNAME
*)n
;
721 else if ( dwRet
!= 0 )
723 // some other error - abort
724 wxLogError(_("Failed to get ISP names: %s"),
725 GetErrorString(dwRet
).c_str());
732 while ( dwRet
!= 0 );
736 for ( size_t n
= 0; n
< (size_t)nEntries
; n
++ )
738 names
.Add(rasEntries
[n
].szEntryName
);
743 // return the number of entries
744 return names
.GetCount();
747 bool wxDialUpManagerMSW::Dial(const wxString
& nameOfISP
,
748 const wxString
& username
,
749 const wxString
& password
,
752 // check preconditions
753 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
755 if ( ms_hRasConnection
)
757 wxFAIL_MSG(wxT("there is already an active connection"));
762 // get the default ISP if none given
763 wxString
entryName(nameOfISP
);
767 size_t count
= GetISPNames(names
);
771 // no known ISPs, abort
772 wxLogError(_("Failed to connect: no ISP to dial."));
777 // only one ISP, choose it
778 entryName
= names
[0u];
782 // several ISPs, let the user choose
784 wxString
*strings
= new wxString
[count
];
785 for ( size_t i
= 0; i
< count
; i
++ )
787 strings
[i
] = names
[i
];
790 entryName
= wxGetSingleChoice
792 _("Choose ISP to dial"),
793 _("Please choose which ISP do you want to connect to"),
809 RASDIALPARAMS rasDialParams
;
810 rasDialParams
.dwSize
= sizeof(rasDialParams
);
811 wxStrlcpy(rasDialParams
.szEntryName
, entryName
.c_str(), RAS_MaxEntryName
);
813 // do we have the username and password?
814 if ( !username
|| !password
)
817 DWORD dwRet
= ms_pfnRasGetEntryDialParams
819 NULL
, // default phonebook
820 &rasDialParams
, // [in/out] the params of this entry
821 &gotPassword
// [out] did we get password?
826 wxLogError(_("Failed to connect: missing username/password."));
833 wxStrlcpy(rasDialParams
.szUserName
, username
.c_str(), UNLEN
);
834 wxStrlcpy(rasDialParams
.szPassword
, password
.c_str(), PWLEN
);
837 // default values for other fields
838 rasDialParams
.szPhoneNumber
[0] = '\0';
839 rasDialParams
.szCallbackNumber
[0] = '\0';
840 rasDialParams
.szCallbackNumber
[0] = '\0';
842 rasDialParams
.szDomain
[0] = '*';
843 rasDialParams
.szDomain
[1] = '\0';
845 // apparently, this is not really necessary - passing NULL instead of the
846 // phone book has the same effect
849 if ( wxGetOsVersion() == wxWINDOWS_NT
)
851 // first get the length
852 UINT nLen
= ::GetSystemDirectory(NULL
, 0);
855 if ( !::GetSystemDirectory(phoneBook
.GetWriteBuf(nLen
), nLen
) )
857 wxLogSysError(_("Cannot find the location of address book file"));
860 phoneBook
.UngetWriteBuf();
862 // this is the default phone book
863 phoneBook
<< "\\ras\\rasphone.pbk";
867 // TODO may be we should disable auto check while async dialing is in
872 DWORD dwRet
= ms_pfnRasDial
874 NULL
, // no extended features
875 NULL
, // default phone book file (NT only)
877 0, // use callback for notifications
878 async
? (void *)wxRasDialFunc
// cast needed for gcc 3.1
879 : 0, // no notifications, sync operation
885 // can't pass a wxWCharBuffer through ( ... )
888 wxLogError(_("Failed to initiate dialup connection: %s"),
889 GetErrorString(dwRet
).c_str());
893 wxLogError(_("Failed to establish dialup connection: %s"),
894 GetErrorString(dwRet
).c_str());
897 // we should still call RasHangUp() if we got a non 0 connection
898 if ( ms_hRasConnection
)
900 ms_pfnRasHangUp(ms_hRasConnection
);
901 ms_hRasConnection
= 0;
909 // for async dialing, we're not yet connected
912 ms_isConnected
= true;
918 bool wxDialUpManagerMSW::IsDialing() const
920 return GetDialer() != NULL
;
923 bool wxDialUpManagerMSW::CancelDialing()
931 wxASSERT_MSG( ms_hRasConnection
, wxT("dialing but no connection?") );
938 bool wxDialUpManagerMSW::HangUp()
940 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
942 // we may terminate either the connection we initiated or another one which
945 if ( ms_hRasConnection
)
947 hRasConn
= ms_hRasConnection
;
949 ms_hRasConnection
= 0;
953 hRasConn
= FindActiveConnection();
958 wxLogError(_("Cannot hang up - no active dialup connection."));
963 // note that it's not an error if the connection had been already
965 const DWORD dwRet
= ms_pfnRasHangUp(hRasConn
);
966 if ( dwRet
!= 0 && dwRet
!= ERROR_NO_CONNECTION
)
968 wxLogError(_("Failed to terminate the dialup connection: %s"),
969 GetErrorString(dwRet
).c_str());
972 ms_isConnected
= false;
977 bool wxDialUpManagerMSW::IsAlwaysOnline() const
979 // assume no permanent connection by default
980 bool isAlwaysOnline
= false;
982 // try to use WinInet functions
984 // NB: we could probably use wxDynamicLibrary here just as well,
985 // but we allow multiple instances of wxDialUpManagerMSW so
986 // we might as well use the ref counted version here too.
988 wxDynamicLibrary
hDll(wxT("WININET"));
989 if ( hDll
.IsLoaded() )
991 typedef BOOL (WINAPI
*INTERNETGETCONNECTEDSTATE
)(LPDWORD
, DWORD
);
992 INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState
;
994 #define RESOLVE_FUNCTION(type, name) \
995 pfn##name = (type)hDll.GetSymbol(wxT(#name))
997 RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE
, InternetGetConnectedState
);
999 if ( pfnInternetGetConnectedState
)
1002 if ( pfnInternetGetConnectedState(&flags
, 0 /* reserved */) )
1004 // there is some connection to the net, see of which type
1005 isAlwaysOnline
= (flags
& (INTERNET_CONNECTION_LAN
|
1006 INTERNET_CONNECTION_PROXY
)) != 0;
1008 //else: no Internet connection at all
1012 return isAlwaysOnline
;
1015 bool wxDialUpManagerMSW::IsOnline() const
1017 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
1019 if ( IsAlwaysOnline() )
1025 if ( ms_userSpecifiedOnlineStatus
!= -1 )
1027 // user specified flag overrides our logic
1028 return ms_userSpecifiedOnlineStatus
!= 0;
1032 // return true if there is at least one active connection
1033 return FindActiveConnection() != 0;
1037 void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline
)
1039 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1041 ms_userSpecifiedOnlineStatus
= isOnline
;
1044 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds
)
1046 wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );
1048 if ( m_autoCheckLevel
++ )
1054 bool ok
= ms_pfnRasConnectionNotification
!= 0;
1058 // we're running under NT 4.0, Windows 98 or later and can use
1059 // RasConnectionNotification() to be notified by a secondary thread
1061 // first, see if we don't have this thread already running
1062 if ( m_hThread
!= 0 )
1064 if ( ::ResumeThread(m_hThread
) != (DWORD
)-1 )
1067 // we're leaving a zombie thread... but what else can we do?
1068 wxLogLastError(wxT("ResumeThread(RasThread)"));
1074 // create all the stuff we need to be notified about RAS connection
1079 // first create an event to wait on
1080 m_data
->hEventRas
= ::CreateEvent
1082 NULL
, // security attribute (default)
1083 FALSE
, // manual reset (no, it is automatic)
1084 FALSE
, // initial state (not signaled)
1087 if ( !m_data
->hEventRas
)
1089 wxLogLastError(wxT("CreateEvent(RasStatus)"));
1097 // create the event we use to quit the thread: using a manual event
1098 // here avoids problems with missing the event if wxDialUpManagerMSW
1099 // is created and destroyed immediately, before wxRasStatusWindowProc
1100 // starts waiting on the event
1101 m_data
->hEventQuit
= ::CreateEvent
1103 NULL
, // default security
1104 TRUE
, // manual event
1105 FALSE
, // initially non signalled
1108 if ( !m_data
->hEventQuit
)
1110 wxLogLastError(wxT("CreateEvent(RasThreadQuit)"));
1112 CleanUpThreadData();
1118 if ( ok
&& !ms_hwndRas
)
1120 // create a hidden window to receive notification about connections
1122 ms_hwndRas
= wxCreateHiddenWindow
1124 &gs_classForDialUpWindow
,
1125 wxMSWDIALUP_WNDCLASSNAME
,
1126 wxRasStatusWindowProc
1130 wxLogLastError(wxT("CreateWindow(RasHiddenWindow)"));
1132 CleanUpThreadData();
1138 m_data
->hWnd
= ms_hwndRas
;
1142 // start the secondary thread
1143 m_data
->dialUpManager
= this;
1146 m_hThread
= CreateThread
1150 (LPTHREAD_START_ROUTINE
)wxRasMonitorThread
,
1158 wxLogLastError(wxT("CreateThread(RasStatusThread)"));
1160 CleanUpThreadData();
1166 // start receiving RAS notifications
1167 DWORD dwRet
= ms_pfnRasConnectionNotification
1169 (HRASCONN
)INVALID_HANDLE_VALUE
,
1171 3 /* RASCN_Connection | RASCN_Disconnection */
1176 wxLogDebug(wxT("RasConnectionNotification() failed: %s"),
1177 GetErrorString(dwRet
).c_str());
1179 CleanUpThreadData();
1187 // we're running under Windows 95 and have to poll ourselves
1188 // (or, alternatively, the code above for NT/98 failed)
1189 m_timerStatusPolling
.Stop();
1190 if ( nSeconds
== 0 )
1195 m_timerStatusPolling
.Start(nSeconds
* 1000);
1200 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
1202 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1204 if ( --m_autoCheckLevel
!= 0 )
1212 // we have running secondary thread, it's just enough to suspend it
1213 if ( SuspendThread(m_hThread
) == (DWORD
)-1 )
1215 wxLogLastError(wxT("SuspendThread(RasThread)"));
1220 // even simpler - just stop the timer
1221 m_timerStatusPolling
.Stop();
1225 // ----------------------------------------------------------------------------
1226 // stubs which don't do anything in MSW version
1227 // ----------------------------------------------------------------------------
1229 void wxDialUpManagerMSW::SetWellKnownHost(const wxString
& WXUNUSED(hostname
),
1232 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1234 // nothing to do - we don't use this
1237 void wxDialUpManagerMSW::SetConnectCommand(const wxString
& WXUNUSED(dial
),
1238 const wxString
& WXUNUSED(hangup
))
1240 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1242 // nothing to do - we don't use this
1245 // ----------------------------------------------------------------------------
1247 // ----------------------------------------------------------------------------
1249 static DWORD
wxRasMonitorThread(wxRasThreadData
*data
)
1252 handles
[0] = data
->hEventRas
;
1253 handles
[1] = data
->hEventQuit
;
1258 DWORD dwRet
= ::WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1263 // RAS connection status changed
1264 SendMessage(data
->hWnd
, wxWM_RAS_STATUS_CHANGED
,
1268 case WAIT_OBJECT_0
+ 1:
1273 wxFAIL_MSG( wxT("unexpected return of WaitForMultipleObjects()") );
1277 // using wxLogLastError() from here is dangerous: we risk to
1278 // deadlock the main thread if wxLog sends output to GUI
1279 DWORD err
= GetLastError();
1280 wxMessageOutputDebug dbg
;
1283 wxT("WaitForMultipleObjects(RasMonitor) failed: 0x%08lx (%s)"),
1288 // no sense in continuing, who knows if the handles we're
1289 // waiting for even exist yet...
1294 // we don't need it any more now and if this thread ran, it is our
1295 // responsability to free the data
1301 static LRESULT APIENTRY
wxRasStatusWindowProc(HWND hWnd
, UINT message
,
1302 WPARAM wParam
, LPARAM lParam
)
1306 case wxWM_RAS_STATUS_CHANGED
:
1308 wxRasThreadData
*data
= (wxRasThreadData
*)lParam
;
1309 data
->dialUpManager
->OnConnectStatusChange();
1313 case wxWM_RAS_DIALING_PROGRESS
:
1315 wxDialUpManagerMSW
*dialMan
= wxDialUpManagerMSW::GetDialer();
1317 dialMan
->OnDialProgress((RASCONNSTATE
)wParam
, lParam
);
1322 return ::DefWindowProc(hWnd
, message
, wParam
, lParam
);
1328 static void WINAPI
wxRasDialFunc(UINT
WXUNUSED(unMsg
),
1329 RASCONNSTATE rasconnstate
,
1332 wxDialUpManagerMSW
*dialUpManager
= wxDialUpManagerMSW::GetDialer();
1334 wxCHECK_RET( dialUpManager
, wxT("who started to dial then?") );
1336 SendMessage(wxDialUpManagerMSW::GetRasWindow(), wxWM_RAS_DIALING_PROGRESS
,
1337 rasconnstate
, dwError
);
1340 #endif // __BORLANDC__
1342 #endif // wxUSE_DIALUP_MANAGER