Domanda

Di recente ho portato un programma Wininet completamente funzionante a WinHttp. Ecco una funzione che ho scritto per avvolgere un'intera richiesta Get in una singola riga di codice:

bool Get(Url url, std::vector<char>& data, ProgressCallbackFunction progressCallback = nullptr) throw()
{
    long cl = -1;
    DWORD clSize = sizeof(cl);
    DWORD readCount = 0;
    DWORD totalReadCount = 0;
    DWORD availableBytes = 0;
    std::vector<char> buf;

    if (_session != NULL)
        throw std::exception("Concurrent sessions are not supported");

    _session = ::WinHttpOpen(_userAgent.c_str(), WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, NULL);
    auto connection = ::WinHttpConnect(_session, url.HostName.c_str(), url.Port, 0);
    auto request = ::WinHttpOpenRequest(connection, TEXT("GET"), url.GetPathAndQuery().c_str(), NULL, NULL, NULL, WINHTTP_FLAG_REFRESH);

    if (request == NULL)
    {
        _lastError = ::GetLastError();
        ::WinHttpCloseHandle(_session);
        _session = NULL;
        return false;
    }

    auto sendRequest = ::WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, WINHTTP_NO_REQUEST_DATA, NULL, NULL, NULL);
    if (sendRequest == FALSE)
    {
        _lastError = ::GetLastError();
        ::WinHttpCloseHandle(request);
        ::WinHttpCloseHandle(_session);
        _session = NULL;
        return false;
    }

    if (::WinHttpReceiveResponse(request, NULL))
    {
        if (progressCallback != nullptr && progressCallback != NULL)
        {
            if (!::WinHttpQueryHeaders(request, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, reinterpret_cast<LPVOID>(&cl), &clSize, 0))
            {
                cl = -1;    
            }
        }

        while (::WinHttpQueryDataAvailable(request, &availableBytes))
        {
            if (availableBytes)
            {
                buf.resize(availableBytes + 1);
                auto hasRead = ::WinHttpReadData(request, &buf[0], availableBytes, &readCount);
                totalReadCount += readCount;
                data.insert(data.end(), buf.begin(), buf.begin() + readCount);
                buf.clear();

                if (progressCallback != nullptr && progressCallback != NULL)
                {
                    progressCallback(totalReadCount, cl, getProgress(totalReadCount, cl));
                }
            }
            else
                break;
        }
    }
    else
    {
        _lastError = ::GetLastError();
        ::WinHttpCloseHandle(request);
        ::WinHttpCloseHandle(_session);
        _session = NULL;
        return false;
    }

    ::WinHttpCloseHandle(request);
    ::WinHttpCloseHandle(_session);
    _session = NULL;
    return true;
}

Il codice lavori In quanto scarica l'URL richiesto. Il problema si presenta quando il server non restituisce l'intestazione della lunghezza del contenuto (che è più del tempo). Il codice scaricherà comunque tutti i dati, ma ci saranno byte nulla incorporati quando convertiti in una stringa.

Il codice sopra si chiama così:

Url url(TEXT("http://msdn.microsoft.com/en-us/site/aa384376"));
Client wc;
std::vector<char> results;
wc.Get(url, results);
StdString html(results.begin(), results.end());
StdOut << html << endl;

Stdstring è typedef std :: basic_stringu003CTCHAR> E STDOUT è una macro che utilizza Cout o WCOUT a seconda che Unicode è definito.

A causa dei null incorporati, non tutta la risposta viene visualizzata sulla console. L'output viene visualizzato quando eseguo il codice con il debug può essere visto qui (Si noti che le interruzioni della linea sono semplicemente dove il testo è avvolto nella mia console). Il primo null viene visto subito dopo "__in" alla fine e si verifica proprio dove viene visualizzato il tasto "Premi qualsiasi tasto per continuare ...". Ecco un tappo dello schermo dell'output:

Console output

Ecco un tappo di schermo del visualizzatore di testo del valore della variabile HTML che mostra esattamente dove compaiono i null in relazione a ciò che è visualizzabile:

Text visualizer for html

Sto facendo un brutto copia da qualche parte o c'è qualche sfumatura di Winhttp di cui non sono a conoscenza?

È stato utile?

Soluzione

Dopo un'ulteriore revisione dell'output, quelli lo sono non nulls. Sono caratteri Unicode che la console non può visualizzare perché vengono archiviati in modo errato (e quindi convertiti in modo errato). Sono stato in grado di risolvere il problema nel metodo Get (e nel codice chiamante) modificando

std::vector<char>

a

std::vector<unsigned char>

E ora va tutto bene.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top