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