AccessViolationException from System.Windows.Forms

2019-07-06 22:58发布

问题:

I'm facing a nasty issue when developing a WPF/WinForms interop application. I've been trying to resolve this issue for three days, but I'm unable to make any headway. I doubt I can provide enough information to get a resolution, but I'm looking for anyone who could explain what on earth is going on here?

The component I am using is AxMapControl (ESRI ArcGIS Engine 9.3.1 SP2), which as far as I know is COM-wrapped native code, exposed as a WinForms control. The component is embedded in our WPF (.NET 3.5) client software using WPF WinFormsHost proxy.

Periodically the application crashes hard with an AccessViolationException. This always happens in reaction to user's mouse click on the map control, but there doesn't seem to be any rhyme or reason on what specific input. Stack trace is always the same:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam) at System.Windows.Forms.NativeWindow.DefWndProc(Message& m) at System.Windows.Forms.Control.DefWndProc(Message& m) at System.Windows.Forms.AxHost.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Because the exception seems to be thrown outside any call stack initiated by my code, I can't figure out how to catch the exception and handle it programmatically.

This issue happends in debug mode, as well as in release builds. It does however not occur on all computers, but I have been able to replicate this issue on Windows 7 and XP, as well as .NET framework 3.5 and 4.0.

Inspecting what the process is up to at the time of a crash, the anomaly seems to be that there seem to be multiple CreateFileMapping operations on GAC-deployed DLLs which fail with the result FILE LOCKED WITH ONLY READERS.

This view has been filtered to show only results of that type, but it seems this happens exactly twice to each DLL. Does this mean something?

Now, it's obvious I am clueless as to what is happening, and how to resolve this issue. If you have a clue, could you be kind and explain to me what type of issue I am dealing with?

Any idea how I could debug this issue?

回答1:

I'm using a different map control other than ESRI, but my setup is very similar: native map code wrapped in COM, wrapped in a Windows Forms control, then brought into a WPF application via WindowsFormsHost. And a few weeks ago, I got the exact same System.AccessViolationException when I clicked on my map, with very few options to help debug.

The culprit for my problem: initialization of the underlying control in WPF does not happen the way I thought it does -- WPF defers certain initialization until the view is fully needed/visible on the screen (I assume to reduce window/control load times). In WPF, I was putting all of my initialization code for the underlying map control into a constructor and a (WPF) UserControl.Loaded event handler. Problem was, WPF calls the constructor and raises the Loaded event before things are truly visible on the screen. So my underlying map control was being initialized with a surface size of 0 height, 0 width, which is legal but not correct. When I clicked on the map, I was making a call to the underlying map control to translate my mouse click (x, y) into a lat long and it raised the AccessViolationException.

My fix was to reinitialize the underlying map control with a new surface size whenever a UserControl.Resize event is raised, which seems to reliably happen right before the map is fully drawn at its proper size, and to keep a bool mapIsInitialized field in my WPF control that stays false until the map is initialized to a non-zero surface size, proper projections are set up, and the map is fully painted for the first time. And my functions (e.g. converting screen points to lat lons) accessing the underlying map control now do nothing unless the mapIsInitialized.

So, you may or may not have a similar problem, but I would try to trace around the initialization code and look at the values of the arguments that are being passed to the underlying map control to see if they make sense and if the initialization is happening as you expect, with the proper values at the proper time.

Good luck!