Jak sprawdzić, czy usługa systemu Windows jest zainstalowana w C #

79

Napisałem usługę Windows, która uwidacznia usługę WCF do GUI zainstalowanego na tym samym komputerze. Kiedy uruchamiam GUI, jeśli nie mogę połączyć się z usługą, muszę wiedzieć, czy dzieje się tak dlatego, że aplikacja usługi nie została jeszcze zainstalowana, czy też dlatego, że usługa nie działa. Jeśli pierwszy, będę chciał go zainstalować (jak opisano tutaj ); jeśli to drugie, będę chciał go uruchomić.

Pytanie brzmi: w jaki sposób wykryjesz, czy usługa jest zainstalowana, a następnie po wykryciu, że jest zainstalowana, jak ją uruchomić?

Shaul Behr
źródło

Odpowiedzi:

147

Posługiwać się:

// add a reference to System.ServiceProcess.dll
using System.ServiceProcess;

// ...
ServiceController ctl = ServiceController.GetServices()
    .FirstOrDefault(s => s.ServiceName == "myservice");
if(ctl==null)
    Console.WriteLine("Not installed");
else    
    Console.WriteLine(ctl.Status);
Aliostad
źródło
Dziękuję - właśnie tego potrzebowałem!
Shaul Behr
1
using (var sc = ServiceController.GetServices (). FirstOrDefault (s => s.ServiceName == "myservice")) - myślę, że jest to lepsze podejście.
Alexandru Dicu,
4
@alexandrudicu: Jakie jest lepsze podejście? Jeśli .GetServices()zwróci 100 ServiceControllerobiektów i pozbyłeś się jednego na sto, ignorując resztę, czy to naprawdę znacznie lepsze? Sam bym tego nie powiedział.
Allon Guralnek
37

Możesz również użyć następujących.

using System.ServiceProcess; 
... 
var serviceExists = ServiceController.GetServices().Any(s => s.ServiceName == serviceName);
Simon Oliver Hurley
źródło
3
IMO, to najbardziej elegancki sposób sprawdzenia, czy Twoja usługa istnieje. Tylko jedna linia kodu, wykorzystująca moc Linq. Nawiasem mówiąc, .Any () zwraca wartość bool, która jest dokładnie tym, czego oczekujesz, zadając pytanie tak / nie :-)
Alex X.
3
Jeśli chcesz sprawdzić usługi na zdalnym komputerze, użyjGetServices(string)
ShooShoSha
7

Właściwie zapętlony w ten sposób:

foreach (ServiceController SC in ServiceController.GetServices())

może zgłosić wyjątek Odmowa dostępu, jeśli konto, na którym działa aplikacja, nie ma uprawnień do wyświetlania właściwości usługi. Z drugiej strony możesz to bezpiecznie zrobić, nawet jeśli nie istnieje usługa o takiej nazwie:

ServiceController SC = new ServiceController("AnyServiceName");

Ale dostęp do jego właściwości, jeśli usługa nie istnieje, spowoduje InvalidOperationException. Oto bezpieczny sposób sprawdzenia, czy usługa jest zainstalowana:

ServiceController SC = new ServiceController("MyServiceName");
bool ServiceIsInstalled = false;
try
{
    // actually we need to try access ANY of service properties
    // at least once to trigger an exception
    // not neccessarily its name
    string ServiceName = SC.DisplayName;
    ServiceIsInstalled = true;
}
catch (InvalidOperationException) { }
finally
{
    SC.Close();
}
ttaaoossuu
źródło
dzięki! i czy chciałbyś zakończyć: w końcu {SC.Close (); }
Cel,
6
Dlaczego nie zawinąć całej rzeczy w użycie? To wyeliminuje ostatecznie potrzebę {SC.Close ()}, ponieważ instrukcja using zostanie automatycznie usunięta. using (ServiceController SC = new ServiceController ("MyServiceName"))
rachunek
2

Dla non-linq możesz po prostu iterować przez tablicę w następujący sposób:

using System.ServiceProcess;

bool serviceExists = false
foreach (ServiceController sc in ServiceController.GetServices())
{
    if (sc.ServiceName == "myServiceName")
    {
         //service is found
         serviceExists = true;
         break;
    }
}
ZTAN
źródło
1

Myślę, że to najlepsza odpowiedź na to pytanie. Nie ma potrzeby dodawania dodatkowego przetwarzania, aby sprawdzić, czy usługa istnieje, ponieważ zgłosi wyjątek, jeśli tak nie jest. Po prostu musisz to złapać. Nie musisz również zamykać () łączenia, jeśli zawiniesz całą metodę za pomocą ().

using (ServiceController sc = new ServiceController(ServiceName))
{
 try
 {
  if (sc.Status != ServiceControllerStatus.Running)
  {
    sc.Start();
    sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 10));
    //service is now Started        
  }      
  else
    //Service was already started
 }
 catch (System.ServiceProcess.TimeoutException)
 {
  //Service was stopped but could not restart (10 second timeout)
 }
 catch (InvalidOperationException)
 {
   //This Service does not exist       
 }     
}
rachunek
źródło
2
Niezbyt dobra odpowiedź. (1) Zarządzanie kodem za pomocą wyjątków jest bardzo złą praktyką - nieefektywną i powolną, oraz (2) przyjęta odpowiedź jest zgrabna, zwięzła i doskonale spełnia wymagania. Czy spojrzałeś na to, zanim zagłębiłeś się w swoją własną odpowiedź?
Shaul Behr
Najwyraźniej nie wiesz, jak czytać, jak zaakceptowana odpowiedź, ponieważ wyraźnie zapytał, jak również uruchomić usługę, czego nie było w pierwotnej odpowiedzi.
rachunek z
Najwyraźniej nie wiesz, jak poprawnie pisać kod. Jak już powiedział @Shaul Behr, twoje podejście jest złą praktyką, ponieważ jest nieefektywne i powolne. Podanie własnej odpowiedzi jest prawdopodobnie najlepsze, a to jeszcze gorsze: chwalenie siebie nigdy nie jest uważane za dobre zachowanie tutaj na SO (i prawdopodobnie na całym świecie).
Yoda
1
Najwyraźniej nie wiem, co jest gorsze ... Twoja niezdolność do użycia prawidłowej gramatyki, aby wyglądać, jakbyś wiedział, co mówisz, lub niezdolność do zrozumienia, że ​​właśnie skomentowałeś wątek z 2014 roku ... Lol.
rachunek
To jedyna odpowiedź, która wyjaśnia, co się stanie, jeśli ktoś usunie usługę między sprawdzeniem jej istnienia a interakcją z nią
Mike Caron
1
 private bool ServiceExists(string serviceName)
    {
        ServiceController[] services = ServiceController.GetServices();
        var service = services.FirstOrDefault(s => string.Equals(s.ServiceName, serviceName, StringComparison.OrdinalIgnoreCase));
        return service != null;
    }
Ajaya Nayak
źródło