views:

217

answers:

3

I'm working for a client that has a VB6 app in the migration process to .NET.

Currently they have a .NET shell, but host some old VB6 controls in .NET. There's an error I stumbled upon is logs that happens when they in .NET asynchronously pull some data from the database, and then forward that data to a COM component to display it:

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()

then the following shows up in the logs:

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_

Did anyone ever encounter something like this? How do I approach fixing it?

+1  A: 

If I understand it correctly, this COM component is a visible UI component in a form? If so, could it be that the problem is that the component is being updated from another thread than the UI thread? You could try the following:

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

This will ensure that the code that updates the component is always executed on the UI thread.

Fredrik Mörk
yes, the component is a UI control, and it's quite likely it's updated from some other thread. Not sure tough as I haven't seen the code yet, just got the logs. However I think I would get other exception if this was indeed a problem with other thread updating UI, or is it for .NET only? Dunno really how COM handles that. Anyway - I'll try your suggestion.
Krzysztof Koźmic
Correct me if I'm wrong, but I believe you can corrupt memory by having a UI component directly updated from a different thread. . .
Jason D
A: 

I had the same kind of problems in C++. (I don't really do COM but maybe it can help you.)
In C++, when I get an Access Violation, it is caused by two problems generally:
- You are using an uninitialized var or a NULL pointer
- You have a buffer overflow

Now I don't know if it is possible in VB6 or in COM but you should verify every place where you allow a new variable and make sure that it is allocated before you try to use it.
You should also check for buffer overflow.

To help you in this task, you can use many tools that can help you. In VB6, at my job, they use "DevPartner" wich is a great tool to find why you have Access Violation.
In Visual Studio 2005, "DevPartner" is still available but Microsoft also put in a tool to help you find buffer overflow and errors.

I found that Access Violation are the worst error to have, and the most difficult to find. It is related to memory use.
I hope this helps! Good luck!

Danielle
I used to do lots of C++, and there is only one thing worse than a vanilla Access Violation... It's when you start executing random memory... *shudder* that happens when the instruction pointer gets hosed up.
Jason D
+1  A: 

This is most like cause by code accessing the UI from another thread. However, if you absolutely need to access the COM object from another thread, you can use a global interface table to marshal the COM pointer across the thread. Here are some tips and tricks on how to use a manipulate COM to marshal.

Andrew Keith
what about the fact that the control is a COM control. Does not COM do its own thread management? Will the component run on the .NET UI thread or its own? What if it spawns its thread?
Krzysztof Koźmic