主文件:
#include "stdafx.h"
#include <UrlMon.h>
#pragma comment(lib, "urlmon.lib")
#include <tchar.h>
#include "cbindCallBack.h"
#include "iostream"
#include <CString> int main()
{ //在url后添加随机数,防止从IE缓存中读取。url后加随机数不会影响下载的。
//如果想要从缓存中提取那么就把下面的注释掉 DWORD rand= GetTickCount(); CBindCallback cbc;
HRESULT hr=URLDownloadToFile(NULL, _T("http://dldir1.qq.com/qqfile/qq/QQ8.9/19983/QQ8.9.exe"), _T("e:\\download\\qq8.9.exe"), NULL, &cbc);
if (hr==S_OK)
{
std::cout << "下载完成!" << std::endl;
system("e:\\download\\qq8.9.exe");
}
else if (hr== E_OUTOFMEMORY)
{
std::cout << "缓冲区长度无效,或内存不足,无法完成操作!" << std::endl;
}
else if (hr== E_OUTOFMEMORY)
{
std::cout << "指定的资源或回调接口无效!" << std::endl;
} getchar();
return ;
} cbindCallback.h #pragma once
#include "stdafx.h"
#include <UrlMon.h>
#pragma comment(lib, "urlmon.lib")
#include <tchar.h>
class CBindCallback : public IBindStatusCallback
{
public:
CBindCallback();
virtual ~CBindCallback(); //接受显示进度窗口的句柄
//CUrlDownloadToFileCallbackTestDlg* m_pdlg; //IBindStatusCallback的方法。除了OnProgress 外的其他方法都返回E_NOTIMPL
STDMETHOD(OnStartBinding)
(DWORD dwReserved,
IBinding __RPC_FAR *pib)
{ return E_NOTIMPL; } STDMETHOD(GetPriority)
(LONG __RPC_FAR *pnPriority)
{ return E_NOTIMPL; } STDMETHOD(OnLowResource)
(DWORD reserved)
{ return E_NOTIMPL; } //OnProgress在这里
STDMETHOD(OnProgress)
(ULONG ulProgress,
ULONG ulProgressMax,
ULONG ulStatusCode,
LPCWSTR wszStatusText); STDMETHOD(OnStopBinding)
(HRESULT hresult,
LPCWSTR szError)
{ return E_NOTIMPL; } STDMETHOD(GetBindInfo)
(DWORD __RPC_FAR *grfBINDF,
BINDINFO __RPC_FAR *pbindinfo)
{ return E_NOTIMPL; } STDMETHOD(OnDataAvailable)
(DWORD grfBSCF,
DWORD dwSize,
FORMATETC __RPC_FAR *pformatetc,
STGMEDIUM __RPC_FAR *pstgmed)
{ return E_NOTIMPL; } STDMETHOD(OnObjectAvailable)
(REFIID riid,
IUnknown __RPC_FAR *punk)
{ return E_NOTIMPL; } // IUnknown方法.IE 不会调用这些方法的 STDMETHOD_(ULONG, AddRef)()
{ return ; } STDMETHOD_(ULONG, Release)()
{ return ; } STDMETHOD(QueryInterface)
(REFIID riid,
void __RPC_FAR *__RPC_FAR *ppvObject)
{ return E_NOTIMPL; }
}; cbindCallBack.cpp #include "stdafx.h"
#include "cbindCallBack.h"
#include "iostream"
using namespace std; //只需实现OnProgress方法,类的实现:
CBindCallback::CBindCallback()
{ } CBindCallback::~CBindCallback()
{ }
//////仅实现OnProgress成员即可
LRESULT CBindCallback::OnProgress(ULONG ulProgress,
ULONG ulProgressMax,
ULONG ulSatusCode,
LPCWSTR szStatusText)
{
/*CProgressCtrl* m_prg = (CProgressCtrl*)m_pdlg->GetDlgItem(IDC_PROGRESS);
m_prg->SetRange32(0, ulProgressMax);
m_prg->SetPos(ulProgress); CString szText;
szText.Format("已下载%d%%", (int)(ulProgress * 100.0 / ulProgressMax));
(m_pdlg->GetDlgItem(IDC_STATUS))->SetWindowText(szText);*/
cout << "文件大小为:" << ulProgressMax // << "MB"<<endl;
cout << ulProgress//<<"MB" << endl;
cout << "已下载:" << ulProgressMax*100.0/ulProgressMax << "%" << endl;
return S_OK;
}

注意事项:

1、下载代码最好放到一个线程里,否则URLDownloadToFile下载过程中等待返回时会阻塞,使UI失去响应。 
2、OnProgress返回S_OK表示正常,还可以通过返回E_ABORT使下载中断,所以可以设置个超时时间,如果超时的话,就让OnProgress返回E_ABORT。另外下次再开始从同一个url下载同一个文件时会直接由IE缓存中读取已下载的部分,达到“断点续传”的效果。
3、实际测试过程中发现URLDownloadToFile读IE缓存中已经下载的文件会有很大的安全隐患,如果哪次下载的文件发生问题,那么在不清除缓存的情况下,这个函数以后会一直读取损坏的文件而不重新下载。网上搜了一下解决方案,大概有三种:
      a.下载前用FindFirstUrlCacheEntry,FindNextUrlCacheEntry,DeleteUrlCacheEntry清除cache,这个代码网上很多。
      b.重载IBindStatusCallback的GetBindInfo方法,指定BINDF_GETNEWESTVERSION和BINDF_NOWRITECACHE属性,但是我测试发现即使指定这两个属性UrlDownloadToFile还是会很执着的读缓存,郁闷。
      c.还有一种方法比较猥琐,在要下载的文件地址后加一个随机字符串,这样既不会影响正常下载(下载时会被指向正确的地址)而且由于每次传给URLDownloadToFile的url都不同,在cache中没有地址匹配的文件,所以会重新下载。上面的代码就使用了这种方法,个人感觉比较省事而且经测试有效。 
4、CBindCallback有个成员变量用来传递进度条所在的窗口句柄m_pdlg,当然这个也可以用其他方式实现。 
5、URLDownloadToFile的好处在于它会自动使用IE的设置,完成下载,不用考虑代理情况。

 
关闭

c++のurlmon实现下载文件并进度回调的更多相关文章

  1. VC下载文件显示进度条

    VC下载文件显示进度条 逗比汪星人2009-09-18上传   by Koma http://blog.csd.net/wangningyu http://download.csdn.net/deta ...

  2. Android OkHttp + Retrofit 下载文件与进度监听

    本文链接 下载文件是一个比较常见的需求.给定一个url,我们可以使用URLConnection下载文件. 使用OkHttp也可以通过流来下载文件. 给OkHttp中添加拦截器,即可实现下载进度的监听功 ...

  3. VC下载文件 + 显示进度条

    在codeproject里找了许久,发现这样一个VC下载文件并显示进度条的源码,于是添加了些中文注释: 1.下载线程函数: UINT DownloadFile(LPVOID pParam) { CWn ...

  4. UrlDownloadFile, 线程下载文件, 带进度条

    unit FileDownLoadThread; interface uses Classes, SysUtils, Windows, ActiveX, UrlMon; const S_ABORT = ...

  5. webclient下载文件 带进度条

    private void button1_Click(object sender, EventArgs e) { doDownload(textBox1.Text.Trim()); } private ...

  6. winform 下载文件显示进度和百分比

    /// <summary> /// 下载完成 /// </summary> private void DownloadFileCompleted() { IsComlate = ...

  7. libcurl开源库在Win32程序中使用下载文件显示进度条实例

    一.配置工程引用libcurl库 #define CURL_STATICLIB #include "curl/curl.h" #ifdef _DEBUG #pragma comme ...

  8. C#使用七牛云存储上传下载文件、自定义回调

    项目需要将音视频文件上传服务器,考虑并发要求高,通过七牛来实现. 做了一个简易的压力测试,同时上传多个文件,七牛自己应该有队列处理并发请求,我无论同时提交多少个文件,七牛是批量一个个排队处理了. 一个 ...

  9. Android 下载文件 显示进度条

    加入两个权限 一个是联网,另一个是读写SD卡 <uses-permission android:name="android.permission.INTERNET">& ...

随机推荐

  1. 根域名服务器(root DNS Servers)会被DDoS打垮么?

    域名服务作为互联网的基础设施,它的重要性不言而喻.目前全球的十三个根域名服务器和成千上万的授权域名服务器承担着超过万亿次的DNS查询,默默为全世界的网民做域名解析服务. 这样重要的基础设施,必然是全世 ...

  2. Asp.net mvc 5 CRUD代码自动生成工具- vs.net 2013 Saffolding功能扩展

    Asp.net mvc 5 CRUD代码自动生成工具 -Visual Studio.net2013 Saffolding功能扩展 上次做过一个<Asp.net webform scaffoldi ...

  3. [总结] LCT学习笔记

    \(emmm\)学\(lct\)有几天了,大概整理一下这东西的题单吧 (部分参考flashhu的博客) 基础操作 [洛谷P1501Tree II] 题意 给定一棵树,要求支持 链加,删边加边,链乘,询 ...

  4. Django之web应用、http协议和django简介

    等了好久终于等到今天,盼了好久终于把梦实现,啦啦啦.....学习python两个多月了,终于等到python的高潮,老师说要是把Django学会了,python的web开发就差不多了,也相当于迎来了p ...

  5. ILSpy

    今日为找泛型序列的一个Select方法源码,就去找了个ILSpy反编译工具. 工具下载地址:http://www.fishlee.net/service/softarchive/57,一般选择较新的. ...

  6. java_二进制的前导的零

    题目内容: 计算机内部用二进制来表达所有的值.一个十进制的数字,比如18,在一个32位的计算机内部被表达为00000000000000000000000000011000.可以看到,从左边数过来,在第 ...

  7. PATH、CLASSPATH、CLASSPATH

    PATH: 说明: 环境变量中的path,意在在向计算机发出指令时的一个指向路径,如 一般会在path里加上:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin 其中:%JAVA_ ...

  8. FullCalendar – jQuery Event Calendar in ASP.NET

    https://github.com/esausilva/ASP.Net-EventCalendar http://trentrichardson.com/examples/timepicker/ h ...

  9. node.js入门学习笔记整理

    (1)node Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境. Node与javaScript的区别在于,javaScript的顶层对象是window,而no ...

  10. 【读书笔记】iOS-对iOS应用进行模糊测试

    一,模糊测试,是指通过反复向待测应用发送畸形的数据,对应用进行动态测试的过程. 二,模糊测试,也称动态分析,是一种构造非法输入并将其提供给应用,以期让应用暴露出某些安全问题的艺术和科学. 参考资料:& ...