The object is currently in use elsewhere

G

Guest

I have a splash screen that is displayed as the application starts. The
splash screen has text dynamically added to it to indicate the authorisation
mechanism and start-up progress. Due to the nature of the splash screen
graphic we have to draw the text onto the splash screen instead of assigning
text directly to each labels text property.

Internittently, one of our XP Pro SP2 test machines gets the following error
when displaying the splash screen that displays itself in a .NET Framework
invoked dialog:

Exception of type 'System.InvalidOperationException'
The object is currently in use elsewhere.
Stack Trace: at System.Drawing.TextureBrush..ctor(Image image, WrapMode
wrapMode)
at System.Windows.Forms.Control.PaintBackground(PaintEventArgs e,
Rectangle rectangle)
at System.Windows.Forms.Control.OnPaintBackground(PaintEventArgs pevent)
at System.Windows.Forms.Control.InvokePaintBackground(Control c,
PaintEventArgs e)
at System.Windows.Forms.Control.PaintTransparentBackground(PaintEventArgs
e, Rectangle rectangle)
at System.Windows.Forms.Control.PaintBackground(PaintEventArgs e,
Rectangle rectangle)
at System.Windows.Forms.Control.OnPaintBackground(PaintEventArgs pevent)
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.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg,
IntPtr wparam, IntPtr lparam)

The splash screen invokes itself on a separate thread via its ShowSplash
method:

/// <summary>
/// Initializes and shows a new <see cref="SplashForm"/>.
/// </summary>
/// <param name="localisedApplicationName">The localised application
name.</param>
/// <param name="versionedAssembly">An <see cref="Assembly"/> from which
version information can be extracted.</param>
/// <param name="localisedCopyright1">A first line of copyright
message.</param>
/// <param name="localisedCopyright2">A second line of copyright
message.</param>
/// <param name="localisedSplashBackdropImage">The splash backdrop
image.</param>
public static SplashForm ShowSplash( string localisedApplicationName,
Assembly versionedAssembly, string localisedCopyright1, string
localisedCopyright2, Image localisedSplashBackdropImage )
{
const string THREAD_NAME = "SplashScreen";

sShownInstance = new SplashForm( localisedApplicationName,
versionedAssembly, localisedCopyright1, localisedCopyright2,
localisedSplashBackdropImage );

// Create the thread and start it; when the instance is
// closed, this thread will stop automatically...
sThread = new Thread(new ThreadStart( DoSplashScreen ) );
sThread.Name = THREAD_NAME;
sThread.Start();

// Return the shown instance
return sShownInstance;
}

The label's paint event calls DrawSmearedText:

private void lblNotice_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
DrawSmearedString( mNotice, lblNotice, Brushes.SteelBlue, Brushes.Red, e
);
}

private void lblBuildNumberAndDate_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
DrawSmearedString( BuildNumberAndDate, lblBuildNumberAndDate,
Brushes.White, Brushes.Red, e);
}

private void lblPrerelease_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
DrawSmearedString( mPrerelease, lblBuildNumberAndDate, Brushes.White,
Brushes.Red, e);
}

private void lblProgress_Paint(object sender,
System.Windows.Forms.PaintEventArgs e)
{
using ( SolidBrush smearBrush = new SolidBrush( Color.FromArgb( 64, 255,
255, 255 ) ) )

using ( SolidBrush textBrush = new SolidBrush( lblProgress.ForeColor ) )
{
DrawSmearedString( mProgress, lblProgress, smearBrush, textBrush, e );
}
}

The DrawSmearedString method is as follows:

private static void DrawSmearedString( string text,
System.Windows.Forms.Label label, System.Drawing.Brush smearColour,
System.Drawing.Brush overwriteColour,
System.Windows.Forms.PaintEventArgs e)
{
// Our background colour changes from light to dark, so we can't draw
// a single text colour across it. So, we do some shadow drawing by
// smearing the text around in one colour, and then overwriting it in
another.

if ( text != null && text.Length > 0 )
{
const int OFFSET = 2;
for ( int x = 0; x <= OFFSET; x++ )
{
for ( int y = 0; y <= OFFSET; y++ )
{
// Assume the label has more than one row and create an offset rectangle
on which to draw the smeared text
RectangleF drawRect = new RectangleF( x, y, label.Width, label.Height);
e.Graphics.DrawString( text, label.Font, smearColour, drawRect );
}
}

e.Graphics.DrawString( text, label.Font, overwriteColour,
label.ClientRectangle );
}
}

I have managed to produce this error once on a W2K machine but not when
using VS 2003 IDE.

We are using .NET Framework v1.1 with appropriate service packs applied.

Any ideas?

Regards,

Ian Rowland
 
J

Jon Skeet [C# MVP]

Ian Rowland said:
I have a splash screen that is displayed as the application starts. The
splash screen has text dynamically added to it to indicate the authorisation
mechanism and start-up progress. Due to the nature of the splash screen
graphic we have to draw the text onto the splash screen instead of assigning
text directly to each labels text property.

Internittently, one of our XP Pro SP2 test machines gets the following error
when displaying the splash screen that displays itself in a .NET Framework
invoked dialog:

<snip>

Well, you're creating the splash screen on one thread and then using it
on another (by the looks of it) - that's a big "no no" in Windows
Forms.

See http://www.pobox.com/~skeet/csharp/threads/winforms.shtml
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top