如何使用 WinInet 时提供下载上载进度信息

概要
许多开发人员都使用 WinInet 函数来下载或上载文件在 Internet 上的想要提供一个进度条以指示多少文件传输已完成,但多少就越长。您可以使用以下机制来完成此。
Collapse image更多信息
使用 InternetSetStatusCallback 来获取下载进度的通知为您提供良好的信息请求的进展如何,包括连接状态通知。但是,它不表示一定百分比的传输已完成。

若要获取的百分比相当完整的通知,您需要确定传输的大小,然后使用小缓冲区中调用 InternetReadFile 或 InternetWriteFile。然后,您可以作为完整的函数调用来计算传输的百分比。

例如,假设您想要下载的 1000 个字节的文件。而不是进行一次调用 InternetReadFile 1000 字节的缓冲区,可以拨打 10 InternetReadFIle 与 100 字节的缓冲区。通过这种方式完成每次调用 InternetReadFile,您知道下载是另一个完整的 10%。

下面的代码说明了此过程:

#include<windows.h>
#include<wininet.h>
#include<iostream.h>

void main(int argc, char *argv[])
{
    if (argc != 3)
    {
        cout << "Usage: progress <host> <object>" << endl;
        return;
    }

    HINTERNET hSession = InternetOpen("WinInet Progress Sample",
                                      INTERNET_OPEN_TYPE_PRECONFIG,
                                      NULL,
                                      NULL,
                                      0);
    HINTERNET hConnection = InternetConnect(hSession,
                                            argv[1],  // Server
                                            INTERNET_DEFAULT_HTTP_PORT,
                                            NULL,     // Username
                                            NULL,     // Password
                                            INTERNET_SERVICE_HTTP,
                                            0,        // Synchronous
                                            NULL);    // No Context

    HINTERNET hRequest = HttpOpenRequest(hConnection,
                                         "GET",
                                         argv[2],
                                         NULL,    // Default HTTP Version
                                         NULL,    // No Referer
                                         (const char**)"*/*", // Accept
                                                                // anything
                                         0,       // Flags
                                         NULL);   // No Context
    HttpSendRequest(hRequest,
                    NULL,    // No extra headers
                    0,       // Header length
                    NULL,    // No Body
                    0);      // Body length

    DWORD dwContentLen;
    DWORD dwBufLen = sizeof(dwContentLen);
    if (HttpQueryInfo(hRequest,
                      HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
                      (LPVOID)&dwContentLen,
                      &dwBufLen,
                      0))
    {
        // You have a content length so you can calculate percent complete
        char *pData = (char*)GlobalAlloc(GMEM_FIXED, dwContentLen + 1);
        DWORD dwReadSize = dwContentLen / 10;   // We will read 10% of data
                                                // with each read.

        cout << "Download Progress:" << endl;
        cout << "    0----------100%" << endl;
        cout << "     ";
        cout.flush();

        DWORD cReadCount;
        DWORD dwBytesRead;
        char *pCopyPtr = pData;
        for (cReadCount = 0; cReadCount < 10; cReadCount++)
        {
            InternetReadFile(hRequest, pCopyPtr, dwReadSize, &dwBytesRead);
            cout << "*";
            cout.flush();
            pCopyPtr = pCopyPtr + dwBytesRead;
        }
        // extra read to account for integer division round off
        InternetReadFile(hRequest,
                         pCopyPtr,
                         dwContentLen - (pCopyPtr - pData),
                         &dwBytesRead);
        // Null terminate data
        pData[dwContentLen] = 0;

        // Display
        cout << endl << "Download Complete" << endl;
        cout << pData;
    }
    else
    {
        DWORD err = GetLastError();
        // No content length...impossible to calculate % complete
        // Just read until we are done.
        char pData[100];
        DWORD dwBytesRead = 1;
        while (dwBytesRead)
        {
            InternetReadFile(hRequest, pData, 99, &dwBytesRead);
            pData[dwBytesRead] = 0;
            cout << pData;
        }
    }
}


                

有几点需要注意的使用这种方法时:

    在开始之前,您必须知道的数据大小。上面的代码将尝试通过阅读使用 HttpQueryInfo 函数的 HTTP 内容长度标头来确定数据大小。尽管许多 HTTP 响应中包括的内容长度标头,则不需要。除非您有另一种机制,用于获取数据的大小,您将不能计算进度,如果在响应中未包括的内容长度标头。
    如果您试图上载或下载 FTP 资源中,您将不能使用 FtpPutFile 或 FtpGetFile,并希望确定进度信息。您应该使用 FtpOpenFile,然后使用 InternetReadFile 和 InternetWriteFile,如上面所述。
    因为提供进度的信息假定您必须知道数据的大小,可以使用 FtpGetFileSize 来下载文件之前获取 FTP 资源的大小。请注意 FtpGetFileSize 并不总是成功由于多种 FTP 服务器返回目录列表信息的方式获取的文件大小。有关使用 FTP 来获取目录列表信息的问题的其他信息,请参阅下面 Microsoft 知识库中相应的文章:
    172712信息: 限制的 WinInet FTP 功能

原文地址:https://www.cnblogs.com/microzone/p/3383236.html