环境: win7 64位 vs2008 ( MFC ASCii)

参考文章:MSDN
      Wininet 错误码
      利用WinINet进行网络程序的编程

写在开头:本文中是用的同步方法 ,
     好处是比较简单,方便 ;
     坏处是 InternetOpenUrl 可能会遇到 卡死不返回的情况;
     更好的方法是使用异步的方式下载。

  下载工作是放在一个线程中的,整体下载流程 InternetOpen - > InternetOpenUrl -> ( HttpQueryInfo可省略) -> InternetReadFile -> InternetCloseHandle

下面正文开始

1. 首先引入库文件

#include <wininet.h>
#pragma comment( lib, "wininet.lib")

2. InternetOpen 初始化
  主要是设置代理和 访问方式 , 这里如果不需要代理的话,前面都可以不用管,最后一个参数 是一个DWORD 的标记符 ,同步的话填0 就可以,具体细节可以参照MSDN

 HINTERNET hSession = InternetOpen(_T("NBDOWNLOAD"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);

3. InternetOpenUrl
函数原型 :

     void InternetOpenUrlA(HINTERNET hInternet,LPCSTR    lpszUrl,LPCSTR    lpszHeaders,DWORD     dwHeadersLength,DWORD     dwFlags,DWORD_PTR dwContext);

参数 : hInternet : InternetOpen 返回的 handle
    lpszUrl : 需要访问的url
   lpszHeaders http 请求头 ,可以用Chrome 访问一下,然后复制下来 ,类似这种形式,也可以用NULL ,默认情况下编译器会自动生成http请求头,不过服务器不一定认,还是用浏览器的头比较保险。

 const TCHAR szHeaders[] = _T("Accept: */*\r\nUser-Agent:  Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36\r\n");

dwHeadersLength 请求头的长度 ,sizeof(szHeaders)
  dwFlags 又是一个DWORD 的标记符,填 INTERNET_FLAG_DONT_CACHE 即可。
  dwContext 异步请求时候传的上下文,这里填 NULL

 HINTERNET hRequest = InternetOpenUrl(hSession, Url, NULL, 0, INTERNET_FLAG_DONT_CACHE, );

4. HttpQueryInfo
  使用这个主要是在下载前先获取文件的总大小,如果不需要可以省略这步(其实可以获取很多种信息,具体可以参照MSDN Query Info Flags)

 char szContentLength[128]={0};DWORD Totallength = sizeof(szContentLength);int ret = HttpQueryInfo(hRequest , HTTP_QUERY_CONTENT_LENGTH,  szContentLength, (LPDWORD)&Totallength,NULL);Singlelen = atoi(szContentLength);  //获取到的长度是字符数组形式的,单位是字节,转换成int 最多可以表示2G大小

第二个参数 就是上面 Query Info Flags 中列举的可查询的信息 ,第三个参数 是返回数据的数组,第四个参数是数组的大小
最后一个参数 MSDN上是这样说的,不过不太清楚什么场景上会用到multiple headers。

A pointer to a zero-based header index used to enumerate multiple headers with the same name. When calling the function, this parameter is the index of the specified header to return. When the function returns, this parameter is the index of the next header. If the next index cannot be found, ERROR_HTTP_HEADER_NOT_FOUND is returned.

5. InternetReadFile
函数原型:

     BOOLAPI InternetReadFile(HINTERNET hFile,LPVOID    lpBuffer,DWORD     dwNumberOfBytesToRead,LPDWORD   lpdwNumberOfBytesRead);

参数:
   hFile : InternetOpenUrl 返回的handle
   lpBuffer : 缓冲区地址
  dwNumberOfBytesToRead : 每次需要读取的字节数 ,一般用 缓冲区大小 -1
   lpdwNumberOfBytesRead : 实际读取的字节数 ,当lpdwNumberOfBytesRead 返回为0 的时候说明已经读取完全部数据了。

 #define  DOWNBLOCK 1024ULONG Number = 1; //不能定义为0 ,如果为0 会影响while判断byte Temp[DOWNBLOCK]={0}; while(Number){BOOL bReadFile = InternetReadFile(hRequest , Temp, DOWNBLOCK - 1, &Number);/******写入本地文件 *********/}

6. 关闭句柄

 InternetCloseHandle(hRequest);InternetCloseHandle(hSession);

7. 以上只是理想情况,事实上,除了InternetCloseHandle()每个步骤都可能失败,可以通过判断函数的返回值来判断函数是否正常,如果返回FALSE 或 NULL 说明函数执行失败了,可以在后面立即调用 GetLastError() 来获取详细的错误信息,错误信息在开头的参考文章里说的很详细,也可能是系统的其他错误,用vs的错误查找工具即可。

另外开头已经说过,InternetOpenUrl 在访问一个无法访问到的网址时,很可能会出现无限等待的情况,更好的方法就是改用异步的方式。

整体参考代码


UINT ThreadDownLoad(LPVOID lpParam){//CPingAnDownLoadDlg* pdlg = (CPingAnDownLoadDlg*)lpParam;byte Temp[DOWNBLOCK]={0}; const TCHAR szHeaders[] = _T("Accept: */*\r\nUser-Agent:  Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36\r\n");ULONG Number = 1;  FILE *stream = NULL; /*char szContentLength[128]={0};//DWORD Totallength =128;int Singlelen = 0; int CurrentLen = 0;*/HINTERNET AhHttp = NULL;HINTERNET hSession = InternetOpen(_T("NBDODNLOAD"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);  if (hSession != NULL){  hHttp  = InternetOpenUrl(hSession, 需要访问的URL, NULL, 0, INTERNET_FLAG_DONT_CACHE, 0);if (hHttp == NULL){return 0;}/* 获取文件大小memset(szContentLength,0,sizeof(szContentLength));int ret = HttpQueryInfo(hHttp, HTTP_QUERY_CONTENT_LENGTH,szContentLength, (LPDWORD)&Totallength,NULL);Singlelen = atoi(szContentLength);if(Singlelen <= 0){InternetCloseHandle(hHttp); hHttp = NULL; return 0;}*/stream = fopen(_T("nbtest.exe"),"wb"); //注意一下打开方式if(stream == NULL){InternetCloseHandle(hHttp); hHttp = NULL; return 0;}while (Number > 0){  BOOL bReadFile = InternetReadFile(hHttp, Temp, DOWNBLOCK - 1, &Number);  if(bReadFile == FALSE){DWORD ret = GetLastError();InternetCloseHandle(hHttp); hHttp = NULL; break;}fwrite(Temp, sizeof (char), Number , stream);  //CurrentLen += Number;}//end whileInternetCloseHandle(hSession);  hSession = NULL;//PostMessage(pdlg->m_hWnd,WM_DOWNLOAD_FIN,DownState,UpdataNumber);}//end ifreturn 0;
}

用 WinInet InternetOpen做一个简单的下载器相关推荐

  1. python写一个文件下载器_python使用tcp实现一个简单的下载器

    上一篇中介绍了tcp的流程,本篇通过写一个简单的文件下载器程序来巩固之前学的知识. 文件下载器的流程如下: 客户端: 输入目标服务器的ip和port 输入要下载文件的名称 从服务器下载文件保存到本地 ...

  2. jmfapplet做一个简单的播放器

    做一个项目,客户要求播放某一时刻的影像or动画, 于是想到了jmf+applet.jar包地址如下: http://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/ ...

  3. java做一个简单的文件管理器

    前言 马上大四了,在大三结束后进入一家国企的研发组工作,短短的两个月实习大部分时间都是在自己学习.最近几天突然有点困倦,决定把之前做的一些东西分享出来. 目的与内容 运用面向对象程序设计思想,基于Ja ...

  4. 使用掌控版制作一个简单的抢答器

    前几天老师布置的作业,要求我们做一个简单的抢答器,我用了掌控版,软件用的是mind+. 这个图形化编程软件简单易懂,容易操作. 这里用到三个掌控版,一个模拟主持人(也就是出题方),另外俩个模拟抢答端. ...

  5. 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截...

    程序猿修仙之路--数据结构之你是否真的懂数组? 数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构  .要想在之后的江湖历练中通关,数据结构必不可少.数据 ...

  6. 【Python】如何用python做一个简单的输入输出交互界面?

    看到知乎上有人在问,如何使用Python做一个简单的输入输出交互界面? 交互界面就涉及到GUI编程. Python有很多GUI框架,功能大同小异. 其中比较出名的有「PyQT」.**wxPython. ...

  7. html控制图的宽,用JointJS做一个简单的功能控制图

    继上一篇介绍了GoJS之后,继续研究JS的绘图工具,毕竟GoJS有些小贵.这次选择了JointJS,完全开源,它还有一个商业版本叫Raddit,功能更强大.不过就我的需求场景,开源的Joint就足够了 ...

  8. 用html5做一个简单网页_用新款ws2812灯带做一个简单的窗花

    本文转自:DF创客社区-未经许可不可转载 原文链接(附件请于原文下方下载): 用新款ws2812灯带做一个简单的窗花-创意生活论坛-DF创客社区​mc.dfrobot.com.cn 作者:屌丝王小明 ...

  9. 用pygame做一个简单的python小游戏---贪吃蛇

    用pygame做一个简单的python小游戏-贪吃蛇 贪吃蛇游戏博客链接:(方法一样,语言不一样) c++贪吃蛇:https://blog.csdn.net/weixin_46791942/artic ...

最新文章

  1. swift中字符串截取方法(substring)
  2. PNAS:人工构建玉米极简微生物组
  3. Java、Android基础之—反射
  4. Docker容器安装配置
  5. 2020-12-5(操作系统---设备管理)
  6. 数据库分区分表以及读写分离
  7. Scala模式匹配中的变量
  8. snmp 获得硬件信息_计算机网络基础课程—简单网络管理协议(SNMP)
  9. SilverLight幻灯片
  10. tq2440修改默认串口不支持打印控制台
  11. EasyUI:textbox自定义验证手机号(正则)
  12. net core获取客户端ip
  13. 使用maven引用第三方jar包
  14. 集合论的ZFC公理系统
  15. GBase 8a里通过rsync加速调度coor节点的扩容和替换效率
  16. Web前端:木兰花令网页案例设计
  17. 基于springboot 支付宝app端支付,可用于uni-app使用
  18. java 累加函数_请你编写一个方法(函数),功能要求从参数x累加到y,并返回累加后的整数结果。...
  19. HAUTOJ 1100~1200题题解
  20. JSPX使用的几点注意

热门文章

  1. mysql输入01变成1_01-MySQL基本操作
  2. C语言typedef的用法详解
  3. 加菲猫的经典语录~~~
  4. jquery之删除节点
  5. 关于校园流浪狗情况的调查
  6. vue上传文件并解析出内容
  7. Linux查看服务器端口使用情况,nginx服务器配置。
  8. matlab代数方程求解
  9. Microsoft Office Word导出高清PDF步骤
  10. 教你如何手写一个Promise