Excel 在VBA中使用异步回调函数安全吗?
关于这个问题的评论太长了,所以我会在这里提问 在VBA代码中使用回调函数指针是否安全(至少从我下面谈到的问题来看);考虑到它与宿主应用程序的关系和解释器的特殊性Excel 在VBA中使用异步回调函数安全吗?,excel,vba,windows,multithreading,winapi,Excel,Vba,Windows,Multithreading,Winapi,关于这个问题的评论太长了,所以我会在这里提问 在VBA代码中使用回调函数指针是否安全(至少从我下面谈到的问题来看);考虑到它与宿主应用程序的关系和解释器的特殊性 关于使用WinAPI注册回调讨论了操作系统调用回调函数时导致崩溃的潜在陷阱。具体来说,它询问为什么与工作表交互偶尔会导致TIMERPROC回调出现问题。阅读描述后,我立即想到的是Excel对象模型 这个问题包括一段“有效”的代码摘录,但我不会在这里包括它,因为我认为一个相关的问题实际上更简洁地说明了这一点: 我能用计算机解决它 On
关于使用WinAPI注册回调讨论了操作系统调用回调函数时导致崩溃的潜在陷阱。具体来说,它询问为什么与工作表交互偶尔会导致TIMERPROC回调出现问题。阅读描述后,我立即想到的是Excel对象模型 这个问题包括一段“有效”的代码摘录,但我不会在这里包括它,因为我认为一个相关的问题实际上更简洁地说明了这一点: 我能用计算机解决它
On Error Resume Next
[……]
Sub TimerProc(ByVal HWnd As Long, ByVal uMsg As Long, ByVal nIDEvent As Long, ByVal dwTimer As Long)
On Error GoTo BeforeExit
Range("A1") = "test"
BeforeExit:
End Sub
…这证实了我的想法,即问题可能来自与对象模型(Range(“A1”)=“test”
)异步交互,而对象模型处于某种锁定状态,并且可以通过使用OERN捕捉错误来解决
在最初的问题中,他给出了Windows调用回调函数时可能导致崩溃的原因,他将其归结为三个原因: [使用API的开发人员]被假定为 已将错误处理和应急管理落实到位 呼叫代码 这些假设是:
WM_TIMER
消息并最终运行回调的消息循环必然与我的VBA代码位于同一线程中;因此,当Excel实际上正忙于处理其他UI消息时,不会调用回调。确保Excel对象模型可能处于某种状态,这意味着尝试访问它将引发错误,但问题是向调用者引发错误,而不是回调不可用
同时,OP和一些人暗示他们的问题实际上是第三个因素(第1点-函数指针无效)。他们所写的内容似乎表明,函数指针后面的TimerProc正在被垃圾收集,并在执行过程中的某个时刻失效,OERN通过保存对它的引用使它保持活动状态 然而,整个想法在我看来真的很奇怪;函数不是VBA中的一级公民,我认为它们不遵循COM引用计数(无论如何,什么会保存对它们的引用,指针只是一个数字而不是引用?)。我假设函数指针是在编译时设置的,甚至是在
End
语句和reset按钮之间设置的,所以我不确定是什么让它们超出OP建议的范围。我还认为,如果他们这样做了,通常会对VBA代码产生影响,而不仅仅是在使用API时。所以我不确定这是否真的是一个值得担心的问题
TL;博士 在异步单线程代码中使用回调时(例如使用
SetTimer
API),是否存在以下风险:
- 调用之间的回调超出范围,因此提供给API的函数指针无效
- Excel/当调用回调时,主机应用程序处于“忙碌状态”,因此调用失败
- 主机应用程序不应影响该线程上VBA代码的“可用性”
- 在我点击F5之后,没有理由让函数指针变得无效(不可调用)——除了一些手动内存破坏
哦,请结合上下文阅读这些评论,我很可能完全误解了它们:)(我在这方面没有太多经验)这并不像看上去那么糟糕,回调仍然是同步的,只有在Excel不忙于其他事情时才会发生。然而,让代码生成一个未经处理的错误是相当不确定的。特别是在64位操作系统上,异常很容易绕过VBA运行时提供的用于显示错误的任何backstop。丑陋的细节。只是有意地生成一个错误以获得信任,请注意链接帖子中有关Win7的注释。它并没有看上去那么糟糕,回调仍然是同步的,并且只能在Excel不忙于其他事情时发生。然而,让代码生成一个未经处理的错误是相当不确定的。特别是在64位操作系统上,异常很容易绕过VBA运行时提供的用于显示错误的任何backstop。丑陋的细节。只是故意产生一个错误以获得信任,请注意链接帖子中有关Win7的注释。