无法调用Invoke或BeginInvoke错误

时间:2013-04-09 00:28:18

标签: c# multithreading visual-studio exception exception-handling

我有一个全球客户使用的程序。我检查了我的错误日志,并且有很多似乎有一个异常(如下所列)被抛出,我无法弄清楚或追踪。

我有一些调用,但它们都受InvokeRequired保护。 现在我在想,如果我应该使用if(HandleCreated)代替。

我甚至不确定抛出异常的地点或时间。

在启动时,在InitializeComponent();之后,我有一些任务需要访问某些控件,例如datagridview。但是,就像我说的,我尝试使用InvokeRequired来保护它们。我不确定这是否是引起问题的地方。

我可以执行哪些建议,请尝试跟踪此问题?

无论如何,这是我的例外:

    System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a 

control until the window handle has been created.
   at System.Windows.Forms.Control.WaitForWaitHandle(WaitHandle waitHandle)
   at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate 

method, Object[] args, Boolean synchronous)
   at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
   at System.Windows.Forms.Control.Invoke(Delegate method)
   at ..()
   at ..()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, 

ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

2 个答案:

答案 0 :(得分:1)

不,如果您使用InvokeRequired,则不会发生这种情况。只有当Handle有效时才会出现这种情况。非常简单,无论如何都要避免,只是不要订阅事件或启动线程,直到Load事件触发。

当表单关闭时发生此崩溃。你在堆栈跟踪中看不到的东西,因为它发生在另一个线程上。 InvokeRequired + Begin / Invoke()中存在竞争条件。 InvokeRequired可能会返回true,稍后表单将关闭。您的开始/调用调用将因此异常而失败。

这不是你能解决的种族。您必须确保线程在允许表单关闭之前不能再调用BeginInvoke()。这总是意味着您必须阻止表单关闭。背景信息位于this answer

答案 1 :(得分:0)

我不确定跟踪是否会完全帮助你。在您创建句柄之前,您在代码中的某个位置显然正在调用invoke / BeginInvoke。现在,我建议的可能需要一些工作,但你会指出过早调用非创建句柄的调用者。在尝试跟踪生产中的一些旧C ++遗留代码中的锁定/解锁线程问题时,我使用了这种技术。它工作得很好,我只是保持原样。

这是我的技巧。创建一个Extension类,接受支持Invoke / BeginInvoke和EndInvoke的对象。它可能看起来像这样:

public static class MyInvokeExtension
{
   public static void TempInvoke(this objectthatsupportsinvoke, ...)
   {
        try
        {
           objectthatsupportsinvoke.Invoke(...);
        }
        catch(Exception ex)
        {
           Console.WriteLine();  // put a break-point here
        }
   }

   // add other BeginInvoke and EndInvoke methods and do the same as above.
}
  • 现在在整个代码中进行搜索和替换,并将所有类似Invoke的调用替换为类似于调用的TempInvoke。
  • 在debug中运行应用程序。
  • 在某些时候你会遇到一个突破点。
  • 使用调用堆栈窗口查找更早调用调用方法的人。

我知道这是很多工作,但从长远来看它值得,相信我。实际上,您甚至可以使用此代码来验证对象是否可以处理给定时间点的调用。

让我知道它是怎么回事。