1

I am working on an application that generally runs 24x7. It does so well for a period of time but I have noticed that after the DisplaySettingsChanging event fires (via an RDP connection) the application will continue to process in the background but the UI becomes completely unusable. It does not tell you in the task manager that the application is unresponsive like when the UI message pump is blocked. I know there is a bug with the SystemEvents class (still in .NET 4?). I have moved our splash screen into the form load event handler and do not create any controls on another thread other than the main UI thread. I have tried subscribing to the following events in the constructor of my main form (which has a valid SynchronizationContext)

SystemEvents.DisplaySettingsChanging 
SystemEvents.DisplaySettingsChanged
SystemEvents.UserPreferencesChanged

but per this related solution but it doesn't seem to help.

What else am I missing here?

EDIT 1: Ok after running spy++ I see there are two threads that own windows other than the main UI thread. However when I examine the threads within my process in visual studio I don't see either one. Does that mean some referenced assembly is the culprit? Probably should be a separate question, but how do I find out?

enter image description here

EDIT 2: The second window is a button click event that opens an open file dialog box. I checked the apartment state for that thread and it is correct STA. I have not determined how or when that other thread is created. Seems like it must be the offender.

Community
  • 1
  • 1
fanuc_bob
  • 857
  • 1
  • 7
  • 20
  • Hmm, no, this is with no doubt the standard deadlock caused by the SystemEvents class. It doesn't have a bug, just a hard time trying to figure out which thread is the UI thread in *some* programs. It takes just one Form to set the time-bomb, especially likely in VB.NET when you use the dreaded [My.Forms feature](https://msdn.microsoft.com/en-us/library/ms233839.aspx). You can stare at such code for an hour and not see that the form is actually created on a worker thread. Keep looking, it is in there somewhere. ShowDialog() is most apt at hiding it. – Hans Passant Oct 21 '15 at 16:02

1 Answers1

2

It certainly was the SystemEvents deadlock. I found a lot of help from a few resources mostly this blog on debugging using windbg. The bottom section was the most helpful in identifying which controls were being created on separate threads... and there were many offenders. Mostly in a shared assembly that creates a splash screen and license check. Anyways I thought I'd include the most useful parts in discovering which controls were causing issues.

For me it went like this

  1. Open executable in windbg

  2. Run, then break execution and run these commands in windbg

.sympath srv*http://msdl.microsoft.com/download/symbols (load MS symbols)

.reload (reloads modules)

.loadby sos.dll clr (loads a helping module)

!name2ee System_Windows_Forms_ni System.Windows.Forms.Application+MarshalingControl..ctor (Gets the pointer where the constructor of controls marshaled onto another thread occurs, then returns a pointer for that location. In my case it was 7fedf04a440)

bp 7fedf04a440 ".echo MarshalingControl creation detected. Callstack follows.;!clrstack;.echo ==============================;gc" (sets a breakpoint to output the callstack when that constructor is called)

I also used concepts from this article on SynchronizationContext to actually implement the solution.

fanuc_bob
  • 857
  • 1
  • 7
  • 20