用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中不同的是,讀取一個結點的屬性值時,要判斷屬性的存在性,試圖讀取返回的空值將引發錯誤。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章