C++Builder利用URLDownloadToFile下载文件并显示进度

函数定义 :

HRESULT URLDownloadToFile( 
   LPUNKNOWN pCaller, 
   LPCSTR szURL, 
   LPCSTR szFileName, 
   DWORD dwReserved, 
   LPBINDSTATUSCALLBACK lpfnCB
);

参数说明:
pCaller : 仅当调用者是一个ActiveX对象才使用,对于一个非ActiveX对象的应用程序这个参数应该为NULL
szURL : 为要下载的绝对URL 文件名,这个参数不能为空。
szFileName : 包含创建的目标文件名 
dwReserved : 必须为零
lpfnCB : 一个指向 IBindStatusCallback 接口的指针, IE通过它向你通知下载的进度。

利用URLDownloadToFile()下载文件可以分下面几个步骤:
1. 提供一个要下载的URL文件名。
2. 构造一个目标创建文件的完整路径含文件名。
3. 创建一个IBindStatusCallback派生类,编写OnProgress()重载函数。
4. 派生一个类对象的实例。
5. 调用URLDownLoad 函数,由于这个函数调用是同步的,因此你最好在一个工作者线程中调用这个函数。
6. 在OnProgress函数中,提供任何你需要的进度指示信息和其它界面,函数返回值告诉IE是继续下载或者是放弃下载。

使用IbindStatusCallback
IBindStatusCallback 回调接口共有8个方法,但是你只需关心OnProgress(). 其它方法只需返回E_NOTIMPL。

OnProgress 实现的规范是:
HRESULT OnProgress( 
   ULONG ulProgress, 
   ULONG ulProgressMax, 
   ULONG ulStatusCode, 
   LPCWSTR szStatusText
);

ulProgress
   到目前为止已经下载的字节数。
ulProgressMax
   要下载的文件大小,0表示大小未知,需要注意的是,这个值仅在OnProgress调用期间变化,所以你不能把它保存到一个静态变量中,你应该在每次调用时检查这个值。 
ulStatusCode
   状态标志,这个值可以为下列一些值:
   BINDSTATUS_BEGINDOWNLOADCOMPONENTS
   BINDSTATUS_INSTALLINGCOMPONENTS
   BINDSTATUS_ENDDOWNLOADCOMPONENTS
szStatusText
   图形界面中使用的字符串,由IE 提供,这个变量可能为NULL,在使用前应该检查这个变量。

OnProgress()返回 S_OK 告诉IE要继续下载, E_ABORT则表示放弃下载。

以下是IBindStatusCallback的派生类写法 :

//头文件

//---------------------------------------------------------------------------
#ifndef CallbackH
#define CallbackH
#include <Urlmon.h>
#include "DownThread.h"
//---------------------------------------------------------------------------
class TCallback : public IBindStatusCallback
{
DWORD m_cRef;
//IBinding *m_pbinding;
private:
    STDMETHODIMP QueryInterface(REFIID riid,void **ppv);
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();
    STDMETHODIMP GetBindInfo(DWORD *grfBINDF,BINDINFO *bindinfo);
    STDMETHODIMP GetPriority(LONG *nPriority);
    STDMETHODIMP OnDataAvailable(DWORD grfBSCF,DWORD dwSize,
        FORMATETC *formatetc,STGMEDIUM *stgmed);
    STDMETHODIMP OnLowResource(DWORD reserved);
    STDMETHODIMP OnObjectAvailable(REFIID iid,IUnknown *punk);
    STDMETHODIMP OnStartBinding(DWORD dwReserved,IBinding *pib);
    STDMETHODIMP OnStopBinding(HRESULT hresult,LPCWSTR szError);
    STDMETHODIMP OnProgress(ULONG ulProgress, ULONG ulProgressMax,
        ULONG ulStatusCode, LPCWSTR szStatusText);
public:
    TDownload *D;
    TCallback() {m_cRef = 1;/*m_pbinding = NULL*/};
    //~TCallback() {if (m_pbinding) m_pbinding->Release();};
};
#endif


//CPP文件

//---------------------------------------------------------------------------
#include "Callback.h"
//---------------------------------------------------------------------------
STDMETHODIMP TCallback::QueryInterface(REFIID riid,void **ppv)
{
    *ppv = NULL;
    if (riid==IID_IUnknown || riid==IID_IBindStatusCallback) {
        *ppv = this;
        AddRef();
        return S_OK;
    }
    return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) TCallback::AddRef()
{
    return m_cRef++;
}
STDMETHODIMP_(ULONG) TCallback::Release()
{
    if(--m_cRef==0) {
        delete this;
        return 0;
    }
    return m_cRef;
}

STDMETHODIMP TCallback::GetBindInfo(DWORD *grfBINDF,BINDINFO *bindinfo)
{
    return E_NOTIMPL;
}
STDMETHODIMP TCallback::GetPriority(LONG *nPriority)
{
    return E_NOTIMPL;
}
STDMETHODIMP TCallback::OnDataAvailable(DWORD grfBSCF,DWORD dwSize,
    FORMATETC *formatetc,STGMEDIUM *stgmed)
{       
    return E_NOTIMPL;
}
STDMETHODIMP TCallback::OnLowResource(DWORD reserved)
{
    return E_NOTIMPL;
}
STDMETHODIMP TCallback::OnObjectAvailable(REFIID iid,IUnknown *punk)
{
    return E_NOTIMPL;
}
STDMETHODIMP TCallback::OnStartBinding(DWORD dwReserved,IBinding *pib)
{
    return E_NOTIMPL;
}
STDMETHODIMP TCallback::OnStopBinding(HRESULT hresult,LPCWSTR szError)
{
    return E_NOTIMPL;
}
STDMETHODIMP TCallback::OnProgress(ULONG ulProgress, ULONG ulProgressMax,
    ULONG ulStatusCode, LPCWSTR szStatusText)
{           
    AnsiString Status;
    switch (ulStatusCode)
    {
      case BINDSTATUS_FINDINGRESOURCE : Status = "Finding resource " + AnsiString(szStatusText); break;
      case BINDSTATUS_CONNECTING : Status = "Connecting to " + AnsiString(szStatusText); break;
      case BINDSTATUS_REDIRECTING : Status = "Redirecting..."; break;
      case BINDSTATUS_BEGINDOWNLOADDATA : Status = "Start to download " + AnsiString(szStatusText); break; 
      case BINDSTATUS_DOWNLOADINGDATA : Status = "Downloading..."; break;
      case BINDSTATUS_ENDDOWNLOADDATA : Status = "Complete downloading " + AnsiString(szStatusText); break;
      case BINDSTATUS_BEGINDOWNLOADCOMPONENTS : Status = "Start to download components"; break;
      case BINDSTATUS_INSTALLINGCOMPONENTS : Status = "Installing components..." ; break;
      case BINDSTATUS_ENDDOWNLOADCOMPONENTS : Status = "Complete downloading components"; break;
      case BINDSTATUS_USINGCACHEDCOPY : Status = "Copying form buffer..."; break;
      case BINDSTATUS_SENDINGREQUEST : Status = "Sending request..."; break;
      case BINDSTATUS_CLASSIDAVAILABLE : Status = "Class ID is available"; break;
      case BINDSTATUS_MIMETYPEAVAILABLE : Status = "MIME type is available"; break;
      case BINDSTATUS_CACHEFILENAMEAVAILABLE : Status = "Cache file name is available"; break;
      case BINDSTATUS_BEGINSYNCOPERATION : Status = "Start sync operation"; break;
      case BINDSTATUS_ENDSYNCOPERATION : Status = "Complete sync operation"; break;
      case BINDSTATUS_BEGINUPLOADDATA : Status = "Start to upload data"; break;
      case BINDSTATUS_UPLOADINGDATA : Status = "Uploading data"; break;
      case BINDSTATUS_ENDUPLOADDATA : Status = "Complete Uploading data"; break;
      case BINDSTATUS_PROTOCOLCLASSID : Status = "Protocol class ID is available"; break;
      case BINDSTATUS_ENCODING : Status = "Encoding..."; break;
      case BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE : Status = "Verified MIME is available"; break;
      case BINDSTATUS_CLASSINSTALLLOCATION : Status = "Class install location"; break;
      case BINDSTATUS_DECODING : Status = "Decoding..."; break;
      case BINDSTATUS_LOADINGMIMEHANDLER : Status = "Loading MIME handler"; break;
      case BINDSTATUS_CONTENTDISPOSITIONATTACH : Status = "Content disposition attach"; break;
      case BINDSTATUS_FILTERREPORTMIMETYPE : Status = "Filter report MIME type"; break;
      case BINDSTATUS_CLSIDCANINSTANTIATE : Status = "Clsid can instantiate"; break;
      case BINDSTATUS_IUNKNOWNAVAILABLE : Status = "Unknown available"; break;
      case BINDSTATUS_DIRECTBIND : Status = "Direct bind"; break;
      case BINDSTATUS_RAWMIMETYPE : Status = "MIME type of the resource, before any code sniffing is done"; break;
      case BINDSTATUS_PROXYDETECTING : Status = "Detecting proxy..."; break;
      case BINDSTATUS_ACCEPTRANGES : Status = "Valid types of range requests for a resource"; break;
      default : Status = "";
    }
    //在这里填入显示进度的代码。
    //如果要实现中断下载,最好在一个线程中调用URLDownloadToFile函数,
    //如下面代码中的 D 既是一个线程,设定DoCancel变量来决定是否取消下载。
    //DoProgress是线程中显示进度的函数。
    if (!Status.IsEmpty()) D->ShowMsg(Status);
    D->DoProgress(ulProgress,ulProgressMax,ulStatusCode);
    if (D->DoCancel) return E_ABORT;
    else return S_OK;
}

使用范例:

#include <Urlmon.h> //还须加入urlmon.lib

...
TCallback Status; //回调类实例
URLDownloadToFile(NULL,"http://...","C://???",0,&Status);

在Visual Basic 6.0中,使用`URLDownloadToFile`函数可以实现文件下载功能。这个函数是Windows API的一部分,用于从指定的URL下载文件并保存到本地磁盘。为了实现带有下载进度文件下载,我们需要结合其他技术来获取下载进度信息。 `URLDownloadToFile`函数本身并不提供下载进度的回调,因此要获取进度信息,可以采用以下方法: 1. **定时轮询法**:通过定时检查临时文件的大小来估算下载进度。这种方法简单,但可能存在一定的延迟和误差。 2. **使用HTTP头信息**:对于HTTP协议的下载,可以通过解析HTTP响应头中的`Content-Length`字段来计算下载进度,这需要能够接收和解析HTTP响应头。 3. **第三方库或工具**:使用支持进度回调的第三方下载库或工具,例如AxWebBrowser控件的`Navigate2`方法,可以通过事件获取下载进度。 下面是一个使用定时轮询法的示例代码,这个方法适用于多种类型的URL,但需要注意的是,对于非HTTP协议的下载,可能无法获取进度信息。 ```vb Private Declare Function URLDownloadToFile Lib "urlmon" Alias "URLDownloadToFileA" ( _ ByVal pCaller As Long, _ ByVal szURL As String, _ ByVal szFileName As String, _ ByVal dwReserved As Long, _ ByVal lpfnCB As Long) As Long Private Sub DownloadFile(url As String, fileName As String) Dim hEvent As Long Dim result As Long Dim fileLength As Long Dim downloaded As Long Dim percent As Long Dim timeInterval As Long Dim timerID As Long ' 初始化下载进度 downloaded = 0 fileLength = 0 percent = 0 ' 设置定时器,例如每500毫秒触发一次检查 timeInterval = 500 timerID = SetTimer(0, 0, timeInterval, AddressOf UpdateProgress) ' 下载文件 result = URLDownloadToFile(0, url, fileName, 0, 0) ' 取消定时器 KillTimer 0, timerID End Sub Private Sub UpdateProgress(ByVal hwnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long) ' 更新下载进度的代码 ' 这里需要自己实现如何获取下载的当前字节和总字节数 ' 更新界面的进度条等组件 End Sub ``` 在上述代码中,`UpdateProgress`子程序需要根据实际情况实现,用于更新下载进度。由于VB6本身不具备直接获取下载进度的能力,需要用户根据具体情况,可能结合第三方库或API来实现此功能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值