Używamy źle napisanej usługi Windows, która zawiesza się, gdy próbujemy powstrzymać ją od kodu. Musimy więc znaleźć proces związany z tą usługą i ją zabić. Jakieś sugestie?Sprawdzanie działającej nazwy usługi systemu Windows .NET 1.1
Odpowiedz
Usługa WMI zawiera następujące informacje: klasa Win32_Service.
WQL kwerendy jak
SELECT ProcessId FROM Win32_Service WHERE Name='MyServiceName'
wykorzystaniem System.Management powinno załatwić sprawę.
Od razu zobacz: taskllist.exe /svc
i inne narzędzia z wiersza poleceń.
Można użyć
tasklist /svc /fi "SERVICES eq YourServiceName"
Aby znaleźć nazwę procesu i id, a także w przypadku tych samych gospodarzy procesowych innych usług.
Możesz użyć System.Management.MangementObjectSearcher
, aby uzyskać identyfikator procesu usługi i System.Diagnostics.Process
, aby uzyskać odpowiednią instancję Process
i ją zabić.
Sposób w następującym programie KillService()
pokazuje jak to zrobić:
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Management;
namespace KillProcessApp {
class Program {
static void Main(string[] args) {
KillService("YourServiceName");
}
static void KillService(string serviceName) {
string query = string.Format(
"SELECT ProcessId FROM Win32_Service WHERE Name='{0}'",
serviceName);
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(query);
foreach (ManagementObject obj in searcher.Get()) {
uint processId = (uint) obj["ProcessId"];
Process process = null;
try
{
process = Process.GetProcessById((int)processId);
}
catch (ArgumentException)
{
// Thrown if the process specified by processId
// is no longer running.
}
try
{
if (process != null)
{
process.Kill();
}
}
catch (Win32Exception)
{
// Thrown if process is already terminating,
// the process is a Win16 exe or the process
// could not be terminated.
}
catch (InvalidOperationException)
{
// Thrown if the process has already terminated.
}
}
}
}
}
Microsoft/SysInternals posiada narzędzie wiersza polecenia o nazwie PsKill który pozwala zabić proces według nazwy. To narzędzie pozwala także zabijać procesy na innych serwerach. Windows SysInternals
Zastosowanie: pskill [-t] [\ komputer [-u nazwa_użytkownika [-p hasło]]] < proces ID | nazwa > -t Zabij proces i jego potomków.
-u Określa opcjonalną nazwę użytkownika do logowania do komputera zdalnego.
-p Określa opcjonalne hasło dla nazwy użytkownika. Jeśli to pominiesz, zostaniesz poproszony o podanie ukrytego hasła.
Sądzę, że jest to proces dwuetapowy - jeśli zawsze jest to ta sama usługa, można łatwo znaleźć nazwę procesu za pomocą metod sugerowanych w innych odpowiedziach.
Mam następnie następujący kod w klasie na .NET 1.1 Web server:
Process[] runningProcs =
Process.GetProcessesByName("ProcessName");
foreach (Process runningProc in runningProcs)
{
// NOTE: Kill only works for local processes
runningProc.Kill();
}
Kill method może rzucić kilka wyjątków, które należy rozważyć wzrok - zwłaszcza Win32Exception, który jest wyrzucany jeśli proces nie może zostać zabity.
Należy pamiętać, że WaitForExit method i HasExited property istnieją również w świecie 1.1, ale nie są wymienione na stronie dokumentacji dla Kill w 1.1.
Aby odpowiedzieć dokładnie na moje pytanie - Jak znaleźć proces związany z pewnym usługi:
ManagementObjectSearcher searcher = new ManagementObjectSearcher
("SELECT * FROM Win32_Service WHERE DisplayName = '" + serviceName + "'");
foreach(ManagementObject result in searcher.Get())
{
if (result["DisplayName"].ToString().ToLower().Equals(serviceName.ToLower()))
{
int iPID = Convert.ToInt32(result["ProcessId"]);
KillProcessByID(iPID, 1000); //some method that will kill Process for given PID and timeout. this should be trivial
}
}
}
kodu Dobrej podziękowania. Jednak zmienię "if (process! = Null)" na "if (process! = Null && process.Id> 0)". Windows nie pozwoli ci zabić procesu zero, ale lepiej nawet nie próbować. Szybciej, aby to sprawdzić, niż podnieść i złapać wyjątek. –