为什么VBA TypeOf操作符在EXCEL中失败

我一直在与Excel 2007问题打了好几天了。 以下是我能想到的所有事实的列表,可能是相关的:

  1. IDetailSheet是一个在VBA项目中用几个方法声明的类,它在它的类初始化程序中抛出了一个错误,所以它不能被实例化(使其成为抽象的)。
  2. Option Explicit在所有模块中设置。
  3. VBA项目中的十个工作表实现 * IDetailSheet *并干净地编译(整个项目也一样)。
  4. CDetailSheets是一个在VBA项目中声明的类,它封装了一个Collection对象,并将Collection对象公开为IDetailSheet的Collection。 它还暴露了一些额外的方法来执行所有收集会员IDetailSheet的某些方法。
  5. 在其初始化类(从Workbook _ Open事件处理程序调用并分配给全局variables)中, CDetailSheet将执行以下代码以填充专用收集DetailSheets

    Dim sht as EXCEL.WorkSheet
    For Each sht in ActiveWorkbook.Worksheets
    If TypeOf sht is IDetailSheet Then
    Dim DetailSheet as IDetailSheet
    Set DetailSheet = sht
    DetailSheets.Add DetailSheet, DetailSheet.Name
    End If
    Next sht

  6. 在某些function区callback中,运行以下代码:
    If TypeOf ActiveWorkbook.ActiveSheet is IDetailSheet Then
    Dim DetailSheet as IDetailSheet
    Set DetailSheet = ActiveWorkbook.ActiveSheet
    DetailSheet.Refresh [correction]
    End If

  7. 所有的ActiveX控件在被识别出其他的稳定性问题之后,已经从Workbook中删除了(原来有几十个)。 Fluent界面function区已被创build,以取代最初与ActiveX控件关联的function。

  8. 公司模板中有一个Hyperion加载项,但不在此工作簿中使用。

完成所有操作后,工作簿运行时会出现以下症状:

  • 任何数量的IDetailSheet的实例都可以通过TypeOf Is从1(最常见)到偶尔2或3在CDetailSheets初始化程序中识别。从零开始,从不超过3次,绝对不会有10次可用。 (并不总是相同的,虽然靠近前面的集合似乎增加被识别的可能性。)
  • 无论在CDetailSheets初始化程序中发现了哪个IDetailSheet实现的实例(以及我所能确定的,只有这些实例), TypeOf也会识别这个实例在Ribboncallback中。

任何人都可以解释为什么大部分TypeOf …操作失败? 或者如何解决这个问题?

我已经采取手动创buildV表(即大丑陋的select案例…结束select语句),以使function工作,但我真的觉得让我的名字旁边这样的代码相当尴尬。 除此之外,我可以看到这是未来的维护噩梦。

更新
考虑到这可能是一个陈旧的p代码问题,我去了从扩展的XLSM zip中删除Project.Bin文件的程度,然后手动导入所有的VBA代码。没有改变。 我也尝试添加项目名称到IDetailSheet的所有用法,使他们miFab.IDetailSheet ,但再次无济于事。 ( miFab是项目名称。)

有几种方法可以使用CallByName作弊。 你将不得不以这种或那种方式解决这个bug。

一个肮脏的例子

每个以实现行开头的表都应该有一个公共的GetType函数。 我将“TestSheet”子文件附加到我的function区上的一个button上。 它将返回的types名称放在单元格A1中以演示该函数。

模块1

 '--- Start Module1 --- Option Explicit Public Sub TestSheet() Dim obj As Object Set obj = ActiveSheet ActiveSheet.[A1] = GetType(obj) End Sub Public Function GetType(obj As Object) As String Dim returnValue As String returnValue = TypeName(obj) On Error Resume Next returnValue = CallByName(obj, "GetType", VbMethod) Err.Clear On Error GoTo 0 GetType = returnValue End Function '--- End Module1 --- 

工作表Sheet1

 '--- Start Sheet1 --- Implements Class1 Option Explicit Public Function Class1_TestFunction() End Function Public Function GetType() As String GetType = "Class1" End Function '--- End Sheet1 --- 

在发布我自己的类似问题后,我发现这个问题,因为TypeOf无法使用实现接口的Excel工作簿的ActiveSheet

我没有一个明确的解释,但我认为我有一个解决方法。

我怀疑这是因为[代码]在Sheet1或Chart上实现一个接口,并且正在扩展Sheet1 / Chart1,但Sheet1已经在扩展Worksheet(而Chart1已经在扩展Chart)。

在我的testing中,我可以强制VBA通过首先访问表单的属性来返回TypeOf的实际值。 这意味着,做一些丑陋的事情就像:

 'Explicitly access ThisWorkbook.ActiveSheet.Name before using TypeOf If TypeOf ThisWorkbook.Sheets(ThisWorkbook.ActiveSheet.Name) Is PublicInterface Then 

如果您不信任TypeOf ,请继续并忽略错误:

 Dim sht as EXCEL.WorkSheet For Each sht in ActiveWorkbook.Worksheets 'If TypeOf sht is IDetailSheet Then Dim DetailSheet As IDetailSheet On Error Resume Next Set DetailSheet = sht On Error GoTo 0 If Not DetailSheet Is Nothing Then DetailSheets.Add DetailSheet, DetailSheet.Name End If Next sht 

如果这不起作用 ,至less当时工作表确实不是IDetailSheet