来自System.Windows.Forms的AccessViolationException,在WPF中使用WinFormsHost

在开发WPF / WinForms互操作应用程序时,我遇到了一个令人讨厌的问题。 我一直试图解决这个问题三天,但我无法取得任何进展。 我怀疑我能提供足够的信息来获得解决方案,但我正在寻找能够解释这里究竟发生了什么的人吗?

我使用的组件是AxMapControl(ESRI ArcGIS Engine 9.3.1 SP2),据我所知,它是COM包装的本机代码,公开为WinForms控件。 该组件使用WPF WinFormsHost代理嵌入在我们的WPF(.NET 3.5)客户端软件中。

应用程序会定期使用AccessViolationException崩溃。 这总是发生在用户鼠标点击地图控件时,但似乎没有任何押韵或原因在什么具体输入。 堆栈跟踪始终相同:

System.AccessViolationException:尝试读取或写入受保护的内存。 这通常表明其他内存已损坏。 在System.Windows.Forns.Forms.Forf.DefWndProc上的System.Windows.Forms.NativeWindow.DefWndProc(Message&m)处的System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc,IntPtr hWnd,Int32 msg,IntPtr wParam,IntPtr lParam) (Message&m)System.Windows.Fornd.OndMessage(Message&m)位于System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&m)的System.Windows.Forms.AxHost.WndProc(Message&m)处的System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message&m)在System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam)

因为exception似乎抛出了我的代码启动的任何调用堆栈之外,我无法弄清楚如何捕获exception并以编程方式处理它。

此问题发生在调试模式以及发布版本中。 但它确实不会出现在所有计算机上,但我能够在Windows 7和XP以及.NET framework 3.5和4.0上复制此问题。

在崩溃时检查进程是什么,exception似乎是在GAC部署的DLL上似乎有多个CreateFileMapping操作失败,结果FILE LOCKED WITH ONLY READERS

ProcMon截图

此视图已被过滤以仅显示该类型的结果,但似乎每个DLL恰好发生两次。 这是什么意思吗?

现在,很明显我对发生的事情毫无头绪,以及如何解决这个问题。 如果你有一个线索,你能否善待并向我解释我正在处理的问题类型?

知道如何调试这个问题吗?

我正在使用除ESRI之外的其他地图控件,但我的设置非常相似:用COM包装的本机地图代码,包装在Windows窗体控件中,然后通过WindowsFormsHost引入WPF应用程序。 几个星期前,当我点击我的地图时,我得到了完全相同的System.AccessViolationException,只有很少的选项可以帮助调试。

我的问题的罪魁祸首:WPF中底层控件的初始化并没有像我想象的那样发生 – WPF推迟某些初始化,直到视图在屏幕上完全需要/可见(我假设减少窗口/控制加载时间) 。 在WPF中,我将基础地图控件的所有初始化代码放入构造函数和(WPF)UserControl.Loaded事件处理程序中。 问题是,WPF调用构造函数并在事物在屏幕上真正可见之前引发Loaded事件。 所以我的底层地图控件正在初始化,表面大小为0高度,0宽度,这是合法但不正确。 当我点击地图时,我正在调用底层地图控件,将我的鼠标单击(x,y)转换为lat long,并引发了AccessViolationException。

我的解决方法是每当引发UserControl.Resize事件时,使用新的表面大小重新初始化底层地图控件,这似乎在地图完全以适当的大小绘制之前可靠地发生,并在我的WPF中保留bool mapIsInitialized字段在地图初始化为非零表面大小之前,控件保持为假,设置了正确的投影,并且第一次完全绘制了地图。 除非mapIsInitialized,否则我的函数(例如,将屏幕点转换为lat lons)访问底层地图控件现在什么都不做。

所以,你可能有或没有类似的问题,但我会尝试跟踪初始化代码并查看传递给底层地图控件的参数的值,看看它们是否有意义,如果初始化是正如您所期望的那样,在适当的时间使用适当的值。

祝好运!