【问题标题】:AccessViolationException in COM control in .NET app.NET 应用程序中 COM 控件中的 AccessViolationException
【发布时间】:2010-12-18 23:57:43
【问题描述】:

我正在为一个在迁移到 .NET 的过程中拥有 VB6 应用程序的客户工作。

目前他们有一个 .NET shell,但在 .NET 中托管了一些旧的 VB6 控件。 我偶然发现的一个错误是当它们在 .NET 中异步从数据库中提取一些数据,然后将该数据转发到 COM 组件以显示它时发生的日志:

The Undo operation encountered a context that is different from what was applied in the corresponding Set operation. The possible cause is that a context was Set on the thread and not reverted(undone).
                Err Source: mscorlib
                Err Type: System.InvalidOperationException

ERROR stack trace:
   at System.Threading.SynchronizationContextSwitcher.Undo()
   at System.Threading.ExecutionContextSwitcher.Undo()
   at System.Threading.ExecutionContext.runFinallyCode(Object userData, Boolean exceptionThrown)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteBackoutCodeHelper(Object backoutCode, Object userData, Boolean exceptionThrown)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
   at System.Windows.Forms.Control.InvokeMarshaledCallbacks()

然后在日志中显示以下内容:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
                Err Source: mscorlib
                Err Type: System.AccessViolationException

ERROR stack trace:
       at System.RuntimeType.ForwardCallToInvokeMember(String memberName, BindingFlags flags, Object target, Int32[] aWrapperTypes, MessageData& msgData)
       at _Client's component that forwards calls to COM_

有没有人遇到过这样的事情?我该如何解决?

【问题讨论】:

    标签: .net com vb6 interop


    【解决方案1】:

    如果我理解正确的话,这个 COM 组件是表单中的可见 UI 组件吗?如果是这样,问题可能是组件是从另一个线程而不是 UI 线程更新的吗?您可以尝试以下方法:

    Private Sub MethodThatUpdatesComponent(ByVal data As WhateverType)
        If Me.InvokeRequired Then
            Dim input As Object = { data }    
            Me.Invoke(new Action(Of WhateverType)(AddressOf MethodThatUpdatesComponent), input)
        Else
            ' put the code to update the COM component here '
        End If
    End Sub
    

    这将确保更新组件的代码始终在 UI 线程上执行。

    【讨论】:

    • 是的,该组件是一个 UI 控件,它很可能是从其他线程更新的。不确定很难,因为我还没有看到代码,只是得到了日志。但是,如果这确实是其他线程更新 UI 的问题,或者仅适用于 .NET,我想我会得到其他异常?不知道 COM 是如何处理的。无论如何 - 我会试试你的建议。
    • 如果我错了,请纠正我,但我相信你可以通过直接从不同的线程更新 UI 组件来破坏内存。 . .
    【解决方案2】:

    这很可能是代码从另一个线程访问 UI 造成的。但是,如果您绝对需要从另一个线程访问 COM 对象,则可以使用 global interface table 跨线程封送 COM 指针。以下是有关如何使用manipulate COM 进行封送处理的一些提示和技巧。

    【讨论】:

    • 控件是 COM 控件这一事实怎么样。 COM不做自己的线程管理吗?组件将在 .NET UI 线程上运行还是在它自己的线程上运行?如果它产生它的线程怎么办?
    【解决方案3】:

    我在 C++ 中也遇到过同样的问题。 (我并没有真正做 COM,但也许它可以帮助你。)
    在 C++ 中,当我遇到访问冲突时,通常是由两个问题引起的:
    - 您正在使用未初始化的 var 或 NULL 指针
    - 你有一个缓冲区溢出

    现在我不知道在 VB6 或 COM 中是否可能,但您应该验证允许新变量的每个位置,并确保在尝试使用它之前分配它。
    您还应该检查缓冲区溢出。

    为了帮助您完成此任务,您可以使用许多可以帮助您的工具。在 VB6 中,在我的工作中,他们使用“DevPartner”,这是一个很好的工具,可以找出您访问冲突的原因。
    在 Visual Studio 2005 中,“DevPartner”仍然可用,但 Microsoft 还提供了一个工具来帮助您查找缓冲区溢出和错误。

    我发现访问冲突是最严重的错误,也是最难找到的。它与内存使用有关。
    我希望这有帮助!祝你好运!

    【讨论】:

    • 我曾经做过很多 C++,只有一件事比普通的访问冲突更糟糕……那就是当你开始执行随机内存时……颤抖当指令指针变大时发生。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-26
    • 1970-01-01
    • 2012-12-06
    • 2017-01-10
    • 1970-01-01
    • 2011-06-11
    • 2010-10-10
    相关资源
    最近更新 更多