VBAStack - Read the callstack in VBA6 and 7 (2 Viewers)

Once we have the stack frames, is it possible to get a list of the local variables and their values?
I haven't worked on local variables much. Values should be possible, fairly easy even - their names would be an ordeal though, Access never loads them in a compiled MDE. I'd have to read the compressed streams that the VBE stores, which I don't think would be feasible in VBA itself. I have however figured out how to get parameter names and values.

I would link my Github, but I don't seem to be able to post links. I think I can attach the file, though? It's definitely too long to fit in a post here now. I've had to attach it as a .txt instead of a .bas due to allowed file types.
 

Attachments

Last edited:
I don't seem to be able to post links.

You are correct. We do that because of folks who opened accounts and IMMEDIATELY posted "free advertising." This way, though it is somewhat of an annoyance to new members, we can dissuade spammers and commercial advertisers. It's nothing personal, it's just something that we can implement through automation without having to adjust each new individual account separately.
 
You are correct. We do that because of folks who opened accounts and IMMEDIATELY posted "free advertising." This way, though it is somewhat of an annoyance to new members, we can dissuade spammers and commercial advertisers. It's nothing personal, it's just something that we can implement through automation without having to adjust each new individual account separately.
I figured it was something along those lines. Don't worry, didn't take it personally.

I do find it odd that .bas isn't an allowed file type for attachments though..!
 
I'm testing your code and I'm getting an Access crash. Using A365-32. Steps to repro (same as post #2):
Northwind 2 Dev Edition > Set a breakpoint on line 20 of ProductAvailable.
In VBAStack module add the below code.
Change the Quantity of a line item of an order and save the record. When you get to the breakpoint, run testDumpStack from the Immediate window.
The below code will assert at line 60 - Good. params is empty - Good.
Continue to step and on the second iteration Access will crash on line 50. Stepping in, it seems to happen in ReadParamValues.
If I run your debug statement DumpMemory curPtr, totalArgSize, Access crashes as well.

Public Sub testDumpStack()
Dim Frames() As VBAStack.StackFrame
Dim str As String
Dim i As Integer
Dim params() As paramInfo

10 Frames = VBAStack.GetCallstack()

20 For i = 0 To UBound(Frames)
30 str = str & Frames(i).ProjectName & "." & Frames(i).ObjectName & "." & Frames(i).ProcedureName & vbCrLf
40 Debug.Print Time$, str

50 params = GetParamInfoForFrame(Frames(i))
60 Debug.Assert False 'Stop here to inspect params in Locals window.
70 Next i
80 MsgBox str, vbInformation
End Sub

Edit: Debugging this a bit more, ReadParamValues calculates pParamBase, and it is 0 for me.
curPtr is then set to -24, and dumping that memory crashes Access.
DumpMemory pExFrame - &H28, 4
13DBAE4: 00 00 00 00

DumpMemory pExFrame - &H40, &H40
13DBACC: DC D0 A5 3F
13DBAD0: 40 BB 3D 01
13DBAD4: 00 00 00 00
13DBAD8: 68 BB 3D 01
13DBADC: 51 8A FC 32
13DBAE0: 70 C8 C7 25
13DBAE4: 00 00 00 00
13DBAE8: 08 9D CD 25
13DBAEC: 90 BE 3D 01
13DBAF0: 24 B8 EA 32
13DBAF4: 2D B8 EA 32
13DBAF8: 07 FB EC 32
13DBAFC: 1F 79 FC 32
13DBB00: 60 1E 06 26
13DBB04: BE B9 EA 32
13DBB08: 00 00 00 00
 
Last edited:
I'm testing your code and I'm getting an Access crash. Using A365-32. Steps to repro (same as post #2):
Northwind 2 Dev Edition > Set a breakpoint on line 20 of ProductAvailable.
In VBAStack module add the below code.
Change the Quantity of a line item of an order and save the record. When you get to the breakpoint, run testDumpStack from the Immediate window.
The below code will assert at line 60 - Good. params is empty - Good.
Continue to step and on the second iteration Access will crash on line 50. Stepping in, it seems to happen in ReadParamValues.
If I run your debug statement DumpMemory curPtr, totalArgSize, Access crashes as well.

Public Sub testDumpStack()
Dim Frames() As VBAStack.StackFrame
Dim str As String
Dim i As Integer
Dim params() As paramInfo

10 Frames = VBAStack.GetCallstack()

20 For i = 0 To UBound(Frames)
30 str = str & Frames(i).ProjectName & "." & Frames(i).ObjectName & "." & Frames(i).ProcedureName & vbCrLf
40 Debug.Print Time$, str

50 params = GetParamInfoForFrame(Frames(i))
60 Debug.Assert False 'Stop here to inspect params in Locals window.
70 Next i
80 MsgBox str, vbInformation
End Sub
Interesting! Found the issue. It seems the weird ".0_#ImmMod#_._ImmedProc" frame that you get from the immediate window doesn't actually have a base address for it's parameter values, but it does actually have 3 parameters, which is.. Really odd. So it can get the parameter names and types for that frame, but not their values. Have added a check for this in ReadParamValues (as well as another CheckAddressSafe that I missed before).
 

Attachments

Edit: Debugging this a bit more, ReadParamValues calculates pParamBase, and it is 0 for me.
curPtr is then set to -24, and dumping that memory crashes Access.
DumpMemory pExFrame - &H28, 4
13DBAE4: 00 00 00 00

DumpMemory pExFrame - &H40, &H40
13DBACC: DC D0 A5 3F
13DBAD0: 40 BB 3D 01
13DBAD4: 00 00 00 00
13DBAD8: 68 BB 3D 01
13DBADC: 51 8A FC 32
13DBAE0: 70 C8 C7 25
13DBAE4: 00 00 00 00
13DBAE8: 08 9D CD 25
13DBAEC: 90 BE 3D 01
13DBAF0: 24 B8 EA 32
13DBAF4: 2D B8 EA 32
13DBAF8: 07 FB EC 32
13DBAFC: 1F 79 FC 32
13DBB00: 60 1E 06 26
13DBB04: BE B9 EA 32
13DBB08: 00 00 00 00
Ah - didn't see you'd debugged further, but yeah you got it. There's a field in the ExFrame structure (well, actually 0x28 before the base address of the frame in x86) that holds the base address for the parameter values, and on the Immediate window's frame, it's just null - that'd usually be fine, since I assumed it just didn't have parameters, but for whatever reason it does. They are;

"_pProject", vbLong (I would guess actually "vbLongPtr" if that existed - these would most likely show up as vbLongLong on x64)
"_pFrame", vbLong
"_v", vbVariant

I suspect that _pFrame parameter is whichever ExFrame was in break mode in the VBE when you run something via Immediate - possibly how it gets contextual values, like local vars used in immediate? Odd that it has no parameter base though, when it has damn near everything else to be a "normal" frame.
 

Users who are viewing this thread

Back
Top Bottom