您的位置:首页 > 其它

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

2008-07-22 08:03 316 查看

概要

loadTOCNode(1, 'summary');

是使用 WinInet 函数来下载或上载文件在 Internet 上许多开发人员要提供一个进度栏来指示完成文件传输的数量和不再将花费多少。 要做到这与以下机制。

更多信息

loadTOCNode(1, 'moreinformation');

以获取有关下载进度通知使用 InternetSetStatusCallback 使您进行请求如何同时, 包括连接状态通知好信息。 但是, 它并不表示已完成的传输特定百分比。

要获取百分比与完成通知, 需要确定传输的大小, 然后调用 InternetReadFile 或 InternetWriteFile 与小缓冲区。 作为函数调用完成然后可计算传输的百分比。

例如, 假设您想要下载 1000 字节文件。 而不是一个呼叫到 InternetReadFile 与 1000 字节缓冲区, 您可以进行到 InternetReadFIle 10 调用与 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**)"*/*/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;
        }
    }
}
有几点要使用此方法时查找出:

开始之前必须知道数据大小。 上述代码试图通过读取 Content-Length HTTP 头使用 HttpQueryInfo 函数确定数据大小。 尽管许多 HTTP 响应包括内容长度头, 它则不需要。 除非有其他机制来获取数据大小, 将不能来计算进度如果响应中不包含内容长度标头。
如果您正试图上载或下载来自一个 FTP 资源, 不会能够使用 FtpPutFile 或 FtpGetFile 和希望确定进度信息。 应使用 FtpOpenFile, 然后使用 InternetReadFile 和 InternetWriteFile 如上所述。
因为提供进度信息假定必须知道数据大小, 可使用 FtpGetFileSize 来获取 FTP 资源的大小之前下载文件。 注意 FtpGetFileSize 是不总是成功中获取文件大小因多种方式 FTP 服务器返回目录列表信息。 有关使用 FTP 来获取目录列表信息, 问题请参见下列文章 Microsoft 知识库文章:
172712 (http://support.microsoft.com/kb/172712/EN-US/) INFO: 限制的 WinInet FTP 函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐