Detener procesos y servicios con Delphi

Resultado de imagen de imagen de cerrar procesos

Examinando los procesos que se estaban ejecutando en mi PC, me dí cuenta que muchos de ellos no servían para nada y lo único que hacían era consumir ciclos de CPU y tiempo de trabajo de disco duro, ocupaban memoria disponible y utilizaban internet para enviar y recibir datos, consumiendo un ancho de banda que es limitado.

Ya sé que desde el Administrador de tareas se pueden finalizar uno a uno, pero me dije ¿por qué no hacer un programa que me los finalice a todos pulsando un botón? y me puse a ello.

Pensé que lo mejor era dividirlo en dos módulos, uno sería un fichero de texto donde colocaría los nombres de los procesos y servicios y otro sería el programa en sí, de tal forma que cuando se iniciase haría lo siguiente:

1) Leer el fichero "ProcesosACerrar.txt"con los nombres de procesos y servicios línea a línea.
2) Después identificaría si es un programa o un servicio, leyendo el carácter que hay antes de la coma.
3) Por último lo detendría mediante la llamada al procedimiento StopProceso o StopService

El fichero "ProcesosACerrar.txt" sería por ejemplo como sigue:

S,Spooler
S,KinectManagement
S,igfxcuiservice1.0.0.0
S,AdobeARMservice
P,ACDaemon.exe
P,ACService.exe
P,jucheck.exe

A continuación os copio el ejecutable que he desarrollado.


//en el uses tengo lo siguiente
USES
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, tlhelp32, winsvc;

// funciones del programa

FUNCTION TForm1.GetToken(Cadena, Separador: ansiSTRING; Token: Integer): ansiSTRING;
{
  Cadena     es el string en el que buscar el token
  Separador  es el string que separa cada token
  Token      es el número de token que buscamos
}
BEGIN
  Cadena := Cadena + Separador;
  WHILE Token > 1 DO
    BEGIN
      Delete(Cadena, 1, AnsiPos(Separador, Cadena));
      Dec(Token);
    END;
  Result := Copy(Cadena, 1, AnsiPos(Separador, Cadena) - Length(Separador));
END;

PROCEDURE TForm1.Button10Click(Sender: TObject);
VAR
  lista: tstringlist;
  i: Integer;
  linea, tipo, ProcesoOServicio, dato: STRING;
BEGIN
memo1.lines.clear;
  IF FileExists('C:\ProcesosACerrar.txt', true) THEN
    BEGIN
      lista := tstringlist.CREATE;
      TRY
        lista.loadfromfile('C:\ProcesosACerrar.txt');
        FOR i := 0 TO lista.Count - 1 DO
          BEGIN
            linea := trim(lista.strings[i]);
            IF linea <> '' THEN
              BEGIN
                // linea es p.ej si es un proceso :   P,notepad.exe
                // linea es p.ej si es un servicio :  S,spooler

                tipo := GetToken(trim(lista.strings[i]), ',', 1);
                //tipo puede ser P o S
                ProcesoOServicio := GetToken(linea, ',', 2);
                //ProcesoOServicio es el nombre del proceso o servicio
                IF tipo = 'P' THEN
                  StopProceso(ProcesoOServicio);
                IF tipo = 'S' THEN
                  StopService(ProcesoOServicio);
              END;
          END;
      FINALLY
        lista.free;
      END;
    END
  ELSE
    showmessage(' no se encuentra el archivo ' + 'C:\ProcesosACerrar.txt')
END;


PROCEDURE TForm1.StopService(nombre: STRING);
VAR
  ServiceControlManager: SC_HANDLE;
  Service: SC_HANDLE;
  ServiceStatus: SERVICE_STATUS;
  Resultado: boolean;
BEGIN
  ServiceControlManager := OpenSCManager(NIL, NIL, SC_MANAGER_CONNECT);
  IF ServiceControlManager <> 0 THEN
    BEGIN
      Service := OpenService(ServiceControlManager, PChar(nombre), SERVICE_ALL_ACCESS);
      IF Service <> 0 THEN
        BEGIN
          IF QueryServiceStatus(Service, ServiceStatus) THEN
            BEGIN
              IF ServiceStatus.dwCurrentState <> SERVICE_STOPPED THEN
                BEGIN
                  Resultado := ControlService(Service, SERVICE_CONTROL_STOP, ServiceStatus);
                  IF Resultado THEN
                    Memo1.lines.add('Servicio ' + nombre + ' detenido')
                  ELSE
                    Memo1.lines.add(' Error al parar el servicio ' + nombre);
                END;
            END;
          CloseServiceHandle(Service);
        END;
      CloseServiceHandle(ServiceControlManager);
    END;
END;


FUNCTION TForm1.StopProceso(nombre: STRING): boolean;
VAR
  ModuleEntry: TModuleEntry32;
  ProcessEntry: TProcessEntry32;
  hSnapshot, hProcess: Cardinal;
BEGIN
  Result := False;
  ModuleEntry.dwSize := SizeOf(TModuleEntry32);
  ProcessEntry.dwSize := SizeOf(TProcessEntry32);
  hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  IF Process32First(hSnapshot, ProcessEntry) THEN
    REPEAT
      IF (lstrcmpi(PChar(nombre), @ProcessEntry.szExeFile) = 0) THEN
        BEGIN
          hProcess := OpenProcess(PROCESS_TERMINATE, False, ProcessEntry.th32processid);
          Result := TerminateProcess(hProcess, 0);
          IF Result THEN
            Memo1.lines.add(nombre + ' - ' + 'Cerrado')
          ELSE
            Memo1.lines.add(nombre + ' - ' + 'Error al cerrar.');

          CloseHandle(hProcess);
        END;
    UNTIL NOT Process32Next(hSnapshot, ProcessEntry);
  CloseHandle(hSnapshot);
END;

Después de haber ejecutado el programa si accedemos al Administrador de tareas de Windows se ve que el consumo de CPU, memoria, disco, ethernet ha disminuido, en mi caso he conseguido cerrar 30 procesos de los 68 que tenía, un 44% de recursos ociosos del sistema y la verdad es que se nota al trabajar con el PC, ahora parece que va "más ligero", las aplicaciones se abren antes y al navegar por internet me da la impresión que las páginas se abren más rápido.
Un detalle que hay que tener en cuenta, es que el ejecutable se debe iniciar como Administrador de la máquina (clic con el botón derecho sobre el programa y en el menú emergente activar el menú "Ejecutar como Administrador", ya que se necesita un usuario con los máximo privilegios para cerrar programas y servicios.


No hay comentarios:

Publicar un comentario