Текущее имя функции получить нечего, но вы можете создать довольно легкую систему трассировки, используя тот факт, что время жизни объекта 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
, а затем использовать этот класс в процедурах, таких как:
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
Если вы запустите «sub1»,вы должны получить следующие выходные данные:
unhandled error in sub2
handled error
, потому что ваш экземпляр Tracer в 'sub2' был детерминированно уничтожен, когда ошибка вызвала выход из подпрограммы.
Этот общий паттерн часто встречается вC ++, под названием «RAII», но он прекрасно работает и в VBA (кроме общего раздражения от использования классов).
РЕДАКТИРОВАТЬ:
Чтобы ответить на комментарий Дэвида Фентона, что этоОтносительно сложное решение простой проблемы, я не думаю, что проблема на самом деле настолько проста!
Я считаю само собой разумеющимся, что мы все согласны с тем, что мы не хотим давать каждую процедуру внаша программа VBA имеет собственный обработчик ошибок.(См. Мои рассуждения здесь: Ошибка VBA "Bubble Up" )
Если некоторые внутренние подпрограммы не имеют своих собственных обработчиков ошибок, тогда, когда мы делаем ловимошибка, все, что мы знаем, это то, что произошло в подпрограмме с обработчиком ошибок, который сработал, или в подпрограмме где-то глубже в стеке вызовов.Так что проблема, насколько я понимаю, на самом деле заключается в отслеживании выполнения нашей программы.Отслеживание рутинного входа легко, конечно.Но отслеживание выхода действительно может быть довольно сложным.Например, может быть ошибка, которая возникает!
Подход 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
Но использовать его все же довольно просто, и он стоит меньше шаблонного, чем «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)
...
Автоматически сгенерировать шаблон очень просто, хотя я на самом деле набираю его, а затем автоматически проверяю, совпадают ли имена подпрограмм / аргументов как часть моих тестов.