如何在运行时获取过程或函数名? [英] How to get the procedure or function name at runtime?

查看:142
本文介绍了如何在运行时获取过程或函数名?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在运行时返回函数或过程名称的方式是否有



我目前正在处理这样的错误:

  Sub foo()
Const proc_name as string =foo
错误GoTo ErrHandler

'做东西

ExitSub:
退出子
ErrHandler:
ErrModule.ShowMessageBoxModuleName,proc_name
恢复ExitSub
End Sub

最近,在更新了函数名称后,我最近经历了一个常数,而不是常量值。我想将过程的名称返回到我的错误处理程序。



我知道我必须与$ code> VBIDE.CodeModule 对象找到它。我已经使用Microsoft Visual Basic应用程序扩展库进行了一些元编程,但是我在运行时没有做到这一点。我没有以前的尝试,在我再次尝试这个尝试之前,我想知道是否可以远程进行。



事情这不会工作


  1. 使用一些内置的VBA库访问调用堆栈。它不存在

  2. 当我进入和退出每个人时,通过从数组中推送和弹出过程名称来实现我自己的调用堆栈。这仍然需要我将proc名称作为一个字符串传递给别的地方。

  3. 第三方工具,如 vbWatchDog 。这个 可以正常工作,但是我不能使用这个项目的第三方工具。

注意



vbWatchdog似乎做这通过API调用直接访问内核内存。

解决方案

我不太确定这将是多么有用..



好的是,您不必担心子/函数名称 - 您可以自由更改它。所有您需要关心的是错误处理程序标签名称的唯一性。



例如



如果您可以避免重复的错误处理程序标签在不同的子/功能



不要做⇩⇩ ⇩⇩

  Sub Main()
错误GoTo ErrHandler
Debug.Print 1 / 0

ErrHandler:
Debug.Print主要处理错误
SubMain
End Sub

Sub SubMain()
错误GoTo ErrHandler
Debug.Print 1/0

ErrHandler:
Debug.PrintSubMain中的处理错误
End Sub

然后下面的代码应该工作。



注意:我无法彻底测试,但我确信你可以调整它,如果有任何帮助,可以让它工作。 em>



注意:添加引用到 Visual Basic for Applications可扩展性5.3 通过工具 - > VBE中的引用



  Sub Main()

'另外你还应该做什么:
'写一个布尔函数,检查是否没有重复的错误处理程序标签
'这将确保您没有收到错误的子/ fn名称返回

Foo
Boo

End Sub


功能Foo()

'记住在处理程序
'中设置标签名称(handlerLabel)每个处理程序标签应该是唯一的,以避免错误
错误GoTo FooErr
单元格(0,1)= vbNullString故意导致错误

FooErr:

Dim handlerLabel $
handlerLabel =FooErr或不要暗淡并通过errHandler名称直接到GetFnOrSubName函数

Debug.Print发生在& Application.VBE.ActiveCodePane.CodeModule.Name& :& GetFnOrSubName(handlerLabel)

结束函数


Sub Boo()

错误GoTo BooErr
单元格(0, 1)= vbNullString'故障原因

BooErr:

Debug.Print错误发生在& Application.VBE.ActiveCodePane.CodeModule.Name& :& GetFnOrSubName(BooErr)

End Sub

'返回GetFnOrSubName中需要的CodeModule引用fn
专用函数GetCodeModule(codeModuleName As String)作为VBIDE.CodeModule
Dim VBProj作为VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent

设置VBProj = ThisWorkbook.VBProject
设置VBComp = VBProj.VBComponents(codeModuleName)

设置GetCodeModule = VBComp.CodeModule
结束函数

'返回发生错误的sub的名称
私有函数GetFnOrSubName $(handlerLabel $)

Dim VBProj作为VBIDE.VBProject
Dim VBComp作为VBIDE.VBComponent
Dim CodeMod作为VBIDE.CodeModule

设置VBProj = ThisWorkbook.VBProject
设置VBComp = VBProj.VBComponents(Application.VBE.ActiveCodePane.CodeModule.Name)
设置CodeMod = VBComp.CodeModule

代码$
代码= CodeMod.Lines(1,CodeMod .CountOfLines)

Dim handlerAt&放大器;
handlerAt = InStr(1,code,handlerLabel,vbTextCompare)

如果handlerAt然后

Dim isFunction&
Dim isSub&

isFunction = InStrRev(Mid $(code,1,handlerAt),Function,-1,vbTextCompare)
isSub = InStrRev(Mid $(code,1,handlerAt) Sub,-1,vbTextCompare)

如果isFunction> isSub Then
'它是一个函数
GetFnOrSubName = Split(Mid $(code,isFunction,40),()(0)
Else
'它是一个子
GetFnOrSubName = Split($ $(code,isSub,40),()(0)
End If

End If

End Function


Is there any way to return the name of a function or procedure at runtime?

I'm currently error handling something like this:

Sub foo()
Const proc_name as string = "foo"
On Error GoTo ErrHandler

    ' do stuff

ExitSub:
    Exit Sub
ErrHandler:
    ErrModule.ShowMessageBox "ModuleName",proc_name
    Resume ExitSub
End Sub

I recently experienced one of my constants lying to me after I updated a function name, but not the constant value. I want to return the name of the procedure to my error handler.

I know that I will have to interact with the VBIDE.CodeModule object to find it. I've done a little bit of meta-programming with the Microsoft Visual Basic for Applications Extensibility library, but I've not had any success with doing this at runtime. I don't have my previous attempts, and before I dig my heels in to try this again, I want to know if it's even remotely possible.

Things that won't work

  1. Using some built in VBA Library to access the call stack. It doesn't exist.
  2. Implementing my own call stack by pushing and popping procedure names from an array as I enter and exit each one. This still requires that I pass the proc name somewhere else as a string.
  3. A third party tool like vbWatchDog. This does work, but I can't use a third party tool for this project.

Note

vbWatchdog seems to do this by directly accessing the kernel memory via API calls.

解决方案

I am not quite sure how helpful this is going to be...

The good thing is that you will not have to worry about the sub/function name - you are free to change it. All you have to care about is the uniqueness of the error handler label name.

For example

if you can avoid duplicate error handler labels in different subs/functions

don't do ⇩⇩⇩⇩⇩

Sub Main()
    On Error GoTo ErrHandler
    Debug.Print 1 / 0

ErrHandler:
    Debug.Print "handling error in Main"
    SubMain
End Sub

Sub SubMain()
    On Error GoTo ErrHandler
    Debug.Print 1 / 0

ErrHandler:
    Debug.Print "handling error in SubMain"
End Sub

then the below code should work.

Note: I haven't been able to test it thoroughly but I am sure you can tweak it and get it work if it's of any help.

Note: Add references to Visual Basic for Applications Extensibility 5.3 via Tools -> References in VBE

Sub Main()

    ' additionally, this is what else you should do:
    ' write a Boolean function that checks if there are no duplicate error handler labels
    ' this will ensure you don't get a wrong sub/fn name returned

    Foo
    Boo

End Sub


Function Foo()

    ' remember to set the label name (handlerLabel) in the handler
    ' each handler label should be unique to avoid errors
    On Error GoTo FooErr
    Cells(0, 1) = vbNullString ' cause error deliberately

FooErr:

    Dim handlerLabel$
    handlerLabel = "FooErr" ' or don't dim this and pass the errHandler name directly to the GetFnOrSubName function

    Debug.Print "Error occured in " & Application.VBE.ActiveCodePane.CodeModule.Name & ": " & GetFnOrSubName(handlerLabel)

End Function


Sub Boo()

    On Error GoTo BooErr
    Cells(0, 1) = vbNullString ' cause error deliberately

BooErr:

    Debug.Print "Error occured in " & Application.VBE.ActiveCodePane.CodeModule.Name & ": " & GetFnOrSubName("BooErr")

End Sub

' returns CodeModule reference needed in the GetFnOrSubName fn
Private Function GetCodeModule(codeModuleName As String) As VBIDE.CodeModule
    Dim VBProj As VBIDE.VBProject
    Dim VBComp As VBIDE.VBComponent

    Set VBProj = ThisWorkbook.VBProject
    Set VBComp = VBProj.VBComponents(codeModuleName)

    Set GetCodeModule = VBComp.CodeModule
End Function

' returns the name of the sub where the error occured
Private Function GetFnOrSubName$(handlerLabel$)

    Dim VBProj As VBIDE.VBProject
    Dim VBComp As VBIDE.VBComponent
    Dim CodeMod As VBIDE.CodeModule

    Set VBProj = ThisWorkbook.VBProject
    Set VBComp = VBProj.VBComponents(Application.VBE.ActiveCodePane.CodeModule.Name)
    Set CodeMod = VBComp.CodeModule

    Dim code$
    code = CodeMod.Lines(1, CodeMod.CountOfLines)

    Dim handlerAt&
    handlerAt = InStr(1, code, handlerLabel, vbTextCompare)

    If handlerAt Then

        Dim isFunction&
        Dim isSub&

        isFunction = InStrRev(Mid$(code, 1, handlerAt), "Function", -1, vbTextCompare)
        isSub = InStrRev(Mid$(code, 1, handlerAt), "Sub", -1, vbTextCompare)

        If isFunction > isSub Then
            ' it's a function
            GetFnOrSubName = Split(Mid$(code, isFunction, 40), "(")(0)
        Else
            ' it's a sub
            GetFnOrSubName = Split(Mid$(code, isSub, 40), "(")(0)
        End If

    End If

End Function

这篇关于如何在运行时获取过程或函数名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆