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
- Using some built in VBA Library to access the call stack. It doesn't exist.
- 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.
- 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 use a linked node based stack class wrapped in a singleton, globally instanced (done through Attributes)
CallStack
class. It allows me to perform error handling like David Zemens suggests (saving the procedure name each time):If it would be helpful to the discussion, I can post the associated code. The CallStack class has a
Peek
method to find out what the most recently called function is and aStackTrace
function to get a string output of the entire stack.More specifically to your question, I've always been interested in using VBA Extensibility to add the boiler-plate error handling code (as above) automatically. I've never gotten around to actually doing it, but I believe it's quite possible.
Use Err.Raise
For the Source parameter pass in:
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 ⇩⇩⇩⇩⇩
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 VBEAdd this function in any module you like:
And then in your sub/function use this as Err Handler:
The following does not exactly answer my question, but it does solve my problem. It will need to be run during development prior to publishing the application.
My workaround relies on the fact that all of my constants are named the same because I am using CPearson's code to insert the constants into my procedures during development.
The VBIDE library doesn't support procedures well, so I wrapped them up in a class module named
vbeProcedure
.Then I added a function to my
DevUtilities
module (that's important later) to create avbeProcedure
object and return a collection of them.Next I loop through each procedure in a given code module.
Finally calling that sub for each code module in my active project (so long as it isn't my "DevUtilities" module).
I'll come back if I ever figure out what kind of sorcery vbWatchDog is using to expose the vba call stack.