2016-04-21 40 views
0

我正在製作一個C++代理,它將使用HttpSendRequest()將信息(例如系統主機名)發回中央服務器。我希望它回發的一條信息是操作系統。我創建了以下函數來獲取系統主機名。HttpSendRequest - 不支持Unicode的POST數據

wstring getOS() 
{ 
    HKEY key; 
    RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE, &key); // Obtains Registry handle 

    DWORD type; 
    wchar_t buffer[MAX_PATH]; // MAX_PATH = 260 - The system hostname should never exceed this value 
    DWORD size = sizeof(buffer); 
    RegQueryValueEx(key, L"ProductName", NULL, &type, (LPBYTE)&buffer, &size); // Queries Registry key - stores value in "buffer" 
    wstring os(buffer); // Converts from C-style character array to wstring 
    return os; // Returns wstring to caller 
} 

該函數將使用註冊表獲取操作系統並將其存儲爲wstring。然後,我想要將返回的「os」wstring傳遞給下面的post()函數,但我注意到您必須使用字符串而不是wstring作爲HTTP POST數據。下面是我的職位代碼()函數:

void post() 
{ 
    HINTERNET hInternetOpen = InternetOpen(userAgent.c_str(), INTERNET_OPEN_TYPE_PROXY, L"http://127.0.0.1:9999", NULL, 0); 
    HINTERNET hInternetConnect = InternetConnect(hInternetOpen, host.c_str(), INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); 
    HINTERNET hHttpOpenRequest = HttpOpenRequest(hInternetConnect, L"POST", file.c_str(), NULL, NULL, NULL, 0, 0); 

    wstring headers = L"Content-Type: application/x-www-form-urlencoded"; // Content-Type is necessary to POST 

    string postData = "os="; // Why does this have to be a string and not a wstring? 

    HttpSendRequest(hHttpOpenRequest, headers.c_str(), headers.length(), (LPVOID)postData.c_str(), postData.size()); 

    InternetCloseHandle(hInternetOpen); 
    InternetCloseHandle(hInternetConnect); 
    InternetCloseHandle(hHttpOpenRequest); 
} 

如果我試圖讓「POSTDATA」一個wstring的,我得到的東西看起來像下面的圖片:

HTTP POST data as wstring

可有人闡明瞭將wstring作爲POST數據的最簡單方法?

+0

你爲什麼說你 '必須使用字符串,而不是wstring的'? – pm100

+0

如果我嘗試使用wstring而不是字符串,它會擾亂POST數據(請參閱附加的屏幕截圖)。 – t3ntman

+1

你想在電匯上發送什麼? UTF8?請參閱這裏http://stackoverflow.com/questions/148403/utf8-to-from-wide-char-conversion-in-stl – pm100

回答

2

HttpSendRequest()只知道原始字節,而不是字符串。您可以使用std::wstring發送UTF-16數據,但必須通過Content-Type標頭中的charset屬性通知服務器您要發送UTF-16。

wstring headers = L"Content-Type: application/x-www-form-urlencoded; charset=utf-16"; 

// TODO: don't forget to URL-encode the value from getOS() to 
// escape reserved characters, including '=' and '&'... 
wstring postData = L"os=" + getOS(); 

HttpSendRequest(hHttpOpenRequest, headers.c_str(), headers.length(), 
    postData.c_str(), postData.length() * sizeof(wchar_t)); 

注意上面的使用sizeof(wchar_t)。在您的屏幕截圖中,您的嗅探器顯示的數據爲,原始數據爲,顯示的數據是UTF-16的樣子,但您只能看到wstring數據的一半,因爲您將參數HttpSendRequest()設置爲字符計數(7),而不是一個字節計數(14)的:

dwOptionalLength [IN]
可選數據的大小,在字節。如果沒有可選數據要發送,此參數可以爲零。

當您使用std::string,該字符數字節數是相同的值。

你真正應該發送爲UTF-8改爲UTF-16,例如:

string Utf8Encode(const wstring &wstr) 
{ 
    // NOTE: C++11 has built-in support for converting between 
    // UTF-8 and UTF-16. See the std::wstring_convert class... 
    /* 
    wstring_convert<codecvt_utf8_utf16<wchar_t>> conv; 
    return conv.to_bytes(wstr); 
    */ 

    string out; 
    int len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), NULL, 0, NULL, NULL); 
    if (len > 0) 
    { 
     out.resize(len); 
     WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.length(), &out[0], len, NULL, NULL); 
    } 
    return out; 
} 

wstring headers = L"Content-Type: application/x-www-form-urlencoded; charset=utf-8"; 

// TODO: don't forget to URL-encode the value from getOS() to 
// escape reserved characters, including '=' and '&'... 
string postData = "os=" + Utf8Encode(getOS()); 

HttpSendRequest(hHttpOpenRequest, headers.c_str(), headers.length(), 
    postData.c_str(), postData.size()); 
+0

你是男人!這工作,應該是被接受的答案。如果我有足夠的聲望,我會鼓勵它:/非常感謝你! – t3ntman

+0

如果它適合你,隨時將其標記爲已接受。 –

+0

我只需點擊複選標記即可。請讓我知道如果這沒有奏效。再次感謝。 – t3ntman