将进度条添加到wininet http上传C++

Posted

技术标签:

【中文标题】将进度条添加到wininet http上传C++【英文标题】:Adding progressbar to wininet http upload C++ 【发布时间】:2017-06-23 04:14:55 【问题描述】:

我正在使用 POST 方法在 HTTP 服务器上上传二进制文件的代码:

http_upload_file(PCHAR szServer, PCHAR szScript, PCHAR szParam, PCHAR szValue, PCHAR szFile)

    PCHAR szHeaders = "Content-Type: multipart/form-data; boundary=----qwerty";
    PCHAR szData    = "------qwerty\r\n"
                      "Content-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n"
                      "------qwerty\r\n"
                      "Content-Disposition: form-data; name=\"files[]\"; filename=\"%s\"\r\n"
                      "Content-Type: application/octet-stream\r\n"
                      "Content-Transfer-Encoding: binary\r\n\r\n";
    PCHAR szDataEnd = "\r\n------qwerty--\r\n";
    char  szHeader[512];

    HINTERNET hSession, hConnect, hRequest;
    DWORD     dwFileSize, dwBytesRead, dwContentLength,dwBytesWritten;

    hSession = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);

    if (hSession)
    
        hConnect = InternetConnect(hSession, szServer, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP,0, 0);

        if (hConnect)
        
            hRequest = HttpOpenRequest(hConnect, "POST", szScript, NULL, NULL, 0, 0, 0);

            if (hRequest)
            
                HANDLE hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

                if (hFile != INVALID_HANDLE_VALUE)
                
                    dwFileSize      = GetFileSize(hFile, NULL);
                    wsprintf(szHeader, szData, szParam, szValue, szFile);
                    dwContentLength = lstrlen(szHeader) + dwFileSize + lstrlen(szDataEnd);
                    LPBYTE pBuf     = (LPBYTE)malloc(dwContentLength);
                    CopyMemory(&pBuf[0], szHeader, lstrlen(szHeader));
                    ReadFile(hFile, &pBuf[lstrlen(szHeader)], dwFileSize, &dwBytesRead, NULL);
                    CopyMemory(&pBuf[lstrlen(szHeader) + dwFileSize], szDataEnd, lstrlen(szDataEnd));
                    HttpSendRequest(hRequest, szHeaders, lstrlen(szHeaders), pBuf, dwContentLength);
                    CloseHandle(hFile);
                    free(pBuf);
                
            

            InternetCloseHandle(hRequest);
        

        InternetCloseHandle(hConnect);
    

    InternetCloseHandle(hSession);

它工作正常,但我想在文件上传时添加一些进度信息。

HttpSendRequest(hRequest, szHeaders, lstrlen(szHeaders), pBuf, dwContentLength); 正在执行时,我可以获取传输内容的大小吗?问题是在上传大文件时,我的Form 被冻结,用户无法看到已经上传了多少数据。因此,我想添加ProggessBar 以显示数据传输的大小,但不知道如何获取此传输数据...

如果有任何建议,我都会很高兴。

【问题讨论】:

【参考方案1】:

您可以将上传的内容拆分成小块,每块发送后更新进度条。

照常致电InternetConnect()HttpOpenRequest()

而不是HttpSendRequest() 调用HttpSendRequestEx()。通过lpBuffersIn 参数定义总文件大小。对于参数dwFlags,传递值HSR_INITIATE 以告诉API 您想要迭代数据传输。参考页中有一个 doc 错误,dwFlags 参数 not 保留。每个人都在使用它,例如MFC。

INTERNET_BUFFERS buffer sizeof(buffer) ;
buffer.dwBufferTotal = totalFileSizeInBytes;
BOOL success = HttpSendRequestEx( hRequest, &buffer, nullptr, HSR_INITIATE, 0 );

循环调用InternetWriteFile() 分段上传文件。使用不太小的缓冲区大小以减少 API 的开销(例如 16k)。每次调用此 API 后,您可以测量当前时间和上次更新进度条的时间之间的差异,并且只有在差异足够大(例如 1/10 秒)以减少更新 GUI 的 API 开销时才更新进度条。

上传完文件后,通过调用HttpEndRequest() 告诉它API。当然关闭句柄,检查错误等等。 pp.

所有这些都应该在一个单独的线程中完成,以保持 GUI 线程响应。通过使用消息 ID 为 WM_APP + x 调用 PostMessage() 向 GUI 线程报告进度。您可以使用wParamlParam 传递进度信息。然后只有在 GUI 线程中,您才会真正更新进度条,以保持业务逻辑和 GUI 清晰分离。

【讨论】:

以上是关于将进度条添加到wininet http上传C++的主要内容,如果未能解决你的问题,请参考以下文章

使用 Wininet 上传文件时如何添加正确的 Content-Type? (HTTP 放置)

C++ 使用 WinINet 上传到 FTP 服务器

如何在 WinInet C++ 中获取 FTP 下载的进度

如何在 Alamofire 4.0 中添加带有上传进度百分比的标签的进度条

C++ WinInet 和回调不起作用

文件上传和进度条