Persistent bug in CodeSnip squashed at long last [I hope]
What a red letter day. 🎆🎇ðŸŒ
For several years a nasty access violation bug has been lurking inside CodeSnip. It crashed the program when the computer was resumed from hibernation, but only sometimes. Because the bug was intermittent and required numerous hibernation / resume cycles to be run before it finally cropped up it defied diagnosis for a long, long time.
Until now. Or up until someone finds my fix doesn't work for them!
The bug fix release is v4.24.1 - get it from GitHub.
Read on if you're interested what the problem turned out to be.
CodeSnip uses a custom drawn tree view control to display the available snippets, grouped under headings. A custom TTreeNode class is used that has an extra property that references an object instance that provides extra information about the item been displayed. This information is used by the custom drawing code.
The problem is that, occasionally, when waking from hibernation, Windows destroys and recreates the window handle of the tree view. The Delphi VCL detects this and stores the TTreeNode properties in a memory stream when the tree view window is destroyed and then re-reads the node properties when the window is recreated. This means that the standard TTreeNode properties are persisted, but not the additional property I added to the the custom TTreeNode class. Consequently where CodeSnip expects to find the object reference it left there it actually finds nil. And the first time the object is read is when things go all pear shaped. Hello access violation!
The window creation and destruction code is not easily available get into. I didn't (and won't) hack TTreeView in the VCL code. However I did try to hack TTreeView by other means. I don't like such hacks and, worse, my hack didn't work reliably!
So, in the end I intercepted the WM_POWERBROADCAST message that Windows sends when there's a change of power state. The message gets sent numerous times: it has a parameter that says what exactly is happening. When hibernation is detected the tree view state is saved. When resume is detected we let Windows do its worst and then jump in and rebuild the tree view properly and finally restore its state. Actually, the message that I needed gets sent twice, once before and once after the tree view gets recreated, so the rebuilding also gets done twice. There's no great overhead of doing this, so that's not worth working around.
This is still a bit of a kludge, and I'm not 100% sure it will work on all versions of Windows: the WM_POWERBROADCAST docs aren't clear.
A better solution would be to re-implement all the tree view handling code to avoid using a custom TTreeNode descendant, but the code is deeply entwined and it's a big job. Maybe one day.
Anyhow, please do try this update. I'm sure you'll report it if the fix doesn't work for you!
View diff of the fix here.
Comments
Post a Comment