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);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章