Pergunta

Estou escrevendo um programa AC# que lançará muitos processos filhos. Em algum momento mais tarde, precisarei recuperar esses processos por ID e, em seguida, corresponder a esses processos a um conjunto de processos armazenados em um dicionário que foram adicionados ao dicionário quando foram criados pela primeira vez. No entanto, estou enfrentando um problema que parece puro ridículo ...

Process notepad = new Process();
notepad.StartInfo.FileName = "notepad";
notepad.Start();

Process n2 = Process.GetProcessById(notepad.Id);

Debug.WriteLine(notepad == n2);       //'False', but Why isn't this true???
Debug.WriteLine(notepad.Id == n2.Id); //'True'

Eu usei o .NET Reflector para descobrir que o GetProcessById retorna um 'novo processo (...)', mas parece que deve encontrar apenas uma referência ao processo já em execução e devolvê -lo.

Você pode assumir que a primeira declaração de depuração é essencialmente uma chamada como

MyCustomDatatype Data = myDictionary [bloco de notas];

Eu esperaria obter os dados que inseriram originalmente; em vez disso, recebo uma KeyNotFoundException provavelmente porque o comparador padrão está fazendo uma verificação de referência. Para combater isso, adicionei um ICOMPARER personalizado ao meu dicionário que apenas verifica se os dois objetos do processo têm o mesmo ID, para que eu possa obter os dados associados conforme o esperado. No entanto, isso tem seu próprio problema, pois os processos que não estão em execução não têm IDs de processo; portanto, às vezes a chamada no meu ICOMPARER personalizado para processar. Então, eu resolvi um problema apenas para criar outro.

Então, acho que tenho duas perguntas:

  • Por que o .NET não retorna uma referência a uma instância de processo já em execução?
  • O que posso fazer para corresponder aos processos armazenados no meu dicionário, pois o uso do ID do processo nem sempre é válido para a vida útil do objeto de processo?
Foi útil?

Solução

Os programas em execução são processos de sistema operacional, não instâncias do tipo gerenciado do processo. o Process O tipo é um tipo de objeto de wrapper gerenciado em torno de um conceito de sistema operacional. Ele permite o controle do processo de destino, ocultando as chamadas P/Invoke. O sistema operacional não requer uma instância específica da classe de processo executa essas operações, e é por isso que GetProcessById Pode devolver uma nova instância e ainda esperar que tudo funcione.

O ID é válido para a vida do próprio processo. Talvez você possa definir EnableraisingEvents para verdadeiro e adicionar um manipulador de eventos ao Process.Exited Evento que remove o processo do seu cache?

Outras dicas

Não tenho muita certeza de por que você teve que recorrer ao refletor, já que o GetProcessByID A documentação do MSDN afirma claramente:

Cria um novo componente de processo e o associa ao recurso de processo existente que você especifica.

A estrutura não pode retornar a você a mesma instância que você tem. Para poder fazer isso, a estrutura teria que manter uma referência a todas as instâncias de processo já criadas e comparar o ID do processo para descobrir o que você já possui. Vou deixar para você imaginar as implicações que isso teria na memória e no perf da estrutura.

Além disso, a classe de processo é um invólucro em torno da alça de processo retornada pelo OpenProcess API WIN32. E é possível ter várias alças para o mesmo processo. E o redirecionamento de entrada/saída pode ser feito por mão, portanto, é esperado que o cenário seja capaz de ter duas instâncias de processo que representam o mesmo processo e um deles lidando com os fluxos de saída e erro e o outro com um com o fluxo de entrada.

Em uma nota separada, parece -me que você está usando o próprio objeto de processo como a chave para o dicionário. Mas o objeto de processo não representa a identidade do processo real, é apenas uma representação do processo. Você deve usar como uma chave algo que representa a identidade do processo.

1) Sua primeira pergunta é análoga a:

var a = new List<string>{"one", "two", "three"};
var b = new List<string>{"one", "two", "three"};

if(a == b) { Debug.WriteLine("awesome"); } // not going to happen

Nada está acompanhando criado List<string>é o mesmo para criado Process's

2) Eu sugiro que você não armazene Process no dicionário e, em vez disso, crie outra classe que armazena o ID do processo e o Process referências e faz algo inteligente quando o processo que o Process refere -se a não estar mais funcionando.

O que você gostaria que o .NET fizesse, neste caso?

1º executável

Process notepad = new Process();
notepad.StartInfo.FileName = "notepad";
notepad.Start();

Suponha que você conhece o ProcessID da instância do bloco de notas.
No segundo executável, você gostaria de se apossar desse processo usando o ID

2º executável

Process n2 = Process.GetProcessById(notepadIdInputByUser);

A comparação de referência de objetos pode ser feita dentro de um aplicativo, desde que a construção do objeto esteja em sua mão (contra o sistema operacional).

Como o .NET obterá a instância do processo do 1º executável para o 2º Exection?

EDIT: Embora Process é uma classe, não pode ser referência em comparação.
Ele age como um struct, onde você pode fazer comparação de membros.

Use ProcessID como chave do seu dicionário.

Não tenha medo de criar uma nova instância de processo usando o GetProcessById toda vez que precisar. É um objeto leve e o coletor de lixo limpará para você.

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