Closed UnhandledCoder closed 6 years ago
Thank you for taking the time for reporting this issue. This is a known issue (#2782 and #2524) with the order in which the VBE tears down tool windows when Rubberduck gets unloaded.
We are trying to fix this. Unfortunately, this is complicated because Rubberduck is living in the process of the host application and the VBE owns the tool windows.
@UnhandledCoder note that this is strictly a teardown issue, it doesn't affect usability of the VBE or its host. Teardown only happens when the host is commanded to close; it's utterly annoying indeed, but shouldn't affect anything since at the moment of the crash the host is already closing.
The root of the problem has to do with the WPF host inside the WinForms user controls in the docked toolwindows: v1.4.3 didn't have WPF UI and didn't have that problem... except many other issues were solved since that version.
It would really suck to have to redo all the WPF UI's in WinForms, but at this point it seems the only way around what appears to be a bug in Microsoft's WPF interop container control.
Thanks for info @MDoerner @retailcoder . Also the aspect, that there is no *.laccdb leftover, indicates that the Access database itself shouldn't be harmed from that problem, but I have seen too much defect databases to trust in Microsoft Access in such exceptional moments. Overall I've still doubts... Since you're fighting with this problem since several months, as I see, what's your strategy? Is it an realistic option to switch back to WinForms? Finally it could be the only reliable way. How long would that take?
Apart from the fact that WPF is immeasurably more flexible and all in all nicer-looking, switching back to pure WinForms would involve redoing the UI for every docked toolwindow... which put the greatest risk on the source control panel I'd say (although.. the SC panel has a number of problems already) - the biggest challenge would be refactoring all the Model-View-ViewModel plumbing to Model-View-Presenter - basically re-wiring every dockable UI to the commands; the functionalities themselves would be unaffected, since everything is implemented in dedicated classes. So... UI work and plumbing essentially.
We could still keep WPF for non-docked dialogs.
It could even be done parallel to everything; destroying all the WPF UI work isn't even needed: just reconfigure the ninject bindings for the dockable presenters, tell it to inject UserControl B instead of UserControl A, and we can still try to figure out how to get a WPF UI to work in a docked toolwindow while shipping a WinForms UI.
I did a bit of work (a proof of concept really) around using the MVVM pattern with Winforms. There may be something useful here. https://github.com/rubberduck203/Rubberduck.Winforms
@rubberduck203 the Rubberduck.Winforms
namespace has that somewhat premonitory feel.
I am also getting a crash every time after opening VBE and then exiting Access with the latest version 2.0.13. This causes Access to always restart, and some data loss such as for settings and layout changes, rendering it unusable / not worth keeping enabled, for me.
Where can I check for error details, since Roaming\Rubberduck\Logs\RubberduckLog.txt seems to have nothing in it, except for the loading entry (Operating System, etc.).
@xeonx1 Thanks for reporting. The crash is a known issue. It doesn't occur on all PCs, which is strange, and neither does it occur with all hosts, but Access and Excel seem to be the most problematic. It's related to Rubberduck's use of WPF and sub-classing, and our inability to unload those WPF forms (and thereby Rubberduck) cleanly. We've made numerous fixes, and numerous attempts, but the fix is, for now, frustratingly out of reach. The architecture of the VBE (being a relic that pre-dates WPF), is proving to be difficult to overcome. We haven't given up, but for now, we're short on ideas, unless Microsoft chooses to assist.
For logging, you can adjust the verbosity by adjusting Rubberduck's settings.
Is there any way to handle VBE closing event - even indirectly by handling first tool window being closed and manually closing all your tool windows with addon cleanup early, even unloading the addon entirely at that point if needed?
Or, could you register and show first a hidden WinForms (not WPF) (tool or not) window and handle it closing (as would only occur on VBE exit since user can't see/close themselves), preemptively closing all your tool windows early and cleaning up/unloading at that point?
Or try to find subscribe to main VBE and/or main Access window closing (eg. by, if needed, finding parent window for your tool windows or hack like GetParent(hWND) or Process.MainWindowHandle(), etc.) or process exiting event, and close/cleanup earlier when that occurs?
Could you try handling the following to see if can catch the error there to see if might prevent a crash and avoid automatic app restart at least, if not avoid the error from occurring?
Or you could possibly just avoid the issue with hosting WPF inside WinForms tool window by showing your windows without technically being dockable VBE windows.
Not only would that certainly be preferable to crash and auto-restart every time Access or Excel is closed, but IMO would be preferable to standard VBE tool windows anyways, with all their bugs and limitations.
Then, you could actually implement real Visual Studio-style tabbed docking with your windows. This could be done, for example, using Extended WPF Toolkit's AvalonDock.
IMO, that especially would be far preferable to old VBE-style docking, with its various limitations and issues with VBE remembering tool window layout position in cases or not showing where window would appear when dragging with certain resolutions/DPI scaling/aspect ratios in cases, etc.
comintern was playing with https://github.com/ButchersBoy/Dragablz and we already use some components from Avalon, like AvalonEdit.
That's great, but can you provide support for Visual Studio-like tabbed docking then (at least when docking Rubberduck's window with another one of your windows, unless you can host the standard VBE windows inside panel tool)
If not, then that's another point in favor of just making your tool windows WPF-only without hosting inside WinForm by making them no longer standard VBE-dockable tool windows.
Even with 4K monitor + 3K dual screens there's not enough room for many of the main VBE tool windows, let alone Rubberduck ones.
Can you look into any of the possible fixes/workarounds described in my previous post, like global error handlers and exit-triggered preemptive closing/clean/unloading?
There's probably a good reason why nobody made a VBE add-in with WPF dockable toolwindows in the decade WPF has been around or so. The nut we're trying to crack is VBE integration - dropping toolwindows sure would work - but modal dialogs would be utterly annoying, as would be hunting down non-modal windows hiding behind the VBE.
We're dealing with access violations stemming from the interaction between WPF and the toolwindows; a global exception handler is of no use, it's already too late to recover at that stage. There's a race between the VBE tearing itself down, and RD trying to do the same, and it's a catch-22: when we win, host crashes. When we lose, we crash.
I'm going to make a MVE barebones VBE add-in with nothing but toolwindows, to further narrow down on the issue. At the end, I suspect we'll just have to redesign everything in WinForms (heart-wrenching, but it takes what it takes).
OK, but those are just the fallback options I had proposed - non-tool window and global error handlers.
First and foremost I had suggested preemptive closing of tool windows, unloading and cleanup. Might any of the following be possible?:
Is there any way to handle VBE closing event - even indirectly by handling first tool window being closed and manually closing all your tool windows with addon cleanup early, even unloading the addon entirely at that point if needed?
Or, could you register and show first a hidden WinForms (not WPF) (tool or not) window and handle it closing (as would only occur on VBE exit since user can't see/close themselves), preemptively closing all your tool windows early and cleaning up/unloading at that point?
Or try to find subscribe to main VBE and/or main Access window closing (eg. by, if needed, finding parent window for your tool windows or hack like GetParent(hWND) or Process.MainWindowHandle(), etc.) or process exiting event, and close/cleanup earlier when that occurs?
There is no "closing" event. There's the VBE invoking IDTExtensibility2.OnDisconnection, and that's not the VBE shutting down (yet per the interface it's our only handle in the shutdown process, along with OnBeginShutdown, which isn't guaranteed to be invoked, depending on the host). We subclass the mainwindow, and pick up WM_DESTROY messages (IIRC we even inject our own message into the pipeline, to signal our toolwindows). TBH I haven't touched that code in a loooong while, there's a lot going on and this whole area is rather foggy, but from comintern's work and chat transcripts the way the VBE shuts down - and signals it, is quite a hacked-up mess with curve balls at every turn.
Feel free to fork & PR a fix.
@xeonx1 it seems that you would really like a different UX. Please open a separate issue with a proposal for the UI you'd like RD to have. Let's keep this issue focused on the crash.
Sure, I can create a separate issue for tabbed docking feature request when I get a chance to go into more detail.
Yep, I'm aware of OnDisconnection, and the woefully limited API for Add-ins - which is unfortunately especially limited when it comes to Access-specific UI and events.
What I'm referring to is WM_CLOSE, which occurs before WM_DESTROY, and handling it for the parent window (eg. VBE MainWIndow), as it occurs there before it does for child/tool windows. Therefore, what I'm suggesting is to preemptively close all tool windows and shutdown when WM_CLOSE occurs for VBE MainWindow instead of waiting for them to be closed by it.
Whether related to timing issues with not yet completed cleanup or something else, this might help. After all, the tool windows do close fine without error when manually closed by user. It's just when closed automatically when exiting Access that this crash occurs.
I started taking a look at the code and may make a few attempts at a fix/workaround when have some time.
@ThunderFrame, @retailcoder, and @rubberduck203, Are you or any of the other developers able to reproduce the crashing with Access and/or Excel? You had mentioned it doesn't seem to occur consistently or for all users.
In any case, thanks for your prompt responses and your to look into this issue. Rubberduck VBA's an impressive 😲 and useful 🔨 tool in, so especially thank you for all the time volunteering to develop it. 👍 😄
I look forward to using Rubberduck further once a fix or workaround can be identified for this issue. Hopefully one can be found without having to resort to a time-consuming port backwards from WPF to WinForms. 🤞
IIRC, comintern did look at WM_CLOSE, but it was insufficiently close to termination. When a ToolWindow is closed, it is not really closed, but instead resized and relocated/hidden.
There's a lot going on. Multiple WinForms hosting WPF controls, The WinForms being hooked/sub-classed, the WPF acting as Dispatcher. And it's all running in a MDI host that predates .NET, and one that uses hidden windows like "MDIChildHack", and proprietary messages, and, I suspect hidden named pipes. There's probably a reason that VBIDE exposes Hwnd, LinkedWindows and LinkedWindowFrame, and yet, in modern VBEs, very often doesn't assign values to them.
The aim is to produce a MCVE that crashes, and then find a fix. We don't have a definitive cause, so until we find that, trying to fix this in RD, IMO, is crazy-difficult because there might be compounding factors or multiple causes. Trying one approach in RD, might make things better, or worse.
This is interesting because I almost never get a crash in Excel or Access anymore (used to get 'em all the time). I do get the hung MSACCESS.EXE process in TaskManager that I have to manually kill each time I shut down Access (never happens in Excel), but rarely do I get a crash.
I've been running 2.0.13 since release, and just jumped on the continuous build bandwagon yesterday, so I'm currently up to 2.1.1994.
FWIW, when closing, I almost always get a crash in Excel, both Excel 2013 x64 on Win7 x64, and Excel 2016 32bit on Win10 x64. So much so, that I'm not sure of the last time Excel closed cleanly.
Ah yes, version info can be helpful... I'm running Office2010 32-bit on Win7 64-bit. Yes, we're a (64-)bit behind the times...
FWIW I haven't had a crash-exit since 2.0..12 I think.. maybe even before that. On Excel 2010, both 32 and 64 bit (home desktop and work laptop), and I get a clean exit in Sage 300 as well (work laptop). That makes it rather hard to debug...
@PowerAccess FYI I reproduced the AccessViolationException in exit (with native debugging turned on) with a bare-bones VBIDE add-in project (SlimDucky), that literally does nothing but bring up two dockable toolwindows (one with a WinForms UI, the other with a WPF element host hosting a WPF UI) - the good news is that I get the exception regardless of whether I create the WPF toolwindow or not, which points to the shutdown issue having something to do with the DockablePresenter
rather than the WPF interop - that's great news: when the exception is successfully avoided in that SlimDucky project, we're looking at a very high probability of fixing the crash-on-exit once and for all! I don't know if you made any progress off the RD fork, but the bare-bones project should be much easier to work with (no Ninject, no parser, no menus, just the toolwindows and the crash-on-exit).
Hi @retailcoder That's good to hear. Thanks for creating SlimDucky, it should be useful for debugging/comparison.
Today I tried Rubberduck v2.1.2084 to see if the promising correction of MDoerner (https://github.com/rubberduck-vba/Rubberduck/pull/3277) maybe fixes my problem.
Finally it does! I can use Rubberduck features and close Microsoft Access without any Problem!
Great job!
Sadly, though, I still get the hung process on exit, even with .2084. :(
Forgot to give feedback here. After some days of work also recognized, that my described problem still occurs multiple times a day. By far not so often and not regular like before, but too often to use it, because I can't trust Microsoft Access itself not destroying my database.
MDoerner pointed out that there are more problematic sections in the code which can cause this behaviour.
Does anyone know, wether it has been take care of in the meantime?
This issue should have become less prevalent in the last prereleases. For more information, please see issue #3614 now being the main issue for the problems on host shutdown.
The upcoming release (v2.2) should largely address the crashes which was due to a bug deep within the .NET framework and has been fixed in various PRs, thanks to efforts of @MDoerner and @WaynePhillipsEA .
For now, I'm closing this issue. If there are any crashes or other issues, please create a new issue with updated steps.
I have an annoying problem in using Rubberduck that Forces me not to use it at all.
When I open an Access database, open and close the VBE and then close Access, I get the following error:
Facts:
The problem is different to 2878 and 2936: I can reproduce the problem with the Rubberduck windows when I pull and dock them around somehow. Then Access really crashes, without a need to close it myself, but with a different message:
And in this situation there is a *.laccdb leftover.
So it must be a different problem.