UtterAccess.com
X   Site Message
(Message will auto close in 2 seconds)

Welcome to UtterAccess! Please ( Login   or   Register )

Custom Search
2 Pages V  1 2 >  (Go to first unread post)
   Reply to this topicStart new topic
> How Can I Access The Call Stack In VBA    
 
   
RiverKing
post Jun 4 2018, 09:32 PM
Post#1



Posts: 171
Joined: 5-August 13
From: North Texas (DFW)


Is there any way I can access the Call Stack from my VBA code. There is an enumerated command, acCmdCallStack, but I can't find any information on how I can use it . . . if I can.

I've got a small routine that is essentially an error trapping function called "IsDefned". IsDefined returns True if the Control identified in the arguments has been defined or False if not (Err 2465). It might make future debugging easier if the error message, displayed when Err<>0 and Err<>2465, could include information from the Call Stack identifying the routine that invoked IsDefined. (Then too, the ability to display such information would probably mean that it is never, ever needed...Murphy's Law.)

Go to the top of the page
 
DanielPineault
post Jun 5 2018, 04:57 AM
Post#2


UtterAccess VIP
Posts: 6,994
Joined: 30-June 11



You'd need to turn towards something like https://www.everythingaccess.com/vbwatchdog/callstack.htm
Go to the top of the page
 
isladogs
post Jun 5 2018, 05:55 AM
Post#3


UtterAccess VIP
Posts: 1,879
Joined: 4-June 18
From: Somerset, UK


Sorry - probably me being dense - but if variable declaration is required, Access will tell you if a variable hasn't been defined.
Breaking the code will take you to the offending item or at least close to it.
Adding line numbers will pin it down precisely
Why do you need to add another level of complexity?

I use this as generic error handling code which allows for line handling where used:

CODE
Sub ExampleProc()

On Error GoTo Err_Handler

'other code here ....

Exit_Handler:
    Exit Sub

Err_Handler:
    strProc = "" 'add proc name here
    If Erl > 0 Then 'line numbers used
        MsgBox "Error " & Err.Number & " in line " & Erl & " in " & strProc & " procedure : " & vbCrLf & _
            Err.description, vbCritical, "Code error"
    Else 'no line numbers
        MsgBox "Error " & Err.Number & " in " & strProc & " procedure : " & vbCrLf & _
            Err.description, vbCritical, "Code error"
    End If

    Resume Exit_Handler
    
End Sub

This post has been edited by isladogs: Jun 5 2018, 06:01 AM
Go to the top of the page
 
GroverParkGeorge
post Jun 5 2018, 06:32 AM
Post#4


UA Admin
Posts: 36,165
Joined: 20-June 02
From: Newcastle, WA


Perhaps I too am missing something, but I think isladog has raised a valid point.

Your routine is intended to determine whether a variable has been defined before being used. Option Explicit does that. Why do you need a roll-your-own version of that same thing?

On the other hand, if you want to pursue the idea of investigating the call stack as an end in itself, the link Daniel provided is about the most effective way to do that of which I am aware.
Go to the top of the page
 
cheekybuddha
post Jun 5 2018, 06:50 AM
Post#5


UtterAccess Moderator
Posts: 11,857
Joined: 6-December 03
From: Telegraph Hill


Curious link you posted, Chuck!

Couldn't find any reference to acCmdCallStack!
Go to the top of the page
 
JonSmith
post Jun 5 2018, 07:22 AM
Post#6


UtterAccess VIP
Posts: 4,053
Joined: 19-October 10



I can 100% recommend logging the call stack in error logging. Its pretty amazing to see what has called it. Lets say you loop through 100 files and deep in the callstack of processing one of the files you get an error. You aren't there to debug at runtime, its a compiled database deployed to your users.
If you just look at the logs IsDefned is shown as the culprit, but if thats used in lots of places how do you know which place it failed. If it works on most files how do you find the one that fails? Its alot of detective work.
With a callstack you can look into this. I actually ended up developing my error handling so it builds the callstack into an XML file, this makes it function as generic logging aswell as error logging. At a quick glance I can see its the 50th file that threw the error and that it was field 32.
Armed with all this info I can root cause extremely quickly.
Sadly though I have no further info about that command. I can also find it in the object browser but I've failed to use it successfully in VBA.



Daniel, thats an interesting addin. Would the caveat be that you need that extra software installed on any machine running the VBA code you write? I can only assume as such but couldn't find any such claims for or against on the site.

JS
Go to the top of the page
 
DanielPineault
post Jun 5 2018, 07:26 AM
Post#7


UtterAccess VIP
Posts: 6,994
Joined: 30-June 11



QUOTE
Daniel, thats an interesting addin. Would the caveat be that you need that extra software installed on any machine running the VBA code you write? I can only assume as such but couldn't find any such claims for or against on the site.


I couldn't say. I have never used it myself, but several other MVPs swear by it as well as their vbMAPI (https://www.everythingaccess.com/vbmapi.asp)! Those that recommended it I trust implicitly!!!
Go to the top of the page
 
isladogs
post Jun 5 2018, 07:37 AM
Post#8


UtterAccess VIP
Posts: 1,879
Joined: 4-June 18
From: Somerset, UK


I had the same issue trying to pin down the cause of vague error descriptions from some clients.
My solution was to introduce error logging on every procedure (error number and description, procedure name, user name, workstation, screen resolution, app version, Access version, windows version)
Then, with clients permission, an email was sent 'silently' to me so I got accurate and full details of each error.
It was a lot of work and, for a few weeks after launch, I regretted it, but once I had fixed the issues arising, all errors became a thing of the past.
That is apart from one client where I was finally able to prove that issues were due to repeated network interruptions.

Anders Ebro (smiley coder) has something similar on his website though minus the email.

I'd be interested to know how the call stack idea compares in terms of coding required and information provided.
Go to the top of the page
 
JonSmith
post Jun 5 2018, 07:43 AM
Post#9


UtterAccess VIP
Posts: 4,053
Joined: 19-October 10



Give me some time and I'll fully flesh out my example.

JS
Go to the top of the page
 
RiverKing
post Jun 5 2018, 11:33 AM
Post#10



Posts: 171
Joined: 5-August 13
From: North Texas (DFW)


Jon: We're on the same page until you put call stack data in a separate file. Your reasons for doing so are exactly what I had in mind but I'm not willing, particularly in the case at hand, to go to that much work creating a solution that hopefully will never be needed.

In my case, I'm settling for the Form and Control specified when the Control has not been defined. Not having been defined, by the way, is not necessarily an error in this case and there is no need for an error message. In fact, it may even be better to rework the code a little bit to trap the error and ignore it when appropriate. That approach might also yield a bit less code. I'm all for that and will try it when I get a chance.


Go to the top of the page
 
isladogs
post Jun 5 2018, 11:45 AM
Post#11


UtterAccess VIP
Posts: 1,879
Joined: 4-June 18
From: Somerset, UK


@RiverKing
Please see the first part of my earlier post #3
Do you have variable declaration required ticked in the VBE & option explicit on every code module.?
If not, you should do so & then compile to check for any missing variable definitions.
Your databases should never be distributed unless they are fully compiled having done the above.

If you're already doing this, there will be no missing variable definitions
This post has been edited by isladogs: Jun 5 2018, 11:46 AM
Go to the top of the page
 
cheekybuddha
post Jun 5 2018, 01:06 PM
Post#12


UtterAccess Moderator
Posts: 11,857
Joined: 6-December 03
From: Telegraph Hill


>> There is an enumerated command, acCmdCallStack, <<

Still not sure how Laura Ingraham's tweet stack relates to the Access call stack! grin.gif
Go to the top of the page
 
GroverParkGeorge
post Jun 5 2018, 01:39 PM
Post#13


UA Admin
Posts: 36,165
Joined: 20-June 02
From: Newcastle, WA


"...Not having been defined, by the way, is not necessarily an error in this case..."

Please explain a process that would somehow generate a NEW variable, on the fly, without declaring it. How would that work?
Go to the top of the page
 
RiverKing
post Jun 5 2018, 11:07 PM
Post#14



Posts: 171
Joined: 5-August 13
From: North Texas (DFW)


In the case at hand, a missing definition would definitely be a programming error on my part. The routine in question will, however, be invoked by the Change Event for almost all Controls on five different Forms and the Current Event for all of those Forms. Being somewhat human, it would not surprise me if one would slip through and cause a problem. What I'm looking for is the most elegant solution (least coding) that will identify the miscreant if this happens. To put it another way, having such a solution in place will mean that Err is always zero after the common Procedure tries to reference one of these Controls.

I think the best solution is going to be a simple error message with Err.Description and the identification of the Control that was not found (Err.Description doesn't do this; it just says, essentially, that a Control was not found without identifying what could not be found).


Go to the top of the page
 
DanielPineault
post Jun 6 2018, 07:34 AM
Post#15


UtterAccess VIP
Posts: 6,994
Joined: 30-June 11



Adding line numbers to a procedure and reporting them greatly helps. You can also customize the description and add procedure specific elements (ctl.name, ...).
Go to the top of the page
 
GroverParkGeorge
post Jun 6 2018, 08:30 AM
Post#16


UA Admin
Posts: 36,165
Joined: 20-June 02
From: Newcastle, WA


Option Explicit in each and every module.

Attached File  optionexplicit.jpg ( 16.96K )Number of downloads: 0


And ALWAYS compile before deploying your code. Problem solved. No new code needed.
Attached File  DebugCompile.jpg ( 34.84K )Number of downloads: 1


That's really all there is to do. What I see here is the equivalent of putting up a barbed wire fence around the outside of an existing chain link fence. Interesting, perhaps, but totally redundant.
Go to the top of the page
 
isladogs
post Jun 6 2018, 08:40 AM
Post#17


UtterAccess VIP
Posts: 1,879
Joined: 4-June 18
From: Somerset, UK


QUOTE
That's really all there is to do. What I see here is the equivalent of putting up a barbed wire fence around the outside of an existing chain link fence. Interesting, perhaps, but totally redundant.


LOL - I agree completely - plus an electric fence as well
Go to the top of the page
 
JonSmith
post Jun 6 2018, 09:14 AM
Post#18


UtterAccess VIP
Posts: 4,053
Joined: 19-October 10



Completely agree here.
The callstack can be awesome at finding errors and good error logging is essential. But the scope defined here, finding missing controls, can and should be solved with Option Explicit and Compile.

JS
Go to the top of the page
 
JonSmith
post Jun 6 2018, 11:02 AM
Post#19


UtterAccess VIP
Posts: 4,053
Joined: 19-October 10



ok, so here is my call stack error logging is great example.

Attached is a screenshot from a new little database I rebuilt the past couple of days.
Its purpose is basically it process 4 types of input files that hold the same type of information but in very different formats. So it basically reads them and maps them all to a standard table present in a SQL server. It does more than that but for this example thats all that relevant.

The screenshot shows my logging screen. It shows the call stack of all the actions I just took. It shows how I loaded a few forms, I changed a calendar value a few times (I have a custom calendar control) and pressed the Import Data button a few times (cmdImportData).
You'll see that when I pressed that button at 17:24:17 its highlighted in orange. This is because there is an error in that call stack.

If you dive into the call stack you see a Note saying it was processing import data from the 05/06/2018 (dd/mm/yyyy format tongue.gif), this is the first key bit of information my stack provides.
Next if you look at the events raised by the ImportData event, it calls ImportChecksFile 3 times, the first 2 times seemed to work. The third one is orange so thats the problem one.
Again dive deeper and you see the error value. If I click on it I can see that its a read/write issue to the file, someone has it open.
A few nodes earlier I can see another note that indicated which file ImportChecksFile was trying to process (I've blanked out the actual UNC path in red).

Now imagine if I didn't have that call stack and just got the error message. I still get useful information. I can tell I need to make sure I close a file, but which file....? If I process 100 files its kind of a slog to work out which one is the issue right? With this I can root cause it instantly and without asking an end user to try and recreate an issue for me. I can just check these logs and boom. Problem found and solved. It also works as a great audit trail.

What is also awesome in this is at any point I can check if my call stack has errors in VBA.
So once I finished looping files at the end of routine I can see if the stack contains any errors. If it does I can warn the user that there were issues during the import and that they need to view the logs. Its a great way of passing information up really easily.

All of this is implemented very easily too. I use MzTools to make mine even easier but basically I just need the following at the top and bottom each of my procs


CODE
On Error GoTo MyError: MessageHandler.StartEvent ("_EventNameGoesHere")


And at the end I have

CODE
EndEvent:           MessageHandler.EndEvent: Exit Sub
MyError:           Call MessageHandler.LogErrorMessage(Err.Number, Err.Description, "_EventNameGoesHere", "modFunctions", Erl, boolSupressErrMessage): GoTo EndEvent
End Sub



Because I use MzTools all the 'variable' information such as the procedure name or the module name are automatically added when I use the 'add error handler' button. Its really all just done with a single click.

All of my logs are in XML format, stored externally from the database itself. This is for many reasons, one is so I can use the same methodology in other VBA programs such as Excel or Word but also because XML is well suited to this kind of 'nested' data. I did once start looking in recording it into a standard table but I would lose alot of huge benefits I get from the XML that allow me to process it really easily. As a result I abandoned that train of thought.

Hopefully this demonstrates how useful this stuff can be! Its made troubleshooting user issues a 5 minute job for me these days rather than significantly longer.

JS
Attached File(s)
Attached File  Capture.PNG ( 51.98K )Number of downloads: 19
 
Go to the top of the page
 
GroverParkGeorge
post Jun 6 2018, 12:39 PM
Post#20


UA Admin
Posts: 36,165
Joined: 20-June 02
From: Newcastle, WA


"...Because I use MzTools all the 'variable' information such as the procedure name or the module name are automatically added when I use the 'add error handler' button. Its really all just done with a single click."

One of my favorite tools for this reason, among others.
Go to the top of the page
 
2 Pages V  1 2 >


Custom Search


RSSSearch   Top   Lo-Fi    5th December 2019 - 07:15 PM