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,设计类库。

最新文章

  1. SVN为什么比Git更好
  2. EF配置模型
  3. java高新技术-枚举
  4. CopyFile类通过调用这个类的delete(String filePath)方法可以组合成一个Cut类
  5. Query对象与DOM对象之间的转换方法
  6. Android 中this、 getApplicationContext()、getApplication()之间的区别
  7. 如何避免遭受HTTS中间人攻击
  8. Tomcat日志问题
  9. jquery中链式操作的this指向
  10. photoshop cs6 mac版
  11. Java 面试宝典-2017
  12. python爬虫的scrapy安装+pymongo的安装
  13. Python - 关于代码阅读的一些建议
  14. 树·二叉查找树ADT(二叉搜索树/排序树)
  15. javascript数据结构与算法---检索算法(顺序查找、最大最小值、自组织查询)
  16. 【LOJ】#2536. 「CQOI2018」解锁屏幕
  17. Java不定参数
  18. 用java解析在OpenStreetMap上下载的地图数据
  19. 跟微软保持适当距离--Hessian + .net 实现RPC体系的企业应用
  20. linux 修改主机名 【root@主机名 ~】

热门文章

  1. html css div固定底部
  2. 用数据让我们的OKR变得“冷酷”却更有价值
  3. Xamarin.Android开发中遇到的问题
  4. 彻底理解C++指针
  5. JVM参数笔记
  6. Eclipse4.9集成Tomcat 9.0.21详细版
  7. seqtk 一款快速处理fasta/fastq 文件的小程序
  8. Python3爬取美女妹子图片转载
  9. 高通平台sensor框架图【学习笔记】
  10. mysql-创建用户报错ERROR 1396 (HY000): Operation CREATE USER failed for 'root'@'localhost'