設置 | 登錄 | 註冊

作者共發了9篇帖子。

【代碼】WinHttp的基本用法

1樓 巨大八爪鱼 2016-3-8 15:05
無關的參數全部傳遞NULL。
【示例1:下載一個png圖像,並保持到磁盤上】
#include <stdio.h>
#include <Windows.h>
#include <winhttp.h>

#pragma comment(lib, "winhttp.lib")

void main()
{
    HINTERNET hSession = WinHttpOpen(L"My Test", NULL, NULL, NULL, NULL);
    HINTERNET hConnect = WinHttpConnect(hSession, L"localhost", 81, NULL); // 可用宏INTERNET_DEFAULT_HTTP_PORT表示默認的http端口號: 80
    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"test/images/background.png", NULL, NULL, NULL, WINHTTP_FLAG_REFRESH);
    WinHttpSendRequest(hRequest, NULL, NULL, NULL, NULL, NULL, NULL);
    WinHttpReceiveResponse(hRequest, NULL);

    FILE *fp;
    fopen_s(&fp, "image.png", "wb"); // 注意, 這裏的b選項非常重要
    DWORD dwSize;
    DWORD dwRead = 0;
    while (WinHttpQueryDataAvailable(hRequest, &dwSize), dwSize > 0)
    {
        char *buffer = (char *)malloc(dwSize * sizeof(char));
        WinHttpReadData(hRequest, buffer, dwSize, &dwRead);
        fwrite(buffer, dwSize, 1, fp);
        free(buffer);
    }
    printf("%d bytes written.\n", dwRead);
    fclose(fp);

    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);
}
2樓 巨大八爪鱼 2016-3-8 15:06
【示例2:下載一個HTML頁面,並保存到磁盤上】
#include <stdio.h>
#include <Windows.h>
#include <winhttp.h>

#pragma comment(lib, "winhttp.lib")

void main()
{
    HINTERNET hSession = WinHttpOpen(L"My Test", NULL, NULL, NULL, NULL);
    HINTERNET hConnect = WinHttpConnect(hSession, L"localhost", INTERNET_DEFAULT_HTTP_PORT, NULL);
    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"test/range.html", NULL, NULL, NULL, WINHTTP_FLAG_REFRESH);
    WinHttpSendRequest(hRequest, NULL, NULL, NULL, NULL, NULL, NULL);
    WinHttpReceiveResponse(hRequest, NULL);

    FILE *fp;
    fopen_s(&fp, "page.html", "wb"); // 注意, 這裏的b選項非常重要
    DWORD dwSize;
    DWORD dwRead = 0;
    while (WinHttpQueryDataAvailable(hRequest, &dwSize), dwSize > 0)
    {
        char *buffer = (char *)malloc(dwSize * sizeof(char));
        WinHttpReadData(hRequest, buffer, dwSize, &dwRead);
        fwrite(buffer, dwSize, 1, fp);
        free(buffer);
    }
    printf("%d bytes written.\n", dwRead);
    fclose(fp);

    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);
}
3樓 巨大八爪鱼 2016-3-8 22:35
【示例3:加載一個HTML頁面到內存中並顯示到屏幕上,不寫入磁盤】
#include <stdio.h>
#include <Windows.h>
#include <winhttp.h>

#pragma comment(lib, "winhttp.lib")

void main()
{
    HINTERNET hSession = WinHttpOpen(L"My Test", NULL, NULL, NULL, NULL);
    HINTERNET hConnect = WinHttpConnect(hSession, L"msdn.microsoft.com", INTERNET_DEFAULT_HTTP_PORT, NULL);
    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"en-us/library/windows/desktop/ms536160(v=vs.85).aspx", NULL, NULL, NULL, WINHTTP_FLAG_REFRESH);
    WinHttpSendRequest(hRequest, NULL, NULL, NULL, NULL, NULL, NULL);
    WinHttpReceiveResponse(hRequest, NULL);

    char *content = NULL;
    DWORD dwSize;
    DWORD dwRead = 0;
    DWORD dwBufSize = 0;
    while (WinHttpQueryDataAvailable(hRequest, &dwSize), dwSize > 0)
    {
        content = (char *)realloc(content, dwBufSize + dwSize + 1);
        WinHttpReadData(hRequest, content + dwBufSize, dwSize, &dwRead);
        dwBufSize += dwSize;
    }
    content[dwBufSize] = '\0'; // 手動添加字符串結束標記
    puts(content); // 輸出
    free(content);

    // 注意: content中保存的內容的編碼與網頁完全相同
    // 因此如果是UTF-8編碼且其中有中文的話,必須進行編碼轉換才能正確顯示
    // 一般轉換為UTF-16(wchar_t)或ANSI
    // 如果要將內容送入MSXML6解析器, 就必須轉換為UTF-16編碼才行

    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);
}

【運行結果】

4樓 巨大八爪鱼 2016-3-9 09:08
【示例4:加載一幅網絡圖像到內存中並顯示到窗口上,不寫入磁盤】
#include <tchar.h>
#include <Windows.h>
#include <gdiplus.h>
#include <winhttp.h>

#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "winhttp.lib")

using namespace Gdiplus;

Image *img;

void LoadPicture(void)
{
    HINTERNET hSession = WinHttpOpen(L"My Test", NULL, NULL, NULL, NULL);
    HINTERNET hConnect = WinHttpConnect(hSession, L"zh.arslanbar.net", INTERNET_DEFAULT_HTTP_PORT, NULL);
    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"Files/TopicImages/2012-7/8_2012-7-13_121400_609-318482.jpg", NULL, NULL, NULL, WINHTTP_FLAG_REFRESH);
    WinHttpSendRequest(hRequest, NULL, NULL, NULL, NULL, NULL, NULL);
    WinHttpReceiveResponse(hRequest, NULL);

    HGLOBAL hMem = NULL;
    char *content = NULL;
    DWORD dwSize;
    DWORD dwRead = 0;
    DWORD dwBufSize = 0;
    while (WinHttpQueryDataAvailable(hRequest, &dwSize), dwSize > 0)
    {
        // 這裏改用GlobalAlloc分配內存
        if (hMem == NULL)
            hMem = GlobalAlloc(GMEM_MOVEABLE, dwSize);
        else
            hMem = GlobalReAlloc(hMem, dwBufSize + dwSize, GMEM_MOVEABLE);
        content = (char *)GlobalLock(hMem); // 獲得分配的內存首地址
        WinHttpReadData(hRequest, content + dwBufSize, dwSize, &dwRead);
        GlobalUnlock(hMem);
        dwBufSize += dwSize;
    }
    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);

    // 轉換為Stream對象並創建圖像
    IStream *is;
    CreateStreamOnHGlobal(hMem, TRUE, &is);
    img = new Image(is);
    is->Release();
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    Graphics *graphics;
    HDC hdc;
    PAINTSTRUCT ps;
    TCHAR szText[100];

    switch (uMsg)
    {
    case WM_CREATE:
        LoadPicture(); // 當窗口創建時加載圖像
        break;
    case WM_DESTROY:
        delete img; // 當窗口關閉時刪除圖像
        PostQuitMessage(0);
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);

        // 顯示圖像
        graphics = new Graphics(hdc);
        graphics->DrawImage(img, 2, 20);
        delete graphics;

        // 顯示圖像尺寸
        _stprintf_s(szText, TEXT("Size: %ux%u"), img->GetWidth(), img->GetHeight());
        TextOut(hdc, 2, 2, szText, _tcslen(szText));

        EndPaint(hWnd, &ps);
        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return FALSE;
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    // 初始化GDI+
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    // 註冊窗口類
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hInstance = hInstance;
    wcex.lpfnWndProc = WndProc;
    wcex.lpszClassName = TEXT("MainWindow"); // 窗口類名稱
    wcex.lpszMenuName = NULL;
    wcex.style = NULL;
    RegisterClassEx(&wcex);

    // 創建並顯示窗口
    HWND hWnd = CreateWindow(wcex.lpszClassName, TEXT("Display Remote Picture"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
    if (!hWnd)
        return 1;
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    // 消息循環
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    GdiplusShutdown(gdiplusToken);
    return msg.wParam;
}
5樓 巨大八爪鱼 2016-3-9 09:09
【運行結果】

8樓 巨大八爪鱼 2016-3-11 09:49
【示例5:提交POST數據】
【C++代碼】
#include <stdio.h>
#include <Windows.h>
#include <winhttp.h>

#pragma comment(lib, "winhttp.lib")

void main()
{
    char *szData = "user=admin&id=49&operation=update&text=abc中文";
    wchar_t *szHeader = L"Content-type: application/x-www-form-urlencoded";
    DWORD dwDataSize = strlen(szData);
    DWORD dwHeaderSize = wcslen(szHeader);

    HINTERNET hSession = WinHttpOpen(L"My Test", NULL, NULL, NULL, NULL);
    HINTERNET hConnect = WinHttpConnect(hSession, L"localhost", INTERNET_DEFAULT_HTTP_PORT, NULL);
    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", L"test/requests/?id=203&param", NULL, NULL, NULL, WINHTTP_FLAG_REFRESH); // 設置為POST方式
    WinHttpAddRequestHeaders(hRequest, szHeader, dwHeaderSize, WINHTTP_ADDREQ_FLAG_ADD); // 添加請求頭
    WinHttpSendRequest(hRequest, NULL, NULL, szData, dwDataSize, dwDataSize, NULL); // 發送POST數據
    WinHttpReceiveResponse(hRequest, NULL);

    char *content = NULL;
    DWORD dwSize;
    DWORD dwRead = 0;
    DWORD dwBufSize = 0;
    while (WinHttpQueryDataAvailable(hRequest, &dwSize), dwSize > 0)
    {
        content = (char *)realloc(content, dwBufSize + dwSize + 1);
        WinHttpReadData(hRequest, content + dwBufSize, dwSize, &dwRead);
        dwBufSize += dwSize;
    }
    content[dwBufSize] = '\0';
    puts(content);
    free(content);

    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);

    system("pause");
}
【PHP代碼】
<?php
echo '[GET]', PHP_EOL;
print_r($_GET);
echo PHP_EOL, '[POST]', PHP_EOL;
print_r($_POST);
?>
【運行結果】
10樓 巨大八爪鱼 2016-3-11 15:57
【示例6:以UTF8方式提交POST數據,然後以wchar_t格式顯示網頁內容】
#include <stdio.h>
#include <Windows.h>
#include <winhttp.h>

#pragma comment(lib, "winhttp.lib")

// 將UTF16(wchar_t)轉換成UTF8, 用後必須釋放空間
char *ToUTF8(wchar_t *data)
{
    int cbSize = WideCharToMultiByte(CP_UTF8, NULL, data, -1, NULL, NULL, NULL, NULL);
    char *buffer = new char[cbSize];
    WideCharToMultiByte(CP_UTF8, NULL, data, -1, buffer, cbSize, NULL, NULL);
    return buffer;
}

// 將UTF8轉換成UTF16, 用後必須釋放空間
wchar_t *ToUTF16(char *data)
{
    int cbSize = MultiByteToWideChar(CP_UTF8, NULL, data, -1, NULL, NULL);
    wchar_t *buffer = new wchar_t[cbSize];
    MultiByteToWideChar(CP_UTF8, NULL, data, -1, buffer, cbSize);
    return buffer;
}

void main()
{
    char *szData = ToUTF8(L"user=admin&id=49&operation=update&text=abc中文");
    wchar_t *szHeader = L"Content-type: application/x-www-form-urlencoded";
    DWORD dwDataSize = strlen(szData);
    DWORD dwHeaderSize = wcslen(szHeader);

    HINTERNET hSession = WinHttpOpen(L"My Test", NULL, NULL, NULL, NULL);
    HINTERNET hConnect = WinHttpConnect(hSession, L"localhost", INTERNET_DEFAULT_HTTP_PORT, NULL);
    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", L"test/requests/?id=203&param", NULL, NULL, NULL, WINHTTP_FLAG_REFRESH); // 設置為POST方式
    WinHttpAddRequestHeaders(hRequest, szHeader, dwHeaderSize, WINHTTP_ADDREQ_FLAG_ADD);
    WinHttpSendRequest(hRequest, NULL, NULL, szData, dwDataSize, dwDataSize, NULL);
    WinHttpReceiveResponse(hRequest, NULL);

    // 由於這裏不是顯示圖像, 因此直接用C語言的內存分配函數就行了
    // 無需使用GlobalAlloc
    char *content = NULL;
    DWORD dwSize;
    DWORD dwRead = 0;
    DWORD dwBufSize = 0;
    while (WinHttpQueryDataAvailable(hRequest, &dwSize), dwSize > 0)
    {
        content = (char *)realloc(content, dwBufSize + dwSize + 1);
        WinHttpReadData(hRequest, content + dwBufSize, dwSize, &dwRead);
        dwBufSize += dwSize;
    }
    if (content != NULL)
        content[dwBufSize] = '\0';
   
    // 網頁內容的編碼是UTF8, 將其轉換為wchar_t(UTF16), 然後顯示到控制台中
    wchar_t *w_content = ToUTF16(content);
    free(content);
    // 在控制台中顯示wchar_t字符串不能用printf或cout, 否則中文和很多其他語言文字不能正常輸出
    HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    WriteConsoleW(hConsoleOutput, w_content, wcslen(w_content), NULL, NULL);
    delete[] w_content;
    delete[] szData;
   
    WinHttpCloseHandle(hRequest);
    WinHttpCloseHandle(hConnect);
    WinHttpCloseHandle(hSession);

    system("pause");
}
【運行結果】
和示例5一樣。
11樓 巨大八爪鱼 2016-3-11 17:34
【示例7:加載一幅網絡圖像到內存中並顯示到對話框的圖像控件中,不寫入磁盤】
代碼請參閱:https://zh.arslanbar.net/post.php?t=23893
【運行效果】
12樓 巨大八爪鱼 2024-4-29 20:09
後來發現IXMLHttpRequest非常好用,還支持HTTPS。現在更推薦用這個。

內容轉換:

回覆帖子
內容:
用戶名: 您目前是匿名發表。
驗證碼:
看不清?換一張
©2010-2025 Purasbar Ver3.0 [手機版] [桌面版]
除非另有聲明,本站採用知識共享署名-相同方式共享 3.0 Unported許可協議進行許可。