]> git.saurik.com Git - wxWidgets.git/blob - src/msw/net.cpp
added wxHTML
[wxWidgets.git] / src / msw / net.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/net.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 #endif
38
39 #include "wx/dynlib.h"
40
41 #include "wx/net.h"
42
43 #include <ras.h>
44 #include <raserror.h>
45
46 #include "wx/msw/private.h"
47
48 // ----------------------------------------------------------------------------
49 // constants
50 // ----------------------------------------------------------------------------
51
52 // this message is sent by the secondary thread when RAS status changes
53 #define wxWM_RAS_STATUS_CHANGED (WM_USER + 10010)
54
55 // ----------------------------------------------------------------------------
56 // types
57 // ----------------------------------------------------------------------------
58
59 // the signatures of RAS functions: all this is quite heavy, but we must do it
60 // to allow running wxWin programs on machine which don't have RAS installed
61 // (this does exist) - if we link with rasapi32.lib, the program will fail on
62 // startup because of the missing DLL...
63
64 #ifndef UNICODE
65 typedef DWORD (* RASDIAL)( LPRASDIALEXTENSIONS, LPCSTR, LPRASDIALPARAMSA, DWORD, LPVOID, LPHRASCONN );
66 typedef DWORD (* RASENUMCONNECTIONS)( LPRASCONNA, LPDWORD, LPDWORD );
67 typedef DWORD (* RASENUMENTRIES)( LPCSTR, LPCSTR, LPRASENTRYNAMEA, LPDWORD, LPDWORD );
68 typedef DWORD (* RASGETCONNECTSTATUS)( HRASCONN, LPRASCONNSTATUSA );
69 typedef DWORD (* RASGETERRORSTRING)( UINT, LPSTR, DWORD );
70 typedef DWORD (* RASHANGUP)( HRASCONN );
71 typedef DWORD (* RASGETPROJECTIONINFO)( HRASCONN, RASPROJECTION, LPVOID, LPDWORD );
72 typedef DWORD (* RASCREATEPHONEBOOKENTRY)( HWND, LPCSTR );
73 typedef DWORD (* RASEDITPHONEBOOKENTRY)( HWND, LPCSTR, LPCSTR );
74 typedef DWORD (* RASSETENTRYDIALPARAMS)( LPCSTR, LPRASDIALPARAMSA, BOOL );
75 typedef DWORD (* RASGETENTRYDIALPARAMS)( LPCSTR, LPRASDIALPARAMSA, LPBOOL );
76 typedef DWORD (* RASENUMDEVICES)( LPRASDEVINFOA, LPDWORD, LPDWORD );
77 typedef DWORD (* RASGETCOUNTRYINFO)( LPRASCTRYINFOA, LPDWORD );
78 typedef DWORD (* RASGETENTRYPROPERTIES)( LPCSTR, LPCSTR, LPRASENTRYA, LPDWORD, LPBYTE, LPDWORD );
79 typedef DWORD (* RASSETENTRYPROPERTIES)( LPCSTR, LPCSTR, LPRASENTRYA, DWORD, LPBYTE, DWORD );
80 typedef DWORD (* RASRENAMEENTRY)( LPCSTR, LPCSTR, LPCSTR );
81 typedef DWORD (* RASDELETEENTRY)( LPCSTR, LPCSTR );
82 typedef DWORD (* RASVALIDATEENTRYNAME)( LPCSTR, LPCSTR );
83 typedef DWORD (* RASCONNECTIONNOTIFICATION)( HRASCONN, HANDLE, DWORD );
84
85 static const char gs_funcSuffix = 'A';
86 #else // Unicode
87 typedef DWORD (* RASDIAL)( LPRASDIALEXTENSIONS, LPCWSTR, LPRASDIALPARAMSW, DWORD, LPVOID, LPHRASCONN );
88 typedef DWORD (* RASENUMCONNECTIONS)( LPRASCONNW, LPDWORD, LPDWORD );
89 typedef DWORD (* RASENUMENTRIES)( LPCWSTR, LPCWSTR, LPRASENTRYNAMEW, LPDWORD, LPDWORD );
90 typedef DWORD (* RASGETCONNECTSTATUS)( HRASCONN, LPRASCONNSTATUSW );
91 typedef DWORD (* RASGETERRORSTRING)( UINT, LPWSTR, DWORD );
92 typedef DWORD (* RASHANGUP)( HRASCONN );
93 typedef DWORD (* RASGETPROJECTIONINFO)( HRASCONN, RASPROJECTION, LPVOID, LPDWORD );
94 typedef DWORD (* RASCREATEPHONEBOOKENTRY)( HWND, LPCWSTR );
95 typedef DWORD (* RASEDITPHONEBOOKENTRY)( HWND, LPCWSTR, LPCWSTR );
96 typedef DWORD (* RASSETENTRYDIALPARAMS)( LPCWSTR, LPRASDIALPARAMSW, BOOL );
97 typedef DWORD (* RASGETENTRYDIALPARAMS)( LPCWSTR, LPRASDIALPARAMSW, LPBOOL );
98 typedef DWORD (* RASENUMDEVICES)( LPRASDEVINFOW, LPDWORD, LPDWORD );
99 typedef DWORD (* RASGETCOUNTRYINFO)( LPRASCTRYINFOW, LPDWORD );
100 typedef DWORD (* RASGETENTRYPROPERTIES)( LPCWSTR, LPCWSTR, LPRASENTRYW, LPDWORD, LPBYTE, LPDWORD );
101 typedef DWORD (* RASSETENTRYPROPERTIES)( LPCWSTR, LPCWSTR, LPRASENTRYW, DWORD, LPBYTE, DWORD );
102 typedef DWORD (* RASRENAMEENTRY)( LPCWSTR, LPCWSTR, LPCWSTR );
103 typedef DWORD (* RASDELETEENTRY)( LPCWSTR, LPCWSTR );
104 typedef DWORD (* RASVALIDATEENTRYNAME)( LPCWSTR, LPCWSTR );
105 typedef DWORD (* RASCONNECTIONNOTIFICATION)( HRASCONN, HANDLE, DWORD );
106
107 static const char gs_funcSuffix = 'W';
108 #endif // ASCII/Unicode
109
110 // structure passed to the secondary thread
111 struct wxRasThreadData
112 {
113 wxRasThreadData()
114 {
115 hWnd = 0;
116 hEventRas = hEventQuit = INVALID_HANDLE_VALUE;
117 dialUpManager = NULL;
118 }
119
120 HWND hWnd; // window to send notifications to
121 HANDLE hEventRas, // event which RAS signals when status changes
122 hEventQuit; // event which we signal when we terminate
123
124 class WXDLLEXPORT wxDialUpManagerMSW *dialUpManager; // the owner
125 };
126
127 // ----------------------------------------------------------------------------
128 // wxDialUpManager class for MSW
129 // ----------------------------------------------------------------------------
130
131 class WXDLLEXPORT wxDialUpManagerMSW : public wxDialUpManager
132 {
133 public:
134 // ctor & dtor
135 wxDialUpManagerMSW();
136 virtual ~wxDialUpManagerMSW();
137
138 // implement base class pure virtuals
139 virtual bool IsOk() const;
140 virtual bool Dial(const wxString& nameOfISP,
141 const wxString& username,
142 const wxString& password);
143 virtual bool HangUp();
144 virtual bool IsOnline();
145 virtual void SetOnlineStatus(bool isOnline = TRUE);
146 virtual bool EnableAutoCheckOnlineStatus(size_t nSeconds);
147 virtual void DisableAutoCheckOnlineStatus();
148 virtual void SetWellKnownHost(const wxString& hostname);
149
150 // for RasTimer
151 void CheckRasStatus(bool firstTime = FALSE);
152
153 // for wxRasStatusWindowProc
154 void OnConnectStatusChange();
155
156 private:
157 // return the error string for the given RAS error code
158 wxString GetErrorString(DWORD error);
159
160 // find the (first) handle of the active connection
161 HRASCONN FindActiveConnection();
162
163 // notify the application about status change
164 void NotifyApp(bool connected) const;
165
166 // destroy the thread data and the thread itself
167 void CleanUpThreadData();
168
169 // timer used for polling RAS status
170 class RasTimer : public wxTimer
171 {
172 public:
173 RasTimer(wxDialUpManagerMSW *dialUpManager)
174 { m_dialUpManager = dialUpManager; }
175
176 virtual void Notify() { m_dialUpManager->CheckRasStatus(); }
177
178 private:
179 wxDialUpManagerMSW *m_dialUpManager;
180 } m_timerStatusPolling;
181
182 // thread handle for the thread sitting on connection change event
183 HANDLE m_hThread;
184
185 // data used by this thread and our hidden window to send messages between
186 // each other
187 wxRasThreadData m_data;
188
189 // the handle of the connection we initiated or 0 if none
190 static HRASCONN ms_hRasConnection;
191
192 // the use count of rasapi32.dll
193 static int ms_nDllCount;
194
195 // the handle of rasapi32.dll when it's loaded
196 static wxDllType ms_dllRas;
197
198 // the pointers to RAS functions
199 static RASDIAL ms_pfnRasDial;
200 static RASENUMCONNECTIONS ms_pfnRasEnumConnections;
201 static RASENUMENTRIES ms_pfnRasEnumEntries;
202 static RASGETCONNECTSTATUS ms_pfnRasGetConnectStatus;
203 static RASGETERRORSTRING ms_pfnRasGetErrorString;
204 static RASHANGUP ms_pfnRasHangUp;
205 static RASGETPROJECTIONINFO ms_pfnRasGetProjectionInfo;
206 static RASCREATEPHONEBOOKENTRY ms_pfnRasCreatePhonebookEntry;
207 static RASEDITPHONEBOOKENTRY ms_pfnRasEditPhonebookEntry;
208 static RASSETENTRYDIALPARAMS ms_pfnRasSetEntryDialParams;
209 static RASGETENTRYDIALPARAMS ms_pfnRasGetEntryDialParams;
210 static RASENUMDEVICES ms_pfnRasEnumDevices;
211 static RASGETCOUNTRYINFO ms_pfnRasGetCountryInfo;
212 static RASGETENTRYPROPERTIES ms_pfnRasGetEntryProperties;
213 static RASSETENTRYPROPERTIES ms_pfnRasSetEntryProperties;
214 static RASRENAMEENTRY ms_pfnRasRenameEntry;
215 static RASDELETEENTRY ms_pfnRasDeleteEntry;
216 static RASVALIDATEENTRYNAME ms_pfnRasValidateEntryName;
217
218 // this function is not supported by Win95
219 static RASCONNECTIONNOTIFICATION ms_pfnRasConnectionNotification;
220
221 // if this flag is different from -1, it overrides IsOnline()
222 static int ms_userSpecifiedOnlineStatus;
223 };
224
225 // ----------------------------------------------------------------------------
226 // private functions
227 // ----------------------------------------------------------------------------
228
229 static LRESULT APIENTRY wxRasStatusWindowProc(HWND hWnd, UINT message,
230 WPARAM wParam, LPARAM lParam);
231
232 static DWORD wxRasMonitorThread(wxRasThreadData *data);
233
234 // ============================================================================
235 // implementation
236 // ============================================================================
237
238 // ----------------------------------------------------------------------------
239 // init the static variables
240 // ----------------------------------------------------------------------------
241
242 wxDialUpManager *wxDialUpManager::ms_dialUpManager = NULL;
243
244 HRASCONN wxDialUpManagerMSW::ms_hRasConnection = 0;
245
246 int wxDialUpManagerMSW::ms_nDllCount = 0;
247 wxDllType wxDialUpManagerMSW::ms_dllRas = 0;
248
249 RASDIAL wxDialUpManagerMSW::ms_pfnRasDial = 0;
250 RASENUMCONNECTIONS wxDialUpManagerMSW::ms_pfnRasEnumConnections = 0;
251 RASENUMENTRIES wxDialUpManagerMSW::ms_pfnRasEnumEntries = 0;
252 RASGETCONNECTSTATUS wxDialUpManagerMSW::ms_pfnRasGetConnectStatus = 0;
253 RASGETERRORSTRING wxDialUpManagerMSW::ms_pfnRasGetErrorString = 0;
254 RASHANGUP wxDialUpManagerMSW::ms_pfnRasHangUp = 0;
255 RASGETPROJECTIONINFO wxDialUpManagerMSW::ms_pfnRasGetProjectionInfo = 0;
256 RASCREATEPHONEBOOKENTRY wxDialUpManagerMSW::ms_pfnRasCreatePhonebookEntry = 0;
257 RASEDITPHONEBOOKENTRY wxDialUpManagerMSW::ms_pfnRasEditPhonebookEntry = 0;
258 RASSETENTRYDIALPARAMS wxDialUpManagerMSW::ms_pfnRasSetEntryDialParams = 0;
259 RASGETENTRYDIALPARAMS wxDialUpManagerMSW::ms_pfnRasGetEntryDialParams = 0;
260 RASENUMDEVICES wxDialUpManagerMSW::ms_pfnRasEnumDevices = 0;
261 RASGETCOUNTRYINFO wxDialUpManagerMSW::ms_pfnRasGetCountryInfo = 0;
262 RASGETENTRYPROPERTIES wxDialUpManagerMSW::ms_pfnRasGetEntryProperties = 0;
263 RASSETENTRYPROPERTIES wxDialUpManagerMSW::ms_pfnRasSetEntryProperties = 0;
264 RASRENAMEENTRY wxDialUpManagerMSW::ms_pfnRasRenameEntry = 0;
265 RASDELETEENTRY wxDialUpManagerMSW::ms_pfnRasDeleteEntry = 0;
266 RASVALIDATEENTRYNAME wxDialUpManagerMSW::ms_pfnRasValidateEntryName = 0;
267 RASCONNECTIONNOTIFICATION wxDialUpManagerMSW::ms_pfnRasConnectionNotification = 0;
268
269 int wxDialUpManagerMSW::ms_userSpecifiedOnlineStatus = -1;
270
271 // ----------------------------------------------------------------------------
272 // ctor and dtor: the dynamic linking happens here
273 // ----------------------------------------------------------------------------
274
275 // the static creator function is implemented here
276 wxDialUpManager *wxDialUpManager::Create()
277 {
278 return new wxDialUpManagerMSW;
279 }
280
281 #ifdef __VISUALC__
282 // warning about "'this' : used in base member initializer list" - so what?
283 #pragma warning(disable:4355)
284 #endif // VC++
285
286 wxDialUpManagerMSW::wxDialUpManagerMSW()
287 : m_timerStatusPolling(this)
288 {
289 if ( !ms_nDllCount++ )
290 {
291 // load the RAS library
292 ms_dllRas = wxDllLoader::LoadLibrary("RASAPI32");
293 if ( !ms_dllRas )
294 {
295 wxLogError(_("Dial up functions are unavailable because the "
296 "remote access service (RAS) is not installed "
297 "on this machine. Please install it."));
298 }
299 else
300 {
301 // resolve the functions we need
302
303 // this will contain the name of the function we failed to resolve
304 // if any at the end
305 const char *funcName = NULL;
306
307 // get the function from rasapi32.dll and abort if it's not found
308 #define RESOLVE_RAS_FUNCTION(type, name) \
309 ms_pfn##name = (type)wxDllLoader::GetSymbol(ms_dllRas, \
310 wxString(#name) + gs_funcSuffix); \
311 if ( !ms_pfn##name ) \
312 { \
313 funcName = #name; \
314 goto exit; \
315 }
316
317 // a variant of above macro which doesn't abort if the function is
318 // not found in the DLL
319 #define RESOLVE_OPTIONAL_RAS_FUNCTION(type, name) \
320 ms_pfn##name = (type)wxDllLoader::GetSymbol(ms_dllRas, \
321 wxString(#name) + gs_funcSuffix);
322
323 RESOLVE_RAS_FUNCTION(RASDIAL, RasDial);
324 RESOLVE_RAS_FUNCTION(RASENUMCONNECTIONS, RasEnumConnections);
325 RESOLVE_RAS_FUNCTION(RASENUMENTRIES, RasEnumEntries);
326 RESOLVE_RAS_FUNCTION(RASGETCONNECTSTATUS, RasGetConnectStatus);
327 RESOLVE_RAS_FUNCTION(RASGETERRORSTRING, RasGetErrorString);
328 RESOLVE_RAS_FUNCTION(RASHANGUP, RasHangUp);
329 RESOLVE_RAS_FUNCTION(RASGETPROJECTIONINFO, RasGetProjectionInfo);
330 RESOLVE_RAS_FUNCTION(RASCREATEPHONEBOOKENTRY, RasCreatePhonebookEntry);
331 RESOLVE_RAS_FUNCTION(RASEDITPHONEBOOKENTRY, RasEditPhonebookEntry);
332 RESOLVE_RAS_FUNCTION(RASSETENTRYDIALPARAMS, RasSetEntryDialParams);
333 RESOLVE_RAS_FUNCTION(RASGETENTRYDIALPARAMS, RasGetEntryDialParams);
334 RESOLVE_RAS_FUNCTION(RASENUMDEVICES, RasEnumDevices);
335 RESOLVE_RAS_FUNCTION(RASGETCOUNTRYINFO, RasGetCountryInfo);
336 RESOLVE_RAS_FUNCTION(RASGETENTRYPROPERTIES, RasGetEntryProperties);
337 RESOLVE_RAS_FUNCTION(RASSETENTRYPROPERTIES, RasSetEntryProperties);
338 RESOLVE_RAS_FUNCTION(RASRENAMEENTRY, RasRenameEntry);
339 RESOLVE_RAS_FUNCTION(RASDELETEENTRY, RasDeleteEntry);
340 RESOLVE_RAS_FUNCTION(RASVALIDATEENTRYNAME, RasValidateEntryName);
341
342 RESOLVE_OPTIONAL_RAS_FUNCTION(RASCONNECTIONNOTIFICATION, RasConnectionNotification);
343
344 // keep your preprocessor name space clean
345 #undef RESOLVE_RAS_FUNCTION
346 #undef RESOLVE_OPTIONAL_RAS_FUNCTION
347
348 exit:
349 if ( funcName )
350 {
351 wxLogError(_("The version of remote access service (RAS) "
352 "installed on this machine is too old, please "
353 "upgrade (the following required function is "
354 "missing: %s)."), funcName);
355
356 wxDllLoader::UnloadLibrary(ms_dllRas);
357 ms_dllRas = 0;
358 }
359 }
360 }
361
362 // initialize our data
363 m_hThread = 0;
364
365 // enable auto check by default
366 EnableAutoCheckOnlineStatus(0);
367 }
368
369 wxDialUpManagerMSW::~wxDialUpManagerMSW()
370 {
371 CleanUpThreadData();
372
373 if ( !--ms_nDllCount )
374 {
375 // unload the RAS library
376 wxDllLoader::UnloadLibrary(ms_dllRas);
377 ms_dllRas = 0;
378 }
379 }
380
381 // ----------------------------------------------------------------------------
382 // helper functions
383 // ----------------------------------------------------------------------------
384
385 wxString wxDialUpManagerMSW::GetErrorString(DWORD error)
386 {
387 wxCHECK_MSG( IsOk(), "", _T("using uninitialized wxDialUpManager") );
388
389 wxChar buffer[512]; // this should be more than enough according to MS docs
390 DWORD dwRet = ms_pfnRasGetErrorString(error, buffer, WXSIZEOF(buffer));
391 switch ( dwRet )
392 {
393 case ERROR_INVALID_PARAMETER:
394 // this was a standard Win32 error probably
395 return wxString(wxSysErrorMsg(error));
396
397 default:
398 {
399 wxLogSysError(dwRet, _("Failed to retrieve text of RAS "
400 "error message"));
401
402 wxString msg;
403 msg.Printf(_("unknown error (error code %08x)."), error);
404 return msg;
405 }
406
407 case 0:
408 // we want the error message to start from a lower case letter
409 buffer[0] = wxTolower(buffer[0]);
410
411 return wxString(buffer);
412 }
413 }
414
415 HRASCONN wxDialUpManagerMSW::FindActiveConnection()
416 {
417 wxCHECK_MSG( IsOk(), 0, _T("using uninitialized wxDialUpManager") );
418
419 // enumerate connections
420 DWORD cbBuf = sizeof(RASCONN);
421 LPRASCONN lpRasConn = (LPRASCONN)malloc(cbBuf);
422 if ( !lpRasConn )
423 {
424 // out of memory
425 return 0;
426 }
427
428 lpRasConn->dwSize = sizeof(RASCONN);
429
430 DWORD nConnections = 0;
431 DWORD dwRet = ERROR_BUFFER_TOO_SMALL;
432
433 while ( dwRet == ERROR_BUFFER_TOO_SMALL )
434 {
435 dwRet = ms_pfnRasEnumConnections(lpRasConn, &cbBuf, &nConnections);
436
437 if ( dwRet == ERROR_BUFFER_TOO_SMALL )
438 {
439 LPRASCONN lpRasConnOld = lpRasConn;
440 lpRasConn = (LPRASCONN)realloc(lpRasConn, cbBuf);
441 if ( !lpRasConn )
442 {
443 // out of memory
444 free(lpRasConnOld);
445
446 return 0;
447 }
448 }
449 else if ( dwRet == 0 )
450 {
451 // ok, success
452 break;
453 }
454 else
455 {
456 // an error occured
457 wxLogError(_("Cannot find active dialup connection: %s"),
458 GetErrorString(dwRet));
459 return 0;
460 }
461 }
462
463 HRASCONN hrasconn;
464
465 switch ( nConnections )
466 {
467 case 0:
468 // no connections
469 hrasconn = 0;
470 break;
471
472 default:
473 // more than 1 connection - we don't know what to do with this
474 // case, so give a warning but continue (taking the first
475 // connection) - the warning is really needed because this function
476 // is used, for example, to select the connection to hang up and so
477 // we may hang up the wrong connection here...
478 wxLogWarning(_("Several active dialup connections found, "
479 "choosing one randomly."));
480 // fall through
481
482 case 1:
483 // exactly 1 connection, great
484 hrasconn = lpRasConn->hrasconn;
485 }
486
487 free(lpRasConn);
488
489 return hrasconn;
490 }
491
492 void wxDialUpManagerMSW::CleanUpThreadData()
493 {
494 if ( m_hThread )
495 {
496 if ( !SetEvent(m_data.hEventQuit) )
497 {
498 wxLogLastError("SetEvent(RasThreadQuit)");
499 }
500
501 CloseHandle(m_hThread);
502
503 m_hThread = 0;
504 }
505
506 if ( m_data.hWnd )
507 {
508 DestroyWindow(m_data.hWnd);
509
510 m_data.hWnd = 0;
511 }
512
513 if ( m_data.hEventQuit )
514 {
515 CloseHandle(m_data.hEventQuit);
516
517 m_data.hEventQuit = 0;
518 }
519
520 if ( m_data.hEventRas )
521 {
522 CloseHandle(m_data.hEventRas);
523
524 m_data.hEventRas = 0;
525 }
526 }
527
528 // ----------------------------------------------------------------------------
529 // connection status
530 // ----------------------------------------------------------------------------
531
532 void wxDialUpManagerMSW::CheckRasStatus(bool firstTime)
533 {
534 static int s_connected = -1;
535
536 // use int, not bool to compare with -1
537 int connected = FindActiveConnection() != 0;
538 if ( connected != s_connected )
539 {
540 if ( (s_connected == -1) || firstTime )
541 {
542 // it's the first time we're called, just update the flag
543 }
544 else
545 {
546 // notify the program
547 NotifyApp(connected != 0);
548 }
549
550 s_connected = connected;
551 }
552 }
553
554 void wxDialUpManagerMSW::NotifyApp(bool connected) const
555 {
556 wxDialUpEvent event(connected);
557 (void)wxTheApp->ProcessEvent(event);
558 }
559
560 void wxDialUpManagerMSW::OnConnectStatusChange()
561 {
562 // we know that status changed, but we don't know whether we're connected
563 // or not - so find it out
564 NotifyApp(FindActiveConnection() != 0);
565 }
566
567 // ----------------------------------------------------------------------------
568 // implementation of wxDialUpManager functions
569 // ----------------------------------------------------------------------------
570
571 bool wxDialUpManagerMSW::IsOk() const
572 {
573 return ms_nDllCount != 0;
574 }
575
576 bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
577 const wxString& username,
578 const wxString& password)
579 {
580 wxCHECK_MSG( IsOk(), FALSE, _T("using uninitialized wxDialUpManager") );
581
582 RASDIALPARAMS rasDialParams;
583 rasDialParams.dwSize = sizeof(rasDialParams);
584 strncpy(rasDialParams.szEntryName, nameOfISP, RAS_MaxEntryName);
585 rasDialParams.szPhoneNumber[0] = '\0';
586 rasDialParams.szCallbackNumber[0] = '*';
587 rasDialParams.szCallbackNumber[0] = '\0';
588
589 rasDialParams.szUserName[0] = '\0';
590 rasDialParams.szPassword[0] = '\0';
591 rasDialParams.szDomain[0] = '*';
592 rasDialParams.szDomain[1] = '\0';
593
594 wxString phoneBook;
595 if ( wxGetOsVersion() == wxWINDOWS_NT )
596 {
597 // first get the length
598 UINT nLen = ::GetSystemDirectory(NULL, 0);
599 nLen++;
600
601 if ( !::GetSystemDirectory(phoneBook.GetWriteBuf(nLen), nLen) )
602 {
603 wxLogSysError(_("Cannot find the location of address book file"));
604 }
605
606 phoneBook.UngetWriteBuf();
607
608 // this is the default phone book
609 phoneBook << "\\ras\\rasphone.pbk";
610 }
611
612 ms_hRasConnection = 0;
613 DWORD dwRet = ms_pfnRasDial
614 (
615 (LPRASDIALEXTENSIONS)NULL,
616 phoneBook, // phone book file (NT only)
617 &rasDialParams,
618 0, // ignored because of next entry
619 NULL, // no notifications - synchronous operations
620 &ms_hRasConnection
621 );
622
623 if ( dwRet != 0 )
624 {
625 wxLogError(_("Failed to establish dialup connection: %s"),
626 GetErrorString(dwRet));
627
628 return FALSE;
629 }
630
631 return TRUE;
632 }
633
634 bool wxDialUpManagerMSW::HangUp()
635 {
636 wxCHECK_MSG( IsOk(), FALSE, _T("using uninitialized wxDialUpManager") );
637
638 // we may terminate either the connection we initiated or another one which
639 // is active now
640 HRASCONN hRasConn = ms_hRasConnection ? ms_hRasConnection
641 : FindActiveConnection();
642
643 if ( !hRasConn )
644 {
645 wxLogError(_("Cannot hang up - no active dialup connection."));
646
647 return FALSE;
648 }
649
650 DWORD dwRet = ms_pfnRasHangUp(hRasConn);
651 if ( dwRet != 0 )
652 {
653 wxLogError(_("Failed to terminate the dialup connection: %s"),
654 GetErrorString(dwRet));
655 }
656
657 return TRUE;
658 }
659
660 bool wxDialUpManagerMSW::IsOnline()
661 {
662 wxCHECK_MSG( IsOk(), FALSE, _T("using uninitialized wxDialUpManager") );
663
664 if ( ms_userSpecifiedOnlineStatus != -1 )
665 {
666 // user specified flag overrides our logic
667 return ms_userSpecifiedOnlineStatus != 0;
668 }
669 else
670 {
671 // return TRUE if there is at least one active connection
672 return FindActiveConnection() != 0;
673 }
674 }
675
676 void wxDialUpManagerMSW::SetOnlineStatus(bool isOnline)
677 {
678 wxCHECK_RET( IsOk(), _T("using uninitialized wxDialUpManager") );
679
680 ms_userSpecifiedOnlineStatus = isOnline;
681 }
682
683 bool wxDialUpManagerMSW::EnableAutoCheckOnlineStatus(size_t nSeconds)
684 {
685 wxCHECK_MSG( IsOk(), FALSE, _T("using uninitialized wxDialUpManager") );
686
687 bool ok = ms_pfnRasConnectionNotification != 0;
688
689 if ( ok )
690 {
691 // we're running under NT 4.0, Windows 98 or later and can use
692 // RasConnectionNotification() to be notified by a secondary thread
693
694 // first, see if we don't have this thread already running
695 if ( m_hThread != 0 )
696 {
697 DWORD dwSuspendCount = 2;
698 while ( dwSuspendCount > 1 )
699 {
700 dwSuspendCount = ResumeThread(m_hThread);
701 if ( dwSuspendCount == (DWORD)-1 )
702 {
703 wxLogLastError("ResumeThread(RasThread)");
704
705 ok = FALSE;
706 }
707 }
708
709 if ( ok )
710 {
711 return TRUE;
712 }
713 }
714 }
715
716 // create all the stuff we need to be notified about RAS connection
717 // status change
718
719 if ( ok )
720 {
721 // first create an event to wait on
722 m_data.hEventRas = CreateEvent
723 (
724 NULL, // security attribute (default)
725 FALSE, // manual reset (not)
726 FALSE, // initial state (not signaled)
727 NULL // name (no)
728 );
729 if ( !m_data.hEventRas )
730 {
731 wxLogLastError("CreateEvent(RasStatus)");
732
733 ok = FALSE;
734 }
735 }
736
737 if ( ok )
738 {
739 // create the event we use to quit the thread
740 m_data.hEventQuit = CreateEvent(NULL, FALSE, FALSE, NULL);
741 if ( !m_data.hEventQuit )
742 {
743 wxLogLastError("CreateEvent(RasThreadQuit)");
744
745 CleanUpThreadData();
746
747 ok = FALSE;
748 }
749 }
750
751 if ( ok )
752 {
753 // create a hidden window to receive notification about connections
754 // status change
755 extern wxChar wxPanelClassName[];
756 m_data.hWnd = ::CreateWindow(wxPanelClassName, NULL,
757 0, 0, 0, 0,
758 0, NULL,
759 (HMENU)NULL, wxGetInstance(), 0);
760 if ( !m_data.hWnd )
761 {
762 wxLogLastError("CreateWindow(RasHiddenWindow)");
763
764 CleanUpThreadData();
765
766 ok = FALSE;
767 }
768
769 // and subclass it
770 FARPROC windowProc = MakeProcInstance
771 (
772 (FARPROC)wxRasStatusWindowProc,
773 wxGetInstance()
774 );
775
776 ::SetWindowLong(m_data.hWnd, GWL_WNDPROC, (LONG) windowProc);
777 }
778
779 if ( ok )
780 {
781 // start the secondary thread
782 m_data.dialUpManager = this;
783
784 DWORD tid;
785 m_hThread = CreateThread
786 (
787 NULL,
788 0,
789 (LPTHREAD_START_ROUTINE)wxRasMonitorThread,
790 (void *)&m_data,
791 0,
792 &tid
793 );
794
795 if ( !m_hThread )
796 {
797 wxLogLastError("CreateThread(RasStatusThread)");
798
799 CleanUpThreadData();
800 }
801 }
802
803 if ( ok )
804 {
805 // start receiving RAS notifications
806 DWORD dwRet = ms_pfnRasConnectionNotification
807 (
808 (HRASCONN)INVALID_HANDLE_VALUE,
809 m_data.hEventRas,
810 3 /* RASCN_Connection | RASCN_Disconnection */
811 );
812
813 if ( dwRet != 0 )
814 {
815 wxLogDebug(_T("RasConnectionNotification() failed: %s"),
816 GetErrorString(dwRet));
817
818 CleanUpThreadData();
819 }
820 else
821 {
822 return TRUE;
823 }
824 }
825
826 // we're running under Windows 95 and have to poll ourselves
827 // (or, alternatively, the code above for NT/98 failed)
828 CheckRasStatus(TRUE /* first time */);
829 m_timerStatusPolling.Stop();
830 if ( nSeconds == 0 )
831 {
832 // default value
833 nSeconds = 60;
834 }
835 m_timerStatusPolling.Start(nSeconds * 1000);
836
837 return TRUE;
838 }
839
840 void wxDialUpManagerMSW::DisableAutoCheckOnlineStatus()
841 {
842 wxCHECK_RET( IsOk(), _T("using uninitialized wxDialUpManager") );
843
844 if ( m_hThread )
845 {
846 // we have running secondary thread, it's just enough to suspend it
847 if ( SuspendThread(m_hThread) == (DWORD)-1 )
848 {
849 wxLogLastError("SuspendThread(RasThread)");
850 }
851 }
852 else
853 {
854 // even simpler - just stop the timer
855 m_timerStatusPolling.Stop();
856 }
857 }
858
859 void wxDialUpManagerMSW::SetWellKnownHost(const wxString& WXUNUSED(hostname))
860 {
861 wxCHECK_RET( IsOk(), _T("using uninitialized wxDialUpManager") );
862
863 // nothing to do - we don't use this
864 }
865
866 // ----------------------------------------------------------------------------
867 // private functions
868 // ----------------------------------------------------------------------------
869
870 static DWORD wxRasMonitorThread(wxRasThreadData *data)
871 {
872 HANDLE handles[2];
873 handles[0] = data->hEventRas;
874 handles[1] = data->hEventQuit;
875
876 bool cont = TRUE;
877 while ( cont )
878 {
879 DWORD dwRet = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
880
881 switch ( dwRet )
882 {
883 case WAIT_OBJECT_0:
884 // RAS connection status changed
885 SendMessage(data->hWnd, wxWM_RAS_STATUS_CHANGED,
886 0, (LPARAM)data);
887 break;
888
889 case WAIT_OBJECT_0 + 1:
890 cont = FALSE;
891 break;
892
893 case WAIT_FAILED:
894 wxLogLastError("WaitForMultipleObjects(RasMonitor)");
895 break;
896 }
897 }
898
899 return 0;
900 }
901
902 static LRESULT APIENTRY wxRasStatusWindowProc(HWND hWnd, UINT message,
903 WPARAM wParam, LPARAM lParam)
904 {
905 if ( message == wxWM_RAS_STATUS_CHANGED )
906 {
907 wxRasThreadData *data = (wxRasThreadData *)lParam;
908 data->dialUpManager->OnConnectStatusChange();
909 }
910
911 return 0;
912 }
913
914 #endif // wxUSE_DIALUP_MANAGER