In my windows forms app clients sometimes report a strange exception:
System.InvalidOperationException: Value Dispose() cannot be called while doing CreateHandle()
at System.Windows.Forms.Control.Dispose(Boolean disposing)
at System.Windows.Forms.ContainerControl.Dispose(Boolean disposing)
at System.ComponentModel.Component.Dispose()
at MyCompany.SomeApp.DialogBox.Show(string caption, string message)
at MyCompany.SomeApp.MainForm.Button1_Click(Object sender, MouseEventArgs e)
The code that causes this error looks like this:
namespace MyCompany.SomeApp
{
public class DialogBox : CustomForm
{
public s开发者_如何学Pythontatic DialogResult Show(string caption, string message)
{
using (DialogBox dialog = new DialogBox())
{
dialog.Text = caption;
dialog.lblMessage.Text = message;
return dialog.ShowDialog();
}
}
}
}
DialogBox is basically a class that inherits from Windows.Forms.Form and does some design changes, nothing special. The excepions happens at
return dialog.ShowDialog();
and not at the end of the using
block as I would expect. It looks like somehow, within the ShowDialog()
method and before the form's handle is created, the Dispose() method is called.
But my DialogBox neither calls Dispose() itself nor swallows other exceptions, it only does some painting in the OnPaint() event.
Does anybody have some clues how to get rid of this exception?
Update:
Here is the only code in my CustomForm class (besides changes mode in the windows forms designer (added 2 Labels, a button and changed some colors)
Public Class CustomForm
Inherits System.Windows.Forms.Form
<DebuggerStepThrough()> _
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
Static pen1 As New Pen(Color.FromArgb(39, 46, 54), 21)
Static pen2 As New Pen(Color.FromArgb(44, 51, 59), 1)
Static pen3 As New Pen(Color.FromArgb(93, 99, 99), 1)
Static pen4 As New Pen(Color.FromArgb(119, 124, 127), 1)
Static pen5 As New Pen(Color.FromArgb(148, 157, 156), 1)
Static pen6 As New Pen(Color.FromArgb(175, 185, 186), 1)
With e.Graphics
.DrawRectangle(Pens.Black, 0, 0, (Me.Width - 1), (Me.Height - 1))
.DrawLine(pen1, 1, 11, Me.Width - 1, 11)
.DrawLine(pen2, 1, 22, Me.Width - 2, 22)
.DrawLine(pen3, 1, 23, Me.Width - 2, 23)
.DrawLine(pen4, 1, 24, Me.Width - 2, 24)
.DrawLine(pen5, 1, 25, Me.Width - 2, 25)
.DrawLine(pen6, 1, 26, Me.Width - 2, 26)
End With
End Sub
Private Const GWL_STYLE As Integer = (-16)
Private Const WS_CAPTION As Integer = &HC00000
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _
(ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer
Public ReadOnly Property HasCaption() As Boolean
Get
return (GetWindowLong(Me.Handle, GWL_STYLE) And WS_CAPTION) = WS_CAPTION
End Get
End Property
End Class
Update: I changed the code a little bit because it was misleading.
In the stacktrace you can see that My.App.DialogBox.Show(...) is called. Which is a static method that contains the using block. Neither DialogBox nore CustomForm override the ShowDialog() method of Form (which is why it is not shown in the stacktrace.Think I found a clou here: http://softwareinvent.com/wordpress/?p=10
I kept getting an odd exception today:
Value Dispose() cannot be called while doing CreateHandle()
I couldn’t figure out what was causing it until I started commenting out large swaths of code (gotta love brute force debugging ). It all came down to a very innocent looking line of code:
if (Handle != IntPtr.Zero)
This line of code grabs an unmanaged Windows handle. As a result, that handle must be manually cleaned up
Looks exactly like my problem. Maybe some weired threading issue in which, in rare conditions the HasCaption property is called exactly at the same time as the property HasCaption gets queried.
Start by breaking it up, because now you can't tell if it's this using block or a Dispose inside the Dialog.
The following will be much more informative in the debugger:
using (DialogBox dialog = new DialogBox())
{
dialog.Text = caption;
var r = dialog.ShowDialog();
return r;
}
Edit
I find this line in the error message
at My.App.DialogBox.Show()
hard to reconcile with
return dialog.ShowDialog();
So, is the error happening with .Show() or .ShowDialog() ?
I was also getting this exception off and on while running unit tests. Turns out it was a threading issue. Depending on timing, another thread was attempting to modify a GUI control while the main test thread was tearing down and disposing of the form that contained the control.
I changed the unit test to wait for all expected GUI updates (even though that wasn't what was being tested) before exiting and the problem was resolved.
This is quite old question. But if someone's interested in, this is my solution.
`Timer tmr = new Timer();
tmr.Interval = 1000;
tmr.Tick += tmrTick;
tmr.Start();
void tmrTick(Object sender, EventArgs e){
Timer tmr = sender as Timer;
tmr.Stop();
Form.Close(); //Form is form which wants to close by instance name. for example: this.Close()
}`
Maybe there are some wrong syntax cause translating Vb to c# by myself. Sorry for this. But it must be nearly like this by c#.
精彩评论