后期绑定IHTML元素

时间:2017-04-27 16:14:45

标签: vba excel-vba mshtml excel

我正在尝试创建一个后期绑定的VBA项目来搜索网络。有一点我有以下代码(早期绑定):

Dim currPage as HTMLDocument: Set currPage = objIE.document 'where objIE is set with Set objIE = CreateObject("InternetExplorer.application")
'(late bound as it is dim'd as Object)
    Dim myDiv As HTMLDivElement: Set myDiv = currPage.getElementById("fbar")
    Dim elemRect As IHTMLRect: Set elemRect = myDiv.getBoundingClientRect
    'Scroll until bottom of page is in view
    Do Until elemRect.bottom > 0
        currPage.parentWindow.scrollBy 0, 10000
        Set elemRect = myDiv.getBoundingClientRect
    Loop

此代码在后期绑定时变为此:(或者我认为)

Dim currPage as Object: Set currPage = objIE.document
    Dim myDiv As Object: Set myDiv = currPage.getElementById("fbar")
    Dim elemRect As Object: Set elemRect = myDiv.getBoundingClientRect
    'Scroll until bottom of page is in view
    Do Until elemRect.bottom > 0
        currPage.parentWindow.scrollBy 0, 10000
        Set elemRect = myDiv.getBoundingClientRect
    Loop

问题,我猜,是I前面的IHTMLRectMSDN tells me表示网页上没有与之关联的实际对象的元素它 - 因此将它分配给未指定的Object只是在代码中没有任何意义。 (这是一个完整的猜测)

无论如何,早期绑定代码工作正常,后期绑定代码退出elemRect.bottom执行

为什么会这样,我该如何解决?

1 个答案:

答案 0 :(得分:2)

VBA中的对象可以实现多个接口,您可以调用的方法/属性取决于您用来访问该对象的接口。一个简单的例子:

reflect

对于MSHTML,我猜想像' This means access the object via the IUnknown interface ' IUnknown is the interface from which all other COM ' interfaces inherit Dim x As IUnknown Set x = ThisWorkbook.Worksheets(1) ' Commented out as this won't compile because the ' Name property isn't defined in IUnknown ' MsgBox x.Name ' This means access the object through the default ' interface associated with the Worksheet object type Dim w As Worksheet Set w = x ' Now we can get to the name (same object, different interface) MsgBox w.Name 这样的方法正在返回一个类似getElementById版本的接口。这意味着无法访问IHTMLElement等接口中定义的方法/属性。

IUnknown有一个名为QueryInterface的方法,用于访问对象实现的不同接口。但是,无法在VBA中直接调用此方法,因为VBA执行此操作的方法是将IHTMLDivElement与适当的接口一起使用,然后使用Dim。只有在设置了必要的引用后才能编译,这反过来又会破坏后期绑定的目的。

使用CallByName有一种解决方法。要返回工作表示例,可以使用:

Set

对于MSHTML问题,这有效(请注意,调用类型更改为Dim x As IUnknown Set x = ThisWorkbook.Worksheets(1) ' Commented out as this won't compile because the ' Name property isn't defined in IUnknown ' MsgBox x.Name ' Can get to the property via CallByName MsgBox CallByName(x, "Name", VbGet) ):

VbMethod

我对COM对象知之甚少,所以可能还有其他问题我没有考虑

完整代码(改编自your answer to another question)。由于IE需要时间关闭,因此快速连续重复运行该功能会产生错误(有关类似问题,请参阅this question)。如果需要连续运行多个查询,请重复使用相同的IE对象:

Dim elemRect As Object: Set elemRect = CallByName(myDiv, "getBoundingClientRect", 
    VbMethod)
stTimer = Timer
'Scroll until bottom of page is in view
Do Until elemRect.bottom > 0 Or tElapsed > timeout 'timeout after n seconds
    currPage.parentWindow.scrollBy 0, 10000
    Set elemRect = CallByName(myDiv, "getBoundingClientRect", VbMethod)
    tElapsed = Timer - stTimer
Loop