As the author of something like Paint.NET, I often get bugs reported that I simply don’t understand. Ever since before Paint.NET 3.0 went into beta, I’ve been getting crash reports like the following:

System.InvalidOperationException: ScratchSurface already borrowed: ‘PaintDotNet.DocumentWorkspace.DoSaveAs() handing off scratch surface to DoSaveAsDialog()’ (trying to borrow for: ‘PaintBucketTool: Tool.Activate()’)

This tells me that the Paint Bucket tool was trying to activate, but it couldn’t get the scratch surface (this is an internal Paint.NET object) because the Save As dialog already had it. Unfortunately, the stack trace didn’t help. All my powers of analysis were for naught, as I could not discern a way that the scratch surface was in use twice. One part of the crash log was pointing a finger at the Save As dialog, but that code was nowhere to be seen in the stack trace!

The number of reports of this particular crash were not alarming, nor were they causing any bad press or user sentiment. So, for months I just accepted the bug and hoped that a future version would work around it accidentally. As a software developer, you quickly learn that software has bugs. And you will ship with some. It’s just the way the world works outside of ivory towers.

See, the problem was that I was trying to use logic to figure out a repro for the bug (“a repro” is just the term for having a set of instructions to reproduce the issue). I looked at the callstack and did not see any of the Save As dialog’s functions, so I concluded that the Save As dialog was not active at the time of the crash. I thought that, somehow, the Save As dialog had closed but for some reason it had not returned the “Scratch Surface”. I probably have spent several hours over the last few months just trying to repro this one specific crash. I looked everywhere except that Save As dialog itself

Well, I was wrong. Yesterday the light bulb went on over my head and I decided I would try to do the following:

  1. Start Paint.NET
  2. Go to File -> Save As
  3. Click on a tool in the Tools window (this should be impossible! The “Save As” dialog is modal! The other windows should just go “beep” if you try to click on them!)

Guess what? Not only was (3) possible, it crashed the program! I finally had a repro! You can try it for yourself right now in the latest 3.08 release. For some reason, the Save As dialog is modal with respect to the main Paint.NET window, but it isn’t preventing clicks from being processed in the four “floating windows” (Tools, History, Layers, Colors). My knowledge of WinForms and Win32 doesn’t give me a way for this to be possible, but a workaround that produces the effect I need should be straight forward.

So, there you go. This will be fixed in the next release of Paint.NET of course.