WinINet 不是给服务端用的,服务端用Microsoft Windows HTTP Services (WinHTTP)WinINet 抽象了Gopher,FTP,HTTP协议的一些细节。
WinINet函数创建、使用的句柄都是HINTERNET类型的,这种类型的句柄无法被转换成其它类型的句柄。换句话说,最好别用ReadFile、CloseHandle之类的函数来操作这些句柄。同样的,也别用WinINet函数来访问、操作其他类型的句柄。比如,用InternetReadFile访问CreateFile创建句柄是无法得到你想要的结果的。想关闭HINTERNET句柄要使用InternetCloseHandle函数。
3.句柄架构
InternetOpen 创建的句柄在顶层,由接下来的一层的 InternetOpenUrl 和 InternetConnect 使用,而 InternetConnect 创建的句柄又被之后的几个函数使用。
下面这张图是依赖 InternetOpenUrl 创建的句柄的几个函数,灰色的方框是返回 HINTERNET 句柄的函数,而白色的框就是使用被创建的HINTERNET 句柄的函数
FTP Hierarchy
HTTP Hierarchy
注意这张图,这张图的意思是 HttpSendRequestEx 先访问 HttpOpenRequest 创建的句柄之后, HttpEndRequest,InternetReadFileEx 和 InternetWriteFile 才能访问这个句柄。 HttpEndRequest 被调用之后,才轮的到InternetReadFile,InternetSetFilePointer 和 InternetQueryDataAvailable 来访问这个句柄。
4.内容编码
HTTP 协议 (RFC 2616) 规定了应用程序可以要求服务器用编码的方式(encoded format)返回HTTP响应。在Windows Server 2008 与 Windows Vista之前,发送给应用程序的内容编码了的请求需要应用程序自己处理,从Windows Server 2008 and Windows Vista开始, 应用程序可以让 WinINet 来解码了(gzip与deflate)。有三种方式开启解码选项(基于会话、请求、连接),它们的作用域不同。可以使用InternetOpen(基于会话), InternetConnect(基于连接), HttpOpenRequest(基于请求)返回的句柄调用InternetSetOption 来打开或关闭解码选项,打开则将 dwOption 参数中INTERNET_OPTION_HTTP_DECODING 选项打开, 令 lpBuffer 指向一个为true的boolean变量. 关闭则dwOption 参数中INTERNET_OPTION_HTTP_DECODING 选项打开, 令 lpBuffer 指向一个为false的boolean变量 .
设置解码选项之后, WinInet 在你调用 InternetReadFile 是就会执行一次解码。不过就算你打开了解码选项,它也不一定就为你解码……当这种情况发生时, InternetReadFile 函数会失败并返回ERROR_INTERNET_DECODING_FAILED.这个时候你可以选择去掉Accept-Encoding头重新发送一次请求,或者把解码关掉然后自己来解码(这时你就得检查Content-Encoding头来判断编码方式了)。
5.协议无关函数
- 从Internet下载文件 (InternetReadFile, InternetSetFilePointer, InternetFindNextFile, InternetQueryDataAvailable).
- 设置同步操作 (InternetSetStatusCallback).
- 查询、修改设置 (InternetSetOption , InternetQueryOption).
- 关闭 HINTERNET 句柄 (InternetCloseHandle).
- 锁定、解锁资源文件 (InternetLockRequestFile , InternetUnlockRequestFile).
Function | Description |
InternetFindNextFile | 继续文件的枚举或搜索. 需要以下函数创建的句柄 FtpFindFirstFile, GopherFindFirstFile, InternetOpenUrl |
InternetLockRequestFile | 允许用户锁定文件. 需要以下函数创建的句柄 FtpOpenFile, GopherOpenFile, HttpOpenRequest, InternetOpenUrl . |
InternetQueryDataAvailable | 查询可用数据的数量. 需要以下函数创建的句柄 FtpOpenFile, GopherOpenFile, HttpOpenRequest . |
InternetQueryOption | 查询 Internet 设置. |
InternetReadFile | 读取 URL 数据. 需要以下函数创建的句柄 InternetOpenUrl, FtpOpenFile, GopherOpenFile, HttpOpenRequest . |
InternetSetFilePointer | 设置文件指针. 需要以下函数创建的句柄 InternetOpenUrl ( HTTP URL only) HttpOpenRequest (GET 方法). |
InternetSetOption | 配置 Internet 设置. |
InternetSetStatusCallback | 设置一个接收状态信息的回调函数. 分配一个回调函数给指定的 HINTERNET 句柄及从其演化而来的句柄. |
InternetUnlockRequestFile | 解锁被 InternetLockRequestFile 锁定的文件. |
读文件
函数 InternetReadFile 用来从一个由函数 InternetOpenUrl, FtpOpenFile, GopherOpenFile, HttpOpenRequest 返回的HINTERNET 句柄下载资源.
WinINet 提供了两种方法来下载整个资源
- InternetQueryDataAvailable 函数.
- 利用 InternetReadFile 的返回值
InternetQueryDataAvailable 使用 InternetOpenUrl, FtpOpenFile, GopherOpenFile, HttpOpenRequest (还记得上面的那个图么,这个函数需要在 HttpSendRequest 操作该句柄之后才能访问这个句柄) 创建的句柄。返回有效数据的字节数,据此,我们就可以分配足够的内存并进行读取,但是这种方法不保险,包头里的长度可能是过时的,而且包头也可能会丢。
当所有数据都被读完的时候, InternetReadFile 会返回0字节被读取(lpdwNumberOfBytesRead 参数保存了读取的字节数). 据此,我们就可以循环调用 InternetReadFile 直到读取结束。
寻找文件
先使用 FtpFindFirstFile, GopherFindFirstFile, 或 InternetOpenUrl ,然后将其返回的句柄作为参数 传递给InternetFindNextFile 进行继续查找,持续调用 InternetFindNextFile 知道返回扩展的错误信息 ERROR_NO_MORE_FILES 来完成整个搜索,调用 GetLastError 来获取最后的错误信息.