API声明:
Private Declare Function CallWindowProc Lib "user32.dll" Alias "CallWindowProcA" ( _
ByVal lpPrevWndFunc As Long, _
ByVal HWnd As Long, _
ByVal msg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
如果为lpPrevWndFunc
参数提供了一个不存在的函数指针,它会导致Excel崩溃。
同样地,
Private Declare Sub RtlMoveMemory Lib "kernel32" (ByRef Destination As LongPtr, _
ByRef Source As LongPtr, _
ByVal Length As Long)
当Destination
或Source
不存在时,会发生崩溃。
我认为这些错误都是内存访问违规。我猜 Windows 会告诉调用者它在做一些无法完成的事情-可能是发送消息给 Excel,但没有处理程序吗?MSDN对此有解释:
调用 Windows 动态链接库 (DLL) 或 Macintosh 代码资源时的系统错误不会导致异常,并且不能通过 Visual Basic 错误跟踪来捕获。 在调用 DLL 函数时,您应该检查每个返回值的成功或失败(根据 API 规范),并在发生故障时,检查 Err 对象的 LastDLLError 属性中的值。LastDLLError 在 Macintosh 上始终返回零。 (强调我自己)
但是,在这些情况下,我没有要检查错误的值,我只会崩溃。
1:提供它捕获错误并且不总是,如果说内存重写有效但未定义。但是肯定应该在执行之前捕获写入受限内存或调用虚假指针吧?
我最感兴趣的是:
是什么导致了这个崩溃(包括如何触发和背后的机制是什么 - Excel 如何知道需要崩溃?)。这些错误是通过哪个消息通道进行通信的,我能否使用 VBA 代码截取它们?
是否可以主动(例如清理输入等)或反应性(处理错误)地预防崩溃。
我认为(1)很可能会对(2)和反之产生启示。
无论如何,如果有人知道如何在 Excel 崩溃之前处理此类 API 错误,或者如何避免它们发生,或任何其他信息,请分享。 On Error Resume Next
似乎不起作用...
Sub CrashExcel()
On Error Resume Next 'Lord preserve us
'Copy 300 bytes from one non existent memory pointer to another
RtlMoveMemory ByVal 100, ByVal 200, 300
On Error Goto 0
Debug.Assert Err.LastDllError = 0 'Yay no errors
End Sub
动机
我提出这个问题有两个主要原因:
在开发代码(调试等过程)时,Excel每次出错都会崩溃,这使得开发变得更加困难。这不是简单的“自己写对了”就可以解决的问题(并向客户端代码公开使用我的现有API调用正确实现的不同接口),因为我很少一次就写对。
我想创建健壮的代码,能够处理用户输入中的错误(例如无效的函数指针或内存写入位置)。这可以通过将函数指针抽象成可调用类来处理一定程度上,但这不是其他类型dll错误的通用解决方案(仍然无法解决1.的问题)。
具体来说,我正在尝试开发一个友好的接口来包装WinAPI timers。这些需要使用回调函数进行注册,而(由于VBA的限制)必须采用Long
函数指针的形式(使用AddressOf
关键字生成)。
回调来自用户代码,可能是无效的。我包装的整个目的是提高API调用的稳定性,而这是需要改进的一个方面。
内存复制问题可能超出了这个问题的范围,这与在VBA中生成器有关,但我认为相同的错误处理技术也适用于那里,并且更容易举例说明。
我还从Timer API生成太多未处理消息而导致错误和崩溃。再一次地,我想知道,Windows如何告诉Excel“现在该崩溃了”,为什么我无法拦截该指令并自行处理错误(即杀死我做的所有定时器并刷新消息队列)?