У меня проблемы с вышеупомянутой ошибкой, о которой часто спрашивают.У нас есть серверное приложение TCP / IP, которое отлично работает уже несколько лет.Теперь мне нужно разрешить приложению принимать подключения от напрямую подключенных USB-устройств, внутренне используя сокетное соединение для подключения к локальному узлу (127.0.0.1) внутри серверного приложения.(Кстати, я упоминаю USB только для объяснения, почему я делаю это - я отключил все функции USB как часть отладки этой проблемы).
Связь по этому сокету может привести к вызовам элементов GUI как на стороне клиента, так и на стороне сервера.Доступ к элементам GUI на стороне клиента вызывает ошибку в заголовке (стек вызовов ниже).Одна из ключевых проблем здесь заключается в том, что отладчик не может остановить исключение: несмотря на то, что все исключения, настроенные для остановки при выбросе, приложение просто завершает работу при возникновении ошибки.
Единственное, что кажется уникальным в моемПриложение заключается в том, что он использует внутренний сокет для подключения к 127.0.0.1.Я также подтвердил, что приложение работает нормально, если клиент разделен на отдельное приложение.Однако я не могу использовать это как постоянное решение по другим причинам.
Есть несколько постов, обсуждающих проблему такого рода, которые я перечислил ниже.К сожалению, ни один из них не дает решения в моем случае:
- В большинстве связанных постов обсуждается необходимость обеспечения выполнения всех операций графического интерфейса в потоке графического интерфейса с помощью Invoke или BeginInvoke.Я уверен, что мое приложение делает это правильно (оно получает форму, используя Application.Forms, чтобы получить основную форму, и вызывает Invoke для этого), и дважды проверило в отладчике.
- В связи с вышесказанным, существует некоторое обсуждение относительно использования Invoke против BeginInvoke для блокировки / отсутствия блокировки.В моем случае оба имеют одинаковый результат.
- Некоторые сообщения предполагают, что необходимо создавать сами сокеты в потоке графического интерфейса (мои есть).
- Этот объясняет, что вы можете получить ошибку, если вы используете DoEvents в своем приложении (я не знаю).
- Этот также подразумевает, что вы могли получить ошибку с отсутствующим вызовом EndConnect при использовании асинхронных вызовов для соединения с сокетом клиента (мое соединение с клиентом является синхронным).
- Этот объясняет, что вы можете получить неверные результаты из InvokeRequired, если дескриптор окна еще не создан (проверил это с помощью IsHandleCreated).
- Этот в Microsoft Connect сообщает о похожей ошибке, но не имеет решения (Microsoft исследует ее с 2006 года!)
- Этот содержит предложениеиспользовать AsyncOperationManager.SynchronizationContext для резервного копирования / восстановления контекста синхронизации, что (неудивительно?) просто вызывает различные ошибки.
- Есть несколько постов, которые предполагают, что ошибка является только отладочной, и следующее заставит ее исчезнуть - но я не потрудился попробовать это:
System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = false
Есть и другие посты, задающие подобные вопросы: здесь , здесь и здесь .Хороший здесь тоже.
Вот фрагмент кода - это вызывает сбой в ProcessCommandCT, когда клиент получает данные сокета:
' Find application main form from any thread
' There is only one instance of 'RibbonForm1' and this is the main form
Public Function GetRibbonForm() As RibbonForm1
Dim rf As RibbonForm1 = Nothing
For Each f As Form In My.Application.OpenForms
rf = TryCast(f, RibbonForm1)
If rf IsNot Nothing Then Return rf
Next
Return Nothing
End Function
Public Sub ProcessCommandCT(ByVal cmd As String)
' code is peppered with these to debug this problem
Debug.Assert(GetRibbonForm.IsHandleCreated)
Debug.Assert(Not GetRibbonForm.InvokeRequired)
Try
Select Case cmd
Case "MYCMD"
Dim f As New Form
f.ShowDialog()
End Select
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
Private Sub sock_Receive(ByVal msg As String) Handles sck.Receive
Dim rf As RibbonForm1 = GetRibbonForm
If rf.InvokeRequired Then
rf.BeginInvoke(New SubWithStringArgDelegate(AddressOf ProcessCommandCT), New Object() {msg})
Else
ProcessCommandCT(msg)
End If
End Sub
I 'Я использую VB .NET 2010 с .NET4.
Спасибо за любую помощь - надеюсь, что приведенный выше список постов также поможет другим.
Тим
Стек вызовов:
The thread '<No Name>' (0x148c) has exited with code 0 (0x0).
System.Transactions Critical: 0 : <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Critical"><TraceIdentifier>http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/Unhandled</TraceIdentifier><Description>Unhandled exception</Description><AppDomain>myapp.vshost.exe</AppDomain><Exception><ExceptionType>System.InvalidOperationException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>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).</Message><StackTrace> 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, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)</StackTrace><ExceptionString>System.InvalidOperationException: 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).
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, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)</ExceptionString></Exception></TraceRecord>
The program '[6324] myapp.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).