Skąd mogę wiedzieć, czy proces jest uruchomiony?

155

Kiedy otrzymuję odwołanie do a System.Diagnostics.Process, skąd mogę wiedzieć, czy proces jest aktualnie uruchomiony?

reshefm
źródło

Odpowiedzi:

252

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);
}
Patrick Desjardins
źródło
To jest dokładnie to, czego szukałem. Mimo że jest to bardzo stary post, czy mógłbyś mi wyjaśnić, jak to jest poprawne w C #. Nie wątpię w to, widzę, że to działa, ale nigdy nie widziałem inaczej bez {}.
MatthewD
4
@MatthewD: Instrukcje języka C # 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 foreachi forwypowiedzi. Sprowadza się do stylu kodowania.
Hallmanac
Zrobiłem też trochę badań na ten temat, znalazłem te informacje, ale nie widziałem forinformacji. 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ź ..
MatthewD
3
@MatthewD tak, dotyczy to właściwie większości języków (takich jak Java). Generalnie dobrą praktyką jest unikanie takich znaków jednoliniowych i zawsze umieszczanie nawiasów klamrowych, ponieważ zawsze istnieje szansa, że ​​będziesz musiał dodać tam więcej instrukcji w przyszłości, w takim przypadku nawiasy będą już dostępne, gdy ich potrzebujesz. Ale w przypadku takich rzeczy, jeśli masz 100% pewności, że potrzebujesz tylko jednej instrukcji, możesz to zrobić i składniowo jest poprawna.
David Mordigal,
1
Jeśli nie możesz znaleźć procesu, spróbuj usunąć rozszerzenie. (Np .: .exe)
DxTx
28

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 ArgumentExceptionw przypadku, gdy proces nie istnieje. Z jakiegoś powodu ProcessManagerzajęcia są wewnętrzne ...

reshefm
źródło
To była naprawdę dobra odpowiedź; jednak nie powinieneś przechodzić przez argument zerowy wyjątek (ponieważ i tak zostałby zgłoszony zerowy wyjątek odwołania i nie zrobiłeś nic z wyjątkiem. Ponadto otrzymasz InvalidOperationException, jeśli nie wywołałeś Start () lub
wywołałeś
16

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.");
}
Coincoin
źródło
6
W przypadku pierwszej opcji: skąd mam wiedzieć, czy proces został uruchomiony w pierwszej kolejności?
reshefm
8

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.

Aelphaeis
źródło
Osobiście wolałbym raczej zobaczyć ArgumentNullException podczas przeglądania zarejestrowanego wyjątku niż NullReferenceException, ponieważ ArgumentNullException jest znacznie bardziej wyraźny na temat tego, co poszło nie tak.
Sean
1
@Sean Normalnie zgodziłbym się z tobą, ale jest to metoda rozszerzenia. Myślę, że bardziej odpowiednie jest zgłoszenie wyjątku wskaźnika zerowego, biorąc pod uwagę składnię, po prostu wydaje się bardziej spójne z wywoływaniem metod obiektów zerowych.
Aelphaeis
Spowoduje to wyzwolenie obsługi zdarzeń FirstHandledException za każdym razem. Sposób na spamowanie tam twoich dzienników, kolego.
Opóźnienie
6

Powinien to być jeden wiersz:

public static class ProcessHelpers {
    public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}
guneysus
źródło
3

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.

JaredPar
źródło
1

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).

Jeff Kotula
źródło
Jeśli umieścisz tę metodę w pętli, kosztuje to wiele cykli procesora. Polecam użycie GetProcessByName () lub GetProcessByID ().
Hao Nguyen
0

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ć.


źródło
0

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.

George Birbilis
źródło
0

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)

Jack Griffin
źródło
3
At openApplication.HasExited(), HasExited nie jest funkcją. Właściwy sposób byłby openApplication.HasExited.
caiosm1005
0

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.

Hao Nguyen
źródło
0

Jest z tym wiele problemów, które wydawały się częściowo rozwiązać inne:

  • Żaden element członkowski instancji nie gwarantuje bezpieczeństwa wątków. Oznacza to, że podczas próby oceny właściwości obiektu mogą wystąpić sytuacje wyścigu, które mogą wystąpić z czasem życia migawki.
  • Uchwyt procesu zgłosi wyjątek Win32Exception dla ODMOWA DOSTĘPU, gdy uprawnienia do oceny tej i innych podobnych właściwości są niedozwolone.
  • W przypadku statusu ISN'T RUNNING, podczas próby oceny niektórych jego właściwości zostanie również podniesiony ArgumentException.

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 ["?"]:

  • „ParentProcessID”
  • „ProcessID”
  • "Nazwa procesu"
  • „SECURITY_DESCRIPTOR”
  • „SessionID”
  • „Sid”
  • „TIME_CREATED”
Czas oczekiwania
źródło
0
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

berkay
źródło
3
Nie byłoby odwrotnie? jeśli długość == 0 to znaczy, że nie działa?
Jay Jacobs
Odpowiedź jest taka sama jak Patricka Desjardinsa: stackoverflow.com/a/262291/7713750
Rekshino
Odwrotnie, długość> 0 oznacza, że ​​znaleziono procesy.
HaseeB Mir
Może to mieć błąd ( length == 0powinien zostać wyświetlony Not Working), ale nadal działa.
Momoro