tags:

views:

65

answers:

2

Hi All -

It is unlikely that there is an answer for this one, but I'm asking anyway.

I am currently maintaining some code, which is likely to be refactored soon. Before that happens, I want to make the standard error handling code, which is injected by an Add-In, more efficient and take up less space. One thing that annoys me is that every module has a constant called m_ksModuleName that is used to construct a big string, which is then rethrown from the error handler so we can trace the error stack. This is all template code, i.e. repetivitve, but I could easily strip it down to a procedure call. Now, I have fixed the code so that you can pass the Me reference to the procedure - but you can't do that for the BAS modules. Nor can you access the project name (the part which would be passed as part of a ProgramID, for instance) - although you get given it when you raise an error yourself.

All these strings are contained in the EXE, DLL or OCX - believe me, I've used a debugger to find them. But how can I access these in code?

-- Mark Bertenshaw

+1  A: 

I'm not sure of an easy way to programmatically get the name of the module that you are in. The usual solution is to set a variable at the top of each method to the name of the module, and then it is available to the error handler for use in logging:

'In MyModule.bas'

Public Sub Foo()

   Const MODULE_NAME As String = "MyModule"

   On Error GoTo ErrorHandler

   ' Code here '

   Exit Sub

ErrorHandler:

   LogError Err.Number, Err.Description, MODULE_NAME

End Sub   

If you are using an add-in such as MZTools, you have it generate this boilerplate code for you.

As for getting the current component name, you can access this using App.EXEName (despite the name, this works for other project types such as DLL's). This value is pulled from the Project Name field in the project's properties (Project -> Properties) when running in the IDE, and from the name of the compiled binary file (minus the file extension) when running outside the IDE.

Mike Spross
+1 For the module name part. You are not quite right about `App.ExeName` though. This is the root file name of the executable file (without the extension). It's not the same as *Project Name* - AFAIK the only way to access *Project Name* is by deliberately raising an error, trapping it, and reading the `Err.Source`, as mentioned in the question. However `App.ExeName` will usually do for diagnostic logging - it identifies the component. Help page on App.ExeName - http://msdn.microsoft.com/en-us/library/aa267360(v=VS.60).aspx
MarkJ
I had actually said I was using constants already. And as MarkJ says, you can't rely on App.ExeName for use in a ProgId. I independently came up with trapping a token error for Err.Source today already; but it is really annoying that you have to do this if the string is already buried in the executable!
Mark Bertenshaw
@MarkJ: Ah, you are right. I compiled a new ActiveX DLL where the DLL name was different from the project name, and sure enough `App.ExeName` returns the name of the DLL minus the file extension when run outside the IDE (I had a simple test class that would show `App.ExeName` and `App.Title` in a message box). `App.Title` will still return whatever is set under _Project Title_ in the project properties, so you might get away with using `App.Title` if you don't want to raise an catch an error to find the project name. I think `App.Title` always defaults to _Project Name_ for new projects.
Mike Spross
@Mark: I should have made it clearer in my answer that I was agreeing with whoever wrote the code originally. Using constants with the module name is the usual solution if you really do want the module name, since the best you can get from raising an error and reading back `Err.Source` is the project name. Since the module name is compiled into the executable, there are ways to get to it, but I'm not sure any of them would be easy or worth the huge hack that would probably be involved. As far as I know, there isn't a built-in function to get this information.
Mike Spross
@Mike: You are right as far as BAS files are concerned - there is no obvious way of getting their names. However, for non-BAS files, the original coders could have used TypeName(MyObject) where MyObject was the Me reference passed into a standard function.
Mark Bertenshaw
+1  A: 

AFAIK there's no way to get the name of a BAS module in code. The usual solution is to use a module-level constant as in Mike's answer.

AFAIK the only way to get the ProgID (programmatic ID, Project Name in project properties dialog) is to raise an error in a BAS module, trap it, and read the Err.Source.

It's all quite a hassle, and that's why we don't usually bother including the module name or the ProgID in our standard error handlers. We "roll our own" call stack, with the names of the routines. That's always enough information to find out which modules are involved. Routines in BAS modules usually have unique names, right?

Something like this, and you can add this automatically with the free MZTools VB6 add-in.

Sub / Function whatever 
On Error Goto Handler
do some stuff
Exit Sub / Function

Handler:
Err.Raise Err.Number, "(function_name)->" & Err.source, Err.Description 
End Sub

Every top-level routine in a DLL or OCX has a similar error handler but also includes App.ExeName so we can tell when errors cross component boundaries.

MarkJ
MarkJ - As I said in reply to Mike's answer, I independently worked out how to get the project name this morning. But since you've got half the answer, that's better than none! I have been going mad with the Visual Studio debugger, but still haven't worked out how to get at those embedded strings. As for MZTools: the legacy code used a modified version of their standard code. As you suggested, the error stack is persisted by throwing Source appended with the previous error stack. I just want some more maintainable code. Coders have changed names, and not updated the associated strings.
Mark Bertenshaw