Excel 在VBA中使用异步回调函数安全吗?

Excel 在VBA中使用异步回调函数安全吗?,excel,vba,windows,multithreading,winapi,Excel,Vba,Windows,Multithreading,Winapi,关于这个问题的评论太长了,所以我会在这里提问 在VBA代码中使用回调函数指针是否安全(至少从我下面谈到的问题来看);考虑到它与宿主应用程序的关系和解释器的特殊性 关于使用WinAPI注册回调讨论了操作系统调用回调函数时导致崩溃的潜在陷阱。具体来说,它询问为什么与工作表交互偶尔会导致TIMERPROC回调出现问题。阅读描述后,我立即想到的是Excel对象模型 这个问题包括一段“有效”的代码摘录,但我不会在这里包括它,因为我认为一个相关的问题实际上更简洁地说明了这一点: 我能用计算机解决它 On

关于这个问题的评论太长了,所以我会在这里提问

在VBA代码中使用回调函数指针是否安全(至少从我下面谈到的问题来看);考虑到它与宿主应用程序的关系和解释器的特殊性


关于使用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的开发人员]被假定为 已将错误处理和应急管理落实到位 呼叫代码

这些假设是:

  • 指针后面肯定会有一个有效的函数
  • 当它被调用时,它肯定是可用的
  • …并且不会给调用方带来任何错误
  • 第3点(我认为)与具体问题最相关,我认为是什么导致了OP的崩溃

    我担心的是,一些评论(,)暗示(至少在我看来)第2点可能是罪魁祸首;Excel处于“编辑模式”会以某种方式暂停VBA代码的运行,这意味着操作系统无法运行回调,而是会出现“Excel正忙”错误

    我知道VBA代码通常在主机的主/UI线程中运行,这意味着如果Excel忙于运行其他UI内容,那么VBA将无法执行。但是,读取
    WM_TIMER
    消息并最终运行回调的消息循环必然与我的VBA代码位于同一线程中;因此,当Excel实际上正忙于处理其他UI消息时,不会调用回调。确保Excel对象模型可能处于某种状态,这意味着尝试访问它将引发错误,但问题是向调用者引发错误,而不是回调不可用


    同时,OP和一些人暗示他们的问题实际上是第三个因素(第1点-函数指针无效)。他们所写的内容似乎表明,函数指针后面的TimerProc正在被垃圾收集,并在执行过程中的某个时刻失效,OERN通过保存对它的引用使它保持活动状态

    然而,整个想法在我看来真的很奇怪;函数不是VBA中的一级公民,我认为它们不遵循COM引用计数(无论如何,什么会保存对它们的引用,指针只是一个数字而不是引用?)。我假设函数指针是在编译时设置的,甚至是在
    End
    语句和reset按钮之间设置的,所以我不确定是什么让它们超出OP建议的范围。我还认为,如果他们这样做了,通常会对VBA代码产生影响,而不仅仅是在使用API时。所以我不确定这是否真的是一个值得担心的问题


    TL;博士 在异步单线程代码中使用回调时(例如使用
    SetTimer
    API),是否存在以下风险:

    • 调用之间的回调超出范围,因此提供给API的函数指针无效
    • Excel/当调用回调时,主机应用程序处于“忙碌状态”,因此调用失败
    我可以想象为什么这些可能是跨线程的问题,但我认为构建Windows的整个消息队列系统可以防止这成为单线程VBA代码的问题

    或者换句话说,我认为:

    • 主机应用程序不应影响该线程上VBA代码的“可用性”
    • 在我点击F5之后,没有理由让函数指针变得无效(不可调用)——除了一些手动内存破坏

    哦,请结合上下文阅读这些评论,我很可能完全误解了它们:)(我在这方面没有太多经验)

    这并不像看上去那么糟糕,回调仍然是同步的,只有在Excel不忙于其他事情时才会发生。然而,让代码生成一个未经处理的错误是相当不确定的。特别是在64位操作系统上,异常很容易绕过VBA运行时提供的用于显示错误的任何backstop。丑陋的细节。只是有意地生成一个错误以获得信任,请注意链接帖子中有关Win7的注释。它并没有看上去那么糟糕,回调仍然是同步的,并且只能在Excel不忙于其他事情时发生。然而,让代码生成一个未经处理的错误是相当不确定的。特别是在64位操作系统上,异常很容易绕过VBA运行时提供的用于显示错误的任何backstop。丑陋的细节。只是故意产生一个错误以获得信任,请注意链接帖子中有关Win7的注释。