• Excel VBA 学习总结 网络、XML、WMI以及API扩充


      前面我已经总结了VBA最常见的一些应用;相对来说,下面这几种应用都比较少见一点,这里就是做一个索引,当需要的时候可以直接查询需要的资源。经过前面的了解,大家肯定也猜到了,这些应用基本上都是通过调用COM实现的。所以只要系统底层COM能完成的功能,基本在VBA中都可以去完成。此外,除了调用COM对象完成相应的功能,扩充VBA的能力最纯粹的手段就是直接调用API了。这个已经超出了VBA的范围,这里就是简单提及一下。对于COM对象创建的时候是“前期绑定”还是“后期绑定”的区别也就不再重复了。每个对象,我就是简单总结一下常见的用法。

    一、网络应用

    直接使用Workbook对象获取网络内容

      在装有Frontpage Server Extension的服务器上,可以直接以Workbook的形式保存和打开Excel。除了分享这些Excel文档,直接使用Workbook也可以直接打开和使用网页上的内容。打开以后,基本上就当Sheet一样处理了。

    Dim oBk As Workbook
    '打开远程Excel
    Set oBk = Workbooks.Open("http://www.MySite.com/book1.xlsx")
    '另存为
    oBk.SaveAs "http://www.MySite.com/Book2.xlsx"

    Dim oRng As Range
    '打开网页
    Set oBk = Workbooks.Open("http://www.x-rates.com/d/USD/table.html")
    '查找内容
    Set oRng = oBk.Worksheets(1).Cells.Find("British Pound")
    '显示内容
    MsgBox oRng.Offset(01).Value

    使用Web Query获取网络数据

      从Excel97加入了Web Query的支持后,几乎在每个新的版本中,这个方面的内容都得到了强化。我们可以使用这个特性获取网络上一张表的数据。主要使用的是Application.QueryTables。例子如下:

    Sub GetRatesWithWebQuery()
      
    Dim oBk As Workbook
      
    Dim oQT As QueryTable
      
    '数字的格式设置
      Dim sDecimal As String
      
    Dim sThousand As String
      
    Dim bUseSystem As Boolean

      
    Set oBk = Workbooks.Add
      
    With oBk.Worksheets(1)
        
    Set oQT = .QueryTables.Add( _
                    Connection:
    ="URL;http://www.x-rates.com/d/USD/table.html", _
                    Destination:
    =.Range("A1"))
      
    End With

      
    '设置QueryTable的相关属性
      With oQT
        .Name 
    = "USD"
        
    '选中特定的表
        .WebSelectionType = xlSpecifiedTables
        
    '导入Page上第14个表
        .WebTables = "14"
        
    '忽略Page上的格式
        .WebFormatting = xlWebFormattingNone
        
    '不会尝试去识别日期
        .WebDisableDateRecognition = True
        
    '每次打开文件的时候不会刷新数据
        .RefreshOnFileOpen = False
        
    '等待查询结束
        .BackgroundQuery = True
        
    '伴随Workbook一起保存数据
        .SaveData = True
        
    '根据表中数据调整列宽度
        .AdjustColumnWidth = True
      
    End With
      
    With Application
        
    '保存当前文档的分隔符格式
        sDecimal = .DecimalSeparator
        sThousand 
    = .ThousandsSeparator
        bUseSystem 
    = .UseSystemSeparators
        
    '设置分隔符
        .DecimalSeparator = "."
        .ThousandsSeparator 
    = ","
        .UseSystemSeparators 
    = True
        
    '忽略任何错误
        On Error Resume Next
        
    '执行查询,等待结束
        oQT.Refresh BackgroundQuery:=False
        
    '恢复文档的分隔符格式
        .DecimalSeparator = sDecimal
        .ThousandsSeparator 
    = sThousand
        .UseSystemSeparators 
    = bUseSystem
      
    End With
    End Sub

     这种方式十分依赖于页面中<table>节点的顺序,需要注意。

    使用InternetExplorer对象操纵DOM模型

      使用前面的方法都有一定的局限性,如果我们关注的不是整个表,而只是页面的某些部分,这个时候使用InternetExplorer对象是最方便的。这个对象的Document属性代表了整个的页面,可以使用这Document的属性和方法获取页面的各个部分(就是常说的DOM操作)。使用这个对象处理页面内容是最强大,最直接的一种方式。InternetExplorer对象的使用示例:

    Sub GetUSDtoGBPRateUsingIE()
      
    Dim oIE As InternetExplorer
      
    Dim sPage As String
      
    Dim iGBP As Long, iDec As Long
      
    Dim iStart As Long, iEnd As Long
      
    Dim dRate As Double
      
    '创建隐藏的IE实例,可以通过设置Visible属性来显示IE
      Set oIE = New InternetExplorer
      
    '打开网页
      oIE.Navigate "http://www.x-rates.com/d/USD/table.html"

      
    '等待加载完毕,也可以使用下面的方式等待:
      'While obIE.Busy = True  
      'DoEventsWend
      Do Until oIE.readyState = 4
        DoEvents
      
    Loop

      
    'DOM操作
      sPage = oIE.Document.body.InnerText

      
    '查找目标
      iGBP = InStr(1, sPage, "British Pound")
      iDec 
    = InStr(iGBP, sPage, ".")
      
      iStart 
    = InStrRev(sPage, " ", iDec) + 1
      iEnd 
    = InStr(iDec, sPage, " ")
      dRate 
    = Val(Mid$(sPage, iStart, iEnd - iStart))
      
      
    MsgBox "The USD/GBP exchange rate is " & dRate
    End Sub

    这种方式其实也是IE自动化的一种手段:http://www.excely.com/excel-vba/ie-automation.shtml

    IE文档对象资料:http://club.excelhome.net/forum.php?mod=viewthread&tid=263887

    网页分析资料:http://club.excelhome.net/thread-377077-1-1.html

    邮箱登陆问题:http://club.excelhome.net/thread-357475-1-1.html

    使用XmlHttp获取网页内容

      XmlHttp是一套可以在Javascript、VbScript、Jscript等脚本语言中通过http协议传送或从接收XML及其他数据的一套API。XmlHttp最大的用处是可以更新网页的部分内容而不需要刷新整个页面。来自MSDN的解释:XmlHttp提供客户端同http服务器通讯的协议。客户端可以通过XmlHttp对象(MSXML2.XMLHTTP.3.0)向http服务器发送请求并使用微软XML文档对象模型Microsoft® XML Document Object Model (DOM)处理回应。现在的绝对多数浏览器都增加了对XmlHttp的支持,IE中使用ActiveXObject方式创建XmlHttp对象,其他浏览器如:Firefox、Opera等通过window.XMLHttpRequest来创建xmlhttp对象。 使用这种方式访问网页内容比较快一点,但是兼容性不如使用IE对象的方式。

      VBA从网络下载文件是可以通过XmlHttp对象实现的,例子如下:

    Set http = CreateObject("Microsoft.XmlHttp")
       
    http.Open 
    "GET", url, True 
    http.send

    If http.ReadyState <> 4 Then
       DoEvents
    Else
       
       
    Set oStream = CreateObject("ADODB.Stream")
       oStream.Type 
    = 1
       oStream.Open
       oStream.Write http.responsebody
       sFile 
    = Replace(Mid(url, InStrRev(url, "/"+ 1), "?""-")
       oStream.SaveToFile 
    "C:" & "\" & sFile, 2 '本地保存文件名
       oStream.Close
    End if

    其它小例子:http://www.excelpx.com/thread-163323-1-1.html

    XmlHttp对象参考:http://blog.csdn.net/tfgdd/article/details/5062767

    VBA调用WebService

    这个在VBA中也可以实现的,一般需要类库辅助,其实与XML操作还是有关系的,可以参看下面链接:

    从Office调用Web Service:http://www.excely.com/excel-vba/ie-automation.shtml

    如何调用Web Service:http://msdn.microsoft.com/en-us/magazine/cc163837.aspx 

    二、XML操作

      在VBA中处理XML文档在前面的文件系统中其实已经介绍过最简单的打开和保存了。下面综合总结一下:

    当做普通文本文档处理或者打开放到Workbook中处理

      使用这种方式,辅助正则表达式,再加上一大把处理字符串的方法,是可以完成任务的,只不过XML的结构优势一点都没用上。

    使用ADO处理XML文档

      这里充分体现了ADO的强大,配合SQL几乎可以完成任何的任务。别忘了添加MS ADO Library引用。

    生成XML的操作示例:

    Sub Create_XML_Recordset() 
        
    Const stSQL As String = "SELECT * FROM [Report]"
        
    Dim stCon As String      
        stCon 
    = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ 
        
    "Data Source=" & ThisWorkbook.FullName & ";" & _ 
        
    "Extended Properties=""Excel 8.0;HDR=Yes"";" 
         
        
    Dim rst As New ADODB.Recordset 
        
    Dim str As New ADODB.Stream 
         
        
    With rst 
            .CursorLocation 
    = adUseClient 
            .Open stSQL, stCon, adOpenStatic, adLockReadOnly, adCmdText 
            .Save str, adPersistXML 
            .Close 
            
    With str 
                .SaveToFile 
    "C:\Report.xml", adSaveCreateOverWrite 
                .Close 
            
    End With 
        
    End With 
         
        
    Set str = Nothing 
        
    Set rst = Nothing 
    End Sub 

    读取XML的操作示例:

    Sub Read_XML_Data() 
        
    Dim rst As ADODB.Recordset 
        
    Dim stCon As String, stFile As String 
        
    Dim i As Long, j As Long 
         
        
    Set rst = New ADODB.Recordset 
         
        stFile 
    = "C:\Report.xml" 
        stCon 
    = "Provider=MSPersist;" 
         
        
    With rst 
            .CursorLocation 
    = adUseClient 
            .Open stFile, stCon, adOpenStatic, adLockReadOnly, adCmdFile 
            
    Set .ActiveConnection = Nothing 
        
    End With 
         
        
    With ActiveSheet 
            
    For j = 0 To i - 1 
                .Cells(
    1, j + 1).Value = rst.Fields(j).Name 
            
    Next j 

            .Range(
    "A2").CopyFromRecordset rst 
        
    End With 
         
        rst.Close 
        
    Set rst = Nothing      
    End Sub 

    使用MSXML处理XML文档

      这应该是处理XML文档的首选策略了,它提供了XML DOM的所有方法和属性,使用起来很顺手。使用这个对象需要添加“Microsoft XML,v6.0”引用。

    Sub ReadXML()
        
    Dim xmlDom As MSXML2.DOMDocument
        
    Dim xmlPlaceMark As MSXML2.IXMLDOMNode
        
    Dim xmlPolygon As MSXML2.IXMLDOMNode
        
    Dim xmlCoord As MSXML2.IXMLDOMNode
        
    Dim sName As String
        
    Dim vaSpace As Variant, vaComma As Variant
        
    Dim i As Long, j As Long
        
        
    Set xmlDom = New MSXML2.DOMDocument    
        xmlDom.Load 
    "C:\Downloads\overlay_1198.kml"
        
        
    For i = 0 To xmlDom.childNodes(1).childNodes(0).childNodes.Length - 1
            
    If xmlDom.childNodes(1).childNodes(0).childNodes.Item(i).nodeName = "Placemark" Then
                
    Set xmlPlaceMark = xmlDom.childNodes(1).childNodes(0).childNodes.Item(i)
                
    Set xmlPolygon = xmlPlaceMark.childNodes(2).childNodes(0)
                
    Set xmlCoord = xmlPolygon.childNodes(0).childNodes(0).childNodes(0)
                sName 
    = xmlPlaceMark.childNodes(1).childNodes(5).nodeTypedValue                

                
    With Sheet4.Cells(Sheet2.Rows.Count, 1).End(xlUp).Offset(10)
                    .Value 
    = sName
                    vaSpace 
    = Split(xmlCoord.childNodes(0).Text, " ")
                    
    For j = LBound(vaSpace) To UBound(vaSpace)
                        vaComma 
    = Split(vaSpace(j), ",")
                        .Offset(
    01).Value = vaComma(0)
                        .Offset(
    02).Value = vaComma(1)
                    
    Next j
                
    End With
            
    End If 
        
    Next i
    End Sub

    XML DOM的方法和属性:http://msdn.microsoft.com/en-us/library/ms764730

    三、WMI信息

      WMI是内置在Windows 2000、 Windows XP和Windows Server 2003 系列操作系统中核心的管理支持技术。基于由 Distributed Management Task Force (DMTF) 所监督的业界标准,WMI是一种规范和基础结构,通过它可以访问、配置、管理和监视几乎所有的Windows资源。大多用户习惯于使用众多的图形化管理工具来管理Windows资源,在WMI之前这些工具都是通过Win32应用程序编程接口(Application ProgrammingInterfaces,API)来访问和管理Windows资源的。只要你熟悉系统编程你就知道API有多么重要。但是大多数脚本语言都不能直接调用Win32 API,WMI的出现使得系统管理员可以通过一种简便的方法即利用常见的脚本语言实现常用的系统管理任务。 利用WMI需要和脚本如WSH和VBScript结合起来,可以实现的功能大家可以看微软的MSDN文档。

    (介绍比较全)VBA中使用WMI:http://club.excelhome.net/thread-733445-1-1.html

    WMI中的Class介绍:http://msdn.microsoft.com/en-us/library/aa394554(v=VS.85).aspx

    四、API扩充

      在VBA中使用API,理论上可以完成任何操作系统提供的功能。但是实际上,除非万不得已,一般使用VBA或者其他COM提供的功能就足够了,真的算是价格便宜量又足。当上述这些功能不符合我们的需求的时候(特别是需要使用VBA中那纤弱的UserForm的时候),那就使用API吧。使用API需要先声明,再使用;声明过程中还涉及到类型的转化。如果想了解更多的内容,可以参考相关的资料。下面是质量比较高的一些资料:

    VBA与API:http://blog.imwebs.com/article.asp?id=469

    VBA调用API:http://www.excelperfect.com/index.php/2009/07/15/usewindowsapi/

    VBA中API的函数集锦:http://www.cnblogs.com/james.wong/articles/93942.html

    窗体API:http://www.vbafan.com/2009/07/19/excel-userform-api-tricks/

    CreateObject与GetObject的不同:前面我已经多次使用CreateObject去创建COM的实例了,这里简单介绍一下另外一个相关的函数。

      如果存在对象的当前实例,或者您希望使用已加载的文件创建对象,请使用 GetObject 函数,只要把COM组件的路径传给这个函数即可。如果不存在当前实例,并且不希望使用已加载的文件启动对象,那么使用 CreateObject 函数。这里最常见的一个用法是把Excel文件的路径传给GetObject,这个时候方法就返回这个文件对应的Workbook对象,但是并不会显式打开文件。这个时候就可以在后台处理文件的内容,比如拷贝Sheet到当前打开的Excel文件中。

    注意:如果对象本身已经注册为 ActiveX 单实例对象,则无论调用多少次 CreateObject,都只会创建对象的一个实例。不能使用 GetObject 获取对用 Visual Basic 创建的类的引用。

    GetObject方法的详细说明:http://msdn.microsoft.com/zh-cn/library/e9waz863(v=vs.80).aspx

  • 相关阅读:
    vue 侦听器
    vue 计算属性
    typeof 运算符
    constructor 属性
    立即执行函数与闭包
    计算属性缓存 vs 方法
    JavaScrip备课
    winform 实现对usb热拔插的监听
    c# async await的使用方式及为啥要用它
    .net5与之前的版本GetBytes长度变化
  • 原文地址:https://www.cnblogs.com/dxy1982/p/2159310.html
Copyright © 2020-2023  润新知