65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 PAD / XML 文件实现有效的在线更新检查机制

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.35/5 (8投票s)

2006 年 12 月 21 日

6分钟阅读

viewsIcon

27675

downloadIcon

357

如何使用 XML / PAD 文件检查新程序版本。

Example

引言

本文介绍了如何使用 MFC 和 TinyXML 中的 PAD 文件实现有效的在线更新检查机制。您至少需要具备 XML 的基本知识和 MFC 库的基本理解。

什么是 PAD 文件?

PAD 是“Portable Application Description”(便携式应用程序描述)的缩写,它是一种由 Association of Shareware Professionals 设计的可机器读取的文档格式。它允许作者以标准的方式,使用标准的数据格式向在线资源提供产品描述和规格,从而使网站管理员和程序库管理员能够自动化程序列表。PAD 为作者和网站管理员节省了时间。要了解更多关于 PAD 文件的信息,请访问此网站。以上文本摘自 Association of Shareware Professionals,并略作修改。

为什么只使用 PAD 文件?

网上大多数大型下载网站都提供两种提交应用程序的方式:一种是您将所有必需的数据(版本、应用程序名称、描述等)输入到一个特殊的表单中,另一种是您可以提供一个指向您自己提供的网络空间上的 PAD 文件的链接。如果您想将您的应用程序提交到很多网站,第一种方式将非常耗时。

或者,想象一下您想通知所有网站您的程序有更新。情况一样:访问所有网站,登录您的账户,更改版本,添加新功能文本……

由于软件开发者通常非常懒惰(嘿,我只说我自己!*笑*),最好提供一个地方来更改以上所有信息,并让网络上的所有网站自动获取这些信息。

嗯,您可能已经猜到了,这个地方就是您的 PAD 文件。您只需要创建一次,将其上传到您的网络空间,让所有网站知道该 URL 上有您的文件,这样就完成了。差不多吧。如果您为您的应用程序提供了更新,只需更改该文件——大多数下载网站都有一个所谓的“机器人”,会定期检查所有 PAD 文件,并自动更新网站内容,无需人工干预。

现在再进一步思考:如果我们已经为所有网站准备了一个 PAD 文件,为什么不能将其用于我们自己的目的呢?当今大多数程序都有一个在程序启动时检查新版本的特性。最简单的方法当然是一个带有版本字符串的简单文本文件。但是等等!这个版本字符串已经在 PAD 文件中存在了。

所以,有了这个 PAD 文件,您只需付出一次努力就可以做三件事:

  • 将新程序提交到当今最知名的下载网站
  • 让所有下载网站更新和维护您在他们网站上的产品
  • 让您的程序检查更新/新版本

实现

我们的实现包含三个步骤:
  • 步骤 1:获取本地.exe文件的版本信息。
  • 步骤 2:从互联网下载当前的 PAD 文件到您的本地计算机。
  • 步骤 3:解析 PAD 文件以获取版本信息。
  • 步骤 4:比较两个版本,并通知用户潜在的更新。

步骤 1:获取本地.exe文件的版本信息

要获取.exe文件的当前版本——CodeProject 上已经有许多提供此功能的例程和/或类!在本教程中,我将使用一个名为 CFileVersionInfo 的类(CFileVersionInfo - 获取文件版本信息),由 Armen Hakobyan 编写。这段精妙的代码正好完成了我们想要的任务:从本地文件中提取各种版本信息。

这是代码

CFileVersionInfo fVer;

if( FALSE == fVer.Open( "your_exe_file.exe" ) )
    return;

DWORD dwExeMajor = fVer.GetFileVersionMajor();
DWORD dwExeMinor = fVer.GetFileVersionMinor();
    DWORD dwExeBuild = fVer.GetFileVersionBuild();

注意:主版本号、次版本号、生成号和 QFE 值是整个版本号的一部分。版本 1.2.40 表示主版本="1",次版本="2",生成号="40"。如果您始终想获取调用 CFileVersionInfo 对象的执行文件的版本,则可以使用 GetModuleFileName() 函数检索文件名。

步骤 2:从互联网下载当前的 PAD 文件到您的本地计算机

要从互联网下载文件,有许多可能的方法。我决定使用一些老式标准类来完成这项工作:CInternetSessionCHttpFile。我的函数以 URL 作为参数,将该文件以文本模式下载到一个 CString 对象中,并返回该对象以供进一步处理。有关实现细节,请参见提供的源代码。

步骤 3:解析 PAD 文件以获取版本信息

现在,让我们看一个 PAD 文件片段。在此处展示一个完整的 PAD 文件会带来过多的开销,因为有大量信息是我们在线更新检查例程不需要的。

<?xml version="1.0" encoding="UTF-8"?>
<XML_DIZ_INFO>
.
.
        <Program_Info>
                .
                .
        <Program_Name>UpdateCheck_Example</Program_Name>
        <Program_Version>0.1.0</Program_Version>
        .
        .
    </Program_Info>
.
.
</XML_DIZ_INFO>

如您所见,容器“Program_Info”有一个名为“Program_Version”的元素。它的值表示您程序的当前发布版本。现在,您所要做的就是读取此字符串,并在稍后将其与当前安装的.exe文件的版本进行比较。

好吧,我们需要一个简单的解决方案来解析 XML 文件。当然,搜索短语 <Program_Version></Program_Version> 并截取中间部分(包含版本字符串)将是一项容易的任务。我不是这种技巧的粉丝,所以我决定在本教程中使用 TinyXML 库。这个库非常快速且易于使用;而且它是开源的!您可以在这里获取 TinyXML。

我就是这样做的:

// Get root node
TiXmlNode* pDIZ = xmlDoc.FirstChild( "XML_DIZ_INFO" );

if( NULL == pDIZ )
    return;

// Get the program info node (parent node is root node above)
TiXmlNode* pPInfo = pDIZ->FirstChild( "Program_Info" );

if( NULL == pPInfo )
    return;

// Get the version node (parent node is program info above)
TiXmlNode* pPVer = pPInfo->FirstChild( "Program_Version" );

if( NULL == pPInfo )
    return;

// Cast our version node to an element
TiXmlElement* pPVerEl = pPVer->ToElement();
ASSERT( NULL != pPVerEl );

// Extract the text of this node into a CString object
CString strVer = pPVerEl->GetText();

DWORD dwFileMajor = 0;
DWORD dwFileMinor = 0;
DWORD dwFileBuild = 0;

// Extract the version information parts into separate variables
char szBuf[ 32 ];
sprintf( szBuf, "%s", strVer.GetBuffer( 1 ) );
sscanf( szBuf, "%d.%d.%d", &dwFileMajor, &dwFileMinor, &dwFileBuild );

步骤 4:比较两个版本,并通知用户潜在的更新

好的,我们得到了两个版本——PAD 文件的版本和我们.exe文件的版本。由于版本由三部分组成(主版本、次版本、生成号),我们如何将这些值互相比较呢?解决方案:直接将它们相加!

这里有一些代码应该能说明问题:

DWORD dwExeSum = ( dwExeMajor * 100 ) + ( dwExeMinor * 10 ) + dwExeBuild;
DWORD dwFileSum = ( dwFileMajor * 100 ) + ( dwFileMinor * 10 ) + dwFileBuild;

if( dwFileSum > dwExeSum )
{
    m_strVer.Format( "%d.%d.%d", dwFileMajor, dwFileMinor, dwFileBuild );
    bUpdate = true;
}

if( bUpdate )
{
    MessageBox()
}

请注意乘数:它们确保较低的主版本号与仅较高的次版本号相比仍然具有更高的计数,例如,4.6.1 大于 3.7.2。

改进/想法

这些例程相当直接;我认为改进的空间不大,因为没有真正的提速需求。但有一点您应该记住:从互联网下载文件和与 Web 服务器通信需要时间。也许服务器因某种原因暂时无法访问?也许防火墙暂时阻止了当前函数调用?为了防止应用程序(尤其是 GUI 本身)挂起,您应该考虑将所有版本检查例程放在单独的线程中,并在工作完成后通过简单的窗口消息通知主应用程序窗口。

关于演示

默认情况下,提供的演示从可执行文件目录加载其 PAD 文件。如果您已经在网上有了另一个 PAD 文件,只需更改默认 URL 和版本文本字段以满足您的需求。

© . All rights reserved.