I've been working on a project that makes use of wunderground's autocomplete API, and I keep running into a very random error. The code is located here.
And the exceptions that I'm getting is an AccessViolationException. It occasionally occurs when typing into the textbox.
Exception Information:
using (XmlReader reader = XmlReader.Create(requestURL))
Exception:Thrown: "The specified registry key does not exist." (System.IO.IOException) A System.IO.IOException was thrown: "The specified registry key does not exist." Time: 2013-05-18 14:55:59 Thread:Main Thread[5672] Exception:Caught: "The specified registry key does not exist." (System.IO.IOException) A System.IO.IOException was caught: "The specified registry key does not exist." Time: 2013-05-18 14:55:59 Thread:Main Thread[5672]
Application.Run(new Form1());
Exception:Thrown: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." (System.AccessViolationException) A System.AccessViolationException was thrown: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." Time: 2013-05-18 14:55:59 Thread:Main Thread[5672]
Exception:Thrown: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." (System.AccessViolationException) A System.AccessViolationException was thrown: "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." Time: 2013-05-18 15:00:01 Thread:Main Thread[4340]
I've tried this on 3 different computers, and after a while .. the same error always happens.
I can repro the AccessViolation on Windows 8. You'd have to enable unmanaged code debugging and enable the symbol server to see the cause, the troublemaker is the AutoComplete message handler built into Windows. In general a rather cranky piece of code, it is implemented by subclassing the edit control to intercept messages. The call stack looks like this:
shell32.dll!CAutoComplete::_StartCompletion() + 0x4e bytes
shell32.dll!CAutoComplete::_OnChar() + 0x7a bytes
shell32.dll!CAutoComplete::_EditWndProc() - 0x6ae52 bytes
shell32.dll!CAutoComplete::s_EditWndProc() + 0x23 bytes
comctl32.dll!_CallNextSubclassProc@20() + 0x92 bytes
comctl32.dll!_MasterSubclassProc@16() + 0xa5 bytes
user32.dll!_InternalCallWinProc@20() + 0x23 bytes
user32.dll!_UserCallWinProcCheckWow@36() + 0xbd bytes
user32.dll!_DispatchMessageWorker@8() + 0xf8 bytes
user32.dll!_DispatchMessageW@4() + 0x10 bytes
[Managed to Native Transition]
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData) + 0x24d bytes
// etc.., not interesting
This goes wrong because of the TextBox.AutoCompleteCustomSource property assignment in the TextChanged event handler. Changing that property has a lot of side effects, it forces the edit control window to be recreated so that the new auto-completion list becomes effective. That interacts very poorly with the subclassing code, probably because it is still using the old edit control whose window was destroyed or runs before Winforms had a chance to re-initialize the new control.
A workaround is to wait setting the property until the event handling is completed. That can be elegantly done with the Control.BeginInvoke() method. Change the property assignment to look like this:
this.BeginInvoke(new Action(() => {
textboxInput.AutoCompleteCustomSource = autoComplete;
}));
Now the window for the textbox gets destroyed and recreated later, taking the sting out of destroying the window just as it is handling a keydown event. Do note how the effect of the window getting recreated is readily visible, the textbox flickers like a cheap motel. I seriously doubt you actually want to use this in a shipping program.