首页 文章

从.Net访问COM对象时的访问冲突

提问于
浏览
1

如果帖子太长,我很抱歉,但如果有人至少会看到粗体 Headers ,我会很高兴,并指出我正确的方向 . 我有几天这个问题,但无法在网上找到答案 . 这些是我到目前为止发现的东西 .

1. "Access violation" exception crushes my managed application

我的C#WinForms应用程序有时会以"Access violation"异常("Attempted to read or write protected memory")关闭,就在Windows窗体TabControl中选择TabPage时 . 从堆栈跟踪(尝试/捕获Application.Run)我可以看到异常发生在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) ,在 UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData) 内部调用 .

-- Message: Attempted to read or write protected memory.
   This is often an indication that other memory is corrupt.
-- Stack trace:
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager
      .System.Windows.Forms.UnsafeNativeMethods
      .IMsoComponentManager.FPushMessageLoop
      (Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext
      .RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext
      .RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(ApplicationContext context)
   at MyApp.Program.Main()

2. The faulting module seems to be a COM object (ChartFX Client Server 6.2)

使用WinDbg(加载了SoS),我在非托管端,ChartFX.ClientServer.Core.dll(我们正在使用的COM图表组件)中捕获它:

(ca84.c98c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=06e67c38 ecx=06e67c38 edx=000018c6 esi=06e7df30 edi=317a9e80
eip=31666110 esp=0015e040 ebp=0015e08c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
ChartFX_ClientServer_Core!Ordinal5507+0x97b7:
31666110 8a404d          mov     al,byte ptr [eax+4Dh]      ds:0023:0000004d=??

[编辑:]我也无法从WinDbg中获取未受管理的堆栈详细信息(它说“堆栈展开信息不可用”):

0:000> kP
ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
0015e08c 3166288b ChartFX_ClientServer_Core!Ordinal5507+0x97b7
0015e394 3165a921 ChartFX_ClientServer_Core!Ordinal5507+0x5f32
0015e480 31678685 ChartFX_ClientServer_Core!Ordinal5496+0x26a
0015e568 3167bef4 ChartFX_ClientServer_Core!Ordinal5492+0x975
0015e668 316a356b ChartFX_ClientServer_Core!Ordinal5492+0x41e4
0015e77c 31709496 ChartFX_ClientServer_Core!Ordinal443+0x5745
0015e7d0 31707f70 ChartFX_ClientServer_Core!Ordinal2584+0x3cdc
0015e7f8 3170817d ChartFX_ClientServer_Core!Ordinal2584+0x27b6
0015e81c 3162fd76 ChartFX_ClientServer_Core!Ordinal2584+0x29c3
0015e86c 7719f8d2 ChartFX_ClientServer_Core!Ordinal899+0x6b6
0015e898 7719f794 USER32!GetMessageW+0x93
0015e910 771a06f6 USER32!GetWindowLongW+0x115
0015e940 771a069c USER32!CallWindowProcW+0x75
0015e960 747fcef4 USER32!CallWindowProcW+0x1b
0015e97c 747fd073 comctl32!Ordinal377+0x5c
0015e9e0 747fd027 comctl32!DefSubclassProc+0x92
0015ea04 747fd4e6 comctl32!DefSubclassProc+0x46
0015ea20 747fd073 comctl32!DefSubclassProc+0x505
0015ea84 747fd118 comctl32!DefSubclassProc+0x92
0015eae4 7719f8d2 comctl32!DefSubclassProc+0x137

3. Bug is not easy to reproduce (although it can be provoked usually in less than 5 min.)

我在几个TabPages中有几个Chart实例,这通常在我切换选项卡时发生 . 我仍然不知道如何重现它,除了在它们发生之前将这些标签切换几分钟,所以我不能使用我们的源代码控制来可靠地找到没有这个问题的构建 . 我通过管理的AxChart包装类(从AxHost派生)访问图表,这是由VS设计器自动创建的 .

4. What should be my next step?

如果有人能指出我下一步我应该找到真正的原因,我将非常感激 . 试验(删除和返回代码)没有多大好处,因为我不知道如何重现它,因此每次迭代需要花费大量时间才能说服自己错误仍在那里 .

我发现人们经常建议像“切换编译器优化”这样的东西,但由于异常没有确定性地抛出,我不想简单地重新安排一些字节并希望它永远不会返回 .

非常感谢提前!

最好的问候,Groo

3 回答

  • 0

    通过在代码中添加大量日志跟踪,我注意到在某些情况下,Chart的某个属性变为Double.NaN . 在我得到它之后,应用程序总是在下一次图表重绘期间崩溃 . 通过处理Chart的PrePaint和PostPaint事件(幸运的是它有这些事件),我确认崩溃发生在这两个事件之间 .

    特别是,只有在我第一次绘制图表的缩放之前(自上次更新以来的第一次),才会发生这种情况 . 我设法以不同的方式做到了,并且从那以后它没有崩溃 .

    我对这个“解决方案”不是很满意,因为它显然是一些在实际崩溃之前无法精确检测到的内部问题,我可能只是这样隐藏它 . 但我现在必须保留现状,因为否则我会失去太多时间 .

    [Update]

    Replicated the bug successfully

    我做了一个快速测试应用程序,在实际绘制之前我将两个图表的属性设置了两次,并且应用程序立即崩溃 . 我已向Software FX报告了该错误,但没有得到答案 . 这不是我对这个控件的第一个恼人的错误,但是对于我们的下一个版本,我们将切换到他们的托管(.Net)版本,所以我们至少会让Reflector找到如何解决这些错误 .

    无论如何,谢谢大家!

  • 1

    它看起来非常像线程安全问题 .
    我建议你从阅读控件的文档开始,专门提到线程安全性 . COM组件通常使用的线程模型与(普通的).NET使用不同 - 并且通常是不兼容的 .

  • 2

    过了一会儿 . 我们的例子是PInvoke调用:OpenPrinter(string port);

    我们的问题是托管代码发送:“LPT1:”但是非托管代码声明了一个字节[1024]数组,并从字符串的地址开始向前读取1024个字节 . 这将读取分配的字符串(“LPT1:”)的边界之外,并偶尔漫游到未分配给应用程序的内存中,从而导致此间歇性AccessViolationException .

    我们通过将调用更改为:OpenPrinter(int length,string port)来修复此问题,因此非托管代码可以声明一个正确长度的字节数组 .

    ctacke的This post也有一些好处,试图弄清楚可能导致这个问题的原因 .

相关问题