Wednesday, October 21, 2009
WinForms App Locked Up - Stack shows OnUserPreferenceChanged leading to a WaitOne after unlocking workstation
Today I had an interesting bug to track down in which an application kept locking up after I locked and then unlocked my workstation. I was able to attach the debugger, do a "Break All" and then use the Thread and Call Stack windows get a trace stack. Somewhere down in the .NET framework, the
Presumably, whatever was suppose to signal the
After Googling for some answers, it became apparent that there was probably a threading problem somewhere in the application (as if you couldn't have assumed that one?). Apparently, all top-level controls automatically register for the
Even with that bit of knowledge, it became difficult to track down the problem. But, "Burn me now, or burn me later" -- I eventually deteremined that it was caused by a cross-threading issue that occurred earlier in the application; for some reason, Visual Studio did not detect it as a cross-thread exception. There was a spot in code that used a
Microsoft.Win32.SystemEvents.OnUserPreferenceChanged method raised the UserPreferenceChanged event, and an event handler attached to that event ultimately lead to WaitOne which was blocking indefinitely on the UI thread. The top of the callstack looked like this:
[In a sleep, wait, or join]
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x2f bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x25 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle = {System.Threading.ManualResetEvent}) + 0x77 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous) + 0x393 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args) + 0x50 bytes
System.Windows.Forms.dll!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback d, object state) + 0x5f bytes
System.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization = true, object[] args = {object[2]}) + 0x62 bytes
System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization = true, object key = {object}, object[] args = {object[2]}) + 0x10f bytes
System.dll!Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(int msg, System.IntPtr wParam, System.IntPtr lParam) + 0x77 bytes
System.dll!Microsoft.Win32.SystemEvents.WindowProc(System.IntPtr hWnd = 9111196, int msg = 8218, System.IntPtr wParam = 47, System.IntPtr lParam = 188618224) + 0x2e0 bytes
Presumably, whatever was suppose to signal the
WaitOne was also on the main UI thread, so there was a deadlock. Whatever was wrong was apparently happening deep-down in the framework, as there was nothing in the application source code that ever attached an event handler to the UserPreferenceChanged event.After Googling for some answers, it became apparent that there was probably a threading problem somewhere in the application (as if you couldn't have assumed that one?). Apparently, all top-level controls automatically register for the
UserPreferenceChanged event so that they can update themselves when the WM_SETTINGCHANGE Windows message is received to indicate that desktop properties (color, theme, etc.) have changed. And, when SystemEvents raises an event to a partiuclar event handler, it checks to see if it is already on the thread appropriate for the object receiving the event; if it is not, it Invokes over to the appropriate thread. But, if the thread onto which the event handler is invoked does not have a message pump, a lockup occurs (summarized from From kbalertz.com) because Invoke waits forever.Even with that bit of knowledge, it became difficult to track down the problem. But, "Burn me now, or burn me later" -- I eventually deteremined that it was caused by a cross-threading issue that occurred earlier in the application; for some reason, Visual Studio did not detect it as a cross-thread exception. There was a spot in code that used a
System.Timers.Timer, and the callback for the Timer was not properly marshalling calls over to the UI thread before updating some UI properties. Somehow, that cross-threading issue "in the past" affected the ability for a some control to process the UserPreferenceChanged event in the future.Wednesday, October 7, 2009
InvalidOperationException - "Cross-thread operation not valid..."
Most C# programmers have probably seen the infamous
Novice programmers may think these cross-thread exceptions are just nuisance messages that can be ignored because they do not happen in the final release build sent to the customer. That, however, couldn't be further from the truth. Rather, you should aggressively seek them out and fix them because they can lead to all kinds of unexplained lock-ups and crashes that are difficult to diagnose. But, in order to find them you have to know when you can see them!
I use to think that cross-thread exceptions are thrown in debug builds, but not thrown in release builds. That seems to be the way it works, at first, and makes sense to me as a programmer. After all, a simple
Rather, my experimentation has shown that cross-thread exceptions only occur if you actually started the application from within Visual Studio. If you run a debug build of the application from outside of Visual Studio, you do not get the cross-thread exceptions even if you "attached" Visual Studio to that application via the "Debug | Attach to Process..." menu.
InvalidOperationException "Cross-thread operation not valid" exception at one time or another. When you see that, you instantly know that your code tried to access the property of a control from a thread other than the thread on which the control's window handle was created. If you recall a previous post of mine (or from MSDN), there are actually only a total of four methods and properties on a control that can be access from another thread:- InvokeRequired
- Invoke()
- BeginInvoke()
- EndInvoke()
Novice programmers may think these cross-thread exceptions are just nuisance messages that can be ignored because they do not happen in the final release build sent to the customer. That, however, couldn't be further from the truth. Rather, you should aggressively seek them out and fix them because they can lead to all kinds of unexplained lock-ups and crashes that are difficult to diagnose. But, in order to find them you have to know when you can see them!
I use to think that cross-thread exceptions are thrown in debug builds, but not thrown in release builds. That seems to be the way it works, at first, and makes sense to me as a programmer. After all, a simple
#if (DEBUG) somewhere down in framework code could easily accomplish that. But, as I have found out the hard way, it is not that simple.Rather, my experimentation has shown that cross-thread exceptions only occur if you actually started the application from within Visual Studio. If you run a debug build of the application from outside of Visual Studio, you do not get the cross-thread exceptions even if you "attached" Visual Studio to that application via the "Debug | Attach to Process..." menu.
Wednesday, September 2, 2009
"To Copy or Not to Copy" delegates used to raise events
There is a long-standing debate amongst C#.NET developers: When raising an event, should you copy the event delegate first or not?
In both cases, you must check to see if the event delegate is
Interestingly, the arguments for doing it one way or another typically involve reasons for not doing it the other way:
The argument for the "with copy" case basically comes down to this: If you do not do the copy, the delegate may change to
The argument for the "without copy" case basically comes down to this: If you do the copy, then you might invoke an event handler that has already unregistered, and that would be bad.
Honestly, I have flip-flopped on this several times over the years. But, I currently believe it to be better to do the copy. In the tradition of saying something is better this way because it is not doing that:
1) If you do not do the copy, you still have the potential NullReferenceException issue. If .NET threw a different type of exception, then you could catch it and ignore it because it would be expected that the last handler may have unregistered before you actually invoked the delegate. But, since it throws the NullRefernceException which could easily have been thrown by one of the handlers, you should probably let that bubble out so that the code raising the event knows something bad happened.
2) Whether you do the copy or not, once the framework starts traversing down the invocation list, it's just like doing a copy anyway. If a handler unregisters for an event while the framework is traversing the list, that handler will still be called. Therefore, handlers must always be written with the understanding that it can still get called after it has been unregistered.
Since you cannot prevent issue 2, which is basically what the "without copy" way is trying to prevent, you should at least do the copy because you can prevent issue 1.
public event EventHandler MyEvent;
private void OnRaiseMyEventWithoutCopy()
{
if (MyEvent != null)
{
MyEvent(this, new EventArgs());
}
}
private void OnRaiseMyEventWithCopy()
{
EventHandler myEvent = MyEvent;
if (myEvent != null)
{
myEvent(this, new EventArgs());
}
}
In both cases, you must check to see if the event delegate is
null; if you attempt to invoke a null delegate you will get a NullReferenceException. Once the last event handler has unregistered, the delegate will be null.Interestingly, the arguments for doing it one way or another typically involve reasons for not doing it the other way:
The argument for the "with copy" case basically comes down to this: If you do not do the copy, the delegate may change to
null after you did the null-check but before the delegate was invoked, and that could be bad.The argument for the "without copy" case basically comes down to this: If you do the copy, then you might invoke an event handler that has already unregistered, and that would be bad.
Honestly, I have flip-flopped on this several times over the years. But, I currently believe it to be better to do the copy. In the tradition of saying something is better this way because it is not doing that:
1) If you do not do the copy, you still have the potential NullReferenceException issue. If .NET threw a different type of exception, then you could catch it and ignore it because it would be expected that the last handler may have unregistered before you actually invoked the delegate. But, since it throws the NullRefernceException which could easily have been thrown by one of the handlers, you should probably let that bubble out so that the code raising the event knows something bad happened.
2) Whether you do the copy or not, once the framework starts traversing down the invocation list, it's just like doing a copy anyway. If a handler unregisters for an event while the framework is traversing the list, that handler will still be called. Therefore, handlers must always be written with the understanding that it can still get called after it has been unregistered.
Since you cannot prevent issue 2, which is basically what the "without copy" way is trying to prevent, you should at least do the copy because you can prevent issue 1.
Wednesday, August 19, 2009
Form.Load() override never called
I came across an issue today that boggled my mind for a few minutes. I had an apparently normal
As it turns out, there was nothing wrong with the form itself, but it was being used in an unconventional way. For some special-case reasons, the code that caused the form to be displayed was using
My solution to this problem was to override the
WinForm's Form, but the OnLoad() override was never getting called. Therefore, the Load event was never rasied. As it turns out, there was nothing wrong with the form itself, but it was being used in an unconventional way. For some special-case reasons, the code that caused the form to be displayed was using
PInvoke calls to SetWindowsPos() and ShowWindow() instead of calling the Form.Show() or Form.ShowDialog() method. Apparently, because neither Show() nor ShowDialog() was used, the OnLoad() method was never called.My solution to this problem was to override the
OnVisibleChanged() method, use a flag field to track whether the initialization code had been executed, and call the initialization code from whithin OnVisibleChanged if it had not yet been executed and Visble just changed to true. The flag, of course was then changed to true so the initialization code would not be called again if the form went invisible and then became visible again.Thursday, August 13, 2009
Use Shift+Enter to insert '\n' characters using the Visual Studio resource editor
This is by no means something new. It's just something I always forget to do, and forget how to do, so I figured I would post it here so I know where to find it when I need it again.
I often use hard-coded strings for message boxes, UI strings, etc. when I initially write the code, and then go back later to add all of those hard-coded strings into resource files so that they can get localized. When adding such strings to resource files, one cannot simply cut and paste it from the source code to the resource file because of the embedded control characters.
The C# Compiler knows that when it sees
I often use hard-coded strings for message boxes, UI strings, etc. when I initially write the code, and then go back later to add all of those hard-coded strings into resource files so that they can get localized. When adding such strings to resource files, one cannot simply cut and paste it from the source code to the resource file because of the embedded control characters.
The C# Compiler knows that when it sees
"\n" in a string [ that does not start with '@' ] it should replace that two-character substring with the '\n' control character. However, the resource files are not so smart; the substring "\n" in a resource string is not converted to the '\n' control character automatically. But, you can insert a '\n' newline control character into the resource string by using Shift+Enter in the Visual Studio resource editor. (For some reason, I always want to do a Ctrl+Enter but that does not work).Wednesday, June 10, 2009
Dangers of Overloading Methods in Derived Classes
Like most languages, C# supports method overloading. Basically, that simply means that you are allowed to have multiple methods with the same name as long as the prototypes (method signatures) are different. In theory, the compiler chooses the "best" method based on the parameters passed into the method. And, it generally does a good job. But, if the overloaded methods are distributed across several classes derived from one another, the compiler may not always choose the method you expect!
Consider the example below.
Given the example above, you might expect
The same thing applies if the method is virtual:
In the case of virtual methods above, it seems like you could override the
The same applies if the method is
I have not really found a good solution to this problem. Luckily, it does not occur often (for me) because I generally do not distribute overloaded methods across multiple class. But, if I do need to do something like that, the only solution I have found is really just a workaround: use the
Consider the example below.
public class BaseClass1
{
public int MyMethod(int x)
{
return x - 1;
}
}
public class DerivedClass1 : BaseClass1
{
public int MyMethod(object obj)
{
return (int)obj + 1;
}
}
DerivedClass1 dc1 = new DerivedClass1();
int x1 = 100;
int y1 = dc1.MyMethod(x1); // y1 == 101
Given the example above, you might expect
y1 to be 99 because MyMethod(int) is a better match than MyMethod(obj). But, if that is what you thought then you would be wrong. The reality is that y1 == 101 because the compiler chooses MyMethod(obj) over MyMethod(int) from the base class.The same thing applies if the method is virtual:
public class BaseClass2
{
public virtual int MyMethod(int x)
{
return x - 1;
}
}
public class DerivedClass2 : BaseClass2
{
public virtual int MyMethod(object obj)
{
return (int)obj + 1;
}
}
DerivedClass2 dc2 = new DerivedClass2();
int x2 = 100;
int y2 = dc2.MyMethod(x2); // y2 == 101
In the case of virtual methods above, it seems like you could override the
MyMethod(int) from the base class to fix the problem. But, if that's what you think, then you would be wrong again.
public class BaseClass3
{
public virtual int MyMethod(int x)
{
return x - 1;
}
}
public class DerivedClass3 : BaseClass3
{
public override int MyMethod(int x)
{
return base.MyMethod(x);
}
public virtual int MyMethod(object obj)
{
return (int)obj + 1;
}
}
DerivedClass3 dc3 = new DerivedClass3();
int x3 = 100;
int y3 = dc3.MyMethod(x3); // y3 == 101
The same applies if the method is
static. Although, in the case of static methods you might have expected that because you are specifically scoping to the class name. But, on the other had, public static methods of a base class are also available as public static methods on the derived class, so you might still have expected the compiler to choose MyMethod(int) over MyMethod(object).
public class BaseClass4
{
public static int MyMethod(int x)
{
return x - 1;
}
}
public class DerivedClass4 : BaseClass4
{
public static int MyMethod(object obj)
{
return (int)obj + 1;
}
}
int x4 = 100;
int y4 = DerivedClass4.MyMethod(x4); // y4 == 101
I have not really found a good solution to this problem. Luckily, it does not occur often (for me) because I generally do not distribute overloaded methods across multiple class. But, if I do need to do something like that, the only solution I have found is really just a workaround: use the
ref keyword to help the compiler pick the right method; since the compiler knows it has to pass the parameter both in and out, it tends to do the method selection better. Although, I would hate to have to do that because it introduces a "new danger" of allowing the method to change the value.
public class BaseClass5
{
public virtual int MyMethod(ref int x)
{
return x - 1;
}
}
public class DerivedClass5 : BaseClass5
{
public virtual int MyMethod(ref object obj)
{
return (int)obj + 1;
}
}
DerivedClass5 dc5 = new DerivedClass5();
int x5 = 100;
int y5 = dc5.MyMethod(ref x5); // y5 == 99
Thursday, March 26, 2009
Nullable Parameters in Public Interfaces
As discussed in previous posts, C# now has the concept of nullable value types via the
Conside, for example, a class with the following public method that uses a paremeter of type
Rather than exposing that method for use by others, it could instead be made
That code is pretty straight forward. The only trick is to cast the parameter as a
? operator. When used correctly, they can be very useful and solve some problems. But, quite honestly, I feel that they're kind of "hackish" to use them in public methods and interfaces. In many cases, you can simply make a few quick overloads to cleanup things up a bit.Conside, for example, a class with the following public method that uses a paremeter of type
int?.
public void MyMethod(int? myParameter)
{
...
}
Rather than exposing that method for use by others, it could instead be made
private and we could define a couple of public overloads.
public void MyMethod()
{
MyMethod();
}
public void MyMethod(int myParameter)
{
MyMethod(myParameter as int?);
}
private void MyMethod(int? myParameter)
{
...
}
That code is pretty straight forward. The only trick is to cast the parameter as a
int? before calling the private overload that does all the work. If you do not do that, then you will very quickly encounter a stack overflow.Subscribe to Posts [Atom]