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