【问题标题】:Unhandled exception of type 'System.ApplicationException' occurred in System.Drawing.dllSystem.Drawing.dll 中发生未处理的“System.ApplicationException”类型异常
【发布时间】:2017-12-09 17:01:51
【问题描述】:

我有一个 winforms 应用程序。在开发模式下,从 Visual Studio .NET 2003 调试时(是的,我知道它很旧,但这是一个遗留项目),当我尝试打开新表单时出现此错误。为了打开一个新表单,我得到一个表单实例,然后调用 ShowDialog() 方法,例如:

frmTest test = new frmTest(here my parameters);
test.ShowDialog();

如果我在调试时按 F11(进入)它不会崩溃,但是如果在我实例化表单的行中我按 F10 进入下一行,即 test.ShowDialog(),那么它会崩溃显示这个错误。

完整的消息错误是:

“发生“System.ApplicationException”类型的未处理异常 在 System.drawing.dll 中。附加信息:已尝试 释放一个不属于进程的互斥"

我已经翻译了最后一部分:附加信息......因为它以西班牙语出现。

我用参数实例化的表单,它的构造函数,包括初始化一些变量,例如:

public frmTest(string param1, string param2)
{
   InitializeComponent();

   this.param1 = param1;
   this.param2 = param2;
}

private void frmTest_Load(object sender, EventArgs e)
{
    // here I call a remote webservice asynchronously.
}

我的表单“frmTest”也有四个图片框、一个标签和一个按钮。其中三个图片框包含一个 png 图像(它在设计时通过 Image 属性分配),最后一个图片框包含一个动画 gif,也在设计时通过 Image 属性加载。可能是因为这些图片导致的错误?

【问题讨论】:

  • 您可以尝试删除所有图片框的图像属性并运行程序。如果运行良好,则开始一次设置一个图片框的属性并运行程序以确定哪个图片框是问题的原因。
  • 如果您无法移植,还可能值得通过获取完整的堆栈跟踪并使用 JetBrains 的免费 dotPeek 等反编译工具来进一步跟踪它,以查看 .net 1.1 dll 的源代码正如@III 建议的那样。
  • 这是一个非常奇怪的例外。但谁知道呢,ApplicationException 是 .NET 1.0 的设计错误之一。这个问题需要更好的、非翻译的异常消息和堆栈跟踪。但这可能是一个线程错误,.NET 1.x 在没有像样的诊断的情况下很容易出错。使用调试器的 Debug > Windows > Threads 窗口查看发生了什么。
  • 我认为您应该向我们展示表单构造函数中发生了什么,也许我们可以为您提供更多帮助
  • 可能图像是异步加载的,表单还没有准备好被调用(ShowDialog 方法)。你不能在你的表单上创建一个可以在加载/渲染后触发的事件/委托。该事件将调用“test.ShowDialog(); 代码。希望这会有所帮助

标签: c# winforms visual-studio picturebox .net-1.1


【解决方案1】:

应用程序异常不是由框架本身抛出的:what-is-applicationexception-for-in-net;问题应该出在你没有框架的代码中。还请务必在执行操作之前检查“InvokeRequired”属性,如果是,请使用“Invoke”方法运行该方法。可以查看c-sharp-cross-thread-call-problem

【讨论】:

    【解决方案2】:

    可能是异步调用正在尝试访问 UI 线程。

    确保您没有使用像TextBox.Text 这样的控件属性。如果是这样,您只需将其值传递给异步调用,或在调用之前将其存储在类变量中。

    此外,在异步调用中,您无法为该属性分配值。请改用Invoke()

    【讨论】:

      【解决方案3】:

      尝试添加异常断点,VS 会在导致异常的指令处停止。实际的堆栈跟踪可能会有所帮助。

      你试过关闭 VS 的局部变量观察窗口吗?也许它正在为您评估 UI 组件上的某些东西,其中访问线程应该等于 UI 组件的所有者线程!

      【讨论】:

      • 为什么是-1?两者都是有效的调试步骤!许多人不知道异常断点。许多人不关心实际值如何在局部变量监视窗口中变得可见。在 VS 实际执行我们的部分代码以显示值时,可能会导致不可预知的功能失常;特别是在 winforms 控件中,其中 hwnd 创建者线程非常重要。
      【解决方案4】:

      TL;DR:您的网络请求处理程序将在不同的线程上执行。确保您没有在该处理程序中执行任何非线程安全的操作。您可以使用Invoke 将回调处理程序的代码分派到主线程。

      诊断

      这里的问题几乎可以肯定隐藏在您的异步调用的缺失细节中。

      // here I call a remote webservice asynchronously.
      

      异步有点太模糊,无法确定究竟发生了什么,但很有可能您使用的异步机制已经执行了它的在与主 UI 线程不同的线程上回调。

      概述

      这在 .NET 模型中很常见。 .NET 模型中的异步 I/O 使用线程池中的线程通过I/O Completion Ports (IOCP) 处理 I/O。这意味着当像Socket.BeginReceiveWebRequest.BeginGetResponse这样的调用(或任何内部使用类似技术的.NET异步Web请求)完成时,回调将在线程池中的线程上执行不是主线程。这可能会让您感到惊讶,因为您没有主动创建另一个线程;你刚刚参与了异步调用。

      您必须非常小心在 Web 请求的回调中执行的操作,因为除了主 UI 线程之外的任何线程都不允许进行许多用户界面/Windows 窗体操作。同样,可能不是 UI 本身导致您出现问题,您可能刚刚访问了一些不是线程安全的资源或对象。如果您不小心使用多线程,许多看似无害的事情可能会导致崩溃或异常。

      解决问题:

      如果有疑问,请尽早在您的回调中调度(又名Invoke)处理程序中的代码,以便它在主线程上运行。

      执行此操作的常见模式如下所示。

      假设你打了这样一个电话:

      IAsyncResult result = (IAsyncResult myHttpWebRequest.BeginGetResponse(
          new AsyncCallback(RespoCallback), myRequestState);
      

      处理程序可能是这样设置的:

      private static void RespCallback(IAsyncResult asynchronousResult)
      {  
          // THIS IS NOT GOING TO WORK BECAUSE WE ARE ON THE WRONG THREAD.  e.g.:
          this.label1.Text = "OK";  // BOOM!  :(
      }
      

      相反,将任何必要的处理分派回主线程。

      private static void RespCallback(IAsyncResult asynchronousResult)
      {  
          this.Invoke((MethodInvoker) delegate { 
             // This block of code will run on the main thread.
             // It is safe to do UI things now.  e.g.:
             this.label1.Text = "OK";  // HOORAY!  :)
          });
      }
      

      建议将此作为一般最佳做法。我不是说要立即将所有处理程序分派回主线程。一种尺寸适合所有人。您应该真正查看您在处理程序中所做的具体细节,并确保您没有做特定于线程的事情。但我说,如果您没有对异步处理程序在做什么做出任何解释,问题可能会通过invoking 主线程上的处理程序代码来解决。 p>

      注意:当然,要解决此技术的问题,它需要您的主线程正在运行。如果您使用this example 中的(坏)技术阻塞了您的主线程,那么您将不得不重新设计您的应用程序的一部分。下面是一个需要更大返工的例子:

      // Start the asynchronous request.
      IAsyncResult result=
        (IAsyncResult) myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback),myRequestState);
      
      // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
      ThreadPool.RegisterWaitForSingleObject (result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), myHttpWebRequest, DefaultTimeout, true);
      
      // The response came in the allowed time. The work processing will happen in the 
      // callback function.
      allDone.WaitOne(); // *** DANGER:  This blocks the main thread, the IO thread
                         // won't be able to dispatch any work to it via `invoke`
      

      注意到WaitOne 电话了吗?这会阻止执行线程的执行。如果此代码在主线程上执行,则主线程将被阻塞,直到 WebRequest 完成。您必须重新设计,以便您不会阻塞主线程(我的建议),或者您更仔细地检查您的回调处理程序,看看为什么它正在做的事情与其他线程发生冲突。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-04-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多