在博客《 windows客户端开发–根据可下载url另存为文件》 中,我们介绍了一个windows api, URLDownloadToFile
今天我们就要实现的是使用URLDownloadToFile下载文件,并显示进度条。
基础知识
认真看一看URLDownloadToFile的参数:
URLDownloadToFile
HRESULT URLDownloadToFile( LPUNKNOWN pCaller, LPCTSTR szURL, LPCTSTR szFileName, _Reserved_ DWORD dwReserved, LPBINDSTATUSCALLBACK lpfnCB );
pCaller
If the calling application is not an ActiveX component, this value can be set to NULL.
我们可以设为NULL
szURL
A pointer to a string value that contains the URL to download.
我们要下载的URL
szFileName
A pointer to a string value containing the name or full path of the file to create for the download.
存储的文件名
dwReserved
Reserved. Must be set to 0.
必须为NULL
lpfnCB
A pointer to the IBindStatusCallback interface of the caller. By using IBindStatusCallback::OnProgress, a caller can receive download status. URLDownloadToFile calls the IBindStatusCallback::OnProgress and IBindStatusCallback::OnDataAvailable methods as data is received.
这个参数是我们关注的重点!!!!!
接下来我们就看看IBindStatusCallback 的定义以及描述:
IBindStatusCallback
The IBindStatusCallback interface inherits from the IUnknown interface。既然是接口,我们就要继承它,根据自己的实际情况实现。这里就介绍一个函数:
OnProgress
Indicates the progress of the bind operation.
撸代码
实现自己的DownloadProgress :
class DownloadProgress : public IBindStatusCallback { public: HRESULT __stdcall QueryInterface(const IID &, void **) { return E_NOINTERFACE; } ULONG STDMETHODCALLTYPE AddRef(void) { return 1; } ULONG STDMETHODCALLTYPE Release(void) { return 1; } HRESULT STDMETHODCALLTYPE OnStartBinding(DWORD dwReserved, IBinding *pib) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE GetPriority(LONG *pnPriority) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE OnLowResource(DWORD reserved) { return S_OK; } virtual HRESULT STDMETHODCALLTYPE OnStopBinding(HRESULT hresult, LPCWSTR szError) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE GetBindInfo(DWORD *grfBINDF, BINDINFO *pbindinfo) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE OnDataAvailable(DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed) { return E_NOTIMPL; } virtual HRESULT STDMETHODCALLTYPE OnObjectAvailable(REFIID riid, IUnknown *punk) { return E_NOTIMPL; } virtual HRESULT __stdcall OnProgress(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) { if (ulProgressMax != 0) { double *percentage = new double(ulProgress * 1.0 / ulProgressMax * 100); //将percentage 发送给显示 delete percentage; } return S_OK; } };
使用:
std::string url = "......"; std::string file_path = "......"; DownloadProgress progress; IBindStatusCallback* callback = (IBindStatusCallback*)&progress; URLDownloadToFile(NULL, url.c_str(), file_path .c_str(), NULL, static_cast(&progress));
最后说一下头文件以及lib:
#include #pragma comment(lib, "urlmon.lib")
最后,记得在子线程中进行下载操作,c++11给我提供了非常方便的多线程: