Back to Home

Features of Microsoft.Win32.SystemEvents in an Application with Multiple AppDomain

.net · c # · appdomain

Features of Microsoft.Win32.SystemEvents in an Application with Multiple AppDomain

    Once upon a time there was a console application that created appdomain and launched a service based on Topshelf in it. But once a bug appeared in it - after pressing Ctrl-C it did not finish its work, but reported receiving a shutdown command and freezing in this state. A brief analysis showed that it hung on domain unloading, but, strangely, it did not throw an exception CannotUnloadAppDomainException.

    It was further noted that the application freezes when it is closed only after performing certain tasks, and there are several “extra” threads before unloading the domain, which are not observed in the case of normal application termination. As you might guess from the name, it turned out to be SystemEvents. When used System.Drawing.SolidBrush, a handler is added toSystemEvents.UserPreferenceChanging, but since this is a separate appdomain, the type is initialized once more, another thread is created with the name ".NET SystemEvents", which at startup adds its own to the console handlers.
    When the application is closed, it is called SystemEvents.Dispose(), and in it when the console handler is deleted, the UnsafeNativeMethods.SetConsoleCtrlHandler(consoleHandler, 0)application freezes. I googled a couple of mentions about the problem with removing console handlers, but all the solutions came down to calling SystemEvents.Shutdown()through Reflection, but that didn’t help me, and it shouldn’t seem to help, it then calls Dispose ().
    Then I decided that I needed to somehow avoid creating a second SystemEvents thread, and a loophole was found in the method SystemEvents.EnsureSystemEvents(bool requireHandle, bool throwOnRefusal):

    if (Thread.GetDomain().GetData(".appDomain") != null) {
      if (throwOnRefusal) {
        throw new InvalidOperationException(SR.GetString(SR.ErrorSystemEventsNotSupported));
      }
      return;
    }
    //тут идёт инициализация SystemEvents
    

    In my case, this method was called with throwOnRefusal = false, so adding domain.SetData(".appDomain", new object())it avoids creating another SystemEvents thread and freezes when its console handler is deleted, the application finishes its work correctly.
    There may be a side effect in the case of code that relies on checking the ".appDomain" property, it can count our application as asp.net)) If someone knows what problems this setting might cause, or knows a safer and more suitable solution to the problem, please share.

    Read Next