首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在VBA中处理DLL错误?

如何在VBA中处理DLL错误?
EN

Stack Overflow用户
提问于 2019-05-22 04:30:32
回答 1查看 0关注 0票数 0

API欺骗

代码语言:javascript
复制
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 。

同样

代码语言:javascript
复制
Private Declare Sub RtlMoveMemory Lib "kernel32" (ByRef Destination As LongPtr, _
                                                  ByRef Source As LongPtr, _
                                                  ByVal Length As Long)

不幸DestinationSource不存在时不开心。

我认为对于这两种错误都是内存访问违规。我假设Windows告诉调用者它正在做它不能做的事情 - 也许它向Excel发送消息并且没有处理程序?MSDN对此有这样的说法:

调用Windows动态链接库(DLL)或Macintosh代码资源期间的系统错误不会引发异常,也不会使用Visual Basic错误捕获捕获。调用DLL函数时,应检查每个返回值的成功或失败(根据API规范),如果发生故障,请检查Err对象的LastDLLError属性中的值。LastDLLError始终在Macintosh上返回零。 (强调我自己)

但在这些情况下,我没有检查错误的价值,我只是遇到了崩溃。

我最感兴趣的是:

  1. 导致崩溃的原因(它是如何被触发的,以及它背后的机制到底是什么 - Excel如何知道它需要崩溃?)。传递这些错误的消息通道是什么,我可以用VBA代码拦截它们吗?
  2. 是否可以主动(即消毒输入等)或反复主动(处理错误)防止崩溃

我认为(1)可能会阐明(2),反之亦然

无论如何,如果有人知道如何在没有Excel崩溃的情况下处理像这样的API错误,或者如何避免它们发生,或者任何可能发生的事情。On Error Resume Next似乎不起作用......

代码语言:javascript
复制
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

用例

我的用例是尝试创建一个友好的界面来包装WinAPI计时器。这些要求回调函数与它们一起注册,它们(鉴于VBA的限制)必须以Long函数指针的形式出现(用AddressOf关键字生成)。

回调来自用户代码,可能无效。我的包装的重点是提高API调用的稳定性,这是一个需要改进的领域。

内存复制问题可能超出了这个问题的范围,它与在VBA中生成生成器有关,但我认为相同的错误处理技术也适用于那里,并且它提供了一个更简单的示例。

我也从Timer API中获取错误和崩溃,为Excel生成太多未处理的消息。我再次想知道,Windows如何告诉Excel“现在崩溃的时间”,为什么我不能拦截该指令并自己处理错误(即杀死我制作的所有计时器并刷新消息队列)?

EN

回答 1

Stack Overflow用户

发布于 2019-05-22 14:06:40

来自评论:

当然,如果我进行了错误的API调用,那么我必须让Excel /我的代码知道它很糟糕

不必要。如果您要求API函数(例如RtlMoveMemory)覆盖您提供指针的位置的内存,它将乐意尝试这样做。然后会发生很多事情:

  • 如果内存不可写(例如代码),那么您将很幸运地获得访问冲突,这将在它可以造成更多损害之前终止该过程。
  • 如果内存可写,它将被覆盖并因此被破坏,之后所有的赌注都将被关闭。

来自你的评论:

我正在设计代码来附加用户提供的回调函数

另一种方法是使用客户端代码可以实现的方法设计接口。然后要求客户端传递实现该接口的类的实例。

如果您的客户端是VBA,那么定义接口的简单方法是使用一个或多个空方法创建公共VBA类模块。按照惯例,您应该使用I(for interface)前缀命名此类- 例如IMyCallback。空方法(子或函数)可以有任何你想要的签名,但我会保持简单:

例:

代码语言:javascript
复制
Class module name: IMyCallback

Option Explicit

Public Sub MyMethod()

End Sub

或者,如果客户端使用VBA以外的语言,则可以使用IDL定义接口,将其编译为类型库,并从VBA项目中引用类型库。我不会再进一步​​讨论这个问题,但如果你想跟进它,可以提出另一个问题。

然后,您的客户端应该创建一个类(VBA类模块),以他们选择的任何方式实现此接口,例如通过创建类模块ClientCallback

代码语言:javascript
复制
Class module name: ClientCallback

Option Explicit

Implements IMyCallback

Private Sub IMyCallback_MyMethod()
    ' Client adds his implementation here
End Sub

然后,您公开一个类型的参数,IMyCallback您的客户端可以传递他的类的实例。

你的方法:

代码语言:javascript
复制
Public Sub RegisterCallback(Callback as IMyCallback)
    ...
End Sub

客户代码:

代码语言:javascript
复制
Dim objCallback as New ClientCallback
RegisterCallback Callback
…

然后,您可以实现从Timer调用的自己的回调函数,并通过该接口安全地调用客户端代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100009047

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档