来自 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.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc,IntPtr hWnd,Int32 msg,IntPtr wParam,IntPtr lParam) 在 System.Windows.Forms.NativeWindow.DefWndProc(Message&m) 在 System.Windows.Forms.Control.DefWndProc(Message&m) 在 System.Windows.Forms.AxHost.WndProc(Message&m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message&m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&m) 在System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam)
因为异常似乎是在我的代码启动的任何调用堆栈之外抛出的,所以我不知道如何捕获异常并以编程方式处理它。
此问题发生在调试模式以及发布版本中。然而,并非所有计算机上都会出现这种情况,但我已经能够在 Windows 7 和 XP 以及 .NET Framework 3.5 和 4.0 上复制此问题。
检查崩溃时进程的状态,发现异常情况似乎是,GAC 部署的 DLL 上似乎存在多个 CreateFileMapping 操作,这些操作失败,结果为 FILE LOCKED WITH仅限读者。
此视图已被过滤为仅显示该类型的结果,但似乎每个 DLL 都会发生两次。这是否意味着什么?
现在,很明显我对发生的事情以及如何解决这个问题一无所知。如果您有线索,能否友善地向我解释一下我正在处理什么类型的问题?
知道如何调试这个问题吗?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我使用的是 ESRI 之外的不同地图控件,但我的设置非常相似:将本机地图代码包装在 COM 中,包装在 Windows 窗体控件中,然后通过 WindowsFormsHost 引入 WPF 应用程序。几周前,当我单击地图时,我得到了完全相同的 System.AccessViolationException,但帮助调试的选项很少。
我的问题的罪魁祸首:WPF 中底层控件的初始化并不像我想象的那样发生——WPF 推迟某些初始化,直到视图完全需要/在屏幕上可见(我假设减少窗口/控件加载时间) 。在 WPF 中,我将底层地图控件的所有初始化代码放入构造函数和 (WPF) UserControl.Loaded 事件处理程序中。问题是,WPF 在屏幕上真正可见之前调用构造函数并引发 Loaded 事件。因此,我的底层地图控件正在使用 0 高度、0 宽度的表面尺寸进行初始化,这是合法的,但不正确。当我单击地图时,我正在调用底层地图控件,将鼠标单击 (x, y) 转换为经纬度,并引发了 AccessViolationException。
我的修复方法是,每当引发 UserControl.Resize 事件时,就使用新的表面大小重新初始化底层地图控件,这似乎可靠地发生在地图以其正确大小完全绘制之前,并在我的 WPF 中保留 bool mapIsInitialized 字段控制保持 false,直到地图初始化为非零表面大小、设置正确的投影以及第一次完全绘制地图。我访问底层地图控件的函数(例如,将屏幕点转换为纬度)现在不执行任何操作,除非 mapIsInitialized。
因此,您可能会或可能不会遇到类似的问题,但我会尝试跟踪初始化代码并查看传递给底层地图控件的参数值,以查看它们是否有意义以及初始化是否正确。正如您所期望的那样,在适当的时间以适当的值发生。
祝你好运!
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!