"Cerrador" de programas  

Enviado Por: Radikal (Q3 Team)
Web : http://www.q3.nu
Email: radikal@q3.nu
Fecha: 08/09/00

Truco accedido 70 veces

 


Mucha gente ha inundado mi carpeta de emails pendientes preguntandome sobre el tema de este truco.
Se trata de lo siguiente: tomar una 'instantanea' de los programas que hay en ejecucion en un momento dado, y luego, cuando lo necesitemos, cerrar todos aquellos programas que se hayan abierto despues.
Por ejemplo, esto sería útil en un programa de control de acceso al ordenador: dejamos que el usuario haga lo que tenga que hacer, pero cuando termine, ejecutamos una funcion que nos cierre todos aquellos programas que el usuario despistado haya olvidado cerrar.
Antes de continuar, deciros que este truco está basado en los siguientes trucos:

[287] - Obtener una lista de los EXEs en ejecución
[290] - Cerrar una aplicacion sabiendo el nombre de su ejecutable

Bien, necesitamos varias cosas:
  • Una funcion que nos haga la instantanea de los programas en ejecucion, asi como un sitio donde guardarla
  • Y otra funcion que nos cierre aquellos programas que no estaban en la instantanea tomada anteriormente


    Empecemos:

  • Primero, añadimos TlHelp32 en el uses de nuestra form

  • Ahora, declaramos esta variable en la parte private de la form:


       private
         { Private declarations }
         ProgramasAntes    : TStringList;
    



    se trata de la lista de programas que guardaremos....

  • Ahora, necesitamos crear y destruir esta lista para poder usarla. Lo haremos en los eventos OnCreate y OnDestroy de la form:


     procedure TForm1.FormCreate(Sender: TObject);
     begin
       ProgramasAntes:=TStringList.Create;
     end;
    
     procedure TForm1.FormDestroy(Sender: TObject);
     begin
       ProgramasAntes.Free;
     end;
    



  • Bien, ahora necesitamos la procedure que hará la "Instantanea" de los programas:



     procedure TForm1.GuardaInstante(const Lista:TStringList);
    
         function SacaExe(MangoW:HWND):string;
         {Obtiene el EXE de una tarea}
         {get EXE of a task}
         var
           Datos    :TProcessEntry32;
           hID       : DWord;
           Snap    : Integer;
         begin
           GetWindowThreadProcessId(MangoW,@hID);
           Snap:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
           try
             Datos.dwSize:=SizeOf(Datos);
             if(Process32First(Snap,Datos))then
             begin
               repeat
                 if Datos.th32ProcessID=hID then
                 begin
                   Result:=UpperCase(StrPas(Datos.szExeFile));
                   Break;
                 end;
               until not(Process32Next(Snap,Datos));
             end;
           finally
             Windows.CloseHandle(Snap);
           end;
         end;
    
    
        function ObtieneVentanas(Mango: HWND;
                 Nada: Pointer): Boolean; stdcall;
        var
           sTemp:string;
        begin
          Result := True;
          {Mango es el handle de la tarea encontrada}
          {Añadimos el .EXE si no está ya añadido...}
          sTemp:=SacaExe(Mango);
           with TStringList(Nada) do
             if IndexOf(sTemp) = - 1 then Add(sTemp);
        end;
    
     begin
       Lista.Clear;
       EnumWindows( @ObtieneVentanas, Integer(Lista) );
     end;
    



    Sin ilvidarnos de su declaracion en la parta private de la form:

         procedure GuardaInstante(const Lista:TStringList);
    



  • Ahora, la procedure que "asesinara" a los programas que no estuvieran en la instantanea tomada con anterioridad:


     procedure TForm1.MataLosQueSobran(const Antes:TStringList);
     var
        i                : integer;
        ProgramasDespues : TStringList;
    
       procedure KillTask(FileName:String);
       var
           ContinueLoop:BOOL;
           FSnapshotHandle:THandle;
           FProcessEntry32:TProcessEntry32;
       const
           PROCESS_TERMINATE=$0001;
       begin
           FSnapshotHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
           FProcessEntry32.dwSize:=Sizeof(FProcessEntry32);
           ContinueLoop:=Process32First(FSnapshotHandle,FProcessEntry32);
           while integer(ContinueLoop)<>0 do
           begin
               if FProcessEntry32.szExeFile=FileName then
                 TerminateProcess( OpenProcess(PROCESS_TERMINATE,BOOL(0),
                                   FProcessEntry32.th32ProcessID),0);
                 ContinueLoop:=Process32Next(FSnapshotHandle,FProcessEntry32);
           end;
           CloseHandle(FSnapshotHandle);
       end;
    
     begin
       ProgramasDespues:=TStringList.Create;
       try
         GuardaInstante(ProgramasDespues);
         for i:=0 to ProgramasDespues.Count-1 do
           If Antes.IndexOf( ProgramasDespues[i] ) = -1 then
             KillTask( ProgramasDespues[i] );
       finally
         ProgramasDespues.Free;
       end;
     end;
    


    y su declaracion, claro:

         procedure MataLosQueSobran(const Antes:TStringList);
    



  • Finalmente, nos falta la llamada que hay que hacer para tomar la "instantanea":


     procedure TForm1.Button1Click(Sender: TObject);
     begin
       GuardaInstante(ProgramasAntes);
     end;
    



    y la que matara los programas que sobran:


     procedure TForm1.Button2Click(Sender: TObject);
     begin
       MataLosQueSobran(ProgramasAntes);
     end;
    



    Para quitaros trabajo, aqui teneis la unit completa del ejemplo. Tendreis que poner dos botones en una form (Button1 y Button2) y pegar este codigo en la unit de la form:


     unit Unit1;
    
     interface
    
     uses
       Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
       TlHelp32, StdCtrls;
    
     type
       TForm1 = class(TForm)
         Button1: TButton;
         Button2: TButton;
         procedure Button1Click(Sender: TObject);
         procedure FormCreate(Sender: TObject);
         procedure FormDestroy(Sender: TObject);
         procedure Button2Click(Sender: TObject);
       private
         { Private declarations }
         ProgramasAntes    : TStringList;
         procedure GuardaInstante(const Lista:TStringList);
         procedure MataLosQueSobran(const Antes:TStringList);
       public
         { Public declarations }
       end;
    
     var
       Form1: TForm1;
    
     implementation
    
     {$R *.DFM}
    
     procedure TForm1.GuardaInstante(const Lista:TStringList);
    
         function SacaExe(MangoW:HWND):string;
         {Obtiene el EXE de una tarea}
         {get EXE of a task}
         var
           Datos    :TProcessEntry32;
           hID       : DWord;
           Snap    : Integer;
         begin
           GetWindowThreadProcessId(MangoW,@hID);
           Snap:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
           try
             Datos.dwSize:=SizeOf(Datos);
             if(Process32First(Snap,Datos))then
             begin
               repeat
                 if Datos.th32ProcessID=hID then
                 begin
                   Result:=UpperCase(StrPas(Datos.szExeFile));
                   Break;
                 end;
               until not(Process32Next(Snap,Datos));
             end;
           finally
             Windows.CloseHandle(Snap);
           end;
         end;
    
    
        function ObtieneVentanas(Mango: HWND;
                 Nada: Pointer): Boolean; stdcall;
        var
           sTemp:string;
        begin
          Result := True;
          {Mango es el handle de la tarea encontrada}
          {Añadimos el .EXE si no está ya añadido...}
          sTemp:=SacaExe(Mango);
           with TStringList(Nada) do
             if IndexOf(sTemp) = - 1 then Add(sTemp);
        end;
    
     begin
       Lista.Clear;
       EnumWindows( @ObtieneVentanas, Integer(Lista) );
     end;
    
     procedure TForm1.MataLosQueSobran(const Antes:TStringList);
     var
        i                : integer;
        ProgramasDespues : TStringList;
    
       procedure KillTask(FileName:String);
       var
           ContinueLoop:BOOL;
           FSnapshotHandle:THandle;
           FProcessEntry32:TProcessEntry32;
       const
           PROCESS_TERMINATE=$0001;
       begin
           FSnapshotHandle:=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
           FProcessEntry32.dwSize:=Sizeof(FProcessEntry32);
           ContinueLoop:=Process32First(FSnapshotHandle,FProcessEntry32);
           while integer(ContinueLoop)<>0 do
           begin
               if FProcessEntry32.szExeFile=FileName then
                 TerminateProcess( OpenProcess(PROCESS_TERMINATE,BOOL(0),
                                   FProcessEntry32.th32ProcessID),0);
                 ContinueLoop:=Process32Next(FSnapshotHandle,FProcessEntry32);
           end;
           CloseHandle(FSnapshotHandle);
       end;
    
     begin
       ProgramasDespues:=TStringList.Create;
       try
         GuardaInstante(ProgramasDespues);
         for i:=0 to ProgramasDespues.Count-1 do
           If Antes.IndexOf( ProgramasDespues[i] ) = -1 then
             KillTask( ProgramasDespues[i] );
       finally
         ProgramasDespues.Free;
       end;
     end;
    
     procedure TForm1.FormCreate(Sender: TObject);
     begin
       ProgramasAntes:=TStringList.Create;
     end;
    
     procedure TForm1.FormDestroy(Sender: TObject);
     begin
       ProgramasAntes.Free;
     end;
    
     procedure TForm1.Button1Click(Sender: TObject);
     begin
       GuardaInstante(ProgramasAntes);
     end;
    
    
     procedure TForm1.Button2Click(Sender: TObject);
     begin
       MataLosQueSobran(ProgramasAntes);
     end;
    
     end.