随着网络的极大发展和普及,很多软件都增加了自动更新的功能,首当其冲的就是Windows了,对于网络游戏的客户端更是必不可少。最近要为一个软件实现自动更新的功能,正好有机会去思考一下这个功能实现起来需要做什么。
光从字面上看,自动更新至少包含两个方面:一个是更新,一个就是自动了。那么更新的话,我们可以认为是客户端通过HTTP、FTP或者其他连接从服务器上获得需要的资源。在Windows中,有一组API就是应用在这个方面的,这就是WinINet。WinINet有以下几个特殊之处:
1、HINTERENT:这是在WinINet中使用的Handle,它跟其他的Win32 Handle很类似,其实说到底就是指针了,但是它却不能够跟其他类型的Win32 Handle相互交换使用。而各个函数返回的HINTERNET处于一个树型结构中,其中InternetOpen函数返回的HINTERNET则是这棵树的根结点,也就是调用绝大多数WinINet的API之前,都需要调用InternetOpen函数去进行一些初始化的工作,并且返回一个HINTERNET;
2、缓存机制:从网络上取得的数据,通常都需要缓存到内存或者硬盘当中,以备后续的程序使用。很多WinINet函数都有支持缓存,我们在使用这些API的时候,都需要去设定缓存标志位来说明采取哪种缓存机制;
3、错误处理机制:WinINet的错误处理与其他的Win32函数不尽相同,我们可以通过一个WinINet函数的返回值是否为有效的HINTERNET,就可以得知函数调用是否发生错误了。而GetLastError()可以得到更多的错误信息。
说完了WinINet,回归主题。我们从服务器上获得需要的资源,大致可以遵循这样一个流程:通过InternetOpen函数得到一个HINTERNET handle:handleA;接着基于handleA再利用InterOpenUrl、FtpOpenFile、GopherOpenFile或者HttpOpenRequest函数得到另一个HINTERNET handle:handleB;最后基于handleB利用InternetReadFile函数将所需的文件读到本地的缓冲区,再利用标准的输入流函数将缓冲区的内容写入本地的目标文件。以下是示例代码:
void Update(const char *Url, const char *
OutFile)
{
HINTERNET handleA = InternetOpen("Update", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (handleA != NULL)
{
HINTERNET handleB = InternetOpenUrl(handleA, Url, NULL, 0, INTERNET_FLAG_DONT_CACHE, 0);
if (handleB != NULL)
{
byte Temp[MAXBLOCKSIZE];
ULONG Number = 1;
FILE *stream;
if( (stream = fopen( OutFile, "wb" )) != NULL )
{
while (Number > 0)
{
InternetReadFile(handleB, Temp, MAXBLOCKSIZE - 1, &Number);
fwrite(Temp, sizeof (char), Number , stream);
}
fclose( stream );
}
InternetCloseHandle(handleB);
handleB = NULL;
}
InternetCloseHandle(handleA);
handleA = NULL;
}
}