I\'ve been dealing with a strange application hang in my clients installations. After trying several things i reached the conclusion that without a dump it won\'t work. So I
If you don't have an idea yet on how to check this out. Look at this page Kim Greenlee blog and try out the spy++ solution. Maybe it helps you, we have about the same issue and cannot simulate the problem with the application that is hanging, but still researching a lot about it!
Well, you have thee classic problem of control 'creation' on non UI thread.
Great read on the subject: (ref 1) (ref 2) and (ref 3).
I don't know of a way to find the control in a dump (tried myself) but you can try to set a breakpoint in code as described in (ref 4) and (ref 5).
Cheers.
Reference:
Mysterious Hang or The Great Deception of InvokeRequired
Control.Trifecta: InvokeRequired, IsHandleCreated, and IsDisposed
.NET 2.0 WinForms multithreading and a few long days
Debugging UI
The case of the leaking thread handles
Following Vlad code, I have found a way to unsubscribe the system events on all objects subscribed out of the main UI thread.
This code works for me and it is solving years of pain dealing with systemevents:
public static void UnsubscribeSystemEvents()
{
try
{
var handlers = typeof(SystemEvents).GetField("_handlers", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
var handlersValues = handlers.GetType().GetProperty("Values").GetValue(handlers);
foreach (var invokeInfos in (handlersValues as IEnumerable).OfType<object>().ToArray())
foreach (var invokeInfo in (invokeInfos as IEnumerable).OfType<object>().ToArray())
{
var syncContext = invokeInfo.GetType().GetField("_syncContext", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(invokeInfo);
if (syncContext == null)
throw new Exception("syncContext missing");
if (!(syncContext is WindowsFormsSynchronizationContext))
continue;
var threadRef = (WeakReference)syncContext.GetType().GetField("destinationThreadRef", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(syncContext);
if (!threadRef.IsAlive)
continue;
var thread = (System.Threading.Thread)threadRef.Target;
if (thread.ManagedThreadId == 1)
continue; // Change here if you have more valid UI threads to ignore
var dlg = (Delegate)invokeInfo.GetType().GetField("_delegate", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(invokeInfo);
var handler = (UserPreferenceChangedEventHandler)Delegate.CreateDelegate(typeof(UserPreferenceChangedEventHandler), dlg.Target, dlg.Method.Name);
SystemEvents.UserPreferenceChanged -= handler;
}
}
catch ()
{
//trace here your errors
}
}
The freezing issue due to SystemEvents.OnUserPreferenceChanged is quite common bug and here is a Microsoft explanation and recommendation how to fix it.
Here is the function you can invoke any time (before or even after freeze) to find out which particular controls subscribed to SystemEvents was created on wrong threads and thus could freeze your app:
private static void CheckSystemEventsHandlersForFreeze()
{
var handlers = typeof(SystemEvents).GetField("_handlers", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
var handlersValues = handlers.GetType().GetProperty("Values").GetValue(handlers);
foreach (var invokeInfos in (handlersValues as IEnumerable).OfType<object>().ToArray())
foreach (var invokeInfo in (invokeInfos as IEnumerable).OfType<object>().ToArray())
{
var syncContext = invokeInfo.GetType().GetField("_syncContext", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(invokeInfo);
if (syncContext == null) throw new Exception("syncContext missing");
if (!(syncContext is WindowsFormsSynchronizationContext)) continue;
var threadRef = (WeakReference) syncContext.GetType().GetField("destinationThreadRef", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(syncContext);
if (!threadRef.IsAlive) continue;
var thread = (Thread)threadRef.Target;
if (thread.ManagedThreadId == 1) continue; // Change here if you have more valid UI threads to ignore
var dlg = (Delegate) invokeInfo.GetType().GetField("_delegate", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(invokeInfo);
MessageBox.Show($"SystemEvents handler '{dlg.Method.DeclaringType}.{dlg.Method.Name}' could freeze app due to wrong thread: "
+ $"{thread.ManagedThreadId},{thread.IsThreadPoolThread},{thread.IsAlive},{thread.Name}");
}
}