Pergunta

Eu estou escrevendo um aplicativo para iniciar e monitorar outros aplicativos em C #. Eu estou usando a classe System.Diagnostics.Process para iniciar aplicações e, em seguida, monitorar os aplicativos usando a propriedade Process.Responding para consultar o estado da aplicação a cada 100 milisecs. Eu uso Process.CloseMainWindow para parar a aplicação ou Process.Kill para matá-lo se ele não está respondendo.

Tenho notado um comportamento estranho onde às vezes o objeto de processo entra em um estado onde a propriedade responder sempre retorna true mesmo quando os trava processo subjacente em um loop e onde ele não responde a CloseMainWindow.

Uma forma de reproduzi-lo é para pesquisar o direito de propriedade de responder depois de iniciar a instância do processo. Assim, por exemplo

_process.Start();
bool responding = _process.Responding;

irá reproduzir o estado de erro, enquanto

_process.Start();
Thread.Sleep(1000);
bool responding = _process.Responding;

vai funcionar. Reduzir o período de sono para 500 irá apresentar o estado de erro novamente.

Algo em chamar _process.Responding muito rápido após o início parece impedir que o objeto de obter o manipulador de fila de mensagens janelas certas. Eu acho que eu preciso esperar para _process.Start para concluir a fazê-lo de trabalho assíncrona. Existe uma maneira melhor esperar para este do que chamar Thread.Sleep? Eu não estou muito confiante de que os 1000 ms sempre será suficiente.

Foi útil?

Solução

Agora, eu preciso verificar isso mais tarde, mas estou certo de que é um método que conta a thread para esperar até que ele está pronto para entrada. Você está monitorando única processos GUI?

Não é Process.WaitForInputIdle de qualquer ajuda para você? Ou estou faltando o ponto? :)

Atualização

Depois de uma bate-papo no Twitter (ou Piu-Piu?) Com Mendelt eu pensei que deveria atualizar a minha resposta para que a comunidade está plenamente consciente ..

  • WaitForInputIdle só irá funcionar em aplicações que têm uma GUI.
  • Você especifica o tempo de espera, e o método retorna um booleano se o processo atinge um estado ocioso dentro desse prazo, você pode, obviamente, usar isso para loop se necessário, ou alça conforme o caso.

Espero que ajude:)

Outras dicas

Eu acho que pode ser melhor para melhorar a verificação de _process.Responding para que você só tentar stop / matar o processo Se a propriedade Respondendo retorna falso por mais de 5 segundos (por exemplo).

Eu acho que você pode achar que, muitas vezes, os pedidos podem ser "não responde" por uma fração de segundo, enquanto eles estão fazendo um processamento mais intensivo.

Eu acredito que uma abordagem mais branda irá funcionar melhor, permitindo um processo para ser "não responde" por um curto período de tempo, tendo somente a ação se for repetidamente "não responde" por alguns segundos (ou o tempo que você quiser) .

Além disso, note:. A documentação Microsoft indica que a propriedade Respondendo refere-se especificamente à interface do usuário, e é por isso um processo recém-iniciado não pode tê-lo de UI responder imediatamente

Obrigado pelas respostas. Este

_process.Start();
_process.WaitForInputIdle();

parece resolver o problema. Ainda é estranho, porque responder e WaitForInputIdle ambos devem estar usando a mesma chamada API Win32 sob as cobertas.

Alguns mais fundo informações
aplicações GUI tem uma janela principal com uma fila de mensagens. Responder e trabalho WaitForInputIdle, verificando se o processo ainda processa as mensagens deste fila de mensagens. É por isso que eles só trabalho com GUI Apps. De alguma forma, parece que chamar Respondendo interfere muito rápido com a obtenção do Processo de obtenção de um identificador para essa fila mensagem. Chamando WaitForInputIdle parece resolver esse problema.

Vou ter que mergulhar no refletor para ver se consigo dar sentido a isso.

update
Parece que recuperar o identificador de janela associado com o processo apenas depois de começar é suficiente para desencadear o comportamento estranho. Como esta:

_process.Start();
IntPtr mainWindow = _process.MainWindowHandle;

Eu verifiquei com refletor e é isso que faz Respondendo debaixo das cobertas. Parece que se você começar a MainWindowHandle muito cedo você começa a errada e ele usa esse identificador errado para o resto da vida útil do processo ou até que você chamar Refresh ();

update
Chamando WaitForInputIdle () só resolve o problema por algum tempo. Chamando Atualizar toda vez que () você lê a propriedade Respondendo parece funcionar melhor.

Eu também notei que em um projeto de cerca de 2 anos. Liguei .Refresh () antes de solicitar certos valores prop. Foi uma abordagem de tentativa e erro para encontrar quando eu precisava chamar .Refresh ().

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top