Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unhandled exception of type 'System.ApplicationException' occurred in System.Drawing.dll

I have a winforms app. In development mode, when debugging from Visual Studio .NET 2003 (Yes, I know it's old, but this is a legacy project), I get this error when I try to open a new form. In order to open a new form I get an instance of the form and then I call ShowDialog() method, for example:

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

If I press F11 (step into) when debugging it is not crashing, but If in the line where I instantiate the form I press F10 to go into next line, that is, test.ShowDialog(), then it crashes showing this error.

The complete message error is:

"An unhandled exception of type 'System.ApplicationException' occurred in System.drawing.dll. Additional Information: An attempt was made to free a mutual exclusion that does not belong to the process"

I have translated last part: Additional information ... since it was appearing in spanish.

The form that I am instantiating with parameters, its constructor, consists on initialize some variables for example:

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.
}

Also my form "frmTest" has four pictureboxes, a label, and a button. Three of the pictureboxes contain a png image (it is assigned on design time through Image property), the last picturebox contains a animated gif, also loaded in design time through Image property. Maybe the error occurs due to these images?

like image 298
Ralph Avatar asked Jul 05 '17 21:07

Ralph


1 Answers

TL;DR: Your web request handler will execute on a different thread. Ensure you don't do anything that isn't thread-safe in that handler. You can use Invoke to dispatch your callback handler's code to the main thread.

Diagnosis

The problem here is almost certainly hiding in the missing details of your asynchronous call.

// here I call a remote webservice asynchronously.

Asynchronously is a little bit too vague to be sure what exactly is happening, but there's a very good chance that the asynchronous mechanism that you are using has executed its callback on a different thread from the main UI thread.

Overview

This is common in the .NET model. Asynchronous I/O in the .NET model makes use of threads in a thread pool to handle I/O via I/O Completion Ports (IOCP). It means that when a call like Socket.BeginReceive or WebRequest.BeginGetResponse (or any .NET asynchronous web request that uses similar technology internally) completes, the callback will execute on a thread in the thread pool, not the main thread. This may be surprising to you, since you didn't actively create another thread; you just participated in making asynchronous calls.

You must be very careful about what you do in the callback from your web request as many user-interface / Windows Forms operations are not permitted on any thread other than the main UI thread. Similarly, it may not be the UI itself that is causing you problems, you may have just accessed some resource or object that is not thread safe. Many seemingly innocuous things can cause a crash or exception if you're not careful with multithreading.

To resolve the issue:

If in doubt, in your callback, as early as you can, dispatch (a.k.a. Invoke) the code in your handler so that it runs on the main thread.

A common pattern for doing this would be something like what follows below.

Suppose you have made a call like this:

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

The handler might be set up like this:

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!  :(
}

Instead, dispatch any necessary processing back to the main thread.

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!  :)
    });
}

I'm not advising this as a general best practice. I'm not saying to just immediately dispatch all your handlers back to the main thread. One size does not fit all. You should really look at the specific details of what you do in your handler and ensure you aren't doing thread-specific things. But I am saying that in the absence of any kind of explanation from you about what your asynchronous handlers are doing, the problem would likely be solved by invoking the handler code on the main thread.

Note: Of course, to fix your problem with this technique, it requires that your main thread is running. If you blocked your main thread with a (bad) technique like the one in this example then you'll have to redesign part of your app. Here's an example of something that would require a bigger rework:

// 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`

Notice the WaitOne call? That blocks execution of the executing thread. If this code executes on the main thread, then the main thread will be blocked until the WebRequest completes. You'll have to redesign so that either you don't block the main thread (my recommendation) or that you more closely examine your callback handler to see why what it's doing is conflicting with other threads.

like image 80
Wyck Avatar answered Oct 18 '22 20:10

Wyck