2012-01-24 18 views
1

我最近將一個完整的WinInet程序移植到了WinHTTP中。這裏有一個功能我寫信來的一行代碼來包裝整個GET請求:是WinHTTP下載空字節還是我錯誤地複製結果緩衝區?

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; 
} 

代碼工作,它的下載請求的URL。當服務器沒有返回Content-Length頭部時(這是當時的大部分)時出現問題。該代碼仍然會下載所有數據,但是當轉換爲字符串時將會嵌入空字節。

上面的代碼被稱爲像這樣:

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_string的<TCHAR>和STDOUT是使用取決於如果UNICODE被定義COUT或wcout的宏。

由於嵌入的空值,並不是所有的響應都顯示在控制檯上。當我使用調試運行代碼時顯示的輸出關閉can be viewed here(請注意,換行符只是文本在控制檯中的包裝位置)。第一個null在最後的「__in」後面出現,並且顯示在「按任意鍵繼續...」輸出的地方。下面是一個輸出的屏幕帽:

Console output

這也正是顯示HTML變量的值的文本可視化屏幕蓋在零點出現在關於什麼是可視:

Text visualizer for html

我在某處做了一些錯誤的複製,或者有一些我不知道的WinHTTP的細微差別?

+0

你能舉一個例子來重現行爲嗎?我複製了你的代碼並且嘗試了那個msdn頁面,並且沒有嵌入的空值。 – Luke

+0

修改爲包含以下鏈接: http://pastebin.com/aEH9GzDE http://i.imgur.com/vRmNL.png http://i.imgur.com/eu8rH.png – jvstech

回答

0

經過對輸出的進一步審查,那些是而不是的空值。它們是控制檯無法顯示的unicode字符,因爲它們存儲不正確(因此被錯誤地轉換)。我能夠通過改變

std::vector<char> 

解決Get方法(和調用代碼)的問題

std::vector<unsigned char> 

,現在一切都很好。