带有日志记录类的 Excel 加载项:如何应对 VBA 状态丢失?



设置

我正在开发和维护一个 Excel 加载项,该加载项在 Excel 的功能区 UI 中带有自己的控件选项卡。我之前遇到过状态丢失的问题(意味着全局范围的所有变量、静态变量等的丢失,这当然包括我对 RibbonUI 的引用)。关于功能区引用,我已经通过包含一个"重置功能区"按钮来"解决"问题,该按钮从永久存储的指针恢复引用,然后使功能区失效。虽然肯定不是最优雅的,但这部分工作得很好。

然而,在引入伐木类之后,状态损失问题再次困扰着我。记录器在此工作簿的模块中实例化:

Private Sub Workbook_Open()
Set LogToFile = SingletonFactory.getToFileLogger
End Sub

然后投入工作,例如,如下所示:

Private Sub buttonReloadObjects_onAction(ByVal control As IRibbonControl)
LogToFile.trace "Event firing: buttonReloadObjects_onAction"
' more stuff happening...
invalidateRibbon ' restores ribbon object and invalidates it
End Sub

加载外接程序时会实例化记录器,以便我可以自由地在外接程序代码的范围内记录所需的任何内容。它有几个日志记录级别,如跟踪/调试/错误/...和其他几种方法。通常它工作得很好 - 直到状态丢失命中(通常由不相关的错误引起,然后单击"结束")。

状态丢失

此时,VBA 环境忘记了我的LogToFile对象的存在,并且不再起作用,因为每次单击功能区控件都会触发一个runtime error 91: Object variable or with block variable not set,指向第一个包含对LogToFile引用的任何行。

解决方案?

现在,除了做疯狂的解决方法,比如放置

if not isObject(LogToFile) then
Set LogToFile = SingletonFactory.getToFileLogger
end if
LogToFile.trace "Message"

发生任何LogToFile之前,我能够想出的唯一真正的"解决方案"是将所有记录器调用包装在函数中(驻留在标准模块中),并在我想向日志发送内容时随时调用这些函数。这样,我可以在需要对象之前捕获缺少的对象引用,并且避免调用未实例化对象的方法.
但是,在将所有内容整齐地封装在类模块中之后,我觉得很奇怪,甚至可能是错误的(?),沿着这条路走下去。


那么,对于丢失记录器实例的问题,是否有"适当"的解决方案?还是我建议的方法已经尽可能合适了?


注意:这个问题当然不是特定于日志记录类的。它会影响所有全局变量,最明显的是我的 ApplicationEventClass。这个问题恰好是记录器最明显的,因为它经常在代码的所有入口点周围使用。

您只需要一个返回原始变量或重置它的函数。如果您调用该函数LogToFile则除了删除多余的Workbook_Open代码外,您无需更改任何其他代码。所以:

Function LogToFile() As WhateverVariableType
Static temp as WhateverVariableType
If temp is Nothing then Set temp = SingletonFactory.getToFileLogger
Set LogToFile = temp
End Function

这样,在编写代码时,您仍将受益于智能感知。

注意:您可能实际上不需要 temp 变量 - 这取决于是否有您想要保留的设置。如果有,您可能也想在函数中重置它们。

最新更新