HOWTO: Provide Download/Upload Progress Information when Using WinInet

ID: Q234913


The information in this article applies to:


SUMMARY

Many developers who are using the WinInet functions to download or upload files on the Internet would like to provide a progress bar to indicate how much of the file transfer has completed and how much longer it will take. You can do this with the following mechanisms.


MORE INFORMATION

Using InternetSetStatusCallback to get notifications of the download progress gives you good information on how the request is progressing, including connecting status notifications. However, it does not indicate that a certain percentage of a transfer has completed.

To get the equivalent of percentage complete notifications, you need to determine the size of the transfer and then call InternetReadFile or InternetWriteFile with small buffers. Then you can calculate the percentage of the transfer as the function calls complete.

For instance, suppose you want to download a 1000 byte file. Instead of making one call to InternetReadFile with a 1000 byte buffer, you can make 10 calls to InternetReadFIle with 100 byte buffers. This way as each call to InternetReadFile completes, you know the download is another 10 percent complete.

The following code illustrates this procedure:


#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**)"*/*\0", // 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;
        }
    }
} 
There are a few things to look out for when using this approach:

Additional query words:


Keywords          : kbIE300 kbIE301 kbIE400 kbIE401 kbIE302 kbIE401sp1 kbIE401sp2 kbIE500 kbGrpInetServer kbDSupport 
Version           : WINDOWS:2.0,2.01,2.1,3.0,3.01,3.02,4.0,4.01,4.01 SP1,4.01 SP2,5.0
Platform          : WINDOWS 
Issue type        : kbhowto 

Last Reviewed: July 8, 1999