URLDownloadToFile是urlmon.dll提供的网络操作API,可以用于从指定的URL下载文件到本地,在C++中通过类很容易实现下载进度的获取,今天需要在C语言中使用到这个函数,这里记录一下使用方法。该函数的定义如下所示。
HRESULT URLDownloadToFile( LPUNKNOWN pCaller, LPCTSTR szURL, LPCTSTR szFileName, _Reserved_ DWORD dwReserved, LPBINDSTATUSCALLBACK lpfnCB );
参数pCaller跟ActiveX和COM有关,如有兴趣参考这里,否则就设置为NULL
参数szURL为下载地址,地址的协议必须要是IE浏览器所支持的
参数szFileName为文件最终的保存路径,例如C:/a.txt
参数dwReserved保留,始终为0
参数lpfnCB是一个IBindStatusCallback指针。
在urlmon.h头文件的定义中,C语言风格的接口定义如下:
typedef struct IBindStatusCallbackVtbl { BEGIN_INTERFACE HRESULT ( STDMETHODCALLTYPE *QueryInterface )( __RPC__in IBindStatusCallback * This, /* [in] */ __RPC__in REFIID riid, /* [annotation][iid_is][out] */ _COM_Outptr_ void **ppvObject); ULONG ( STDMETHODCALLTYPE *AddRef )( __RPC__in IBindStatusCallback * This); ULONG ( STDMETHODCALLTYPE *Release )( __RPC__in IBindStatusCallback * This); HRESULT ( STDMETHODCALLTYPE *OnStartBinding )( __RPC__in IBindStatusCallback * This, /* [in] */ DWORD dwReserved, /* [in] */ __RPC__in_opt IBinding *pib); HRESULT ( STDMETHODCALLTYPE *GetPriority )( __RPC__in IBindStatusCallback * This, /* [out] */ __RPC__out LONG *pnPriority); HRESULT ( STDMETHODCALLTYPE *OnLowResource )( __RPC__in IBindStatusCallback * This, /* [in] */ DWORD reserved); HRESULT ( STDMETHODCALLTYPE *OnProgress )( __RPC__in IBindStatusCallback * This, /* [in] */ ULONG ulProgress, /* [in] */ ULONG ulProgressMax, /* [in] */ ULONG ulStatusCode, /* [unique][in] */ __RPC__in_opt LPCWSTR szStatusText); HRESULT ( STDMETHODCALLTYPE *OnStopBinding )( __RPC__in IBindStatusCallback * This, /* [in] */ HRESULT hresult, /* [unique][in] */ __RPC__in_opt LPCWSTR szError); /* [local] */ HRESULT ( STDMETHODCALLTYPE *GetBindInfo )( IBindStatusCallback * This, /* [out] */ DWORD *grfBINDF, /* [unique][out][in] */ BINDINFO *pbindinfo); /* [local] */ HRESULT ( STDMETHODCALLTYPE *OnDataAvailable )( IBindStatusCallback * This, /* [in] */ DWORD grfBSCF, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC *pformatetc, /* [in] */ STGMEDIUM *pstgmed); HRESULT ( STDMETHODCALLTYPE *OnObjectAvailable )( __RPC__in IBindStatusCallback * This, /* [in] */ __RPC__in REFIID riid, /* [iid_is][in] */ __RPC__in_opt IUnknown *punk); END_INTERFACE } IBindStatusCallbackVtbl; interface IBindStatusCallback { CONST_VTBL struct IBindStatusCallbackVtbl *lpVtbl; };
这里的interface在C语言中的定义为struct, IBindStatusCallback回调实际上就是一个结构体,结构体只有一个字段IBindStatusCallbackVtbl *指针,你需要做的就是对这个结构体内的IBindStatusCallbackVtbl 指针进行实例化。IBindStatusCallbackVtbl 结构中包含了一系列的函数指针,也就是用于URLDownloadToFile下载时的回调函数。若要实现下载进度的获取,只需要在OnProgress回调中处理即可。
控制台示例代码
#define _CRT_SECURE_NO_WARNINGS #include <windows.h> #include <urlmon.h> #include <stdio.h> #pragma comment(lib,"urlmon") HRESULT (STDMETHODCALLTYPE QueryInterface)( IBindStatusCallback* This, /* [in] */ REFIID riid, /* [iid_is][out] */ void** ppvObject) { return E_NOTIMPL; } ULONG (STDMETHODCALLTYPE AddRef)( IBindStatusCallback* This) { return E_NOTIMPL; } ULONG (STDMETHODCALLTYPE Release)( IBindStatusCallback* This) { return E_NOTIMPL; } HRESULT (STDMETHODCALLTYPE OnStartBinding)( IBindStatusCallback* This, /* [in] */ DWORD dwReserved, /* [in] */ IBinding* pib) { return E_NOTIMPL; } HRESULT (STDMETHODCALLTYPE GetPriority)( IBindStatusCallback* This, /* [out] */ LONG* pnPriority) { return E_NOTIMPL; } HRESULT (STDMETHODCALLTYPE OnLowResource)( IBindStatusCallback* This, /* [in] */ DWORD reserved) { return E_NOTIMPL; } HRESULT (STDMETHODCALLTYPE OnProgress)( IBindStatusCallback* This, /* [in] */ ULONG ulProgress, /* [in] */ ULONG ulProgressMax, /* [in] */ ULONG ulStatusCode, /* [in] */ LPCWSTR szStatusText) { if (ulProgress == 0) { return S_OK; } printf("%d / %d bytes , %.2f%%\n", ulProgress, ulProgressMax,100*(double)ulProgress/(double)ulProgressMax); return S_OK; } HRESULT (STDMETHODCALLTYPE OnStopBinding)( IBindStatusCallback* This, /* [in] */ HRESULT hresult, /* [unique][in] */ LPCWSTR szError) { return E_NOTIMPL; } HRESULT (STDMETHODCALLTYPE GetBindInfo)( IBindStatusCallback* This, /* [out] */ DWORD* grfBINDF, /* [unique][out][in] */ BINDINFO* pbindinfo) { return E_NOTIMPL; } HRESULT (STDMETHODCALLTYPE OnDataAvailable)( IBindStatusCallback* This, /* [in] */ DWORD grfBSCF, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC* pformatetc, /* [in] */ STGMEDIUM* pstgmed) { return E_NOTIMPL; } HRESULT (STDMETHODCALLTYPE OnObjectAvailable)( IBindStatusCallback* This, /* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown* punk) { return E_NOTIMPL; } int main(int argc,char * argv[]) { char path[MAX_PATH]; char downloadURL[] ="https://down.qq.com/qqweb/PCQQ/PCQQ_EXE/PCQQ2020.exe"; IBindStatusCallback callBack; IBindStatusCallbackVtbl vtbl; vtbl.QueryInterface = QueryInterface; vtbl.AddRef = AddRef; vtbl.Release = Release; vtbl.OnStartBinding = OnStartBinding; vtbl.GetPriority = GetPriority; vtbl.OnLowResource = OnLowResource; vtbl.OnProgress = OnProgress;//进度回调操作 vtbl.OnStopBinding = OnStopBinding; vtbl.GetBindInfo = GetBindInfo; vtbl.OnDataAvailable = OnDataAvailable; vtbl.OnObjectAvailable = OnObjectAvailable; callBack.lpVtbl = &vtbl; GetTempPath(sizeof(path),path); strcat(path, "tmpqq.exe"); printf("保存位置: %s\n", path); URLDownloadToFile(NULL,downloadURL, path,0,&callBack); return 0; }

转载请注明:悠然品鉴 » C语言URLDownloadToFile获取文件下载进度