dialup.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,333 行 · 第 1/3 页

CPP
1,333
字号

        // keep your preprocessor name space clean
        #undef RESOLVE_RAS_FUNCTION
        #undef RESOLVE_OPTIONAL_RAS_FUNCTION

exit:
        if ( funcName )
        {
            static const wxChar *msg = wxTRANSLATE(
"The version of remote access service (RAS) installed on this machine is too\
old, please upgrade (the following required function is missing: %s)."
                                                   );

            wxLogError(wxGetTranslation(msg), funcName);
            m_dllRas.Unload();
            return;
        }
    }

    // enable auto check by default
    EnableAutoCheckOnlineStatus(0);
}

wxDialUpManagerMSW::~wxDialUpManagerMSW()
{
    CleanUpThreadData();
}

// ----------------------------------------------------------------------------
// helper functions
// ----------------------------------------------------------------------------

wxString wxDialUpManagerMSW::GetErrorString(DWORD error)
{
    wxChar buffer[512]; // this should be more than enough according to MS docs
    DWORD dwRet = ms_pfnRasGetErrorString(error, buffer, WXSIZEOF(buffer));
    switch ( dwRet )
    {
        case ERROR_INVALID_PARAMETER:
            // this was a standard Win32 error probably
            return wxString(wxSysErrorMsg(error));

        default:
            {
                wxLogSysError(dwRet,
                      _("Failed to retrieve text of RAS error message"));

                wxString msg;
                msg.Printf(_("unknown error (error code %08x)."), error);
                return msg;
            }

        case 0:
            // we want the error message to start from a lower case letter
            buffer[0] = (wxChar)wxTolower(buffer[0]);

            return wxString(buffer);
    }
}

HRASCONN wxDialUpManagerMSW::FindActiveConnection()
{
    // enumerate connections
    DWORD cbBuf = sizeof(RASCONN);
    LPRASCONN lpRasConn = (LPRASCONN)malloc(cbBuf);
    if ( !lpRasConn )
    {
        // out of memory
        return 0;
    }

    lpRasConn->dwSize = sizeof(RASCONN);

    DWORD nConnections = 0;
    DWORD dwRet = ERROR_BUFFER_TOO_SMALL;

    while ( dwRet == ERROR_BUFFER_TOO_SMALL )
    {
        dwRet = ms_pfnRasEnumConnections(lpRasConn, &cbBuf, &nConnections);

        if ( dwRet == ERROR_BUFFER_TOO_SMALL )
        {
            LPRASCONN lpRasConnOld = lpRasConn;
            lpRasConn = (LPRASCONN)realloc(lpRasConn, cbBuf);
            if ( !lpRasConn )
            {
                // out of memory
                free(lpRasConnOld);

                return 0;
            }
        }
        else if ( dwRet == 0 )
        {
            // ok, success
            break;
        }
        else
        {
            // an error occurred
            wxLogError(_("Cannot find active dialup connection: %s"),
                       GetErrorString(dwRet).c_str());
            return 0;
        }
    }

    HRASCONN hrasconn;

    switch ( nConnections )
    {
        case 0:
            // no connections
            hrasconn = 0;
            break;

        default:
            // more than 1 connection - we don't know what to do with this
            // case, so give a warning but continue (taking the first
            // connection) - the warning is really needed because this function
            // is used, for example, to select the connection to hang up and so
            // we may hang up the wrong connection here...
            wxLogWarning(_("Several active dialup connections found, choosing one randomly."));
            // fall through

        case 1:
            // exactly 1 connection, great
            hrasconn = lpRasConn->hrasconn;
    }

    free(lpRasConn);

    return hrasconn;
}

void wxDialUpManagerMSW::CleanUpThreadData()
{
    if ( m_hThread )
    {
        if ( !SetEvent(m_data->hEventQuit) )
        {
            wxLogLastError(_T("SetEvent(RasThreadQuit)"));
        }
        else // sent quit request to the background thread
        {
            // the thread still needs m_data so we can't free it here, rather
            // let the thread do it itself
            m_data = NULL;
        }

        CloseHandle(m_hThread);

        m_hThread = 0;
    }

    if ( m_data )
    {
        delete m_data;
        m_data = NULL;
    }
}

// ----------------------------------------------------------------------------
// connection status
// ----------------------------------------------------------------------------

void wxDialUpManagerMSW::CheckRasStatus()
{
    // use int, not bool to compare with -1
    int isConnected = FindActiveConnection() != 0;
    if ( isConnected != ms_isConnected )
    {
        if ( ms_isConnected != -1 )
        {
            // notify the program
            NotifyApp(isConnected != 0);
        }
        // else: it's the first time we're called, just update the flag

        ms_isConnected = isConnected;
    }
}

void wxDialUpManagerMSW::NotifyApp(bool connected, bool fromOurselves) const
{
    wxDialUpEvent event(connected, fromOurselves);
    (void)wxTheApp->ProcessEvent(event);
}

// this function is called whenever the status of any RAS connection on this
// machine changes by RAS itself
void wxDialUpManagerMSW::OnConnectStatusChange()
{
    // we know that status changed, but we don't know whether we're connected
    // or not - so find it out
    CheckRasStatus();
}

// this function is called by our callback which we give to RasDial() when
// calling it asynchronously
void wxDialUpManagerMSW::OnDialProgress(RASCONNSTATE rasconnstate,
                                        DWORD dwError)
{
    if ( !GetDialer() )
    {
        // this probably means that CancelDialing() was called and we get
        // "disconnected" notification
        return;
    }

    // we're only interested in 2 events: connected and disconnected
    if ( dwError )
    {
        wxLogError(_("Failed to establish dialup connection: %s"),
                   GetErrorString(dwError).c_str());

        // we should still call RasHangUp() if we got a non 0 connection
        if ( ms_hRasConnection )
        {
            ms_pfnRasHangUp(ms_hRasConnection);
            ms_hRasConnection = 0;
        }

        ms_dialer = NULL;

        NotifyApp(false /* !connected */, true /* we dialed ourselves */);
    }
    else if ( rasconnstate == RASCS_Connected )
    {
        ms_isConnected = true;
        ms_dialer = NULL;

        NotifyApp(true /* connected */, true /* we dialed ourselves */);
    }
}

// ----------------------------------------------------------------------------
// implementation of wxDialUpManager functions
// ----------------------------------------------------------------------------

bool wxDialUpManagerMSW::IsOk() const
{
    return m_dllRas.IsLoaded();
}

size_t wxDialUpManagerMSW::GetISPNames(wxArrayString& names) const
{
    // fetch the entries
    DWORD size = sizeof(RASENTRYNAME);
    RASENTRYNAME *rasEntries = (RASENTRYNAME *)malloc(size);
    rasEntries->dwSize = sizeof(RASENTRYNAME);

    DWORD nEntries;
    DWORD dwRet;
    do
    {
        dwRet = ms_pfnRasEnumEntries
                  (
                   NULL,                // reserved
                   NULL,                // default phone book (or all)
                   rasEntries,          // [out] buffer for the entries
                   &size,               // [in/out] size of the buffer
                   &nEntries            // [out] number of entries fetched
                  );

        if ( dwRet == ERROR_BUFFER_TOO_SMALL )
        {
            // reallocate the buffer
            rasEntries = (RASENTRYNAME *)realloc(rasEntries, size);
        }
        else if ( dwRet != 0 )
        {
            // some other error - abort
            wxLogError(_("Failed to get ISP names: %s"),
                       GetErrorString(dwRet).c_str());

            free(rasEntries);

            return 0u;
        }
    }
    while ( dwRet != 0 );

    // process them
    names.Empty();
    for ( size_t n = 0; n < (size_t)nEntries; n++ )
    {
        names.Add(rasEntries[n].szEntryName);
    }

    free(rasEntries);

    // return the number of entries
    return names.GetCount();
}

bool wxDialUpManagerMSW::Dial(const wxString& nameOfISP,
                              const wxString& username,
                              const wxString& password,
                              bool async)
{
    // check preconditions
    wxCHECK_MSG( IsOk(), false, wxT("using uninitialized wxDialUpManager") );

    if ( ms_hRasConnection )
    {
        wxFAIL_MSG(wxT("there is already an active connection"));

        return true;
    }

    // get the default ISP if none given
    wxString entryName(nameOfISP);
    if ( !entryName )
    {
        wxArrayString names;
        size_t count = GetISPNames(names);
        switch ( count )
        {
            case 0:
                // no known ISPs, abort
                wxLogError(_("Failed to connect: no ISP to dial."));

                return false;

            case 1:
                // only one ISP, choose it
                entryName = names[0u];
                break;

            default:
                // several ISPs, let the user choose
                {
                    wxString *strings = new wxString[count];
                    for ( size_t i = 0; i < count; i++ )
                    {
                        strings[i] = names[i];
                    }

                    entryName = wxGetSingleChoice
                                (
                                 _("Choose ISP to dial"),
                                 _("Please choose which ISP do you want to connect to"),
                                 count,
                                 strings
                                );

                    delete [] strings;

                    if ( !entryName )
                    {
                        // cancelled by user
                        return false;
                    }
                }
        }
    }

    RASDIALPARAMS rasDialParams;
    rasDialParams.dwSize = sizeof(rasDialParams);
    wxStrncpy(rasDialParams.szEntryName, entryName, RAS_MaxEntryName);

    // do we have the username and password?
    if ( !username || !password )
    {
        BOOL gotPassword;
        DWORD dwRet = ms_pfnRasGetEntryDialParams
                      (
                       NULL,            // default phonebook
                       &rasDialParams,  // [in/out] the params of this entry
                       &gotPassword     // [out] did we get password?
                      );

        if ( dwRet != 0 )
        {
            wxLogError(_("Failed to connect: missing username/password."));

            return false;
        }
    }
    else
    {
        wxStrncpy(rasDialParams.szUserName, username, UNLEN);
        wxStrncpy(rasDialParams.szPassword, password, PWLEN);
    }

    // default values for other fields
    rasDialParams.szPhoneNumber[0] = '\0';
    rasDialParams.szCallbackNumber[0] = '\0';
    rasDialParams.szCallbackNumber[0] = '\0';

    rasDialParams.szDomain[0] = '*';
    rasDialParams.szDomain[1] = '\0';

    // apparently, this is not really necessary - passing NULL instead of the
    // phone book has the same effect
#if 0
    wxString phoneBook;
    if ( wxGetOsVersion() == wxWINDOWS_NT )
    {
        // first get the length
        UINT nLen = ::GetSystemDirectory(NULL, 0);
        nLen++;

        if ( !::GetSystemDirectory(phoneBook.GetWriteBuf(nLen), nLen) )
        {
            wxLogSysError(_("Cannot find the location of address book file"));
        }

        phoneBook.UngetWriteBuf();

        // this is the default phone book
        phoneBook << "\\ras\\rasphone.pbk";
    }
#endif // 0

    // TODO may be we should disable auto check while async dialing is in
    //      progress?

    ms_dialer = this;

    DWORD dwRet = ms_pfnRasDial
                  (
                   NULL,                    // no extended features
                   NULL,                    // default phone book file (NT only)
                   &rasDialParams,
                   0,                       // use callback for notifications
                   async ? (void *)wxRasDialFunc  // cast needed for gcc 3.1
                         : 0,               // no notifications, sync operation
                   &ms_hRasConnection
                  );

    if ( dwRet != 0 )
    {
        // can't pass a wxWCharBuffer through ( ... )
        wxLogError(_("Failed to %s dialup connection: %s"),
                   wxString(async ? _("initiate") : _("establish")).c_str(),
                   GetErrorString(dwRet).c_str());

        // we should still call RasHangUp() if we got a non 0 connection
        if ( ms_hRasConnection )
        {
            ms_pfnRasHangUp(ms_hRasConnection);
            ms_hRasConnection = 0;
        }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?