windows SDK中的wininet写http客户端
BOOL InternetSetOption(
_In_ HINTERNET hInternet,
_In_ DWORD dwOption,
_In_ LPVOID lpBuffer,
_In_ DWORD dwBufferLength
);
BOOL InternetQueryOption(
_In_ HINTERNET hInternet,
_In_ DWORD dwOption,
_Out_ LPVOID lpBuffer,
_Inout_ LPDWORD lpdwBufferLength
);
这两个函数是用来设置和查询internet选项进行操作。第二个参数是要设置的选项类型。有几十种选项类型,具体可参阅:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa385328(v=vs.85).aspx
第三、四个参数我一直无法理解,一个void指针和一个DWORD指针。要怎么用呢。
如果要设置或查询代理IP,调用这个函数的时候我们得把字符串传递进去,如果要设置或查询超时值,我们得把整型变量传递进去。按理说这个函数应该写N种重载形式,以对应不同的选项。但要知道,可设置、查询的选项有几十种,近百种。很多选项要传递的参数类型都是不同的,有字符串型的、整型的,还有各种各样的自定义结构体。如果要写几十种,近百种函数重载形式,未免太麻烦了。微软在这里偷了个懒,当然,可能也是有他自己的考虑。他用void*作形参使得任何类型的参数都能传入,但是各种数据类型的大小是不一样的,于是便用第四个参数DWORD,告诉他你传入的参数有多大。
那么,要设置超时值的时候,我们这样用:
DWORD dwTimeOut = 30000;
InternetSetOption(NULL,OPTION_CONNECT_TIMEOUT,&dwTimeOut,sizeof(dwTimeOut));
要设置代理IP时,我们这样用:
INTERNET_PROXY_INFO info;
info.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
info.lpszProxy = "192.168.1.250:8080";
info.lpszProxyBypass = "192.168.1.250:8080";
InternetSetOption(NULL,OPTION_PROXY,&info,sizeof(info));
是不是很巧妙,这个void*使得我们可以根据不同的选项,传入不用的数据类型,当然,第四个参数,我们得告诉他我们传入的数据类型有多大。
要查询超时值的时候,我们这样用:
DWORD dwTimeOut,dwSize = sizeof(dwTimeOut);
InternetQueryOption(NULL,OPTION_CONNECT_TIMEOUT,&dwTimeOut,&dwSize);
你会发现InternetQueryOption和InternetSetOption的第四个参数是不同的,InternetQueryOption的第四个参数是DWORD的指针。为什么这里要用指针,因为调用InternetQueryOption的时候,你是要获取数据,调用的时候,你告诉API你第三个参数有多大,能容纳多少字节的数据。函数返回的时候,API会修改你第四个参数传进去的变量为实际写入的字节数。上面dwTimeOut是32位无符号整型,能容纳4个字节的数据。假如你传递进去的dwSize是5,那么调用后dwSize将变成4,因为实际只写入了4个字节的数据。假如你传递进去的dwSize是3,那么函数将调用失败。
也许你会很疑惑,不就一个DWORD吗,有必要那么麻烦吗?试想,如果你需要InternetQueryOption返回一个字符串,第三个参数传递一个char*进去,这种机制会变得非常有用。
要查询代理IP时,我们这样用:
DWORD dwSize=0;
//第三个参数为NULL,第一次调用,我们的目的是为了知道需要多大的缓冲区
InternetQueryOption(NULL,OPTION_PROXY,NULL,&dwSize);
LPINTERNET_PROXY_INFO pInfo = (LPINTERNET_PROXY_INFO)malloc(dwSize);
//第二次调用,获取数据
InternetQueryOption(NULL,OPTION_PROXY,pInfo,&dwSize);
free(pInfo);
当然,我们也可以在栈上分配足够大的缓冲区,而不用先调用一次以知道需要多大的缓冲区:
DWORD dwSize=1000;
byte buff[1000];
LPINTERNET_PROXY_INFO pInfo = (LPINTERNET_PROXY_INFO)buff;
InternetQueryOption(NULL,OPTION_PROXY,pInfo,&dwSize);
运行效果如上图。dwSize为50,说明需要50字节的缓冲区。手动计算一下是不是这样。
有趣的是LPINTERNET_PROXY_INFO pInfo = (LPINTERNET_PROXY_INFO)malloc(dwSize);
INTERNET_PROXY_INFO指针指向它。这两串字符串就是写到了后面这32字节上。
仔细看上图。pInfo的内存地址是0x0012fb58。加12字节,刚好就是0x0012fb64。第一个字符串是紧跟在结构体pInfo之后的。第一个字符串的地址0x0012fb64再加19字节(字符串的长度),刚好是0x0012fb77(注意是十六进制)。
微软的这种API设计真是高啊。不过也有缺点,就是类型检查不严,容易因程序员的疏忽而出错。另一个就是很多程序员刚开始不适应这种API调用方式。随便看了一下MSDN上的函数原型就开始按照自己的想法调用。我一开始就是给微软的API设计,类库的设计,都是非常成熟、优秀的。我们不仅要学会使用API,使用类库,以后还应该学会设计API,设计类库。
windows SDK中的wininet写http客户端的更多相关文章
- 将WCF寄宿在托管的Windows服务中
在我之前的一篇博客中我介绍了如何发布WCF服务并将该服务寄宿于IIS上,今天我再来介绍一种方式,就是将WCF服务寄宿在Windows服务中,这样做有什么好处呢?当然可以省去部署IIS等一系列的问题,能 ...
- 从DirectX SDK升级到Windows SDK
原来的DirectX SDK到June 2010,微软就不更新了.之后新的版本被集成到了Windows SDK中. 在微软的博客里找到一篇升级指南:http://blogs.msdn.com/b/ch ...
- DX11 Without DirectX SDK--使用Windows SDK来进行开发
在看龙书(Introduction to 3D Game Programming with Directx 11)的时候,里面所使用的开发工具包为Microsoft DirectX SDK(June ...
- 关于DirectShow SDK 和Windows SDK,及DirectX SDK
关于DirectShow SDK 和Windows SDK,及DirectX SDK 本文描述了DirectShow SDK ,Windows SDK,DirectX SDK ,VS200?之间的 ...
- Windows编程中回调函数的使用心得(MFC篇)
回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用,而是在特定 ...
- Windows操作系统中的I/O(读/写 输入/输出)
导言 写一个Windows平台下的应用程序大多时候都是离不开读写文件,网络通信的. 比如一个服务应用程序来说,它可能从网络适配器接受用户的请求,对请求进行处理计算,最终将用户端所需的数据返回,中间可能 ...
- 用 C# 在 Windows 7 中写注册表想到的
摘自:http://blog.163.com/dpj_001/blog/static/2742941520110251500753/ 某日做一个项目,需要在注册表中加入键,同时写值,操作系统环境为 W ...
- Windows编程中的若干难点 - Windows程序设计(SDK)007
Windows编程中的若干难点 让编程改变世界 Change the world by program 一个窗口的生与死 我记得有童鞋会问:如果我的程序需要在关闭前让用户判断是否确定要关闭窗口,我应该 ...
- [Java.File]如果写 File filesFolder = new File("/") ,在windows系统中,filesFolder 会去找哪个盘符? 答案:程序运行路径的根盘符.
首先这段代码在Unix/Linux系统上会去找根路径,但在Windows系统上会去找C:盘还是D:盘还是其它盘呢? 其实它会去找user.dir所在盘符的根目录,user.dir即用户的当前工作目录, ...
随机推荐
- [Java] key
Z2VueW1vJTIwJTI2JTI2JTI2JTIwMTYzJTNBJTBBdXNyJTIwLSUyMHd1a29uZ3N1bjEyMzQlMjAlMjMlMjAxNjMuc3VmZml4JTIw ...
- HHHOJ #153. 「NOI模拟 #2」Kotomi
抽代的成分远远大于OI的成分 首先把一个点定为原点,然后我们发现如果我们不旋转此时答案就是所有位置的\(\gcd\) 如果要选择怎么办,我们考虑把我们选定的网格边连同方向和大小看做单位向量\(\vec ...
- Linux下的零拷贝
Reference: https://segmentfault.com/a/1190000011989008 零拷贝是什么? 维基百科对“零拷贝”是这样描述的: "Zero-copy&qu ...
- [SDOI2011]染色(信息学奥赛一本通 1563)(洛谷 2486)
Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“ ...
- Windows 文件过滤驱动经验总结
Windows 文件过滤驱动经验总结作者:sinister 本文转载自驱动开发网 看了 ChuKuangRen 的第二版<文件过滤驱动开发教程>后,颇有感触.我想,交流都是建立在平等的基础 ...
- 【Docker】容器与系统时间同步
宿主机时间 [root@slave-1 ~]# date Fri May 12 11:20:30 CST 2017 容器时间 [root@slave-1 ~]# docker exec -ti 879 ...
- Kafka的安装与使用(转)
9.1 Kafka 基础知识 9.1.1 消息系统 点对点消息系统:生产者发送一条消息到queue,一个queue可以有很多消费者,但是一个消息只能被一个消费者接受,当没有消费者可用时,这个消息会被保 ...
- 查看ssh有没有被黑的IP
#grep "Failed password " /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -nr ...
- Python 技术篇-pip版本查看和升级
一.pip show pip查看pip版本,下面还提示安装命令和pip可以升级到的最新版本. 二.python -m pip install --upgrade pip升级我们的pip
- Superset配置mysql数据源
1.添加mysql数据源 测试连接的时候遇到 No module named 'MySQLdb'" 安装mysqlclient pip install mysqlclient 如果遇到 ER ...