1 /////////////////////////////////////////////////////////////////////////////
2 // Name: palmos/dialup.cpp
3 // Purpose: Palm OS implementation of network/dialup classes and functions
4 // Author: Vadim Zeitlin
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #if wxUSE_DIALUP_MANAGER
37 #include "wx/generic/choicdgg.h"
39 #include "wx/dynlib.h"
40 #include "wx/dialup.h"
42 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED
)
43 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED
)
45 // This needs to be written using Palm OS Network API calls, but for now this
47 #if (!defined(__PALMOS__)
55 #ifndef INTERNET_CONNECTION_LAN
56 #define INTERNET_CONNECTION_LAN 2
58 #ifndef INTERNET_CONNECTION_PROXY
59 #define INTERNET_CONNECTION_PROXY 4
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
66 // this message is sent by the secondary thread when RAS status changes
67 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010)
68 #define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011)
70 // ----------------------------------------------------------------------------
72 // ----------------------------------------------------------------------------
74 // the signatures of RAS functions: all this is quite heavy, but we must do it
75 // to allow running wxWin programs on machine which don't have RAS installed
76 // (this does exist) - if we link with rasapi32.lib, the program will fail on
77 // startup because of the missing DLL...
80 typedef DWORD (APIENTRY
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCSTR
, LPRASDIALPARAMSA
, DWORD
, LPVOID
, LPHRASCONN
);
81 typedef DWORD (APIENTRY
* RASENUMCONNECTIONS
)( LPRASCONNA
, LPDWORD
, LPDWORD
);
82 typedef DWORD (APIENTRY
* RASENUMENTRIES
)( LPCSTR
, LPCSTR
, LPRASENTRYNAMEA
, LPDWORD
, LPDWORD
);
83 typedef DWORD (APIENTRY
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSA
);
84 typedef DWORD (APIENTRY
* RASGETERRORSTRING
)( UINT
, LPSTR
, DWORD
);
85 typedef DWORD (APIENTRY
* RASHANGUP
)( HRASCONN
);
86 typedef DWORD (APIENTRY
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD
);
87 typedef DWORD (APIENTRY
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCSTR
);
88 typedef DWORD (APIENTRY
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCSTR
, LPCSTR
);
89 typedef DWORD (APIENTRY
* RASSETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, BOOL
);
90 typedef DWORD (APIENTRY
* RASGETENTRYDIALPARAMS
)( LPCSTR
, LPRASDIALPARAMSA
, LPBOOL
);
91 typedef DWORD (APIENTRY
* RASENUMDEVICES
)( LPRASDEVINFOA
, LPDWORD
, LPDWORD
);
92 typedef DWORD (APIENTRY
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOA
, LPDWORD
);
93 typedef DWORD (APIENTRY
* RASGETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, LPDWORD
, LPBYTE
, LPDWORD
);
94 typedef DWORD (APIENTRY
* RASSETENTRYPROPERTIES
)( LPCSTR
, LPCSTR
, LPRASENTRYA
, DWORD
, LPBYTE
, DWORD
);
95 typedef DWORD (APIENTRY
* RASRENAMEENTRY
)( LPCSTR
, LPCSTR
, LPCSTR
);
96 typedef DWORD (APIENTRY
* RASDELETEENTRY
)( LPCSTR
, LPCSTR
);
97 typedef DWORD (APIENTRY
* RASVALIDATEENTRYNAME
)( LPCSTR
, LPCSTR
);
98 typedef DWORD (APIENTRY
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD
);
100 static const wxChar gs_funcSuffix
= _T('A');
102 typedef DWORD (APIENTRY
* RASDIAL
)( LPRASDIALEXTENSIONS
, LPCWSTR
, LPRASDIALPARAMSW
, DWORD
, LPVOID
, LPHRASCONN
);
103 typedef DWORD (APIENTRY
* RASENUMCONNECTIONS
)( LPRASCONNW
, LPDWORD
, LPDWORD
);
104 typedef DWORD (APIENTRY
* RASENUMENTRIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYNAMEW
, LPDWORD
, LPDWORD
);
105 typedef DWORD (APIENTRY
* RASGETCONNECTSTATUS
)( HRASCONN
, LPRASCONNSTATUSW
);
106 typedef DWORD (APIENTRY
* RASGETERRORSTRING
)( UINT
, LPWSTR
, DWORD
);
107 typedef DWORD (APIENTRY
* RASHANGUP
)( HRASCONN
);
108 typedef DWORD (APIENTRY
* RASGETPROJECTIONINFO
)( HRASCONN
, RASPROJECTION
, LPVOID
, LPDWORD
);
109 typedef DWORD (APIENTRY
* RASCREATEPHONEBOOKENTRY
)( HWND
, LPCWSTR
);
110 typedef DWORD (APIENTRY
* RASEDITPHONEBOOKENTRY
)( HWND
, LPCWSTR
, LPCWSTR
);
111 typedef DWORD (APIENTRY
* RASSETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, BOOL
);
112 typedef DWORD (APIENTRY
* RASGETENTRYDIALPARAMS
)( LPCWSTR
, LPRASDIALPARAMSW
, LPBOOL
);
113 typedef DWORD (APIENTRY
* RASENUMDEVICES
)( LPRASDEVINFOW
, LPDWORD
, LPDWORD
);
114 typedef DWORD (APIENTRY
* RASGETCOUNTRYINFO
)( LPRASCTRYINFOW
, LPDWORD
);
115 typedef DWORD (APIENTRY
* RASGETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, LPDWORD
, LPBYTE
, LPDWORD
);
116 typedef DWORD (APIENTRY
* RASSETENTRYPROPERTIES
)( LPCWSTR
, LPCWSTR
, LPRASENTRYW
, DWORD
, LPBYTE
, DWORD
);
117 typedef DWORD (APIENTRY
* RASRENAMEENTRY
)( LPCWSTR
, LPCWSTR
, LPCWSTR
);
118 typedef DWORD (APIENTRY
* RASDELETEENTRY
)( LPCWSTR
, LPCWSTR
);
119 typedef DWORD (APIENTRY
* RASVALIDATEENTRYNAME
)( LPCWSTR
, LPCWSTR
);
120 typedef DWORD (APIENTRY
* RASCONNECTIONNOTIFICATION
)( HRASCONN
, HANDLE
, DWORD
);
122 static const wxChar gs_funcSuffix
= _T('W');
123 #endif // ASCII/Unicode
125 // structure passed to the secondary thread
126 struct WXDLLEXPORT wxRasThreadData
133 dialUpManager
= NULL
;
142 CloseHandle(hEventQuit
);
145 CloseHandle(hEventRas
);
148 HWND hWnd
; // window to send notifications to
149 HANDLE hEventRas
, // automatic event which RAS signals when status changes
150 hEventQuit
; // manual event which we signal when we terminate
152 class WXDLLEXPORT wxDialUpManagerMSW
*dialUpManager
; // the owner
155 // ----------------------------------------------------------------------------
156 // wxDialUpManager class for MSW
157 // ----------------------------------------------------------------------------
159 class WXDLLEXPORT wxDialUpManagerMSW
: public wxDialUpManager
163 wxDialUpManagerMSW();
164 virtual ~wxDialUpManagerMSW();
166 // implement base class pure virtuals
167 virtual bool IsOk() const;
168 virtual size_t GetISPNames(wxArrayString
& names
) const;
169 virtual bool Dial(const wxString
& nameOfISP
,
170 const wxString
& username
,
171 const wxString
& password
,
173 virtual bool IsDialing() const;
174 virtual bool CancelDialing();
175 virtual bool HangUp();
176 virtual bool IsAlwaysOnline() const;
177 virtual bool IsOnline() const;
178 virtual void SetOnlineStatus(bool isOnline
= TRUE
);
179 virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds
);
180 virtual void DisableAutoCheckOnlineStatus();
181 virtual void SetWellKnownHost(const wxString
& hostname
, int port
);
182 virtual void SetConnectCommand(const wxString
& commandDial
,
183 const wxString
& commandHangup
);
186 void CheckRasStatus();
188 // for wxRasStatusWindowProc
189 void OnConnectStatusChange();
190 void OnDialProgress(RASCONNSTATE rasconnstate
, DWORD dwError
);
193 static HWND
GetRasWindow() { return ms_hwndRas
; }
194 static wxDialUpManagerMSW
*GetDialer() { return ms_dialer
; }
197 // return the error string for the given RAS error code
198 static wxString
GetErrorString(DWORD error
);
200 // find the (first) handle of the active connection
201 static HRASCONN
FindActiveConnection();
203 // notify the application about status change
204 void NotifyApp(bool connected
, bool fromOurselves
= FALSE
) const;
206 // destroy the thread data and the thread itself
207 void CleanUpThreadData();
209 // number of times EnableAutoCheckOnlineStatus() had been called minus the
210 // number of times DisableAutoCheckOnlineStatus() had been called
211 int m_autoCheckLevel
;
213 // timer used for polling RAS status
214 class WXDLLEXPORT RasTimer
: public wxTimer
217 RasTimer(wxDialUpManagerMSW
*dialUpManager
)
218 { m_dialUpManager
= dialUpManager
; }
220 virtual void Notify() { m_dialUpManager
->CheckRasStatus(); }
223 wxDialUpManagerMSW
*m_dialUpManager
;
225 DECLARE_NO_COPY_CLASS(RasTimer
)
226 } m_timerStatusPolling
;
228 // thread handle for the thread sitting on connection change event
231 // data used by this thread and our hidden window to send messages between
233 wxRasThreadData
*m_data
;
235 // the handle of rasapi32.dll when it's loaded
236 wxDynamicLibrary m_dllRas
;
238 // the hidden window we use for passing messages between threads
239 static HWND ms_hwndRas
;
241 // the handle of the connection we initiated or 0 if none
242 static HRASCONN ms_hRasConnection
;
244 // the pointers to RAS functions
245 static RASDIAL ms_pfnRasDial
;
246 static RASENUMCONNECTIONS ms_pfnRasEnumConnections
;
247 static RASENUMENTRIES ms_pfnRasEnumEntries
;
248 static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus
;
249 static RASGETERRORSTRING ms_pfnRasGetErrorString
;
250 static RASHANGUP ms_pfnRasHangUp
;
251 static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo
;
252 static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry
;
253 static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry
;
254 static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams
;
255 static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams
;
256 static RASENUMDEVICES ms_pfnRasEnumDevices
;
257 static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo
;
258 static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties
;
259 static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties
;
260 static RASRENAMEENTRY ms_pfnRasRenameEntry
;
261 static RASDELETEENTRY ms_pfnRasDeleteEntry
;
262 static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName
;
264 // this function is not supported by Win95
265 static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification
;
267 // if this flag is different from -1, it overrides IsOnline()
268 static int ms_userSpecifiedOnlineStatus
;
270 // this flag tells us if we're online
271 static int ms_isConnected
;
273 // this flag tells us whether a call to RasDial() is in progress
274 static wxDialUpManagerMSW
*ms_dialer
;
276 DECLARE_NO_COPY_CLASS(wxDialUpManagerMSW
)
279 // ----------------------------------------------------------------------------
281 // ----------------------------------------------------------------------------
283 static LRESULT WINAPI
wxRasStatusWindowProc(HWND hWnd
, UINT message
,
284 WPARAM wParam
, LPARAM lParam
);
286 static DWORD
wxRasMonitorThread(wxRasThreadData
*data
);
288 static void WINAPI
wxRasDialFunc(UINT unMsg
,
289 RASCONNSTATE rasconnstate
,
292 // ============================================================================
294 // ============================================================================
296 // ----------------------------------------------------------------------------
297 // init the static variables
298 // ----------------------------------------------------------------------------
300 HRASCONN
wxDialUpManagerMSW::ms_hRasConnection
= 0;
302 HWND
wxDialUpManagerMSW::ms_hwndRas
= 0;
304 RASDIAL
wxDialUpManagerMSW::ms_pfnRasDial
= 0;
305 RASENUMCONNECTIONS
wxDialUpManagerMSW::ms_pfnRasEnumConnections
= 0;
306 RASENUMENTRIES
wxDialUpManagerMSW::ms_pfnRasEnumEntries
= 0;
307 RASGETCONNECTSTATUS
wxDialUpManagerMSW::ms_pfnRasGetConnectStatus
= 0;
308 RASGETERRORSTRING
wxDialUpManagerMSW::ms_pfnRasGetErrorString
= 0;
309 RASHANGUP
wxDialUpManagerMSW::ms_pfnRasHangUp
= 0;
310 RASGETPROJECTIONINFO
wxDialUpManagerMSW::ms_pfnRasGetProjectionInfo
= 0;
311 RASCREATEPHONEBOOKENTRY
wxDialUpManagerMSW::ms_pfnRasCreatePhonebookEntry
= 0;
312 RASEDITPHONEBOOKENTRY
wxDialUpManagerMSW::ms_pfnRasEditPhonebookEntry
= 0;
313 RASSETENTRYDIALPARAMS
wxDialUpManagerMSW::ms_pfnRasSetEntryDialParams
= 0;
314 RASGETENTRYDIALPARAMS
wxDialUpManagerMSW::ms_pfnRasGetEntryDialParams
= 0;
315 RASENUMDEVICES
wxDialUpManagerMSW::ms_pfnRasEnumDevices
= 0;
316 RASGETCOUNTRYINFO
wxDialUpManagerMSW::ms_pfnRasGetCountryInfo
= 0;
317 RASGETENTRYPROPERTIES
wxDialUpManagerMSW::ms_pfnRasGetEntryProperties
= 0;
318 RASSETENTRYPROPERTIES
wxDialUpManagerMSW::ms_pfnRasSetEntryProperties
= 0;
319 RASRENAMEENTRY
wxDialUpManagerMSW::ms_pfnRasRenameEntry
= 0;
320 RASDELETEENTRY
wxDialUpManagerMSW::ms_pfnRasDeleteEntry
= 0;
321 RASVALIDATEENTRYNAME
wxDialUpManagerMSW::ms_pfnRasValidateEntryName
= 0;
322 RASCONNECTIONNOTIFICATION
wxDialUpManagerMSW::ms_pfnRasConnectionNotification
= 0;
324 int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus
= -1;
325 int wxDialUpManagerMSW::ms_isConnected
= -1;
326 wxDialUpManagerMSW
*wxDialUpManagerMSW::ms_dialer
= NULL
;
328 // ----------------------------------------------------------------------------
329 // ctor and dtor: the dynamic linking happens here
330 // ----------------------------------------------------------------------------
332 // the static creator function is implemented here
333 wxDialUpManager
*wxDialUpManager::Create()
335 return new wxDialUpManagerMSW
;
339 // warning about "'this' : used in base member initializer list" - so what?
340 #pragma warning(disable:4355)
343 wxDialUpManagerMSW::wxDialUpManagerMSW()
344 : m_timerStatusPolling(this),
345 m_dllRas(_T("RASAPI32"))
347 // initialize our data
348 m_autoCheckLevel
= 0;
350 m_data
= new wxRasThreadData
;
352 if ( !m_dllRas
.IsLoaded() )
354 wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it."));
356 else if ( !ms_pfnRasDial
)
358 // resolve the functions we need
360 // this will contain the name of the function we failed to resolve
362 const char *funcName
= NULL
;
364 // get the function from rasapi32.dll and abort if it's not found
365 #define RESOLVE_RAS_FUNCTION(type, name) \
366 ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name)) \
368 if ( !ms_pfn##name ) \
374 // a variant of above macro which doesn't abort if the function is
375 // not found in the DLL
376 #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \
377 ms_pfn##name = (type)m_dllRas.GetSymbol( wxString(_T(#name)) \
380 RESOLVE_RAS_FUNCTION(RASDIAL
, RasDial
);
381 RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS
, RasEnumConnections
);
382 RESOLVE_RAS_FUNCTION(RASENUMENTRIES
, RasEnumEntries
);
383 RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS
, RasGetConnectStatus
);
384 RESOLVE_RAS_FUNCTION(RASGETERRORSTRING
, RasGetErrorString
);
385 RESOLVE_RAS_FUNCTION(RASHANGUP
, RasHangUp
);
386 RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS
, RasGetEntryDialParams
);
388 // suppress error messages about missing (non essential) functions
392 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO
, RasGetProjectionInfo
);
393 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY
, RasCreatePhonebookEntry
);
394 RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY
, RasEditPhonebookEntry
);
395 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS
, RasSetEntryDialParams
);
396 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES
, RasGetEntryProperties
);
397 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES
, RasSetEntryProperties
);
398 RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY
, RasRenameEntry
);
399 RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY
, RasDeleteEntry
);
400 RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME
, RasValidateEntryName
);
401 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO
, RasGetCountryInfo
);
402 RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES
, RasEnumDevices
);
403 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION
, RasConnectionNotification
);
406 // keep your preprocessor name space clean
407 #undef RESOLVE_RAS_FUNCTION
408 #undef RESOLVE_OPTIONAL_RAS_FUNCTION
413 static const wxChar
*msg
= wxTRANSLATE(
414 "The version of remote access service (RAS) installed on this machine is too\
415 old, please upgrade (the following required function is missing: %s)."
418 wxLogError(wxGetTranslation(msg
), funcName
);
424 // enable auto check by default
425 EnableAutoCheckOnlineStatus(0);
428 wxDialUpManagerMSW::~wxDialUpManagerMSW()
433 // ----------------------------------------------------------------------------
435 // ----------------------------------------------------------------------------
437 wxString
wxDialUpManagerMSW::GetErrorString(DWORD error
)
439 wxChar buffer
[512]; // this should be more than enough according to MS docs
440 DWORD dwRet
= ms_pfnRasGetErrorString(error
, buffer
, WXSIZEOF(buffer
));
443 case ERROR_INVALID_PARAMETER
:
444 // this was a standard Win32 error probably
445 return wxString(wxSysErrorMsg(error
));
450 _("Failed to retrieve text of RAS error message"));
453 msg
.Printf(_("unknown error (error code %08x)."), error
);
458 // we want the error message to start from a lower case letter
459 buffer
[0] = wxTolower(buffer
[0]);
461 return wxString(buffer
);
465 HRASCONN
wxDialUpManagerMSW::FindActiveConnection()
467 // enumerate connections
468 DWORD cbBuf
= sizeof(RASCONN
);
469 LPRASCONN lpRasConn
= (LPRASCONN
)malloc(cbBuf
);
476 lpRasConn
->dwSize
= sizeof(RASCONN
);
478 DWORD nConnections
= 0;
479 DWORD dwRet
= ERROR_BUFFER_TOO_SMALL
;
481 while ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
483 dwRet
= ms_pfnRasEnumConnections(lpRasConn
, &cbBuf
, &nConnections
);
485 if ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
487 LPRASCONN lpRasConnOld
= lpRasConn
;
488 lpRasConn
= (LPRASCONN
)realloc(lpRasConn
, cbBuf
);
497 else if ( dwRet
== 0 )
505 wxLogError(_("Cannot find active dialup connection: %s"),
506 GetErrorString(dwRet
).c_str());
513 switch ( nConnections
)
521 // more than 1 connection - we don't know what to do with this
522 // case, so give a warning but continue (taking the first
523 // connection) - the warning is really needed because this function
524 // is used, for example, to select the connection to hang up and so
525 // we may hang up the wrong connection here...
526 wxLogWarning(_("Several active dialup connections found, choosing one randomly."));
530 // exactly 1 connection, great
531 hrasconn
= lpRasConn
->hrasconn
;
539 void wxDialUpManagerMSW::CleanUpThreadData()
543 if ( !SetEvent(m_data
->hEventQuit
) )
545 wxLogLastError(_T("SetEvent(RasThreadQuit)"));
547 else // sent quit request to the background thread
549 // the thread still needs m_data so we can't free it here, rather
550 // let the thread do it itself
554 CloseHandle(m_hThread
);
566 // ----------------------------------------------------------------------------
568 // ----------------------------------------------------------------------------
570 void wxDialUpManagerMSW::CheckRasStatus()
572 // use int, not bool to compare with -1
573 int isConnected
= FindActiveConnection() != 0;
574 if ( isConnected
!= ms_isConnected
)
576 if ( ms_isConnected
!= -1 )
578 // notify the program
579 NotifyApp(isConnected
!= 0);
581 // else: it's the first time we're called, just update the flag
583 ms_isConnected
= isConnected
;
587 void wxDialUpManagerMSW::NotifyApp(bool connected
, bool fromOurselves
) const
589 wxDialUpEvent
event(connected
, fromOurselves
);
590 (void)wxTheApp
->ProcessEvent(event
);
593 // this function is called whenever the status of any RAS connection on this
594 // machine changes by RAS itself
595 void wxDialUpManagerMSW::OnConnectStatusChange()
597 // we know that status changed, but we don't know whether we're connected
598 // or not - so find it out
602 // this function is called by our callback which we give to RasDial() when
603 // calling it asynchronously
604 void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate
,
609 // this probably means that CancelDialing() was called and we get
610 // "disconnected" notification
614 // we're only interested in 2 events: connected and disconnected
617 wxLogError(_("Failed to establish dialup connection: %s"),
618 GetErrorString(dwError
).c_str());
620 // we should still call RasHangUp() if we got a non 0 connection
621 if ( ms_hRasConnection
)
623 ms_pfnRasHangUp(ms_hRasConnection
);
624 ms_hRasConnection
= 0;
629 NotifyApp(FALSE
/* !connected */, TRUE
/* we dialed ourselves */);
631 else if ( rasconnstate
== RASCS_Connected
)
633 ms_isConnected
= TRUE
;
636 NotifyApp(TRUE
/* connected */, TRUE
/* we dialed ourselves */);
640 // ----------------------------------------------------------------------------
641 // implementation of wxDialUpManager functions
642 // ----------------------------------------------------------------------------
644 bool wxDialUpManagerMSW::IsOk() const
646 return m_dllRas
.IsLoaded();
649 size_t wxDialUpManagerMSW::GetISPNames(wxArrayString
& names
) const
652 DWORD size
= sizeof(RASENTRYNAME
);
653 RASENTRYNAME
*rasEntries
= (RASENTRYNAME
*)malloc(size
);
654 rasEntries
->dwSize
= sizeof(RASENTRYNAME
);
660 dwRet
= ms_pfnRasEnumEntries
663 NULL
, // default phone book (or all)
664 rasEntries
, // [out] buffer for the entries
665 &size
, // [in/out] size of the buffer
666 &nEntries
// [out] number of entries fetched
669 if ( dwRet
== ERROR_BUFFER_TOO_SMALL
)
671 // reallocate the buffer
672 rasEntries
= (RASENTRYNAME
*)realloc(rasEntries
, size
);
674 else if ( dwRet
!= 0 )
676 // some other error - abort
677 wxLogError(_("Failed to get ISP names: %s"),
678 GetErrorString(dwRet
).c_str());
685 while ( dwRet
!= 0 );
689 for ( size_t n
= 0; n
< (size_t)nEntries
; n
++ )
691 names
.Add(rasEntries
[n
].szEntryName
);
696 // return the number of entries
697 return names
.GetCount();
700 bool wxDialUpManagerMSW::Dial(const wxString
& nameOfISP
,
701 const wxString
& username
,
702 const wxString
& password
,
705 // check preconditions
706 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
708 if ( ms_hRasConnection
)
710 wxFAIL_MSG(wxT("there is already an active connection"));
715 // get the default ISP if none given
716 wxString
entryName(nameOfISP
);
720 size_t count
= GetISPNames(names
);
724 // no known ISPs, abort
725 wxLogError(_("Failed to connect: no ISP to dial."));
730 // only one ISP, choose it
731 entryName
= names
[0u];
735 // several ISPs, let the user choose
737 wxString
*strings
= new wxString
[count
];
738 for ( size_t i
= 0; i
< count
; i
++ )
740 strings
[i
] = names
[i
];
743 entryName
= wxGetSingleChoice
745 _("Choose ISP to dial"),
746 _("Please choose which ISP do you want to connect to"),
762 RASDIALPARAMS rasDialParams
;
763 rasDialParams
.dwSize
= sizeof(rasDialParams
);
764 wxStrncpy(rasDialParams
.szEntryName
, entryName
, RAS_MaxEntryName
);
766 // do we have the username and password?
767 if ( !username
|| !password
)
770 DWORD dwRet
= ms_pfnRasGetEntryDialParams
772 NULL
, // default phonebook
773 &rasDialParams
, // [in/out] the params of this entry
774 &gotPassword
// [out] did we get password?
779 wxLogError(_("Failed to connect: missing username/password."));
786 wxStrncpy(rasDialParams
.szUserName
, username
, UNLEN
);
787 wxStrncpy(rasDialParams
.szPassword
, password
, PWLEN
);
790 // default values for other fields
791 rasDialParams
.szPhoneNumber
[0] = '\0';
792 rasDialParams
.szCallbackNumber
[0] = '\0';
793 rasDialParams
.szCallbackNumber
[0] = '\0';
795 rasDialParams
.szDomain
[0] = '*';
796 rasDialParams
.szDomain
[1] = '\0';
798 // apparently, this is not really necessary - passing NULL instead of the
799 // phone book has the same effect
802 if ( wxGetOsVersion() == wxWINDOWS_NT
)
804 // first get the length
805 UINT nLen
= ::GetSystemDirectory(NULL
, 0);
808 if ( !::GetSystemDirectory(phoneBook
.GetWriteBuf(nLen
), nLen
) )
810 wxLogSysError(_("Cannot find the location of address book file"));
813 phoneBook
.UngetWriteBuf();
815 // this is the default phone book
816 phoneBook
<< "\\ras\\rasphone.pbk";
820 // TODO may be we should disable auto check while async dialing is in
825 DWORD dwRet
= ms_pfnRasDial
827 NULL
, // no extended features
828 NULL
, // default phone book file (NT only)
830 0, // use callback for notifications
831 async
? (void *)wxRasDialFunc
// cast needed for gcc 3.1
832 : 0, // no notifications, sync operation
838 // can't pass a wxWCharBuffer through ( ... )
839 wxLogError(_("Failed to %s dialup connection: %s"),
840 wxString(async
? _("initiate") : _("establish")).c_str(),
841 GetErrorString(dwRet
).c_str());
843 // we should still call RasHangUp() if we got a non 0 connection
844 if ( ms_hRasConnection
)
846 ms_pfnRasHangUp(ms_hRasConnection
);
847 ms_hRasConnection
= 0;
855 // for async dialing, we're not yet connected
858 ms_isConnected
= TRUE
;
864 bool wxDialUpManagerMSW::IsDialing() const
866 return GetDialer() != NULL
;
869 bool wxDialUpManagerMSW::CancelDialing()
877 wxASSERT_MSG( ms_hRasConnection
, wxT("dialing but no connection?") );
884 bool wxDialUpManagerMSW::HangUp()
886 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
888 // we may terminate either the connection we initiated or another one which
891 if ( ms_hRasConnection
)
893 hRasConn
= ms_hRasConnection
;
895 ms_hRasConnection
= 0;
899 hRasConn
= FindActiveConnection();
904 wxLogError(_("Cannot hang up - no active dialup connection."));
909 DWORD dwRet
= ms_pfnRasHangUp(hRasConn
);
912 wxLogError(_("Failed to terminate the dialup connection: %s"),
913 GetErrorString(dwRet
).c_str());
916 ms_isConnected
= FALSE
;
921 bool wxDialUpManagerMSW::IsAlwaysOnline() const
923 // assume no permanent connection by default
924 bool isAlwaysOnline
= FALSE
;
926 // try to use WinInet functions
928 // NB: we could probably use wxDynamicLibrary here just as well,
929 // but we allow multiple instances of wxDialUpManagerMSW so
930 // we might as well use the ref counted version here too.
932 wxDynamicLibrary
hDll(_T("WININET"));
933 if ( hDll
.IsLoaded() )
935 typedef BOOL (WINAPI
*INTERNETGETCONNECTEDSTATE
)(LPDWORD
, DWORD
);
936 INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState
;
938 #define RESOLVE_FUNCTION(type, name) \
939 pfn##name = (type)hDll.GetSymbol(_T(#name))
941 RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE
, InternetGetConnectedState
);
943 if ( pfnInternetGetConnectedState
)
946 if ( pfnInternetGetConnectedState(&flags
, 0 /* reserved */) )
948 // there is some connection to the net, see of which type
949 isAlwaysOnline
= (flags
& (INTERNET_CONNECTION_LAN
|
950 INTERNET_CONNECTION_PROXY
)) != 0;
952 //else: no Internet connection at all
956 return isAlwaysOnline
;
959 bool wxDialUpManagerMSW::IsOnline() const
961 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
963 if ( IsAlwaysOnline() )
969 if ( ms_userSpecifiedOnlineStatus
!= -1 )
971 // user specified flag overrides our logic
972 return ms_userSpecifiedOnlineStatus
!= 0;
976 // return TRUE if there is at least one active connection
977 return FindActiveConnection() != 0;
981 void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline
)
983 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
985 ms_userSpecifiedOnlineStatus
= isOnline
;
988 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds
)
990 wxCHECK_MSG( IsOk(), FALSE
, wxT("using uninitialized wxDialUpManager") );
992 if ( m_autoCheckLevel
++ )
998 bool ok
= ms_pfnRasConnectionNotification
!= 0;
1002 // we're running under NT 4.0, Windows 98 or later and can use
1003 // RasConnectionNotification() to be notified by a secondary thread
1005 // first, see if we don't have this thread already running
1006 if ( m_hThread
!= 0 )
1008 if ( ::ResumeThread(m_hThread
) != (DWORD
)-1 )
1011 // we're leaving a zombie thread... but what else can we do?
1012 wxLogLastError(wxT("ResumeThread(RasThread)"));
1018 // create all the stuff we need to be notified about RAS connection
1023 // first create an event to wait on
1024 m_data
->hEventRas
= CreateEvent
1026 NULL
, // security attribute (default)
1027 FALSE
, // manual reset (no, it is automatic)
1028 FALSE
, // initial state (not signaled)
1031 if ( !m_data
->hEventRas
)
1033 wxLogLastError(wxT("CreateEvent(RasStatus)"));
1041 // create the event we use to quit the thread: using a manual event
1042 // here avoids problems with missing the event if wxDialUpManagerMSW
1043 // is created and destroyed immediately, before wxRasStatusWindowProc
1044 // starts waiting on the event
1045 m_data
->hEventQuit
= CreateEvent
1047 NULL
, // default security
1048 TRUE
, // manual event
1049 FALSE
, // initially non signalled
1052 if ( !m_data
->hEventQuit
)
1054 wxLogLastError(wxT("CreateEvent(RasThreadQuit)"));
1056 CleanUpThreadData();
1062 if ( ok
&& !ms_hwndRas
)
1064 // create a hidden window to receive notification about connections
1066 extern const wxChar
*wxCanvasClassName
;
1067 ms_hwndRas
= ::CreateWindow(wxCanvasClassName
, NULL
,
1070 (HMENU
)NULL
, wxGetInstance(), 0);
1073 wxLogLastError(wxT("CreateWindow(RasHiddenWindow)"));
1075 CleanUpThreadData();
1081 wxSetWindowProc(ms_hwndRas
, wxRasStatusWindowProc
);
1084 m_data
->hWnd
= ms_hwndRas
;
1088 // start the secondary thread
1089 m_data
->dialUpManager
= this;
1092 m_hThread
= CreateThread
1096 (LPTHREAD_START_ROUTINE
)wxRasMonitorThread
,
1104 wxLogLastError(wxT("CreateThread(RasStatusThread)"));
1106 CleanUpThreadData();
1112 // start receiving RAS notifications
1113 DWORD dwRet
= ms_pfnRasConnectionNotification
1115 (HRASCONN
)INVALID_HANDLE_VALUE
,
1117 3 /* RASCN_Connection | RASCN_Disconnection */
1122 wxLogDebug(wxT("RasConnectionNotification() failed: %s"),
1123 GetErrorString(dwRet
).c_str());
1125 CleanUpThreadData();
1133 // we're running under Windows 95 and have to poll ourselves
1134 // (or, alternatively, the code above for NT/98 failed)
1135 m_timerStatusPolling
.Stop();
1136 if ( nSeconds
== 0 )
1141 m_timerStatusPolling
.Start(nSeconds
* 1000);
1146 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
1148 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1150 if ( --m_autoCheckLevel
)
1158 // we have running secondary thread, it's just enough to suspend it
1159 if ( SuspendThread(m_hThread
) == (DWORD
)-1 )
1161 wxLogLastError(wxT("SuspendThread(RasThread)"));
1166 // even simpler - just stop the timer
1167 m_timerStatusPolling
.Stop();
1171 // ----------------------------------------------------------------------------
1172 // stubs which don't do anything in MSW version
1173 // ----------------------------------------------------------------------------
1175 void wxDialUpManagerMSW::SetWellKnownHost(const wxString
& WXUNUSED(hostname
),
1178 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1180 // nothing to do - we don't use this
1183 void wxDialUpManagerMSW::SetConnectCommand(const wxString
& WXUNUSED(dial
),
1184 const wxString
& WXUNUSED(hangup
))
1186 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1188 // nothing to do - we don't use this
1191 // ----------------------------------------------------------------------------
1193 // ----------------------------------------------------------------------------
1195 static DWORD
wxRasMonitorThread(wxRasThreadData
*data
)
1198 handles
[0] = data
->hEventRas
;
1199 handles
[1] = data
->hEventQuit
;
1204 DWORD dwRet
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
1209 // RAS connection status changed
1210 SendMessage(data
->hWnd
, wxWM_RAS_STATUS_CHANGED
,
1214 case WAIT_OBJECT_0
+ 1:
1219 wxFAIL_MSG( _T("unexpected return of WaitForMultipleObjects()") );
1224 // using wxLogLastError() from here is dangerous: we risk to
1225 // deadlock the main thread if wxLog sends output to GUI
1226 DWORD err
= GetLastError();
1227 wxMessageOutputDebug().Printf
1229 wxT("WaitForMultipleObjects(RasMonitor) failed: 0x%08lx (%s)"),
1233 #endif // __WXDEBUG__
1235 // no sense in continuing, who knows if the handles we're
1236 // waiting for even exist yet...
1241 // we don't need it any more now and if this thread ran, it is our
1242 // responsability to free the data
1248 static LRESULT APIENTRY
wxRasStatusWindowProc(HWND hWnd
, UINT message
,
1249 WPARAM wParam
, LPARAM lParam
)
1253 case wxWM_RAS_STATUS_CHANGED
:
1255 wxRasThreadData
*data
= (wxRasThreadData
*)lParam
;
1256 data
->dialUpManager
->OnConnectStatusChange();
1260 case wxWM_RAS_DIALING_PROGRESS
:
1262 wxDialUpManagerMSW
*dialMan
= wxDialUpManagerMSW::GetDialer();
1264 dialMan
->OnDialProgress((RASCONNSTATE
)wParam
, lParam
);
1269 return ::DefWindowProc(hWnd
, message
, wParam
, lParam
);
1275 static void WINAPI
wxRasDialFunc(UINT
WXUNUSED(unMsg
),
1276 RASCONNSTATE rasconnstate
,
1279 wxDialUpManagerMSW
*dialUpManager
= wxDialUpManagerMSW::GetDialer();
1281 wxCHECK_RET( dialUpManager
, wxT("who started to dial then?") );
1283 SendMessage(dialUpManager
->GetRasWindow(), wxWM_RAS_DIALING_PROGRESS
,
1284 rasconnstate
, dwError
);
1287 #endif // __PALMOS__
1289 #endif // wxUSE_DIALUP_MANAGER