.NET 4.0 e o temido OnUserPreferenceChanged travar

Eu tenho sido atormentado com o temido OnUserPreferenceChanged Hang que é muito bem referido por Ivan Krivyakov, aqui:

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

Postei uma pergunta há algum tempo, quando encontrei o problema originalmente:

Ainda outra questão de debugging de deadlock C #

Eu pensei que tinha resolvido isso, removendo um controle que foi construído fora do thread de interface do usuário, mas depois de um tempo ele reapareceu (provavelmente nunca saiu …).

Estamos usando o .NET 3.5, que eu entendo usa o CLR 2.0. Recentemente, o applciation foi atualizado para usar o .NET 4.0 Client Profile / CLR 4.0. Além disso, atualizamos do Infragistics WinForms 10.1 para 10.3. A única outra diferença é que a versão anterior é ofuscada … alguém já teve problemas com ofuscação e enforcamento?

Eu tive outra tentativa de se livrar de qualquer aplicativo trava de uma vez por todas, mas, raramente, eu não fui capaz de reproduzir o jeito na versão mais recente (usando o .NET 4.0). O problema é simples de reproduzir na versão anterior (usando o .NET 3.5), usando o prático aplicativo Freezer de Ivan Krivyakov (consulte o artigo dele), que triggers uma mensagem WM_SETTINGCHANGE mediante solicitação.

Pode ser que eu esteja um pouco esperançoso de que a questão tenha desaparecido por conta própria, mas alguém sabe se houve alguma mudança no CLR de 2.0 para 4.0 que causaria isso?

————————————————– —SOLUÇÃO———————————————- —-

Assim, após testar as variações da aplicação, por exemplo, CLR 2.0 + Infragistics 2010.1, CLR 2.0 + Infragistics 2010.3 e CLR 4.0 + Infragistics 2010.1, acreditamos que identificamos o problema como um problema com um componente Infragistics no WinForms 2010.1 (sem hot fixes ). Ainda temos que reproduzir o congelamento usando o CLR 2.0 ou o CLR 4.0 com o Infragistics 2010.3 (e estamos muito bem reproduzindo isso agora …).

um controle que foi construído fora do thread da interface do usuário …

Sim, essa é uma boa maneira de acionar esse problema. O problema subjacente é causado pela class SystemEvents, ele tem a tarefa invejável de aumentar seus events no thread correto. O evento UserPreferenceChanged é o típico criador de problemas, muitos controles o assinam para que eles possam repintar a si mesmos quando o usuário altera o tema da área de trabalho. Um fornecedor de componentes não ignoraria a necessidade disso. Nem o padrão .NET framework controla na checkbox de ferramentas.

Uma maneira geralmente decente de testar esse problema é travar a estação de trabalho (pressione as teclas Win + L), e também o modo como o deadlock é comumente acionado na máquina do usuário. A mudança para a área de trabalho segura tende a acionar o evento. Com as peculiaridades adicionais, isso nunca acontece quando você depura seu programa e tem um comportamento complicado relacionado ao tempo, já que isso costuma acontecer quando ninguém está na máquina. Extra difícil de depurar.

Uma maneira padrão de se meter em problemas como esse é por causa de um problema de boot no programa. O primeiro evento SystemEvents que é assinado faz com que a class SystemEvents seja inicializada e configure o encanamento necessário para receber essas notifications e aumentar o evento correspondente. Uma canvas inicial personalizada que faz muito (ou seja, mais do que apenas exibir um bitmap) e é executada em um thread de trabalho marcada como STA é suficiente para fazer isso errado. Algo tão simples quanto um ProgressBar já é suficiente. SystemEvents pressupõe que o thread de trabalho é o thread principal do programa e agora pode gerar facilmente os events no thread errado no futuro. Há um bom diagnóstico para isso, se esse thread de trabalho não estiver mais por perto, isso gerará uma exceção de primeira chance. Você pode vê-lo na janela Saída.

Ou você cria outro thread de interface do usuário e tem formulários em ambos os segmentos. Inevitavelmente, um desses formulários sempre obterá o evento no thread errado.

O único conselho decente é reconhecer que criar interface do usuário em um segmento de trabalho é ciência de foguetes que a Microsoft não sabia como fazer corretamente também. Notável é que os controles .NET 1.x têm um manipulador de events que ainda funciona corretamente quando é chamado do thread errado, ele simplesmente chama Control.Invalidate (). Mas esse foi o conhecimento que parece ter sido perdido em 2.0, ToolStrip é um bom exemplo . E não confie em um fornecedor de componentes para acertar isso, o Infragistics em particular não tem uma reputação escanvasr. Não faça isso.

O melhor guia que encontrei para resolver esse problema está aqui:

  • Depuração do aplicativo Windows Forms trava durante SystemEvents.UserPreferenceChanged – o Blog da equipe DSUI – Site Home – MSDN Blogs

Ele orienta você usando o WinDbg para verificar a causa do erro e mostra como encontrar o que está causando isso. Como você mencionou, é mais provável que um controle esteja sendo criado em um thread não-ui.

No meu caso, resolvi o problema criando uma fábrica que usa o SynchronizationContext do thread da interface do usuário para criar o controle e, em seguida, chamo CreateControl () para forçar a criação de um identificador de interface do usuário.

O artigo do suporte da Microsoft está aqui:

  • Aplicativo do Windows Forms congela quando as configurações do sistema são alteradas ou a estação de trabalho está bloqueada

Se você executar o aplicativo de amostra de sua página com o primeiro CLR 2.0 e, em seguida, o CLR 4.0, você notará que o problema parece ter desaparecido na versão 4.0 – não tem idéia do que foi alterado, mas talvez eles realmente tenham resolvido o problema. BR