.NET应用程序中的COM控件中的AccessViolationException

时间:2009-11-21 08:39:04

标签: .net com vb6 interop

我正在为一个在.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_

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

3 个答案:

答案 0 :(得分: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线程上执行。

答案 1 :(得分:1)

这最常见的原因是代码从另一个线程访问UI。但是,如果您绝对需要从另一个线程访问COM对象,则可以使用global interface table来编组线程中的COM指针。以下是有关如何使用manipulate COM编组的一些提示和技巧。

答案 2 :(得分:0)

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

现在我不知道在VB6或COM中是否可以,但是你应该验证允许新变量的每个地方,并确保在你尝试使用它之前分配它。 您还应该检查缓冲区溢出
为了帮助您完成此任务,您可以使用许多可以帮助您的工具。在VB6中,在我的工作中,他们使用“DevPartner”,这是一个很好的工具,可以找到访问冲突的原因。 在Visual Studio 2005中,“DevPartner”仍然可用,但Microsoft还提供了一个工具来帮助您查找缓冲区溢出和错误。

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