]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dialup.cpp
Removed spurious wxCHECK which forgot about the possibility of ~wxScreenDC...
[wxWidgets.git] / src / msw / dialup.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/dialup.cpp
3 // Purpose: MSW implementation of network/dialup classes and functions
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 07.07.99
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
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
32
33 #if wxUSE_DIALUP_MANAGER
34
35 #ifndef WX_PRECOMP
36 #include "wx/log.h"
37 #include "wx/intl.h"
38 #include "wx/event.h"
39 #endif
40
41 #include "wx/timer.h"
42 #include "wx/app.h"
43 #include "wx/generic/choicdgg.h"
44
45 #include "wx/msw/private.h" // must be before #include "dynlib.h"
46
47 #if !wxUSE_DYNLIB_CLASS
48 #error You need wxUSE_DYNLIB_CLASS to be 1 to compile dialup.cpp.
49 #endif
50
51 #include "wx/dynlib.h"
52
53 #include "wx/dialup.h"
54
55 DEFINE_EVENT_TYPE(wxEVT_DIALUP_CONNECTED)
56 DEFINE_EVENT_TYPE(wxEVT_DIALUP_DISCONNECTED)
57
58 // Doesn't yet compile under VC++ 4, BC++, Watcom C++: no wininet.h
59 #if !defined(__BORLANDC__) && \
60 !defined(__GNUWIN32_OLD__) && \
61 !defined(__WATCOMC__) && \
62 (!defined(__VISUALC__) || (__VISUALC__ >= 1020))
63 // FIXME: add this back as soon as wxCHECK_W32API_VERSION is chcked in
64 // (!defined(__GNUWIN32__) || wxCHECK_W32API_VERSION(0, 5)) && \
65
66 #include <ras.h>
67 #include <raserror.h>
68
69 #include <wininet.h>
70
71 // Not in VC++ 5
72 #ifndef INTERNET_CONNECTION_LAN
73 #define INTERNET_CONNECTION_LAN 2
74 #endif
75 #ifndef INTERNET_CONNECTION_PROXY
76 #define INTERNET_CONNECTION_PROXY 4
77 #endif
78
79 // ----------------------------------------------------------------------------
80 // constants
81 // ----------------------------------------------------------------------------
82
83 // this message is sent by the secondary thread when RAS status changes
84 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010)
85 #define wxWM_RAS_DIALING_PROGRESS (WM_USER + 10011)
86
87 // ----------------------------------------------------------------------------
88 // types
89 // ----------------------------------------------------------------------------
90
91 // the signatures of RAS functions: all this is quite heavy, but we must do it
92 // to allow running wxWin programs on machine which don't have RAS installed
93 // (this does exist) - if we link with rasapi32.lib, the program will fail on
94 // startup because of the missing DLL...
95
96 #ifndef UNICODE
97 typedef DWORD (APIENTRY * RASDIAL)( LPRASDIALEXTENSIONS, LPCSTR, LPRASDIALPARAMSA, DWORD, LPVOID, LPHRASCONN );
98 typedef DWORD (APIENTRY * RASENUMCONNECTIONS)( LPRASCONNA, LPDWORD, LPDWORD );
99 typedef DWORD (APIENTRY * RASENUMENTRIES)( LPCSTR, LPCSTR, LPRASENTRYNAMEA, LPDWORD, LPDWORD );
100 typedef DWORD (APIENTRY * RASGETCONNECTSTATUS)( HRASCONN, LPRASCONNSTATUSA );
101 typedef DWORD (APIENTRY * RASGETERRORSTRING)( UINT, LPSTR, DWORD );
102 typedef DWORD (APIENTRY * RASHANGUP)( HRASCONN );
103 typedef DWORD (APIENTRY * RASGETPROJECTIONINFO)( HRASCONN, RASPROJECTION, LPVOID, LPDWORD );
104 typedef DWORD (APIENTRY * RASCREATEPHONEBOOKENTRY)( HWND, LPCSTR );
105 typedef DWORD (APIENTRY * RASEDITPHONEBOOKENTRY)( HWND, LPCSTR, LPCSTR );
106 typedef DWORD (APIENTRY * RASSETENTRYDIALPARAMS)( LPCSTR, LPRASDIALPARAMSA, BOOL );
107 typedef DWORD (APIENTRY * RASGETENTRYDIALPARAMS)( LPCSTR, LPRASDIALPARAMSA, LPBOOL );
108 typedef DWORD (APIENTRY * RASENUMDEVICES)( LPRASDEVINFOA, LPDWORD, LPDWORD );
109 typedef DWORD (APIENTRY * RASGETCOUNTRYINFO)( LPRASCTRYINFOA, LPDWORD );
110 typedef DWORD (APIENTRY * RASGETENTRYPROPERTIES)( LPCSTR, LPCSTR, LPRASENTRYA, LPDWORD, LPBYTE, LPDWORD );
111 typedef DWORD (APIENTRY * RASSETENTRYPROPERTIES)( LPCSTR, LPCSTR, LPRASENTRYA, DWORD, LPBYTE, DWORD );
112 typedef DWORD (APIENTRY * RASRENAMEENTRY)( LPCSTR, LPCSTR, LPCSTR );
113 typedef DWORD (APIENTRY * RASDELETEENTRY)( LPCSTR, LPCSTR );
114 typedef DWORD (APIENTRY * RASVALIDATEENTRYNAME)( LPCSTR, LPCSTR );
115 typedef DWORD (APIENTRY * RASCONNECTIONNOTIFICATION)( HRASCONN, HANDLE, DWORD );
116
117 static const wxChar gs_funcSuffix = _T('A');
118 #else // Unicode
119 typedef DWORD (APIENTRY * RASDIAL)( LPRASDIALEXTENSIONS, LPCWSTR, LPRASDIALPARAMSW, DWORD, LPVOID, LPHRASCONN );
120 typedef DWORD (APIENTRY * RASENUMCONNECTIONS)( LPRASCONNW, LPDWORD, LPDWORD );
121 typedef DWORD (APIENTRY * RASENUMENTRIES)( LPCWSTR, LPCWSTR, LPRASENTRYNAMEW, LPDWORD, LPDWORD );
122 typedef DWORD (APIENTRY * RASGETCONNECTSTATUS)( HRASCONN, LPRASCONNSTATUSW );
123 typedef DWORD (APIENTRY * RASGETERRORSTRING)( UINT, LPWSTR, DWORD );
124 typedef DWORD (APIENTRY * RASHANGUP)( HRASCONN );
125 typedef DWORD (APIENTRY * RASGETPROJECTIONINFO)( HRASCONN, RASPROJECTION, LPVOID, LPDWORD );
126 typedef DWORD (APIENTRY * RASCREATEPHONEBOOKENTRY)( HWND, LPCWSTR );
127 typedef DWORD (APIENTRY * RASEDITPHONEBOOKENTRY)( HWND, LPCWSTR, LPCWSTR );
128 typedef DWORD (APIENTRY * RASSETENTRYDIALPARAMS)( LPCWSTR, LPRASDIALPARAMSW, BOOL );
129 typedef DWORD (APIENTRY * RASGETENTRYDIALPARAMS)( LPCWSTR, LPRASDIALPARAMSW, LPBOOL );
130 typedef DWORD (APIENTRY * RASENUMDEVICES)( LPRASDEVINFOW, LPDWORD, LPDWORD );
131 typedef DWORD (APIENTRY * RASGETCOUNTRYINFO)( LPRASCTRYINFOW, LPDWORD );
132 typedef DWORD (APIENTRY * RASGETENTRYPROPERTIES)( LPCWSTR, LPCWSTR, LPRASENTRYW, LPDWORD, LPBYTE, LPDWORD );
133 typedef DWORD (APIENTRY * RASSETENTRYPROPERTIES)( LPCWSTR, LPCWSTR, LPRASENTRYW, DWORD, LPBYTE, DWORD );
134 typedef DWORD (APIENTRY * RASRENAMEENTRY)( LPCWSTR, LPCWSTR, LPCWSTR );
135 typedef DWORD (APIENTRY * RASDELETEENTRY)( LPCWSTR, LPCWSTR );
136 typedef DWORD (APIENTRY * RASVALIDATEENTRYNAME)( LPCWSTR, LPCWSTR );
137 typedef DWORD (APIENTRY * RASCONNECTIONNOTIFICATION)( HRASCONN, HANDLE, DWORD );
138
139 static const wxChar gs_funcSuffix = _T('W');
140 #endif // ASCII/Unicode
141
142 // structure passed to the secondary thread
143 struct WXDLLEXPORT wxRasThreadData
144 {
145 wxRasThreadData()
146 {
147 hWnd = 0;
148 hEventRas = hEventQuit = INVALID_HANDLE_VALUE;
149 dialUpManager = NULL;
150 }
151
152 HWND hWnd; // window to send notifications to
153 HANDLE hEventRas, // event which RAS signals when status changes
154 hEventQuit; // event which we signal when we terminate
155
156 class WXDLLEXPORT wxDialUpManagerMSW *dialUpManager; // the owner
157 };
158
159 // ----------------------------------------------------------------------------
160 // wxDialUpManager class for MSW
161 // ----------------------------------------------------------------------------
162
163 class WXDLLEXPORT wxDialUpManagerMSW : public wxDialUpManager
164 {
165 public:
166 // ctor & dtor
167 wxDialUpManagerMSW();
168 virtual ~wxDialUpManagerMSW();
169
170 // implement base class pure virtuals
171 virtual bool IsOk() const;
172 virtual size_t GetISPNames(wxArrayString& names) const;
173 virtual bool Dial(const wxString& nameOfISP,
174 const wxString& username,
175 const wxString& password,
176 bool async);
177 virtual bool IsDialing() const;
178 virtual bool CancelDialing();
179 virtual bool HangUp();
180 virtual bool IsAlwaysOnline() const;
181 virtual bool IsOnline() const;
182 virtual void SetOnlineStatus(bool isOnline = TRUE);
183 virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds);
184 virtual void DisableAutoCheckOnlineStatus();
185 virtual void SetWellKnownHost(const wxString& hostname, int port);
186 virtual void SetConnectCommand(const wxString& commandDial,
187 const wxString& commandHangup);
188
189 // for RasTimer
190 void CheckRasStatus();
191
192 // for wxRasStatusWindowProc
193 void OnConnectStatusChange();
194 void OnDialProgress(RASCONNSTATE rasconnstate, DWORD dwError);
195
196 // for wxRasDialFunc
197 static HWND GetRasWindow() { return ms_hwndRas; }
198 static wxDialUpManagerMSW *GetDialer() { return ms_dialer; }
199
200 private:
201 // return the error string for the given RAS error code
202 static wxString GetErrorString(DWORD error);
203
204 // find the (first) handle of the active connection
205 static HRASCONN FindActiveConnection();
206
207 // notify the application about status change
208 void NotifyApp(bool connected, bool fromOurselves = FALSE) const;
209
210 // destroy the thread data and the thread itself
211 void CleanUpThreadData();
212
213 // timer used for polling RAS status
214 class WXDLLEXPORT RasTimer : public wxTimer
215 {
216 public:
217 RasTimer(wxDialUpManagerMSW *dialUpManager)
218 { m_dialUpManager = dialUpManager; }
219
220 virtual void Notify() { m_dialUpManager->CheckRasStatus(); }
221
222 private:
223 wxDialUpManagerMSW *m_dialUpManager;
224 } m_timerStatusPolling;
225
226 // thread handle for the thread sitting on connection change event
227 HANDLE m_hThread;
228
229 // data used by this thread and our hidden window to send messages between
230 // each other
231 wxRasThreadData m_data;
232
233 // the hidden window we use for passing messages between threads
234 static HWND ms_hwndRas;
235
236 // the handle of the connection we initiated or 0 if none
237 static HRASCONN ms_hRasConnection;
238
239 // the use count of rasapi32.dll
240 static int ms_nDllCount;
241
242 // the handle of rasapi32.dll when it's loaded
243 static wxDllType ms_dllRas;
244
245 // the pointers to RAS functions
246 static RASDIAL ms_pfnRasDial;
247 static RASENUMCONNECTIONS ms_pfnRasEnumConnections;
248 static RASENUMENTRIES ms_pfnRasEnumEntries;
249 static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus;
250 static RASGETERRORSTRING ms_pfnRasGetErrorString;
251 static RASHANGUP ms_pfnRasHangUp;
252 static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo;
253 static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry;
254 static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry;
255 static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams;
256 static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams;
257 static RASENUMDEVICES ms_pfnRasEnumDevices;
258 static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo;
259 static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties;
260 static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties;
261 static RASRENAMEENTRY ms_pfnRasRenameEntry;
262 static RASDELETEENTRY ms_pfnRasDeleteEntry;
263 static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName;
264
265 // this function is not supported by Win95
266 static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification;
267
268 // if this flag is different from -1, it overrides IsOnline()
269 static int ms_userSpecifiedOnlineStatus;
270
271 // this flag tells us if we're online
272 static int ms_isConnected;
273
274 // this flag is the result of the call to IsAlwaysOnline() (-1 if not
275 // called yet)
276 static int ms_isAlwaysOnline;
277
278 // this flag tells us whether a call to RasDial() is in progress
279 static wxDialUpManagerMSW *ms_dialer;
280 };
281
282 // ----------------------------------------------------------------------------
283 // private functions
284 // ----------------------------------------------------------------------------
285
286 static LRESULT WINAPI wxRasStatusWindowProc(HWND hWnd, UINT message,
287 WPARAM wParam, LPARAM lParam);
288
289 static DWORD wxRasMonitorThread(wxRasThreadData *data);
290
291 static void WINAPI wxRasDialFunc(UINT unMsg,
292 RASCONNSTATE rasconnstate,
293 DWORD dwError);
294
295 // ============================================================================
296 // implementation
297 // ============================================================================
298
299 // ----------------------------------------------------------------------------
300 // init the static variables
301 // ----------------------------------------------------------------------------
302
303 HRASCONN wxDialUpManagerMSW::ms_hRasConnection = 0;
304
305 HWND wxDialUpManagerMSW::ms_hwndRas = 0;
306
307 int wxDialUpManagerMSW::ms_nDllCount = 0;
308 wxDllType wxDialUpManagerMSW::ms_dllRas = 0;
309
310 RASDIAL wxDialUpManagerMSW::ms_pfnRasDial = 0;
311 RASENUMCONNECTIONS wxDialUpManagerMSW::ms_pfnRasEnumConnections = 0;
312 RASENUMENTRIES wxDialUpManagerMSW::ms_pfnRasEnumEntries = 0;
313 RASGETCONNECTSTATUS wxDialUpManagerMSW::ms_pfnRasGetConnectStatus = 0;
314 RASGETERRORSTRING wxDialUpManagerMSW::ms_pfnRasGetErrorString = 0;
315 RASHANGUP wxDialUpManagerMSW::ms_pfnRasHangUp = 0;
316 RASGETPROJECTIONINFO wxDialUpManagerMSW::ms_pfnRasGetProjectionInfo = 0;
317 RASCREATEPHONEBOOKENTRY wxDialUpManagerMSW::ms_pfnRasCreatePhonebookEntry = 0;
318 RASEDITPHONEBOOKENTRY wxDialUpManagerMSW::ms_pfnRasEditPhonebookEntry = 0;
319 RASSETENTRYDIALPARAMS wxDialUpManagerMSW::ms_pfnRasSetEntryDialParams = 0;
320 RASGETENTRYDIALPARAMS wxDialUpManagerMSW::ms_pfnRasGetEntryDialParams = 0;
321 RASENUMDEVICES wxDialUpManagerMSW::ms_pfnRasEnumDevices = 0;
322 RASGETCOUNTRYINFO wxDialUpManagerMSW::ms_pfnRasGetCountryInfo = 0;
323 RASGETENTRYPROPERTIES wxDialUpManagerMSW::ms_pfnRasGetEntryProperties = 0;
324 RASSETENTRYPROPERTIES wxDialUpManagerMSW::ms_pfnRasSetEntryProperties = 0;
325 RASRENAMEENTRY wxDialUpManagerMSW::ms_pfnRasRenameEntry = 0;
326 RASDELETEENTRY wxDialUpManagerMSW::ms_pfnRasDeleteEntry = 0;
327 RASVALIDATEENTRYNAME wxDialUpManagerMSW::ms_pfnRasValidateEntryName = 0;
328 RASCONNECTIONNOTIFICATION wxDialUpManagerMSW::ms_pfnRasConnectionNotification = 0;
329
330 int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus = -1;
331 int wxDialUpManagerMSW::ms_isConnected = -1;
332 int wxDialUpManagerMSW::ms_isAlwaysOnline = -1;
333 wxDialUpManagerMSW *wxDialUpManagerMSW::ms_dialer = NULL;
334
335 // ----------------------------------------------------------------------------
336 // ctor and dtor: the dynamic linking happens here
337 // ----------------------------------------------------------------------------
338
339 // the static creator function is implemented here
340 wxDialUpManager *wxDialUpManager::Create()
341 {
342 return new wxDialUpManagerMSW;
343 }
344
345 #ifdef __VISUALC__
346 // warning about "'this' : used in base member initializer list" - so what?
347 #pragma warning(disable:4355)
348 #endif // VC++
349
350 wxDialUpManagerMSW::wxDialUpManagerMSW()
351 : m_timerStatusPolling(this)
352 {
353 // initialize our data
354 m_hThread = 0;
355
356 if ( !ms_nDllCount++ )
357 {
358 // load the RAS library
359 ms_dllRas = wxDllLoader::LoadLibrary("RASAPI32");
360 if ( !ms_dllRas )
361 {
362 wxLogError(_("Dial up functions are unavailable because the remote access service (RAS) is not installed on this machine. Please install it."));
363 }
364 else
365 {
366 // resolve the functions we need
367
368 // this will contain the name of the function we failed to resolve
369 // if any at the end
370 const char *funcName = NULL;
371
372 // get the function from rasapi32.dll and abort if it's not found
373 #define RESOLVE_RAS_FUNCTION(type, name) \
374 ms_pfn##name = (type)wxDllLoader::GetSymbol(ms_dllRas, \
375 wxString(_T(#name)) + gs_funcSuffix); \
376 if ( !ms_pfn##name ) \
377 { \
378 funcName = #name; \
379 goto exit; \
380 }
381
382 // a variant of above macro which doesn't abort if the function is
383 // not found in the DLL
384 #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \
385 ms_pfn##name = (type)wxDllLoader::GetSymbol(ms_dllRas, \
386 wxString(_T(#name)) + gs_funcSuffix);
387
388 RESOLVE_RAS_FUNCTION(RASDIAL, RasDial);
389 RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS, RasEnumConnections);
390 RESOLVE_RAS_FUNCTION(RASENUMENTRIES, RasEnumEntries);
391 RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS, RasGetConnectStatus);
392 RESOLVE_RAS_FUNCTION(RASGETERRORSTRING, RasGetErrorString);
393 RESOLVE_RAS_FUNCTION(RASHANGUP, RasHangUp);
394 RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS, RasGetEntryDialParams);
395
396 // suppress wxDllLoader messages about missing (non essential)
397 // functions
398 {
399 wxLogNull noLog;
400
401 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETPROJECTIONINFO, RasGetProjectionInfo);
402 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY, RasCreatePhonebookEntry);
403 RESOLVE_OPTIONAL_RAS_FUNCTION(RASEDITPHONEBOOKENTRY, RasEditPhonebookEntry);
404 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYDIALPARAMS, RasSetEntryDialParams);
405 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETENTRYPROPERTIES, RasGetEntryProperties);
406 RESOLVE_OPTIONAL_RAS_FUNCTION(RASSETENTRYPROPERTIES, RasSetEntryProperties);
407 RESOLVE_OPTIONAL_RAS_FUNCTION(RASRENAMEENTRY, RasRenameEntry);
408 RESOLVE_OPTIONAL_RAS_FUNCTION(RASDELETEENTRY, RasDeleteEntry);
409 RESOLVE_OPTIONAL_RAS_FUNCTION(RASVALIDATEENTRYNAME, RasValidateEntryName);
410 RESOLVE_OPTIONAL_RAS_FUNCTION(RASGETCOUNTRYINFO, RasGetCountryInfo);
411 RESOLVE_OPTIONAL_RAS_FUNCTION(RASENUMDEVICES, RasEnumDevices);
412 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION, RasConnectionNotification);
413 }
414
415 // keep your preprocessor name space clean
416 #undef RESOLVE_RAS_FUNCTION
417 #undef RESOLVE_OPTIONAL_RAS_FUNCTION
418
419 exit:
420 if ( funcName )
421 {
422 static const wxChar *msg = wxTRANSLATE(
423 "The version of remote access service (RAS) installed on this machine is too\
424 old, please upgrade (the following required function is missing: %s)."
425 );
426
427 wxLogError(wxGetTranslation(msg), funcName);
428
429 wxDllLoader::UnloadLibrary(ms_dllRas);
430 ms_dllRas = 0;
431 ms_nDllCount = 0;
432
433 return;
434 }
435 }
436 }
437
438 // enable auto check by default
439 EnableAutoCheckOnlineStatus(0);
440 }
441
442 wxDialUpManagerMSW::~wxDialUpManagerMSW()
443 {
444 CleanUpThreadData();
445
446 if ( !--ms_nDllCount )
447 {
448 // unload the RAS library
449 wxDllLoader::UnloadLibrary(ms_dllRas);
450 ms_dllRas = 0;
451 }
452 }
453
454 // ----------------------------------------------------------------------------
455 // helper functions
456 // ----------------------------------------------------------------------------
457
458 wxString wxDialUpManagerMSW::GetErrorString(DWORD error)
459 {
460 wxChar buffer[512]; // this should be more than enough according to MS docs
461 DWORD dwRet = ms_pfnRasGetErrorString(error, buffer, WXSIZEOF(buffer));
462 switch ( dwRet )
463 {
464 case ERROR_INVALID_PARAMETER:
465 // this was a standard Win32 error probably
466 return wxString(wxSysErrorMsg(error));
467
468 default:
469 {
470 wxLogSysError(dwRet,
471 _("Failed to retrieve text of RAS error message"));
472
473 wxString msg;
474 msg.Printf(_("unknown error (error code %08x)."), error);
475 return msg;
476 }
477
478 case 0:
479 // we want the error message to start from a lower case letter
480 buffer[0] = wxTolower(buffer[0]);
481
482 return wxString(buffer);
483 }
484 }
485
486 HRASCONN wxDialUpManagerMSW::FindActiveConnection()
487 {
488 // enumerate connections
489 DWORD cbBuf = sizeof(RASCONN);
490 LPRASCONN lpRasConn = (LPRASCONN)malloc(cbBuf);
491 if ( !lpRasConn )
492 {
493 // out of memory
494 return 0;
495 }
496
497 lpRasConn->dwSize = sizeof(RASCONN);
498
499 DWORD nConnections = 0;
500 DWORD dwRet = ERROR_BUFFER_TOO_SMALL;
501
502 while ( dwRet == ERROR_BUFFER_TOO_SMALL )
503 {
504 dwRet = ms_pfnRasEnumConnections(lpRasConn, &cbBuf, &nConnections);
505
506 if ( dwRet == ERROR_BUFFER_TOO_SMALL )
507 {
508 LPRASCONN lpRasConnOld = lpRasConn;
509 lpRasConn = (LPRASCONN)realloc(lpRasConn, cbBuf);
510 if ( !lpRasConn )
511 {
512 // out of memory
513 free(lpRasConnOld);
514
515 return 0;
516 }
517 }
518 else if ( dwRet == 0 )
519 {
520 // ok, success
521 break;
522 }
523 else
524 {
525 // an error occured
526 wxLogError(_("Cannot find active dialup connection: %s"),
527 GetErrorString(dwRet).c_str());
528 return 0;
529 }
530 }
531
532 HRASCONN hrasconn;
533
534 switch ( nConnections )
535 {
536 case 0:
537 // no connections
538 hrasconn = 0;
539 break;
540
541 default:
542 // more than 1 connection - we don't know what to do with this
543 // case, so give a warning but continue (taking the first
544 // connection) - the warning is really needed because this function
545 // is used, for example, to select the connection to hang up and so
546 // we may hang up the wrong connection here...
547 wxLogWarning(_("Several active dialup connections found, choosing one randomly."));
548 // fall through
549
550 case 1:
551 // exactly 1 connection, great
552 hrasconn = lpRasConn->hrasconn;
553 }
554
555 free(lpRasConn);
556
557 return hrasconn;
558 }
559
560 void wxDialUpManagerMSW::CleanUpThreadData()
561 {
562 if ( m_hThread )
563 {
564 if ( !SetEvent(m_data.hEventQuit) )
565 {
566 wxLogLastError(_T("SetEvent(RasThreadQuit)"));
567 }
568
569 CloseHandle(m_hThread);
570
571 m_hThread = 0;
572 }
573
574 if ( m_data.hWnd )
575 {
576 DestroyWindow(m_data.hWnd);
577
578 m_data.hWnd = 0;
579 }
580
581 if ( m_data.hEventQuit )
582 {
583 CloseHandle(m_data.hEventQuit);
584
585 m_data.hEventQuit = 0;
586 }
587
588 if ( m_data.hEventRas )
589 {
590 CloseHandle(m_data.hEventRas);
591
592 m_data.hEventRas = 0;
593 }
594 }
595
596 // ----------------------------------------------------------------------------
597 // connection status
598 // ----------------------------------------------------------------------------
599
600 void wxDialUpManagerMSW::CheckRasStatus()
601 {
602 // use int, not bool to compare with -1
603 int isConnected = FindActiveConnection() != 0;
604 if ( isConnected != ms_isConnected )
605 {
606 if ( ms_isConnected != -1 )
607 {
608 // notify the program
609 NotifyApp(isConnected != 0);
610 }
611 // else: it's the first time we're called, just update the flag
612
613 ms_isConnected = isConnected;
614 }
615 }
616
617 void wxDialUpManagerMSW::NotifyApp(bool connected, bool fromOurselves) const
618 {
619 wxDialUpEvent event(connected, fromOurselves);
620 (void)wxTheApp->ProcessEvent(event);
621 }
622
623 // this function is called whenever the status of any RAS connection on this
624 // machine changes by RAS itself
625 void wxDialUpManagerMSW::OnConnectStatusChange()
626 {
627 // we know that status changed, but we don't know whether we're connected
628 // or not - so find it out
629 CheckRasStatus();
630 }
631
632 // this function is called by our callback which we give to RasDial() when
633 // calling it asynchronously
634 void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate,
635 DWORD dwError)
636 {
637 if ( !GetDialer() )
638 {
639 // this probably means that CancelDialing() was called and we get
640 // "disconnected" notification
641 return;
642 }
643
644 // we're only interested in 2 events: connected and disconnected
645 if ( dwError )
646 {
647 wxLogError(_("Failed to establish dialup connection: %s"),
648 GetErrorString(dwError).c_str());
649
650 // we should still call RasHangUp() if we got a non 0 connection
651 if ( ms_hRasConnection )
652 {
653 ms_pfnRasHangUp(ms_hRasConnection);
654 ms_hRasConnection = 0;
655 }
656
657 ms_dialer = NULL;
658
659 NotifyApp(FALSE /* !connected */, TRUE /* we dialed ourselves */);
660 }
661 else if ( rasconnstate == RASCS_Connected )
662 {
663 ms_isConnected = TRUE;
664 ms_dialer = NULL;
665
666 NotifyApp(TRUE /* connected */, TRUE /* we dialed ourselves */);
667 }
668 }
669
670 // ----------------------------------------------------------------------------
671 // implementation of wxDialUpManager functions
672 // ----------------------------------------------------------------------------
673
674 bool wxDialUpManagerMSW::IsOk() const
675 {
676 return ms_dllRas != 0;
677 }
678
679 size_t wxDialUpManagerMSW::GetISPNames(wxArrayString& names) const
680 {
681 // fetch the entries
682 DWORD size = sizeof(RASENTRYNAME);
683 RASENTRYNAME *rasEntries = (RASENTRYNAME *)malloc(size);
684 rasEntries->dwSize = sizeof(RASENTRYNAME);
685
686 DWORD nEntries;
687 DWORD dwRet;
688 do
689 {
690 dwRet = ms_pfnRasEnumEntries
691 (
692 NULL, // reserved
693 NULL, // default phone book (or all)
694 rasEntries, // [out] buffer for the entries
695 &size, // [in/out] size of the buffer
696 &nEntries // [out] number of entries fetched
697 );
698
699 if ( dwRet == ERROR_BUFFER_TOO_SMALL )
700 {
701 // reallocate the buffer
702 rasEntries = (RASENTRYNAME *)realloc(rasEntries, size);
703 }
704 else if ( dwRet != 0 )
705 {
706 // some other error - abort
707 wxLogError(_("Failed to get ISP names: %s"),
708 GetErrorString(dwRet).c_str());
709
710 free(rasEntries);
711
712 return 0u;
713 }
714 }
715 while ( dwRet != 0 );
716
717 // process them
718 names.Empty();
719 for ( size_t n = 0; n < (size_t)nEntries; n++ )
720 {
721 names.Add(rasEntries[n].szEntryName);
722 }
723
724 free(rasEntries);
725
726 // return the number of entries
727 return names.GetCount();
728 }
729
730 bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
731 const wxString& username,
732 const wxString& password,
733 bool async)
734 {
735 // check preconditions
736 wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
737
738 if ( ms_hRasConnection )
739 {
740 wxFAIL_MSG(wxT("there is already an active connection"));
741
742 return TRUE;
743 }
744
745 // get the default ISP if none given
746 wxString entryName(nameOfISP);
747 if ( !entryName )
748 {
749 wxArrayString names;
750 size_t count = GetISPNames(names);
751 switch ( count )
752 {
753 case 0:
754 // no known ISPs, abort
755 wxLogError(_("Failed to connect: no ISP to dial."));
756
757 return FALSE;
758
759 case 1:
760 // only one ISP, choose it
761 entryName = names[0u];
762 break;
763
764 default:
765 // several ISPs, let the user choose
766 {
767 wxString *strings = new wxString[count];
768 for ( size_t i = 0; i < count; i++ )
769 {
770 strings[i] = names[i];
771 }
772
773 entryName = wxGetSingleChoice
774 (
775 _("Choose ISP to dial"),
776 _("Please choose which ISP do you want to connect to"),
777 count,
778 strings
779 );
780
781 delete [] strings;
782
783 if ( !entryName )
784 {
785 // cancelled by user
786 return FALSE;
787 }
788 }
789 }
790 }
791
792 RASDIALPARAMS rasDialParams;
793 rasDialParams.dwSize = sizeof(rasDialParams);
794 wxStrncpy(rasDialParams.szEntryName, entryName, RAS_MaxEntryName);
795
796 // do we have the username and password?
797 if ( !username || !password )
798 {
799 BOOL gotPassword;
800 DWORD dwRet = ms_pfnRasGetEntryDialParams
801 (
802 NULL, // default phonebook
803 &rasDialParams, // [in/out] the params of this entry
804 &gotPassword // [out] did we get password?
805 );
806
807 if ( dwRet != 0 )
808 {
809 wxLogError(_("Failed to connect: missing username/password."));
810
811 return FALSE;
812 }
813 }
814 else
815 {
816 wxStrncpy(rasDialParams.szUserName, username, UNLEN);
817 wxStrncpy(rasDialParams.szPassword, password, PWLEN);
818 }
819
820 // default values for other fields
821 rasDialParams.szPhoneNumber[0] = '\0';
822 rasDialParams.szCallbackNumber[0] = '\0';
823 rasDialParams.szCallbackNumber[0] = '\0';
824
825 rasDialParams.szDomain[0] = '*';
826 rasDialParams.szDomain[1] = '\0';
827
828 // apparently, this is not really necessary - passing NULL instead of the
829 // phone book has the same effect
830 #if 0
831 wxString phoneBook;
832 if ( wxGetOsVersion() == wxWINDOWS_NT )
833 {
834 // first get the length
835 UINT nLen = ::GetSystemDirectory(NULL, 0);
836 nLen++;
837
838 if ( !::GetSystemDirectory(phoneBook.GetWriteBuf(nLen), nLen) )
839 {
840 wxLogSysError(_("Cannot find the location of address book file"));
841 }
842
843 phoneBook.UngetWriteBuf();
844
845 // this is the default phone book
846 phoneBook << "\\ras\\rasphone.pbk";
847 }
848 #endif // 0
849
850 // TODO may be we should disable auto check while async dialing is in
851 // progress?
852
853 ms_dialer = this;
854
855 DWORD dwRet = ms_pfnRasDial
856 (
857 (LPRASDIALEXTENSIONS)NULL, // no extended features
858 NULL, // default phone book file (NT only)
859 &rasDialParams,
860 0, // use callback for notifications
861 async ? wxRasDialFunc // the callback
862 : 0, // no notifications - sync operation
863 &ms_hRasConnection
864 );
865
866 if ( dwRet != 0 )
867 {
868 wxLogError(_("Failed to %s dialup connection: %s"),
869 async ? _("initiate") : _("establish"),
870 GetErrorString(dwRet).c_str());
871
872 // we should still call RasHangUp() if we got a non 0 connection
873 if ( ms_hRasConnection )
874 {
875 ms_pfnRasHangUp(ms_hRasConnection);
876 ms_hRasConnection = 0;
877 }
878
879 ms_dialer = NULL;
880
881 return FALSE;
882 }
883
884 // for async dialing, we're not yet connected
885 if ( !async )
886 {
887 ms_isConnected = TRUE;
888 }
889
890 return TRUE;
891 }
892
893 bool wxDialUpManagerMSW::IsDialing() const
894 {
895 return GetDialer() != NULL;
896 }
897
898 bool wxDialUpManagerMSW::CancelDialing()
899 {
900 if ( !GetDialer() )
901 {
902 // silently ignore
903 return FALSE;
904 }
905
906 wxASSERT_MSG( ms_hRasConnection, wxT("dialing but no connection?") );
907
908 ms_dialer = NULL;
909
910 return HangUp();
911 }
912
913 bool wxDialUpManagerMSW::HangUp()
914 {
915 wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
916
917 // we may terminate either the connection we initiated or another one which
918 // is active now
919 HRASCONN hRasConn;
920 if ( ms_hRasConnection )
921 {
922 hRasConn = ms_hRasConnection;
923
924 ms_hRasConnection = 0;
925 }
926 else
927 {
928 hRasConn = FindActiveConnection();
929 }
930
931 if ( !hRasConn )
932 {
933 wxLogError(_("Cannot hang up - no active dialup connection."));
934
935 return FALSE;
936 }
937
938 DWORD dwRet = ms_pfnRasHangUp(hRasConn);
939 if ( dwRet != 0 )
940 {
941 wxLogError(_("Failed to terminate the dialup connection: %s"),
942 GetErrorString(dwRet).c_str());
943 }
944
945 ms_isConnected = FALSE;
946
947 return TRUE;
948 }
949
950 bool wxDialUpManagerMSW::IsAlwaysOnline() const
951 {
952 // we cache the result (presumably this won't change while the program is
953 // running!)
954 if ( ms_isAlwaysOnline != -1 )
955 {
956 return ms_isAlwaysOnline != 0;
957 }
958
959 // try to use WinInet function first
960 bool ok;
961 wxDllType hDll = wxDllLoader::LoadLibrary(_T("WININET"), &ok);
962 if ( ok )
963 {
964 typedef BOOL (*INTERNETGETCONNECTEDSTATE)(LPDWORD, DWORD);
965 INTERNETGETCONNECTEDSTATE pfnInternetGetConnectedState;
966
967 #define RESOLVE_FUNCTION(type, name) \
968 pfn##name = (type)wxDllLoader::GetSymbol(hDll, _T(#name))
969
970 RESOLVE_FUNCTION(INTERNETGETCONNECTEDSTATE, InternetGetConnectedState);
971
972 if ( pfnInternetGetConnectedState )
973 {
974 DWORD flags = 0;
975 if ( pfnInternetGetConnectedState(&flags, 0 /* reserved */) )
976 {
977 // there is some connection to the net, see of which type
978 ms_isAlwaysOnline = (flags & INTERNET_CONNECTION_LAN != 0) ||
979 (flags & INTERNET_CONNECTION_PROXY != 0);
980 }
981 else
982 {
983 // no Internet connection at all
984 ms_isAlwaysOnline = FALSE;
985 }
986 }
987
988 wxDllLoader::UnloadLibrary(hDll);
989 }
990
991 // did we succeed with WinInet? if not, try something else
992 if ( ms_isAlwaysOnline == -1 )
993 {
994 if ( !IsOnline() )
995 {
996 // definitely no permanent connection because we are not connected
997 // now
998 ms_isAlwaysOnline = FALSE;
999 }
1000 else
1001 {
1002 // of course, having a modem doesn't prevent us from having a
1003 // permanent connection as well, but we have to guess somehow and
1004 // it's probably more common that a system connected via a modem
1005 // doesn't have any other net access, so:
1006 ms_isAlwaysOnline = FALSE;
1007 }
1008 }
1009
1010 wxASSERT_MSG( ms_isAlwaysOnline != -1, wxT("logic error") );
1011
1012 return ms_isAlwaysOnline != 0;
1013 }
1014
1015 bool wxDialUpManagerMSW::IsOnline() const
1016 {
1017 wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
1018
1019 if ( ms_userSpecifiedOnlineStatus != -1 )
1020 {
1021 // user specified flag overrides our logic
1022 return ms_userSpecifiedOnlineStatus != 0;
1023 }
1024 else
1025 {
1026 // return TRUE if there is at least one active connection
1027 return FindActiveConnection() != 0;
1028 }
1029 }
1030
1031 void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline)
1032 {
1033 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1034
1035 ms_userSpecifiedOnlineStatus = isOnline;
1036 }
1037
1038 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
1039 {
1040 wxCHECK_MSG( IsOk(), FALSE, wxT("using uninitialized wxDialUpManager") );
1041
1042 bool ok = ms_pfnRasConnectionNotification != 0;
1043
1044 if ( ok )
1045 {
1046 // we're running under NT 4.0, Windows 98 or later and can use
1047 // RasConnectionNotification() to be notified by a secondary thread
1048
1049 // first, see if we don't have this thread already running
1050 if ( m_hThread != 0 )
1051 {
1052 DWORD dwSuspendCount = 2;
1053 while ( dwSuspendCount > 1 )
1054 {
1055 dwSuspendCount = ResumeThread(m_hThread);
1056 if ( dwSuspendCount == (DWORD)-1 )
1057 {
1058 wxLogLastError(wxT("ResumeThread(RasThread)"));
1059
1060 ok = FALSE;
1061 }
1062 }
1063
1064 if ( ok )
1065 {
1066 return TRUE;
1067 }
1068 }
1069 }
1070
1071 // create all the stuff we need to be notified about RAS connection
1072 // status change
1073
1074 if ( ok )
1075 {
1076 // first create an event to wait on
1077 m_data.hEventRas = CreateEvent
1078 (
1079 NULL, // security attribute (default)
1080 FALSE, // manual reset (not)
1081 FALSE, // initial state (not signaled)
1082 NULL // name (no)
1083 );
1084 if ( !m_data.hEventRas )
1085 {
1086 wxLogLastError(wxT("CreateEvent(RasStatus)"));
1087
1088 ok = FALSE;
1089 }
1090 }
1091
1092 if ( ok )
1093 {
1094 // create the event we use to quit the thread
1095 m_data.hEventQuit = CreateEvent(NULL, FALSE, FALSE, NULL);
1096 if ( !m_data.hEventQuit )
1097 {
1098 wxLogLastError(wxT("CreateEvent(RasThreadQuit)"));
1099
1100 CleanUpThreadData();
1101
1102 ok = FALSE;
1103 }
1104 }
1105
1106 if ( ok && !ms_hwndRas )
1107 {
1108 // create a hidden window to receive notification about connections
1109 // status change
1110 extern const wxChar *wxPanelClassName;
1111 ms_hwndRas = ::CreateWindow(wxPanelClassName, NULL,
1112 0, 0, 0, 0,
1113 0, NULL,
1114 (HMENU)NULL, wxGetInstance(), 0);
1115 if ( !ms_hwndRas )
1116 {
1117 wxLogLastError(wxT("CreateWindow(RasHiddenWindow)"));
1118
1119 CleanUpThreadData();
1120
1121 ok = FALSE;
1122 }
1123
1124 // and subclass it
1125 FARPROC windowProc = MakeProcInstance
1126 (
1127 (FARPROC)wxRasStatusWindowProc,
1128 wxGetInstance()
1129 );
1130
1131 ::SetWindowLong(ms_hwndRas, GWL_WNDPROC, (LONG) windowProc);
1132 }
1133
1134 m_data.hWnd = ms_hwndRas;
1135
1136 if ( ok )
1137 {
1138 // start the secondary thread
1139 m_data.dialUpManager = this;
1140
1141 DWORD tid;
1142 m_hThread = CreateThread
1143 (
1144 NULL,
1145 0,
1146 (LPTHREAD_START_ROUTINE)wxRasMonitorThread,
1147 (void *)&m_data,
1148 0,
1149 &tid
1150 );
1151
1152 if ( !m_hThread )
1153 {
1154 wxLogLastError(wxT("CreateThread(RasStatusThread)"));
1155
1156 CleanUpThreadData();
1157 }
1158 }
1159
1160 if ( ok )
1161 {
1162 // start receiving RAS notifications
1163 DWORD dwRet = ms_pfnRasConnectionNotification
1164 (
1165 (HRASCONN)INVALID_HANDLE_VALUE,
1166 m_data.hEventRas,
1167 3 /* RASCN_Connection | RASCN_Disconnection */
1168 );
1169
1170 if ( dwRet != 0 )
1171 {
1172 wxLogDebug(wxT("RasConnectionNotification() failed: %s"),
1173 GetErrorString(dwRet).c_str());
1174
1175 CleanUpThreadData();
1176 }
1177 else
1178 {
1179 return TRUE;
1180 }
1181 }
1182
1183 // we're running under Windows 95 and have to poll ourselves
1184 // (or, alternatively, the code above for NT/98 failed)
1185 m_timerStatusPolling.Stop();
1186 if ( nSeconds == 0 )
1187 {
1188 // default value
1189 nSeconds = 60;
1190 }
1191 m_timerStatusPolling.Start(nSeconds * 1000);
1192
1193 return TRUE;
1194 }
1195
1196 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
1197 {
1198 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1199
1200 if ( m_hThread )
1201 {
1202 // we have running secondary thread, it's just enough to suspend it
1203 if ( SuspendThread(m_hThread) == (DWORD)-1 )
1204 {
1205 wxLogLastError(wxT("SuspendThread(RasThread)"));
1206 }
1207 }
1208 else
1209 {
1210 // even simpler - just stop the timer
1211 m_timerStatusPolling.Stop();
1212 }
1213 }
1214
1215 // ----------------------------------------------------------------------------
1216 // stubs which don't do anything in MSW version
1217 // ----------------------------------------------------------------------------
1218
1219 void wxDialUpManagerMSW::SetWellKnownHost(const wxString& WXUNUSED(hostname),
1220 int WXUNUSED(port))
1221 {
1222 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1223
1224 // nothing to do - we don't use this
1225 }
1226
1227 void wxDialUpManagerMSW::SetConnectCommand(const wxString& WXUNUSED(dial),
1228 const wxString& WXUNUSED(hangup))
1229 {
1230 wxCHECK_RET( IsOk(), wxT("using uninitialized wxDialUpManager") );
1231
1232 // nothing to do - we don't use this
1233 }
1234
1235 // ----------------------------------------------------------------------------
1236 // callbacks
1237 // ----------------------------------------------------------------------------
1238
1239 static DWORD wxRasMonitorThread(wxRasThreadData *data)
1240 {
1241 HANDLE handles[2];
1242 handles[0] = data->hEventRas;
1243 handles[1] = data->hEventQuit;
1244
1245 bool cont = TRUE;
1246 while ( cont )
1247 {
1248 DWORD dwRet = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1249
1250 switch ( dwRet )
1251 {
1252 case WAIT_OBJECT_0:
1253 // RAS connection status changed
1254 SendMessage(data->hWnd, wxWM_RAS_STATUS_CHANGED,
1255 0, (LPARAM)data);
1256 break;
1257
1258 case WAIT_OBJECT_0 + 1:
1259 cont = FALSE;
1260 break;
1261
1262 case WAIT_FAILED:
1263 wxLogLastError(wxT("WaitForMultipleObjects(RasMonitor)"));
1264 break;
1265 }
1266 }
1267
1268 return 0;
1269 }
1270
1271 static LRESULT APIENTRY wxRasStatusWindowProc(HWND hWnd, UINT message,
1272 WPARAM wParam, LPARAM lParam)
1273 {
1274 if ( message == wxWM_RAS_STATUS_CHANGED )
1275 {
1276 wxRasThreadData *data = (wxRasThreadData *)lParam;
1277 data->dialUpManager->OnConnectStatusChange();
1278 }
1279 else if ( message == wxWM_RAS_DIALING_PROGRESS )
1280 {
1281 wxDialUpManagerMSW *dialUpManager = wxDialUpManagerMSW::GetDialer();
1282
1283 dialUpManager->OnDialProgress((RASCONNSTATE)wParam, lParam);
1284 }
1285
1286 return 0;
1287 }
1288
1289 static void WINAPI wxRasDialFunc(UINT unMsg,
1290 RASCONNSTATE rasconnstate,
1291 DWORD dwError)
1292 {
1293 wxDialUpManagerMSW *dialUpManager = wxDialUpManagerMSW::GetDialer();
1294
1295 wxCHECK_RET( dialUpManager, wxT("who started to dial then?") );
1296
1297 SendMessage(dialUpManager->GetRasWindow(), wxWM_RAS_DIALING_PROGRESS,
1298 rasconnstate, dwError);
1299 }
1300
1301 #endif
1302 // __BORLANDC__
1303 #endif // wxUSE_DIALUP_MANAGER