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