Open Ik-12 opened 1 year ago
Known limitation I'm afraid. I imagine Application.Run uses this exact same mechanism under the hood. I believe the IDispatch::Invoke
of the VBComponent creates an independent debugger session. So would need to manually disable it and that would likely require some assembly instruction hacking. I think IIRC Rubberduck itself struggles in this area - if you have an unhandled error in a unit test RD cannot suppress it.
Workaround is of course to add error handling inside the TestCallback
function, similar to how RD inserts automatic error handling code in the default test method template:
'@TestMethod("Uncategorized")
Private Sub TestMethod1()
On Error GoTo TestFail
'Arrange:
'Act:
'Assert:
Assert.Succeed
TestExit:
Exit Sub
TestFail:
Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
Resume TestExit
End Sub
Sidenote:
Dim exampleModuleAccessor As Object
Set exampleModuleAccessor = GetStandardModuleAccessor("SomeModule", Application.VBE.VBProjects("SomeProject"))
' Brings up the Debug Dialog; expected behavior is to handle the error with the error handler
' (as happens if "TestCallback" is method of a real class module).
CallByName exampleModuleAccessor, "TestCallback", VbMethod
Could be
Dim exampleModuleAccessor As Object
Set exampleModuleAccessor = GetExtendedModuleAccessor("SomeModule", Application.VBE.VBProjects("SomeProject"))
' Brings up the Debug Dialog; expected behavior is to handle the error with the error handler
' (as happens if "TestCallback" is method of a real class module).
exampleModuleAccessor.TestCallback
although that won't help with the error trapping, it is just a neater syntax
Thanks for the prompt response and the suggestions! It seems that this is indeed a VBA language limitation.
I investigated the error handling issue a bit further:
CallByName(obj, "fcn", ...)
exactly as with calling obj.fcn
: the returned Err.Description
is always "Application-defined or object-defined error" (see also https://stackoverflow.com/questions/18241906/vba-callbyname-and-invokehook and http://web.archive.org/web/20090104123310/http://support.microsoft.com/kb/194418)Thanks for the research!
Does InvokeHook enable error handling/trapping? Or is it the same as CallByName - untrappable errors but at least the correct error message.
The vtable trick is actually my post:) Thinking aloud - I don't believe just because the method is called from a class, that is what is enabling the error handling, I think vba's AddressOf operator points to a wrapper function that contains the debugger context because otherwise you couldn't put breakpoints in window subclassing procs, which IIRC you can.
Does dispcallfunc AddressOf Foo
with the error raising .bas method trap errors?
I didn't test InvokeHook because it requires distributing/installing TLBINF32.DLL, which isn't possible in our case. However, I assume it works as it's the official workaround provided by Microsoft.
Error trapping from caller doesn't work with dispcallfunc
(tested).
Yet another undocumented detail about CallByName
: If the error number raised by the called method is in range 0-65535, it's returned correctly as is. But if error number is < 0 (as it often should be, see 6.1.3.2.1.2 in MS-VBAL), it's replace by generic error number 440.
InvokeHook most likely calls ITypeInfo::Invoke
under the hood - this is possible to do without TLBINF32.dll (I left a comment on that qu you linked pointing to the VBA version of this repo on codereview. In this repo's original VBA implementation, I use QueryInterface and various vtable calls to navigate the typelibs manually to avoid a dependency on TLBINF32).
However I understood from that linked microsoft article that it only fixed the Err.Number, and didn't make mention of whether it fixed the problem with Error handlers being ignored., which is what you care about?
So worth checking if TLBINF32.InvokeHook on the StandardModuleAccessor's ITypeInfo allows invocation with error handling, or even gets the error numbers right (unlike callbyname). I would be surprised if it did help since CreateStdDispatch makes IDispatch::Invoke forward calls to ITypeInfo::Invoke so I don't see these as behaving differently. But perhaps VBA uses a custom IDispatch implementation or something...
Thanks for this great utility. I hoped I could use it to fix the issue that Application.Run ignores the active error handler. However, calling a function with this method suffers from the same problem. Please see below for a minimal reproducible example.
Any ideas if this could be made to work?
(Tested with MS Access 2019 16.0.10397.20021 64-bit)