Roman
Roman

Reputation: 1711

A generic error ocurred in GDI+ (not in ASP.NET)

I have a really simple form with an image inside (a "loading" GIF). That's all. Sometimes, when my program is really busy doing something, I want to show this form to tell the user that the system is busy, and I do that on a separate thread, this way (MainThreadBase.SystemBusy is the form and it's static):

public static void SetSystemBusy(bool isBusy)
{
    try
    {
        if (isBusy)
        {
            if (threadSystemBusy == null)
            {
                if (MainThreadBase.SystemBusy == null)
                {
                    MainThreadBase.SystemBusy = new Controls.OutputControls.OutputControl_SystemBusy();
                }
                threadSystemBusy = new Thread(() => SetSystemBusyThread());
                threadSystemBusy.Start();
            }
        }
        else
        {
            if (threadSystemBusy != null)
            {
                threadSystemBusy.Abort();
                threadSystemBusy.Join();
                threadSystemBusy = null;
            }
            MainThreadBase.SystemBusy = null;
        }
    }
    catch (Exception e)
    {
        LogFile.appendLine_error(e);
    }
}

private static void SetSystemBusyThread()
{
    try
    {
        MainThreadBase.SystemBusy.BringToFront();
        MainThreadBase.SystemBusy.TopLevel = true;
        MainThreadBase.SystemBusy.TopMost = true;
        MainThreadBase.SystemBusy.ShowDialog();
    }
    catch (ThreadAbortException tae)
    {
    }
    catch (Exception e)
    {
        LogFile.appendLine_error(e);
    }
}

So, sometimes (I cannot see a pattern, but I suspect that it is when I try to show it more than once at the same time, but as you can see I assure that there is just one active thread) it throws this error and I cannot know why or where it is thrown. The stack trace is the following:

   at System.Drawing.Image.SelectActiveFrame(FrameDimension dimension, Int32 frameIndex)
   at System.Drawing.ImageAnimator.ImageInfo.UpdateFrame()
   at System.Drawing.ImageAnimator.UpdateFrames()
   at System.Windows.Forms.Label.OnPaint(PaintEventArgs e)
   at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
   at System.Windows.Forms.Control.WmPaint(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.Label.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at PCC.Program.Main() in C:\Documents and Settings\rhervas\My Documents\Proyectos\PCC\SCFMV_MAIN\Program.cs:line 46

Line 46 in Program.cs is just this:

Interface_Login interfaceLogin = new Interface_Login();
Application.Run(interfaceLogin);

So it tells me nothing. How do I fix this problem?

(Note: I have seen a lot of questions related to this error, and none of them fit my case. I have seen that many of them are solved using MemoryStream, but I am not editing or saving any image. Said this, here I go.)

Upvotes: 1

Views: 659

Answers (1)

Hans Passant
Hans Passant

Reputation: 941455

if (MainThreadBase.SystemBusy == null)
{
    MainThreadBase.SystemBusy = new Controls.OutputControls.OutputControl_SystemBusy();
}

This is fertile ground for trouble after you've called threadSystemBusy.Abort(). The state of objects used on an aborted thread is very unpredictable. The only reasonable thing to do with them is disposing them, re-using them like you do is asking for trouble.

But this is just fundamentally getting it wrong. Slow operations must be performed on a worker thread, never the UI thread. Blocking the UI thread is forbidden by the COM STA contract. The BackgroundWorker class helps you get it right. Simply show the dialog after starting it, close the dialog in the RunWorkerCompleted event. Plus anything else you'd want to do with the results of the operation, like binding or updating controls. Move the slow code into the DoWork event handler.

Upvotes: 2

Related Questions