用VB6写在线更新程序(上篇)(2/3)

到这里又遇到问题了,命令行参数是拆分到数组里的,如果不指定命令参数时,则数组保持为“空数组”。而对“空数组”的任何操作(包括用UBound函数测长度)都会引发错误,这个问题困扰了我很久。怎么才能将这种情况区分出来呢?没办法,最终还是只能借助API函数:SafeArrayGetDim,其实这个函数的真正作用是:取得 OLE Variant 数组元素的数组维度,不过,勉强解决问题吧。

从命令行参数得到XML配置文件地址后,接着是解析XML文件获取更新信息与文件列表。当然,在解析XML配置信息之前,得先定好XML配置文件的格式,如下面的代码:

 

<?xml version="1.0" encoding="gb2312" ?>

<update>

  <publish>

  <force>0</force>

  <publishDate>20090902 19:51:32</publishDate>

  <version>1.0.0.0</version>

  <remark />

  <run />

  </publish>

<paths>

  <configUrl url="Update.xml" />

  <configPath path="D:/Current/VBUpdate/Publisher/" />

  <baseUrl url="http://localhost/update/" />

  <localPath url="D:/Current/VBUpdate/Publisher/" />

  <remotePath url="D:/Current/VBUpdate/Publisher/" />

  </paths>

   <files>

  <file name="Publisher.exe" main="1" version="1.0.0.0" />

  <file name="../Update/Update.exe" version="1.0.0.0" />

  <file name="../Update/olelib.tlb" version="20040201 22:54:16" />

  <file name="../Update/SetSys.ico" version="20090813 10:38:54" />

   </files>

</update>

 

其中,publish结点描述的上所发布程序的基本信息,包括以下子结点:

 

序号

结点名称

用途

可能值

备注

1

force

指明是否强制更新。

0(可取消更新)或1(强制更新)

0值均解析为1(强制更新)

2

publishDate

表示发布时间。

发布当时时间。

 

3

version

主程序版本号。

主程序文件版本号。

通过比较这个版本号决定是否需要更新。

4

remark

发布说明。

历次发布的修订内容。

每次的修订内容占一行,新的在上面。

5

run

更新后运行命令。

DOS命令。

一般为调用批处理。

 

paths结点描述与更新及发布相关的路径,包括以下子结点:

序号

结点名称

用途

可能值

备注

1

configUrl

指定XML配置文件URL

包括XML文件名的完整URL

要与主程序中读取的URL一致。

2

configPath

保存XML配置文件的远程地址。

文件路径,以“/”结束。

不支持FTP路径。

3

baseUrl

指定下载基地址。

http://路径,以“/”结束。

 

4

localPath

指定本地路径。

本地待发布程序路径,以“/”结束。

一般以主程序路径为基准。

5

remotePath

指定远程路径。

程序发布到的路径,以“/”结束。

不运行FTP路径。

 

files描述要更新文件列表,每个文件以一个子结点表示,结点为固定为“file”,“name”属性指定源文件名,以上述的下载基地址(baseUrl)为基准,支持相对路径;“target”属性指定目的文件名,以主程序所在路径为基准,支持相对路径,缺省时直接使用源文件名;“version”属性表示该文件发布的版本号,如果文件不包括版本信息,则用“date”属性指定其最后修改时间,“version”或“date”决定了该文件的新旧、是否需要更新;“main”属性指定该文件是否主程序,1(或非0)表示是,0表示否。

XML配置文件格式清楚了,下面要开始VB读取XML之旅了,好XML解析用的是MicrosoftXML分析器组件,而且在Delphi中已经用过,写起来还不是很太吃力。MSXML分析器有很多版本,但为了安全起见还是引用了较低的版本:2.0(Microsoft XML, version 2.0)

要解析XML配置之前,首先需要创建XML文档处理对象,由于习惯了OOP,当然在VB里也要这样用好一点,所以将XML配置解析写成了类:XmlConfiguration,在构造函数(我自认为Class_Initialize过程应该就等同于构造函数吧?)中创建XML文档实例:

Set XmlDoc = New DOMDocument

XmlDoc.preserveWhiteSpace = False 这句感觉是多余的,本来是想让它自动缩进、换行的,但就是没找到适合的属性,保存得到的XML文件乱糟糟的。

创建XML文档实例后,开始装载XML配置文件,用到Load方法:

XmlDoc.Load(ConfigFile)

Delphi中不同的是,这里的Load是异步执行的,调用后尚不能立即读取结点,需要监测其状态,等待装载完成后才行。我是通过Timer定时(100毫秒)检测的,当XmlDoc.readyState = 4时即开始解析XML配置。首先写一个Analysis方法,依次读取update(根结点)下的每一个子结点,然后再处理每一个子结点:

 

'{ 解析每个子结点的值到各个属性。Cable Fan 2009-08-14 }

Public Sub Analysis()

    Dim i As Integer

    Dim Root As IXMLDOMNode

    Dim Node As IXMLDOMNode

   

    Set Root = XmlDoc.documentElement

    If Root Is Nothing Then

        MsgBox "无法读取XML配置!"

    Else

        For i = 0 To Root.childNodes.Length - 1

            Set Node = Root.childNodes(i)

            Select Case Node.nodeName

                Case "publish"

                    LoadPublish Node '发布信息。

                Case "paths"

                    LoadPaths Node ' 装载下载路径。

                Case "files"

                    LoadFiles Node ' 装载文件列表。

            End Select

        Next

    End If

End Sub

 

'{ 装载下载路径。Cable Fan 2009-08-14 }

Private Sub LoadPublish(PNode As IXMLDOMNode)

    On Error GoTo CATCH

   

    ' 遍历所有文件子结点。

    Dim Node As IXMLDOMNode

    Dim Attr As IXMLDOMNode

    Dim i As Integer

   

    For i = 0 To PNode.childNodes.Length - 1

        Set Node = PNode.childNodes(i)

        Select Case Node.nodeName

            Case "force"

                m_Force = (Node.Text = "1")

            Case "publishDate"

                m_PublishDate = CDate(Node.Text)

            Case "version"

                m_Version = Node.Text

            Case "remark"

                m_Remark = Node.Text

            Case "run"

                m_RunCmd = Node.Text

        End Select

    Next

   

    Exit Sub

CATCH:

    Err.Raise MODULEID + 12, "XMLConfiguration.LoadPublish"

    Err.Clear

End Sub

 

'{ 装载下载路径。Cable Fan 2009-08-14 }

Private Sub LoadPaths(PNode As IXMLDOMNode)

    On Error GoTo CATCH

   

    ' 遍历所有文件子结点。

    Dim Node As IXMLDOMNode

    Dim Attr As IXMLDOMNode

    Dim i As Integer

   

    For i = 0 To PNode.childNodes.Length - 1

        Set Node = PNode.childNodes(i)

        Select Case Node.nodeName

            Case "configUrl"

                Set Attr = Node.Attributes.getNamedItem("url")

                If Not Attr Is Nothing Then m_ConfigUrl = Attr.nodeValue

            Case "configPath"

                Set Attr = Node.Attributes.getNamedItem("path")

                If Not Attr Is Nothing Then m_ConfigPath = Attr.nodeValue

            Case "baseUrl"

                Set Attr = Node.Attributes.getNamedItem("url")

                If Not Attr Is Nothing Then m_BaseUrl = Attr.nodeValue

            Case "localPath"

                Set Attr = Node.Attributes.getNamedItem("path")

                If Not Attr Is Nothing Then m_LocalPath = Attr.nodeValue

            Case "remotePath"

                Set Attr = Node.Attributes.getNamedItem("path")

                If Not Attr Is Nothing Then m_RemotePath = Attr.nodeValue

        End Select

    Next

   

    Exit Sub

CATCH:

'    Err.Raise MODULEID + 12, "XMLConfiguration.LoadPaths"

'    Err.Clear

End Sub

 

'{ 装载下载路径。Cable Fan 2009-08-14 }

Private Sub LoadPaths(PNode As IXMLDOMNode)

    On Error GoTo CATCH

   

    ' 遍历所有文件子结点。

    Dim Node As IXMLDOMNode

    Dim Attr As IXMLDOMNode

    Dim i As Integer

   

    For i = 0 To PNode.childNodes.Length - 1

        Set Node = PNode.childNodes(i)

        Select Case Node.nodeName

            Case "configUrl"

                Set Attr = Node.Attributes.getNamedItem("url")

                If Not Attr Is Nothing Then m_ConfigUrl = Attr.nodeValue

            Case "configPath"

                Set Attr = Node.Attributes.getNamedItem("path")

                If Not Attr Is Nothing Then m_ConfigPath = Attr.nodeValue

            Case "baseUrl"

                Set Attr = Node.Attributes.getNamedItem("url")

                If Not Attr Is Nothing Then m_BaseUrl = Attr.nodeValue

            Case "localPath"

                Set Attr = Node.Attributes.getNamedItem("path")

                If Not Attr Is Nothing Then m_LocalPath = Attr.nodeValue

            Case "remotePath"

                Set Attr = Node.Attributes.getNamedItem("path")

                If Not Attr Is Nothing Then m_RemotePath = Attr.nodeValue

        End Select

    Next

    

    Exit Sub

CATCH:

'    Err.Raise MODULEID + 12, "XMLConfiguration.LoadFiles"

'    Err.Clear

End Sub

 

Delphi中不同的是,读取一个结点的属性值时,要判断属性的存在性,试图读取返回的空值将引发错误。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值