好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

利用Win32的网络函数创建一个网络浏览器

利用Win32的网络函数创建一个网络浏览器

利用 Win32 的网络函数创建一个网络浏览器



Dale Rogerson

Microsoft 网络开发技术小组

 

 

摘要

这篇技术性文章讨论了如何利用 Microsoft Win32 网络函数创建一个网络浏览器。这篇文章的宗旨是让读者了解一些 Win32 网络函数的作用、能力和使用范围,而不是为这些功能给出一个详细的文档。这篇文章所配合的 SurfBear 样本应用程序使用 Win32 网络函数从网络服务器上读取 HTML 文件,并把它们显示成原始的、没有经过格式化的文本。

 

介绍

不通过网络,你就无法了解我的一个朋友。计算机杂志已经在 internet 上设置了电子期刊,而本地的报纸也已经把整个段落都放到了网络上。事实上,许多报纸都在联机。每个人都有一个主页,甚至一些无家可归的人都有一个主页。虽然有许多关于网络的消息难免言过其实,但网络正在变成计算机整体的一部分已经是无庸置疑的了。

Microsoft 已经介绍了 Microsoft Win32 网络函数来协助开发者把网络变成他们的应用程序的整体部分。这些新的功能简化了使用 FTP (文件传输协议)、和 HTTP (超文本传输协议)访问网络。使用 Win32 网络函数的开发者不需要对 TCP/IP 或 Windows 配件。对于一些最普通的操作,开发者不需要知道他们正在使用的某个协议的细节。

最终, Win32 网络函数将成为 Win32 应用程序接口的一部分并且与基于 Windows 的不同的平台一起发布。最初, Win32 网络函数将安装在一个叫做 WININET.DLL 的再分布式动态链接库里。(来自 Microsoft 网络软件开发工具包,其网址是 :http://www.microsoft.com/inter/sdle/ )。这属于网络开发工具包的一部分。

这篇文章说明了如何使用 Win32 网络函数去创建一个简单的网络浏览器。它没有具体详细的讨论这些功能的细节,但对他们的用法和操作给出了一个演示。请参考网址是 http://www.microsoft.com/intdev/sdk/docs/wininet 的 Microsoft Win32 网络函数的主题,可以了解到全部的细节。

这篇文章是配合 SurfBear 样本应用程序而创作的。 SurfBear 是一个 HTML 文件。覆盖了这个过程种特定的网络部分,但它没有涉及与这个过程有关的用户接口问题或 HTML 文件的显示或操作问题。

注意:这篇文章是基于 WININET.DLL 一个相当早的版本。很可能其中的参数名、标识名和函数名发生了改变。但是函数的范围和意图应该还是和这篇文章中描述的是一致的。

 

网络函数

最好的探讨 Win32 网络函数的方法是直接进入代码。下面的代码是样本的代码,为了方便阅读,错误处理部分已经被删除掉了。

 HINTERNET hNet = ::InternetOpen("MSDN SurfBear",
PRE_CONFIG_INTERNET_ACCESS,
NULL,
INTERNET_INVALID_PORT_NUMBER,
0) ;

HINTERNET hUrlFile = ::InternetOpenUrl(hNet,
"http://www.microsoft.com",
NULL,
0,
INTERNET_FLAG_RELOAD,
0) ;

char buffer[10*1024] ;
DWORD dwBytesRead = 0;
BOOL bRead = ::InternetReadFile(hUrlFile,
buffer,
sizeof(buffer),
&dwBytesRead);

::InternetCloseHandle(hUrlFile) ;

::InternetCloseHandle(hNet) ;

上面列举的代码包括四个网络函数: InternetOpen 、 InternetOpenOrl 、 InternetReadFile 和 InternetCloseHandle 。下面我们依次对这些函数进行分析。

InternetOpen

InternetOpen 初始化 WININET.DLL 。它在其他的 Win32 网络函数之前被调用。

 HINTERNET hNet = ::InternetOpen(
"MSDN SurfBear", // 1 LPCTSTR lpszCallerName
PRE_CONFIG_INTERNET_ACCESS, // 2 DWORD dwAccessType
"", // 3 LPCTSTR lpszProxyName
INTERNET_INVALID_PORT_NUMBER, // 4 INTERNET_PORT nProxyPort
0 // 5 DWORD dwFlags
) ;

InternetOpen 返回一个类型为 HINTERNET 的句柄。其他的 Win32 网络函数把这个句柄当作一个参数。现在你不能把一个 HINTERNET 句柄用在类似于 ReadFile 之类的其他 Win32 函数中。但是随着 Microsoft Windows 和 Microsoft Windows NT 网络支持的成熟,这一点在将来不是不可能实现的。

当你已经结束使用 Wein32 网络函数时,你应该调用 InternetCloseHandle 释放 InternetOpen 分配的资源。使用 Microsoft 基础类( MFC )的应用程序将从文件的构造程序里象征性地调用 InternetOpen 。绝大多数应用程序都将在每一进程里调用 InternetOpen 。

InternetOpen 的第一个参数 lpszCallerName 指定正在使用网络函数的应用程序。当 HTTP 协议使用时,这个名字将变成用户代理。

第二个参数 dwAccessType 指定访问类型。在上面的例子里, PRE_CONFIG_INTERNET_ACCESS 访问类型指示 Win32 网络函数使用登记信息去发现一个服务器。使用 PRE_CONFIG_INTERNET_ACCESS 需要正确设定登记信息。这里我耍了一个小花招并让网络开发者替我登记注册。如果你不想欺骗,你需要按图 1 所示设定登记信息。

 

 

 

 

在登记注册中,把 AccessType 设置为 1 ,则意味着“直接入网”,把 AccessType 设置为 2 ,意味着“使用网关”。把 DisableServiceLocation 设置为 1 ,将让它使用一个已经命名的服务器;否则将找到一个使用注册信息和名字决议( RNR )应用程序接口的服务器,它是 Windows 接口的一部分。

其他的访问类型包括以下几种:

LOCAL_INTERNET_ACCESS 只连接到当地 Internet 网站。例如,如果我使用 SurfBear 标志,我就只能访问 Microsoft 整体的 Internet 网站。 CERN_PROXY_INTERNET_ACCESS 使用一个 CERN 代理去访问 web 。 CERN 代理是一个充当网关的 web 服务器并且能向要使用代理的服务器发送 HTTP 请求。 GATEWAY_INTERNET_ACCESS 允许连接到 World Wide Web 。我可以用这个访问类型去访问 web 上的任何站点。

GATEWAY_PROXY_INTERNET_ACCESS 和 CERN_PROXY_ACCESS 访问类型要求第三个参数给 InternetOpen :服务器名( lpszProxyName )。 PRE_CONFIG_INTERNET_ACCESS 不要求服务器名,因为他可以为服务器搜索寄存信息。

NProxyPort 参数用在 CERN_PROXY_INTERNET_ACCESS 中用来指定使用的端口数。使用 INTERNET_INVALID_PORT_NUMBER 相当于提供却省的端口数。

最后一个参数棗 dwFlags ,设置额外的选择。你可以使用 INTERNET_FLAG_ASYNC 标志去指示使用返回句句柄的将来的 Internet 函数将为回调函数发送状态信息,使用 InternetSetStatusCallback 进行此项设置。

 

InternetOpenUrl

一旦你把 Win32 网络函数初始化了,你就可以使用其他网络函数。下一个要调用的 Internet 函数是 InternetOpenUrl 。这个函数连接到一个网络服务器上并且最被从服务器上读取数据。 InternetOpenUrl 能对 FTP , Gopher 或 HTTP 协议起作用。在这篇文章中,我们只涉及 HTTP 协议。

 HINTERNET hUrlFile = ::InternetOpenUrl(
hNet, // 1 HINTERNET hInternetSession
"http://www.microsoft.com", // 2 LPCTSTR lpszUrl
NULL, // 3 LPCTSTR lpszHeaders
0, // 4 DWORD dwHeadersLength
INTERNET_FLAG_RELOAD, // 5 DWORD dwFlags
0 // 6 DWORD dwContext
) ;

InternetOpenUrl 也返回一个 HINTERNET ,它被传递给在这个 URL (统一资源定位)上操作的函数。你应该使用 InternetClose 来关闭这个句柄的处理。

InternetOpenUrl 的第一个参数 hInternetSession 是从 InternetOpen 返回的句柄。第二个参数 lpszUrl 是我们需要的资源的 URL (统一资源定位)。在上面的例子中,我们想得到一个 Microsoft 的 web 主页。下面两个参数 lpszHeaders 和 HeaderLength 用来向服务器传送额外的信息。使用这些参数要求具有正在使用的特定协议的知识。

DwFlag 是一个可以用几种方式修改 InternetOpenUrl 行为的标志, InternetOpenUrl 的行为包括关闭、隐藏,使原始数据可用和用存在的连接取代开辟一个新的连接。

最后一个参数 dwContext 是一个 DWORD 上下文值。如果有一个值已经被指定,它将被送到状态回调函数。如果这个值是 0 ,信息将不会被送到状态回调函数。

 

InternetReadFile

你打开一个文件后,就要读它,所以下一个函数是 InternetReadFile 是符合逻辑的:

 char buffer[10*1024] ;
DWORD dwBytesRead = 0;
BOOL bRead = ::InternetReadFile(
hUrlFile, // 1 HINTERNET hFile
buffer, // 2 LPVOID lpBuffer
sizeof(buffer), // 3 DWORD dwNumberOfBytesToRead
&dwBytesRead // 4 LPDWORD lpdwNumberOfBytesRead
);

buffer[dwBytesRead] = 0 ;
pEditCtrl->SetWindowText(buffer) ;

InternetReadFile 接收 InternetOpenUrl 返回的句柄。它也对其他 Win32 网络函数,例如 FtpOpenFile,FopherOpenFile 和 HttpOpenRequest 返回的句柄有影响。

剩下的 InternetReadFile 的三个参数也非常的明白直接。 Inbuffer 是指向保留数据的缓冲区的一个无返回值指针, dwNumberOfByteToRead 以字节为单位指定缓冲区的尺寸。最后一个参数, lpdwNumberOfBytesRead 是一个指向包含读入缓冲区字节数的变量的指针。如果返回值是 TRUE ,而且 lpdwNumberOfBytesRead 指向 0 ,则文件已经读到了文件的末尾。这个行为与 Win32 Re3adFile 的函数的行为是一致的。一个真正的 web 浏览器将在 InternetReadFile 上循环 ,不停地从 Internet 上读入数据块。

为了显示缓冲区,向缓冲区添加一个 0 并把它送到编辑器控制。

这样, InternetOpen 、 InternetOpenUrl 和 InternetReadFile 一起创建了 Internet 浏览器的基础。他们使从 Internet 上读取文件就象从你的本地硬盘驱动器上读取文件一样容易。

 

HTTP 函数

在一些例子中, InternetOpenUrl 太普通了,所以你可能需要其他的 Win32 网络函数。 InternetOpenUrl 相当与不同的 FTP , GOPHER 和 HTTP 函数的封皮。当使用 HTTP 时, InternetOpenUrl 调用 InternetConnect , HttpOpenRequest 以及 HttpSendRequest ,比如说我们想要在下载一个 HTML 页之前得到它的尺寸以便于我们在缓冲区中为其分配适当的尺寸, HttpQueryInfo 将得到 web 页的大小。

警告:不是所有 web 页都支持得到页尺寸。(例如: www.toystory.com 和 www.movielink.com 不支持这个功能)另外, TCP/IP 能传递的数据也比要求的要少。所以,你的应用程序应该处理着两种情况并且围绕 InternetReadFile 循环直到结果为 TRUE 同时 *lpdwNumberOfBytesRead 为 0 。

使用 HttpOpenRequest , HttpSendRequest 和 HttpQueryInfo 去打开文件 http://www.microsoft.com/msdn/msdninfo 的代码显示如下,错误检测已经被删除。

 // Open Internet session.
HINTERNET hSession = ::InternetOpen("MSDN SurfBear",
PRE_CONFIG_INTERNET_ACCESS,
NULL,

INTERNET_INVALID_PORT_NUMBER,
0) ;

// Connect to www.microsoft.com.
HINTERNET hConnect = ::InternetConnect(hSession,
"www.microsoft.com",
INTERNET_INVALID_PORT_NUMBER,
"",
"",
INTERNET_SERVICE_HTTP,
0,
0) ;

// Request the file /MSDN/MSDNINFO/ from the server.
HINTERNET hHttpFile = ::HttpOpenRequest(hConnect,
"GET",
"/MSDN/MSDNINFO/",
HTTP_VERSION,
NULL,
0,
INTERNET_FLAG_DONT_CACHE,
0) ;

// Send the request.
BOOL bSendRequest = ::HttpSendRequest(hHttpFile, NULL, 0, 0, 0);

// Get the length of the file.




char bufQuery[32] ;
DWORD dwLengthBufQuery = sizeof(bufQuery);
BOOL bQuery = ::HttpQueryInfo(hHttpFile,
HTTP_QUERY_CONTENT_LENGTH,

bufQuery,

&dwLengthBufQuery) ;

// Convert length from ASCII string to a DWORD.
DWORD dwFileSize = (DWORD)atol(bufQuery) ;

// Allocate a buffer for the file.



char* buffer = new char[dwFileSize+1] ;

// Read the file into the buffer.

DWORD dwBytesRead ;
BOOL bRead = ::InternetReadFile(hHttpFile,
buffer,
dwFileSize+1,

&dwBytesRead);
// Put a zero on the end of the buffer.
buffer[dwBytesRead] = 0 ;

// Close all of the Internet handles.
::InternetCloseHandle(hHttpFile);

::InternetCloseHandle(hConnect) ;
::InternetCloseHandle(hSession) ;

// Display the file in an edit control.
pEditCtrl->SetWindowText(buffer) ;

InternetConnect
InternetConnet函数连接到一个HTTP,FTP或Gopher服务器:
HINTERNET hConnect = ::InternetConnect(
hSession, //1 HINTERNET hInternetSession
"www.microsoft.com", //2 LPCTSTR lpszServerName
INTERNET_INVALID_PORT_NUMBER, //3 INTERNET_PORT nServerPort
"", //4 LPCTSTR lpszUsername
"", //5 LPCTSTR lpszPassword
INTERNET_SERVICE_HTTP, //6 DWORD dwService
0, //7 DWORD dwFlags
O //8 DWORD dwContext
) ;
第六个参数dwService决定服务类型(HTTP,FTP或Gopher)。在上面的例子中,InternetConnect连接到一个HTTP服务器上,因为dwService被设置成INTERNET_SERVICE_HTTP。第二个参数(设置成www.microsoft.com)提供了服务器的地址。注意,HTTP地址必须为服务器名作语法分析,InternetOpenUrl为我们作语法分析。第一个参数hInternetSession是从InternetOpen返回的句柄。第四个、第五个参数提供一个用户姓名和密码 。这七个参数没有控制任何标志影响HTTP操作。最后一个参数为状态回调函数提供前后关系的信息。

HttpOpenRequest
一旦和服务器的连接已经建立,我们打开了想要的文件。HttpOpenRequest和HttpSenRequest一起工作打开文件。HttpOpenRequest去创建一个请求句柄并且把参数存储在句柄中。HttpOpenRequest把请求参数送到HTTP服务器。
HINTERNET hHttpFile = ::HttpOpenRequest(
hConnect, // 1 HINTERNET hHttpSession
"GET", // 2 LPCTSTR lpszVerb
"/MSDN/MSDNINFO/", // 3 LPCTSTR lpszObjectName
HTTP_VERSION, // 4 LPCTSTR lpszVersion
NULL, // 5 LPCTSTR lpszReferer
0, // 6 LPCTSTR FAR * lplpszAcceptTypes
INTERNET_FLAG_DONT_CACHE, // 7 DWORD dwFlags
0 // 8 DWORD dwContext
) ;
到现在为止,网络函数的许多参数看起来都类似。HttpOpenResult的第一个参数是由InternetConnet返回的 HINTERNET。HttpOpenRequest的第七和第八个参数执行与InternetConnect中有相同名字的参数一样的功能。
第二个参数(“GET”)指定我们想要得到由第三个参数(“/MSDN/MSDNINFO/”)命名的对象。HTTP版已经传递第四个参数;现在,它肯定是HTTP棗VERSION。因为“GET”是最流行的动词类型,HttpOpenRequest将为这个参数接收一个空指针。
第五个参数lpszReferer是一个网点的地址。在这个网点上我们发现了我们现在想要看见的URL(统一资源定位)。换而言之,如果你在 www.home.com 上而且单击了跳到 www.microsoft.com 的一个连接,第五个参数就是 www.home.com 。因为它使你指向了目标URL(统一资源定位)。这个值可以为空。第六个参数执行一个我们的程序接收的文件类型列表。把空值传递给HttpOpenRequest即通知了服务器只有文本文件可以被接收。

 

HttpSendRequest

除了传送请求外, HttpSendRequest 允许你传送额外的 HTTP 标题给服务器。关于 HTTP 标题的信息可以在 http://www.w3.org/ 上的最新的说明上找到。在这个例子中, HttpSendRequest 的所有参数都被传递为缺省值。

 BOOL bSendRequest = ::HttpSendRequest(
hHttpFile, // 1 HINTERNET hHttpRequest
NULL, // 2 LPCTSTR lpszHeaders
0, // 3 DWORD dwHeadersLength
0, // 4 LPVOID lpOptional
0 // 5 DWORD dwOptionalLength
);

HttpQueryInfo

为了得到关于文件的信息,在调用 HttpSendRequest 后使用 HttpQueryInfo 函数:

 BOOL bQuery = ::HttpQueryInfo(
hHttpFile, // 1 HINTERNET hHttpRequest
HTTP_QUERY_CONTENT_LENGTH, // 2 DWORD dwInfoLevel
bufQuery, // 3 LPVOID lpvBuffer
&dwLengthBufQuery // 4 LPDWORD lpdwBufferLength
) ;

查询的结构是字符串或 lpvBuffer 中的字符串列表。 HTTP_QUERY_CONTENT_LENGTH 查询得到文件的长度。你可以使用 HttpQueryInfo 查询大范围的信息。要获知详细情形可查阅网点 http://www.microsoft.com/intdev/sdk/docs/wininet 上的 Microsoft Win32 网络函数专题。

SurfBear 样本应用程序

SurBear 样本应用程序使用 Win32 网络函数从 Internet 上得到文件并且在编辑器上显示原始的 HTML 格式。 SurfBear 使用 HttpOpenRequest 和 HttpSendRequest 取代 InternetOpenUrl ,纯粹是为了演示的需要。

 

图 2 SurfBear 屏幕

SurfBear 是一个 MFC4.0 版本的对话应用程序。它所有与 Internet 有关的功能都在 InternetThread.h 和 InternetThread.cpp 文件中。

从 internet 上读取文件要花费相当数量的时间,所以从一个工作线程调用网络函数是一个明智的主意。通过这种方式,当系统在等待得到数据时,应用程序的窗口能被改变尺寸和移动。

图 3 显示了 SurfBear 的控制流。

 

 

当用户按下 GOTO 按钮时, CsurfBearDlg::OnBtnGoto 调用 CinternetThread:GetWebPoge, 传递想要的 web 页的 HTTP 地址。 GetWebPage 把 HTTP 地址语法分析成服务器和对象名,存储在 CinternetThread 的成员变量中。 GetWebPage 然后调用 AfxBeginThread ,它产生一个运行静态成员函数的线程 GetWebPage WorkerThread 。如果网络函数没有被初始化, GetWebPageWorkerThread 调用 InternetOpen ,然后它尝试读取想要的 web 页。当 GetWebPageWorkerThread 结束时,它发送一个用户定义的 WM_READFILECOMPLETED 消息给 SurfBear 对话框。 OnReadFileCompleted 处理这个消息并且把一个 web 页复制到编辑器控制里。

总结

Win32 网络函数使从 FTP , Gopher 和 HTTP 服务器上读取信息就想从你的硬盘驱动器上读取信息一样容易。仅仅使用 4 个函数棗 InternetOpen,InternetOpenUrl,InternetReadFile 和 InternetCloseHandle 和很少的 HTTP 知识,你就可以写一个简单的网络浏览器。

把这个简单的浏览器变成一个工业性质的浏览器将要花费很多工作,包括 一些对 HTTP 的了解,对如何显示 HTML 文件的了解和以及使用多线程方式的能力。 Win32 网络函数将开发者从与 TCP/IP , Windows Sockets 和 HTTP 编程有关的大多数烦闷工作中解脱出来。

 

查看更多关于利用Win32的网络函数创建一个网络浏览器的详细内容...

  阅读:39次

CopyRight:2016-2025好得很程序员自学网 备案ICP:湘ICP备09009000号-16 http://www.haodehen.cn
本站资讯不构成任何建议,仅限于个人分享,参考须谨慎!
本网站对有关资料所引致的错误、不确或遗漏,概不负任何法律责任。
本网站刊载的所有内容(包括但不仅限文字、图片、LOGO、音频、视频、软件、程序等)版权归原作者所有。任何单位或个人认为本网站中的内容可能涉嫌侵犯其知识产权或存在不实内容时,请及时通知本站,予以删除。

网站内容来源于网络分享,如有侵权发邮箱到:kenbest@126.com,收到邮件我们会即时下线处理。
网站框架支持:HDHCMS   51LA统计 百度统计
Copyright © 2018-2025 「好得很程序员自学网
[ SiteMap ]