获取当前VBA功能的名称

max*_*gen 30 ms-access vba

对于错误处理代码,我想获取发生错误的当前VBA函数(或子)的名称.有谁知道如何做到这一点?

[编辑]谢谢大家,我曾希望存在一个无证的技巧来自我确定功能,但这显然不存在.猜猜我会继续使用我当前的代码:

Option Compare Database: Option Explicit: Const cMODULE$ = "basMisc"

Public Function gfMisc_SomeFunction$(target$)
On Error GoTo err_handler: Const cPROC$ = "gfMisc_SomeFunction"
    ...
exit_handler:
    ....
    Exit Function
err_handler:
    Call gfLog_Error(cMODULE, cPROC, err, err.Description)
    Resume exit_handler
End Function
Run Code Online (Sandbox Code Playgroud)

jto*_*lle 15

没有什么可以获得当前的函数名称,但是您可以使用VBA对象生存期是确定性的这一事实构建一个相当轻量级的跟踪系统.例如,您可以使用以下代码创建名为"Tracer"的类:

Private proc_ As String

Public Sub init(proc As String)
    proc_ = proc
End Sub

Private Sub Class_Terminate()
    If Err.Number <> 0 Then
        Debug.Print "unhandled error in " & proc_
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

然后在例程中使用该类:

Public Sub sub1()
    Dim t As Tracer: Set t = New Tracer
    Call t.init("sub1")

    On Error GoTo EH

    Call sub2

    Exit Sub

EH:
    Debug.Print "handled error"
    Call Err.Clear
End Sub

Public Sub sub2()
    Dim t As Tracer: Set t = New Tracer
    Call t.init("sub2")

    Call Err.Raise(4242)
End Sub
Run Code Online (Sandbox Code Playgroud)

如果你运行'sub1',你应该得到这个输出:

unhandled error in sub2
handled error
Run Code Online (Sandbox Code Playgroud)

因为当错误导致例程退出时,'sub2'中的Tracer实例被确定性地销毁了.

这种一般模式在C++中以"RAII"的名称出现很多,但它在VBA中也能正常工作(除了使用类的一般烦恼之外).

编辑:

为了解决David Fenton的评论,即对于一个简单的问题,这是一个相对复杂的解决方案,我认为问题实际上并不那么简单!

我理所当然地认为我们都同意我们不希望在我们的VBA程序中为每个例程提供自己的错误处理程序.(请参阅我的推理:VBA错误"冒泡")

如果一些内部程序没有自己的错误处理程序,那么当我们捕获错误,我们所知道的是,在与解雇或在例行调用堆栈更深某处错误处理日常发生的事情.所以我理解的问题实际上是跟踪我们程序的执行情况.当然,追踪例行录入很容易.但追踪退出确实非常复杂.例如,可能会出现错误!

RAII方法允许我们使用VBA对象生命管理的自然行为来识别我们何时退出例程,无论是通过"退出","结束"还是错误.我的玩具示例只是为了说明这个概念.我自己的小VBA框架中真正的"跟踪器"肯定更复杂,但也做得更多:

Private Sub Class_Terminate()
    If unhandledErr_() Then
        Call debugTraceException(callID_, "Err unhandled on exit: " & fmtCurrentErr())
    End If

    If sendEntryExit_ Then
        Select Case exitTraceStatus_
            Case EXIT_UNTRACED
                Call debugTraceExitImplicit(callID_)
            Case EXIT_NO_RETVAL
                Call debugTraceExitExplicit(callID_)
            Case EXIT_WITH_RETVAL
                Call debugTraceExitExplicit(callID_, retval_)
            Case Else
                Call debugBadAssumption(callID_, "unrecognized exit trace status")
        End Select
    End If
End Sub
Run Code Online (Sandbox Code Playgroud)

但是使用它仍然非常简单,无论如何都比"每个例程中的EH"方法更少:

Public Function apply(functID As String, seqOfArgs)
    Const PROC As String = "apply"
    Dim dbg As FW_Dbg: Set dbg = mkDbg(MODL_, PROC, functID, seqOfArgs)

...
Run Code Online (Sandbox Code Playgroud)

自动生成样板很容易,虽然我实际输入然后自动检查以确保例程/ arg名称与我的测试一致.

  • 在我看来,这是一个相对简单问题的非常复杂的解决方案。 (2认同)

Ton*_*ews 6

我在免费的MZTools for VBA中使用错误处理程序按钮. 它会自动添加代码行以及子/函数名称.现在,如果您重命名子/函数,则必须记住更改代码.

MZTools内置了许多不错的功能.比如改进的查找屏幕,最重要的是一个按钮,显示调用此子/函数的所有位置.

  • 嗯,我已经使用 MZ 工具一年了……所以托尼,我现在使用的功能超过 1 或 2 个!作为一名长期的 Access 程序员(有他自己的一套好的/坏的做法),MZT 已成为“必备”的附件 :) 谢谢! (2认同)

mwo*_*e02 5

vbWatchdog是该问题的商业解决方案。就其功能而言,它的价格非常合理。除其他功能外,它还提供对 VBA 调用堆栈的完全访问。据我所知,没有其他产品可以做到这一点(而且我已经看过)。

还有其他几个功能,包括变量检查和自定义错误对话框,但仅访问堆栈跟踪就值得入场。

注意:除了我是一个非常满意的用户之外,我与该产品没有任何关系。


小智 5

严重地?为什么开发人员不断地一遍又一遍地解决同样的问题?使用 Err.Raise... 将过程名称发送到 Err 对象中

对于 Source 参数传入:

Me.Name & "." & Application.VBE.ActiveCodePane.CodeModule.ProcOfLine(Application.VBE.ActiveCodePane.TopLine, 0)
Run Code Online (Sandbox Code Playgroud)

我知道这不是最短的一个,但如果您买不起商业产品来增强 VBA IDE,或者像我们许多人一样,仅限于在锁定的环境中工作,那么这是最简单的解决方案。


p.c*_*ell 3

不使用任何内置的VBA方式。您能做的最好的事情就是通过将方法名称硬编码为常量或常规方法级变量来重复自己。

Const METHOD_NAME = "GetCustomer"

 On Error Goto ErrHandler:
 ' Code

ErrHandler:
   MsgBox "Err in " & METHOD_NAME
Run Code Online (Sandbox Code Playgroud)

您也许可以在MZ Tools for VBA中找到一些方便的东西。它是 VB 系列语言的开发人员插件。由 MVP 撰写。