我遇到了上述很多问题的问题。我们有一个多年来一直运行良好的 TCP/IP 服务器应用程序。我现在需要允许应用程序接受来自直接连接的 USB 设备的连接,方法是在内部使用套接字连接修补服务器应用程序中的 localhost (127.0.0.1)。(顺便说一句,我提到 USB 只是为了解释我这样做的原因 - 作为调试此问题的一部分,我禁用了所有 USB 功能)。
沿着这个套接字的通信会导致在客户端和服务器端调用 GUI 元素。在客户端访问 GUI 元素会导致标题中的错误(下面的调用堆栈)。这里的关键问题之一是调试器无法停止异常:尽管所有异常都设置为在抛出时停止,但应用程序只是在错误发生时终止。
我的应用程序唯一看起来独特的是它使用内部套接字连接到 127.0.0.1。我还确认如果客户端被分离到一个单独的应用程序中,该应用程序可以正常工作。但是,由于其他原因,我不能将其用作永久解决方案。
有几篇文章讨论了我在下面列出的这类问题。不幸的是,在我的情况下似乎没有人提供解决方案:
- 大多数相关帖子都讨论了使用 Invoke 或 BeginInvoke 确保所有 GUI 操作都在 GUI 线程上执行的必要性。我相信我的应用程序可以正确执行此操作(它使用 Application.Forms 获取表单以获取主表单并在此调用 Invoke)并在调试器中进行了双重检查。
- 与上述相关,有一些关于使用 Invoke 与 BeginInvoke 来阻止/不阻止的讨论。在我的情况下,两者都有相同的结果。
- 一些帖子建议有必要在 GUI 线程上自己创建套接字(我的是)。
- 这解释了如果您在应用程序中使用 DoEvents 会出现错误(我没有)。
- 这也意味着在对客户端套接字连接使用异步调用(我的客户端连接是同步的)时,您可能会收到缺少 EndConnect 调用的错误。
- 这解释了如果尚未创建窗口句柄,您可能会从 InvokeRequired 获得不正确的结果(已使用 IsHandleCreated 进行了检查)。
- microsoft connect 上的这个报告了一个类似的错误,但没有解决方案(微软自 2006 年以来一直在“调查”它!)
- 这个包含使用 AsyncOperationManager.SynchronizationContext 备份/恢复同步上下文的建议,这(不出所料?)只会导致不同的错误。
- 有几篇文章表明错误只是调试,以下将使它消失 - 但我没有费心尝试:
System.Windows.Forms.Form.CheckForIllegalCrossThreadCalls = false
还有其他帖子提出了类似的问题:here、here和here。这里也不错。
这是一个代码片段 - 当客户端接收到套接字数据时,这会导致 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
我正在使用带有 .NET4 的 VB .NET 2010。
感谢您的帮助 - 我希望上述帖子的综合列表也对其他人有所帮助。
蒂姆
调用堆栈:
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).