Odpowiedzi:
Oto sposób na zrobienie tego z nazwą:
Process[] pname = Process.GetProcessesByName("notepad");
if (pname.Length == 0)
MessageBox.Show("nothing");
else
MessageBox.Show("run");
Możesz zapętlić cały proces, aby uzyskać identyfikator do późniejszej manipulacji:
Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}
if/else
, które mają tylko jeden wiersz długości, nie muszą mieć nawiasów klamrowych, aby wskazać instrukcję blokową. Dotyczy to także foreach
i for
wypowiedzi. Sprowadza się do stylu kodowania.
for
informacji. Lata tworzenia c # .net dev i nigdy nie widziałem tego stylu. Jak mówią, „każdego dnia uczysz się czegoś nowego”. Dziękuję za wiadomość i odpowiedź ..
To najprostszy sposób, jaki znalazłem po zastosowaniu reflektora. Stworzyłem do tego metodę rozszerzenia:
public static class ProcessExtensions
{
public static bool IsRunning(this Process process)
{
if (process == null)
throw new ArgumentNullException("process");
try
{
Process.GetProcessById(process.Id);
}
catch (ArgumentException)
{
return false;
}
return true;
}
}
Process.GetProcessById(processId)
Metoda wywołuje ProcessManager.IsProcessRunning(processId)
metodę i rzuca ArgumentException
w przypadku, gdy proces nie istnieje. Z jakiegoś powodu ProcessManager
zajęcia są wewnętrzne ...
Rozwiązanie synchroniczne:
void DisplayProcessStatus(Process process)
{
process.Refresh(); // Important
if(process.HasExited)
{
Console.WriteLine("Exited.");
}
else
{
Console.WriteLine("Running.");
}
}
Rozwiązanie asynchroniczne:
void RegisterProcessExit(Process process)
{
// NOTE there will be a race condition with the caller here
// how to fix it is left as an exercise
process.Exited += process_Exited;
}
static void process_Exited(object sender, EventArgs e)
{
Console.WriteLine("Process has exited.");
}
reshefm miał całkiem niezłą odpowiedź; nie uwzględnia jednak sytuacji, w której proces nigdy się nie rozpoczął.
Oto zmodyfikowana wersja tego, co opublikował.
public static bool IsRunning(this Process process)
{
try {Process.GetProcessById(process.Id);}
catch (InvalidOperationException) { return false; }
catch (ArgumentException){return false;}
return true;
}
Usunąłem jego ArgumentNullException, ponieważ w rzeczywistości przypuszcza się, że jest to wyjątek zerowego odwołania, a mimo to jest wyrzucany przez system, a także uwzględniłem sytuację, w której proces nigdy nie został uruchomiony lub metoda close () została użyta do zamknięcia proces.
To zależy od tego, jak niezawodna ma być ta funkcja. Jeśli chcesz wiedzieć, czy konkretna instancja procesu, którą posiadasz, nadal działa i jest dostępna ze 100% dokładnością, to nie masz szczęścia. Powodem jest to, że z obiektu zarządzanego procesu istnieją tylko 2 sposoby identyfikacji procesu.
Pierwsza to identyfikator procesu. Niestety, identyfikatory procesów nie są unikalne i można je poddać recyklingowi. Przeszukanie listy procesów pod kątem pasującego identyfikatora pokaże tylko, że działa proces o tym samym identyfikatorze, ale niekoniecznie jest to Twój proces.
Drugą pozycją jest uchwyt procesu. Ma ten sam problem co Id i jest trudniejszy w obsłudze.
Jeśli szukasz niezawodności na średnim poziomie, wystarczy sprawdzić bieżącą listę procesów pod kątem procesu o tym samym identyfikatorze.
Process.GetProcesses()
jest droga do zrobienia. Jednak może być konieczne użycie jednego lub więcej różnych kryteriów, aby znaleźć proces, w zależności od tego, jak działa (np. Jako usługa lub zwykła aplikacja, niezależnie od tego, czy ma pasek tytułu, czy nie).
Może (prawdopodobnie) źle czytam pytanie, ale czy szukasz właściwości HasExited, która powie Ci, że proces reprezentowany przez obiekt Process zakończył się (normalnie lub nie).
Jeśli proces, do którego się odwołujesz, ma interfejs użytkownika, możesz użyć właściwości Responding, aby określić, czy interfejs użytkownika aktualnie odpowiada na dane wejściowe użytkownika, czy nie.
Możesz także ustawić EnableRaisingEvents i obsłużyć zdarzenie Exited (które jest wysyłane asychronicznie) lub wywołać WaitForExit (), jeśli chcesz zablokować.
Możesz utworzyć instancję Process raz dla żądanego procesu i kontynuować śledzenie tego procesu za pomocą tego obiektu .NET Process (będzie on śledził aż do jawnego wywołania Close na tym obiekcie .NET, nawet jeśli śledzony proces nie działa [to ma być w stanie podać czas zakończenia procesu, inaczej ExitTime itp.])
Cytując http://msdn.microsoft.com/en-us/library/fb4aw7b8.aspx :
Kiedy skojarzony proces kończy pracę (to znaczy, gdy jest zamykany przez system operacyjny w wyniku normalnego lub nieprawidłowego zakończenia), system przechowuje informacje administracyjne o procesie i wraca do komponentu, który nazwał WaitForExit. Składnik Process może następnie uzyskać dostęp do informacji, w tym ExitTime, przy użyciu Handle do zakończonego procesu.
Ponieważ skojarzony proces został zakończony, właściwość Handle składnika nie wskazuje już na istniejący zasób procesu. Zamiast tego uchwyt może służyć tylko do uzyskiwania dostępu do informacji systemu operacyjnego o zasobach procesu. System jest świadomy dojścia do zakończonych procesów, które nie zostały zwolnione przez składniki Process, dlatego przechowuje informacje o czasie zakończenia i obsługi w pamięci, dopóki składnik Process nie zwolni zasobów. Z tego powodu za każdym razem, gdy wywołasz Start dla instancji Process, wywołaj Close, gdy skojarzony proces zostanie zakończony i nie potrzebujesz już żadnych informacji administracyjnych na jego temat. Zamknij zwalnia pamięć przydzieloną dla zakończonego procesu.
Wypróbowałem rozwiązanie Coincoin:
przed przetworzeniem jakiegoś pliku kopiuję go jako plik tymczasowy i otwieram.
Kiedy skończę, zamykam aplikację, jeśli jest nadal otwarta, i usuwam plik tymczasowy:
po prostu używam zmiennej procesowej i sprawdzam ją później:
private Process openApplication;
private void btnOpenFile_Click(object sender, EventArgs e) {
...
// copy current file to fileCache
...
// open fileCache with proper application
openApplication = System.Diagnostics.Process.Start( fileCache );
}
Później zamykam aplikację:
...
openApplication.Refresh();
// close application if it is still open
if ( !openApplication.HasExited() ) {
openApplication.Kill();
}
// delete temporary file
System.IO.File.Delete( fileCache );
Działa (na razie)
openApplication.HasExited()
, HasExited nie jest funkcją. Właściwy sposób byłby openApplication.HasExited
.
Pomimo obsługiwanego API z platform .Net w zakresie sprawdzania istniejącego procesu według identyfikatora procesu, funkcje te działają bardzo wolno. Uruchamianie Process.GetProcesses () lub Process.GetProcessById / Name () kosztuje ogromną liczbę cykli procesora.
Znacznie szybszą metodą sprawdzenia działającego procesu według identyfikatora jest użycie natywnego API OpenProcess () . Jeśli uchwyt zwrotny ma wartość 0, proces nie istnieje. Jeśli uchwyt jest inny niż 0, proces jest uruchomiony. Nie ma gwarancji, że ta metoda będzie działać w 100% przez cały czas ze względu na pozwolenie.
Jest z tym wiele problemów, które wydawały się częściowo rozwiązać inne:
Niezależnie od tego, czy właściwości, o których wspominali inni, są wewnętrzne, czy nie, nadal możesz uzyskać od nich informacje poprzez refleksję, jeśli pozwolenie na to pozwala.
var x = obj.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);
Możesz przypiąć kod Win32 do Snapshot lub możesz użyć wolniejszego WMI .
HANDLE CreateToolhelp32Snapshot(
DWORD dwFlags,
DWORD th32ProcessID
);
Inną opcją byłoby OpenProcess / CloseProcess, ale nadal będziesz mieć te same problemy z wyjątkami, które są wyrzucane tak samo jak wcześniej.
WMI - OnNewEvent.Properties ["?"]:
string process = "notepad";
if (Process.GetProcessesByName(process).Length == 0)
{
MessageBox.Show("Working");
}
else
{
MessageBox.Show("Not Working");
}
możesz również użyć timera do sprawdzania procesu za każdym razem
length == 0
powinien zostać wyświetlony Not Working
), ale nadal działa.