Onuserpreferencechanged hangs with multiple forms and mutlipe ui threads

I think my problem is similar:

.NET 4.0 and the scary OnUserPreferenceChanged Hang

I also looked at:

http://ikriv.com/en/prog/info/dotnet/MysteriousHang.html#BeginInvokeDance

I deleted our screensaver.

I also tried adding the suggested code: Microsoft.Win32.SystemEvents.UserPreferenceChanged + = delegate {}; to our main () method.

I am looking for some ideas and troubleshooting information.

For our main () method, we run the windowmanager class, which is a form using Application.Run. It's just an icon in the taskbar (we don't show the window).

Whenever we run an object, we have a background thread that creates the form and then does Application.Run (form)

During form Application.Run (form) .IsHandleCreated = false.

I am using the freeze app from the MysteriousHang website. (I changed it to continue sending notification of changes in the loop).

How do I handle creating and starting a new form? Does it matter that the form is created in the background thread, even if its handle has not yet been created?

+2
source share
1 answer

I am also confused by the terminology of "user interface thread".

A UI thread is a thread that pumps a message loop. And it works in a mode compatible with user interface objects, it must be STA, a single-threaded apartment. This is a detail of the COM implementation that is of great importance to general user interface operations that are not thread safe and require STAs like Drag + Drop, Clipboard, shell dialogs like OpenFileDialog and ActiveX components.

The task of the CLR is to call CoInitializeEx () and select the type of apartment. It does this based on the [STAThread] attribute at the starting point of Main () in your program. Represented in projects that create user interface objects such as Winforms or WPF. But not an application or service in console mode. For a workflow, in other words, the thread created by your code instead of Windows, the type of apartment is selected by what you passed to the Thread.SetApartmentState () method. The default is MTA, the wrong taste. Thread threadpool is always an MTA that cannot be changed.

The SystemEvents class has the unenviable task of figuring out which thread is the user interface thread in your program. It is important that he can create events on the correct thread. He does this using heuristics, it is believed that the first thread that signs the event and is an STA thread is considered suitable.

Things went wrong when this assumption was not accurate. Or, of course, in your case, when you try to create several threads that create user interface objects, the hunch can only be true for one of them. You probably also forgot to call Thread.SetApartmentState () so that it was not right for any of them. WPF more strongly asserts this and throws an exception when the thread is not an STA.

The UserPreferenceChanged event is a problem creator, it is signed by some controls that you will find on the toolbar. They use it to know that the theme of the active visual style has been changed so that they are repainted using the new colors of the theme. A significant drawback of event handlers in some of these controls is that they assume that the event is raised in the correct thread, the same thread that created the control.

Your program will not . The result tends to be unpleasant, subtle problems with painting are a minor flaw, of course, a dead end is possible. For some reason, locking a workstation using Windows + L and unlocking it is especially prone to deadlocks. The UserPreferenceChanged event occurs in this case due to switching the desktop from the protected desktop to the user's desktop.

The controls that listen for the UserPreferenceChanged event and do not use secure streaming methods (using Control.BeginInvoke) are DataGridView, NumericUpDown, DomainUpDown, ToolStrip + MenuStrip and ToolStripItem derived classes, possibly RichTextBox and ProgressBar (unclear).

The message should be clear, you are using unsafe streaming methods, and they can be bytes. In general, it never made any sense to create a workflow user interface; the main Winforms or WPF program thread is already quite capable of supporting multiple windows. In short, avoiding dangerous controls is what you should strive for to get rid of the problem.

+5
source

Source: https://habr.com/ru/post/1488159/


All Articles