将进度条添加到 wininet http 上传 C++
Adding progressbar to wininet http upload C++
我有使用 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
用于显示数据传输的大小,但不知道如何获取此传输数据...
我很乐意提供任何建议。
您可以将上传分成小块,并在每个小块发送后更新进度条。
像往常一样调用 InternetConnect()
和 HttpOpenRequest()
。
而不是 HttpSendRequest()
调用 HttpSendRequestEx()
. Define the total file size via the lpBuffersIn
parameter. For parameter dwFlags
pass the value HSR_INITIATE
to tell the API that you want iterative data transfer. There is a doc bug in the reference page, the dwFlags
parameter is not reserved. Everyone is using it, for example MFC。
INTERNET_BUFFERS buffer{ sizeof(buffer) };
buffer.dwBufferTotal = totalFileSizeInBytes;
BOOL success = HttpSendRequestEx( hRequest, &buffer, nullptr, HSR_INITIATE, 0 );
循环调用InternetWriteFile()
来分段上传文件。使用不太小的缓冲区大小以减少 API(比如 16k)的开销。每次调用此 API 后,您可以测量当前时间和上次进度条更新时间之间的差异,并且仅在差异足够大(比如 1/10 秒)以减少 API 开销时才更新进度条更新 GUI。
上传完文件后,通过调用 HttpEndRequest()
告诉它 API。当然关闭句柄,检查错误等等。pp.
所有这些都应该在单独的线程中完成,以保持 GUI 线程的响应。通过使用消息 ID WM_APP + x
调用 PostMessage()
向 GUI 线程报告进度。您可以使用 wParam
和 lParam
传递进度信息。然后只有在 GUI 线程中你才会实际更新进度条以保持业务逻辑和 GUI 清楚地分开。
我有使用 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
用于显示数据传输的大小,但不知道如何获取此传输数据...
我很乐意提供任何建议。
您可以将上传分成小块,并在每个小块发送后更新进度条。
像往常一样调用 InternetConnect()
和 HttpOpenRequest()
。
而不是 HttpSendRequest()
调用 HttpSendRequestEx()
. Define the total file size via the lpBuffersIn
parameter. For parameter dwFlags
pass the value HSR_INITIATE
to tell the API that you want iterative data transfer. There is a doc bug in the reference page, the dwFlags
parameter is not reserved. Everyone is using it, for example MFC。
INTERNET_BUFFERS buffer{ sizeof(buffer) };
buffer.dwBufferTotal = totalFileSizeInBytes;
BOOL success = HttpSendRequestEx( hRequest, &buffer, nullptr, HSR_INITIATE, 0 );
循环调用InternetWriteFile()
来分段上传文件。使用不太小的缓冲区大小以减少 API(比如 16k)的开销。每次调用此 API 后,您可以测量当前时间和上次进度条更新时间之间的差异,并且仅在差异足够大(比如 1/10 秒)以减少 API 开销时才更新进度条更新 GUI。
上传完文件后,通过调用 HttpEndRequest()
告诉它 API。当然关闭句柄,检查错误等等。pp.
所有这些都应该在单独的线程中完成,以保持 GUI 线程的响应。通过使用消息 ID WM_APP + x
调用 PostMessage()
向 GUI 线程报告进度。您可以使用 wParam
和 lParam
传递进度信息。然后只有在 GUI 线程中你才会实际更新进度条以保持业务逻辑和 GUI 清楚地分开。