到这里又遇到问题了,命令行参数是拆分到数组里的,如果不指定命令参数时,则数组保持为“空数组”。而对“空数组”的任何操作(包括用UBound函数测长度)都会引发错误,这个问题困扰了我很久。怎么才能将这种情况区分出来呢?没办法,最终还是只能借助API函数:SafeArrayGetDim,其实这个函数的真正作用是:取得 OLE 或 Variant 数组元素的数组维度,不过,勉强解决问题吧。
从命令行参数得到XML配置文件地址后,接着是解析XML文件获取更新信息与文件列表。当然,在解析XML配置信息之前,得先定好XML配置文件的格式,如下面的代码:
<?xml version="1.0" encoding="gb2312" ?> <force>0</force> <publishDate>20090902 19:51:32</publishDate> <version>1.0.0.0</version> <remark /> <run /> </publish> <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> <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。 |
要与主程序中读取的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解析用的是Microsoft的XML分析器组件,而且在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 |
原文链接:https://www.f2er.com/vb/262700.html