gpt4 book ai didi

vba - 什么时候VBA中的两个对象相同?

转载 作者:行者123 更新时间:2023-12-01 23:30:51 25 4
gpt4 key购买 nike

我在Excel 2010中使用功能区,其中包含一个按钮:

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="rx_onLoad">
<ribbon>
<tabs>
<tab id="TestTab" label="Test Tab" insertAfterMso="TabHome">
<group id="TestGroup" label="TestGroup">
<button id="TestButton" label="TestButton" size="normal" onAction="OnTestButton" tag="TestButton" imageMso="Coffee" />
</group>
</tab>
</tabs>
</ribbon>
</customUI>

OnTestButton方法在模块中实现
Sub OnTestButton(Control As IRibbonControl)

Dim Ws As Object
Set Ws = Control.Context.ActiveSheet
MsgBox ActiveSheet Is Ws ' Shows True

Debug.Print ActiveSheet.Name 'OK
Debug.Print Ws.Name ' OK

ActiveSheet.Test ' OK
Debug.Print Ws.Test ' Runtime Error

End Sub

Activity 表有方法
Public Sub Test()
MsgBox "Test"
End Sub

如果单击测试按钮,则会调用 OnTestButton方法。 Control.Context.ActiveSheet -operator下的对象 ActiveSheetIS相同。当我使用 Name这样的属性(即 WorkSheet的接口(interface))时,它们的行为相同。
但是,当我调用不在接口(interface)中的方法 Test时,我在 Control.Context.ActiveSheet而不是 ActiveSheet上收到运行时错误458“对象不支持此属性或方法”。

那么,为什么两个引用 Control.Context.ActiveSheetActiveSheet在运行时应该引用“相同”对象时却表现不同?

最佳答案

我有理由(> 90%)确信以下内容是正确的。

首先回答标题中的问题:VBA中的两个对象什么时候相同?

当COM说它们相同时,两个对象在VBA中是相同的;当request the IUnknown interface from both and the pointers come out equal时,COM说它们是相同的。

现在到有问题的对象。

功能区的Control.Context只不过是Excel的Application.ActiveWindow,所以问题就变成了ActiveWindow.ActiveSheetApplication.ActiveSheet是否相同。

是的,它们是-就COM而言。
它们在内部可能未实现为单个对象,因为它们的指针彼此距离很远,但是当您从中请求IUnknown时,它们将返回相同的指针值。 (您可以通过声明类型为IUnknown的变量并通过IUnknown将对象声明为来请求Set。)

旁注。
Excel对于“真实对象”的单个“实际”“内部”实例具有多个“外部”“实例”对象是很自然的。

例如。您可以创建Range对象的多个实例,所有这些实例都是不同的实例(Is = False),它们引用实际图纸上完全相同的实际范围。因此,每个人仅是“实际事物”的“视口”。

我推测WindowSheet会发生类似的事情(每个实际的事物可能有多个“视口”),但是为了避免混淆/简化VBA编码,Excel开发人员决定使用Sheet s包装器通过返回相同的IUnknown指针报告它们是同一对象。

就COM而言,这很好:只要遵循所有COM规则,就可以在内部将对象实现为多个对象,这无关紧要,因为只要遵循所有COM规则,就无法分辨他们反正分开了。

现在是实际问题,为什么不能在Test() 上调用ActiveWindow.ActiveSheet

因为ActiveWindow.ActiveSheet返回Worksheet接口(interface),所以它没有Test()方法,并且是non-extensible。就如此容易。

那么,为什么可以在Test()上调用Application.ActiveSheet呢?
因为Application.ActiveSheet不返回Worksheet。它返回Sheet1(或您的工作表名称)。
Sheet1是一个动态接口(interface),它继承自Worksheet并包含您的Test()。它是Worksheet的超集。

您可能想知道为什么当用户尝试在Worksheet上调用Test()时,VBA为什么不要求更好的Worksheet的超集。答案是,既不应该,也不能!

VBA不需要也不应该了解托管它的应用程序的内部实现细节。它不知道存在一个“更好”的接口(interface),可以从当前接口(interface)中查询该接口(interface)。如果它确实怀疑存在一个“更好的”接口(interface),那么鉴于每个对象可以具有数百个接口(interface),它将确切地尝试查询哪个接口(interface)?

VBA唯一需要执行后绑定(bind)调用的就是IDispatch接口(interface)。
所有Excel接口(interface)都从IDispatch继承。
也就是说,Excel中的每个类Is IDispatch

类型As Object的变量也表示As IDispatch
Object变量设置一些内容意味着从该对象中查询IDispatch
ActiveWindow.ActiveSheet返回IDispatch的一部分Worksheet。这是存储在IDispatch类型的变量中的有效的完整IDispatch,因此不需要VBA要求“更好的IDispatch。它使用已经拥有的一个,调用失败。
Application.ActiveSheet返回IDispatch,它是另一个接口(interface)Sheet1的一部分。这次Test()成功。

ActiveWindow.ActiveSheet返回IDispatchWorksheet是否是错误是否值得商bat。
从技术上讲,这不是错误,因为WorksheetIDispatch,因此该方法有权返回该值。
但是可以说,返回“更好的IDispatch”是我们在Excel中的工作方式,实际上他们应该这样做。
我个人倾向于声明它是一个小错误。

但是您可以自己请求“更好的IDispatch”。
如果仅声明另一个Object变量,然后对现有工作表引用Set,则无法使用-VBA将观察到这两个变量的类型相同,即Object,并且将直接复制指针而不尝试查询其他接口(interface)。

要让VBA实际上请求另一个接口(interface),您需要首先查询另一个不同于IDispatch的接口(interface),然后从该接口(interface)请求IDispatch:

Dim BadIDispatch As Object
Set BadIDispatch = Control.Context.ActiveSheet 'ActiveWindow.ActiveSheet

Dim Ws As Worksheet
Set Ws = BadIDispatch 'Querying another interface

Dim WsAsObject As Object
Set WsAsObject = Ws 'Querying IDispatch - this time going to get a good one

关于vba - 什么时候VBA中的两个对象相同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36495738/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com