Que tu aplicacion se ejecute al arrancar Windows  

Enviado Por: Radikal (Q3 Team)
Web : http://www.q3.nu
Email: radikal@q3.nu
Fecha: 26/05/20

Truco accedido 228 veces

 


Windows dispone de un 'mecanismo' que permite indicarle una serie de programas que serán ejecutados en el arranque del sistema.
Es bastante simple, consiste en colocar un valor de tipo string con el nombre del ejecutable que queremos que se ejecute en una clave determinada del registro.
Además de esto, dicho mecanismo nos permite especificar si queremos que el programa se ejecute sólo la siguiente vez que se inicie Windows (por ejemplo, para terminar con un proceso de desinstalacion) o bien cada una de las veces que se arranque Windows.
Las claves que hay que utilizar en cada caso son las siguientes:

Para que se ejecute cada vez que se arranque la máquina:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run

Para que se arranque sólo la próxima vez que se arranque Windows:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce

Para que se arranque cada vez que el usuario en curso abra una sesión:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run

Para que se arranque la próxima vez que el usuario en curso abra una sesión:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce

Es decir, si te fijas, cambia o bien la clave raiz ( HKEY_LOCAL_MACHINE/HKEY_CURRENT_USER) o bien la clave final (Run/RunOnce)

Sabiendo todo esto, sería interesante disponer de alguna herramienta para facilitarnos las tareas a la hora de añadir, eliminar o comprobar si un ejecutable está en una de estas claves ¿no crees?, asi que aqui van estas tres funciones con un ejemplo de utilización.

Nota: Añadir Registry al uses


 procedure TForm1.Button1Click(Sender: TObject);

   function SeEjecutaEnInicio ( NombreEjecutable : string;
                                SoloUnaVez, SoloUsuario: Boolean ): boolean;
   {
       ENTRADA:
         NombreEjecutable    = Nombre del ejecutable a comprobar
         SoloUnaVez          = TRUE  para comprobar sólo el siguiente arranque
                               FALSE para comprobar la ejecucion en todos los arranques
         SoloUsuario         = TRUE para comprobar sólo en el usuario en curso

       SALIDA:
         Devuelve TRUE si el programa se encuentra en el regitro, en la clave:
         HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run ó RunOnce ó bien en la clave
         HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run ó RunOnce en funcion de la ENTRADA
   }
   var
     Registro     : TRegistry;
     RegInfo      : TRegDataInfo;
     Clave        : string;
     Valores      : TStringList;
     n            : integer;

   begin
     Result:=FALSE;
     Clave:='Software\Microsoft\Windows\CurrentVersion\Run';
     If SoloUnaVez then Clave := Clave+'Once';

     Registro:=TRegistry.Create;
     try
       //Seleccionamos HKEY_LOCAL_MACHINE o bien si no la cambiamos, se queda
       //HKEY_CURRENT_USER que es la clave por defecto al crear un TRegistry
       if NOT SoloUsuario then Registro.RootKey := HKEY_LOCAL_MACHINE;

       //Abrimos la clave en cuestión:
       if NOT Registro.OpenKey(Clave,FALSE) then raise exception.create( 'Error: No se pudo abrir la clave '+
                                                                         Clave +' del registro de windows' );


       Valores:=TStringList.Create;
       try
         //Obtenemos una lista de los Nombres de los valores de la clave
         Registro.GetValueNames(Valores);

         //Comprobamos si esos valores son string, si lo son, los leemos, sino, lo borramos de la lista:
         for n:=0 to Pred(Valores.Count) do begin
           //Comprobamos si se trata de un valor string:
           If Registro.GetDataInfo( Valores[n], RegInfo) then begin
             if (RegInfo.RegData = rdString) then begin
                if Lowercase(NombreEjecutable)=LowerCase( Registro.ReadString(Valores[n]) ) then begin
                  Result:=TRUE;
                  Break;
                end;
             end;
           end else Valores[n]:='';
         end; //for n

       finally
         Valores.Free;
       end;
     finally
       Registro.Free;
     end;
   end; //SeEjecutaEnInicio


   procedure EjecutarEnInicio( NombrePrograma, NombreEjecutable: string;
                               SoloUnaVez, SoloUsuario: Boolean );
   {
       COMETIDO DE LA PROCEDURE:
         Añade un programa en el registro de Windows, para que se ejecute cuando Windows arranque.
         Se puede seleccionar que se arranque siempre o sólo una vez en el siguiente arranque y tambien
         si ha de ejecutarse en cada arranque de máquina o bien cuando el usuario en curso abra una sesion

       ENTRADA:
         NombrePrograma      = Nombre del programa
         NombreEjecutable    = Nombre del ejecutable del programa con el path completo
         SoloUnaVez          = TRUE  para comprobar sólo el siguiente arranque
                               FALSE para comprobar la ejecucion en todos los arranques
         SoloUsuario         = TRUE para comprobar sólo en el usuario en curso
   }

   var
     Registro     : TRegistry;
     Clave        : string;
   begin
     Clave:='Software\Microsoft\Windows\CurrentVersion\Run';
     if SoloUnaVez then Clave := Clave+'Once';

     Registro:=TRegistry.Create;
     try
       //Seleccionamos HKEY_LOCAL_MACHINE o bien si no la cambiamos, se queda
       //HKEY_CURRENT_USER que es la clave por defecto al crear un TRegistry
       if NOT SoloUsuario then Registro.RootKey := HKEY_LOCAL_MACHINE;

       //Abrimos la clave en cuestión:
       if NOT Registro.OpenKey(Clave,FALSE) then raise exception.create( 'Error: No se pudo abrir la clave '+
                                                                         Clave +' del registro de windows' );
       //Escribimos el valor para que se arranque el programa especificado:
       Registro.WriteString(NombrePrograma,NombreEjecutable);
     finally
       Registro.Free;
     end;
   end; //procedure EjecutarEnInicio


   procedure QuitarEjecutarEnInicio( NombreEjecutable: string;
                                     SoloUnaVez, SoloUsuario: Boolean );
   {
       COMETIDO DE LA PROCEDURE:
         Si el ejecutable 'NombreEjecutable' esta en el registro de Windows, en la clave
         que hace que se ejecute en cada arranque de Windows, la funcion lo borra de ahí.


       ENTRADA:
         NombreEjecutable    = Nombre del ejecutable del programa con el path completo
         SoloUnaVez          = TRUE  para borrar sólo del siguiente arranque
                               FALSE para borrar la ejecucion en todos los arranques
         SoloUsuario         = TRUE para borrar sólo en el usuario en curso
   }
   var
     Registro     : TRegistry;
     RegInfo      : TRegDataInfo;
     Clave        : string;
     Valores      : TStringList;
     n            : integer;
   begin
     Clave:='Software\Microsoft\Windows\CurrentVersion\Run';
     If SoloUnaVez then Clave := Clave+'Once';

     Registro:=TRegistry.Create;
     try
       //Seleccionamos HKEY_LOCAL_MACHINE o bien si no la cambiamos, se queda
       //HKEY_CURRENT_USER que es la clave por defecto al crear un TRegistry
       if NOT SoloUsuario then Registro.RootKey := HKEY_LOCAL_MACHINE;

       //Abrimos la clave en cuestión:
       if NOT Registro.OpenKey(Clave,FALSE) then raise exception.create( 'Error: No se pudo abrir la clave '+
                                                                         Clave +' del registro de windows' );


       Valores:=TStringList.Create;
       try
         //Obtenemos una lista de los Nombres de los valores de la clave
         Registro.GetValueNames(Valores);

         //Comprobamos si el nombre del ejecutable figura en alguno de los valores
         for n:=0 to Pred(Valores.Count) do begin
           //Comprobamos si se trata de un valor string:
           If Registro.GetDataInfo( Valores[n], RegInfo) then begin
             if (RegInfo.RegData = rdString) then begin
                if Lowercase(NombreEjecutable)=LowerCase( Registro.ReadString(Valores[n]) ) then begin
                  //Si figura, borramos ese valor
                  Registro.DeleteValue( Valores[n] );
                end;
             end;
           end;
         end; //for n

       finally
         Valores.Free;
       end;
     finally
       Registro.Free;
     end;
   end; //procedure QuitarEjecutarEnInicio


 begin
  //Unos cuantos ejemplos de utilización:


  //Comprobar si un programa se ejecuta en cada arranque de la máquina:
  if SeEjecutaEnInicio( 'c:\winnt\notepad.exe',
                        FALSE,FALSE) then ShowMessage('Si, se ejecuta en cada arranque')
                                     else ShowMessage('NO, NO se ejecuta en cada arranque');

  //Hacer que se ejecute el Notepad.exe en cada arranque para todos los usuarios:
  EjecutarEnInicio('Block de Notas','c:\winnt\notepad.exe',FALSE,FALSE);

  //Hacer que deje de ejecutarse el Notepad.exe de cada arranque:
  QuitarEjecutarEnInicio('c:\winnt\notepad.exe',FALSE,FALSE);

 end;




Enviado por: labgalia el 26-05-2005

Labgalia ha encapsulado las tres funciones en un componente no visible, para mayor comodidad.
El componente se puede usar, una vez instalado, simplemente soltándolo en tu form, o bien, puedes utilizarlo sin instalarlo, simplemente creándolo en runtime tras añadir su unit en tu linea uses.

Esta es la unit del componente. Copia el texto y la grabas en un fichero llamado BootExec.pas


 Unit BootExec;

 Interface

 Uses
   Classes,Windows,SysUtils,Registry;

 Type
   TBootExec = class(TComponent)

   Private
      NombreClave : String;
      NombreExec  : String;
      ProximaVez  : Boolean;
      Usuario     : Boolean;

   Protected

   Public
     Constructor Create(AOwner: TComponent); override;
     Function AppInReg  : Boolean;
     Function AddAppReg : Boolean;
     Function DelAppReg : Boolean;

   Published
     Property NombrePrograma : String
              Read NombreClave
              Write NombreClave;
     Property NombreEjecutable : String
              Read NombreExec
              Write NombreExec;
     Property SoloUnaVez : Boolean
              Read ProximaVez
              Write ProximaVez;
     Property SoloUsuario : Boolean
              Read Usuario
              Write Usuario;
   end;

 Procedure Register;

 Implementation

 {==============================================================================}
 Constructor TBootExec.Create(AOwner: TComponent);

 Begin
   Inherited;
   AddAppReg;
 End;

 {==============================================================================}
 Function TBootExec.AppInReg : Boolean;

 Var
   Reg      : TRegistry;
   RegInfo  : TRegDataInfo;
   Clave    : String;
   Valores  : TStringList;
   I        : Integer;

 Begin
   Result:=False;//No está en el Registro
   Clave:='Software\Microsoft\Windows\CurrentVersion\Run';
   If ProximaVez Then Clave := Clave+'Once';
   Reg:=TRegistry.Create;
   If Not(Usuario) Then Reg.RootKey := HKEY_LOCAL_MACHINE;
   If Not(Reg.KeyExists(Clave)) Then//comprobar prexistencia de clave
     Begin
        Reg.Free;
        Exit;
     End;
   Reg.OpenKey(Clave,False);//existe, por tanto podemos abrirla.
   Valores := TStringList.Create;
   Reg.GetValueNames(Valores);//Obtenemos una lista de los Nombres de los valores de la clave
   For I:=0 To (Valores.Count-1) Do
     Begin
       If Reg.GetDataInfo( Valores[i], RegInfo) Then
         Begin
           If (RegInfo.RegData = rdString) Then
             Begin
               If Lowercase(NombreExec)=LowerCase( Reg.ReadString(Valores[I]) ) Then
                 Begin
                  Result:=True;
                  Break;
                 End;
             End;
         End
        Else
          Valores[I]:='';
     End;//For
   Valores.Free;
   Reg.Free;
 End;

 {==============================================================================}
 Function TBootExec.AddAppReg : Boolean;

 Var
   Reg   : TRegistry;
   Clave : string;

 Begin
   Result:=False;
   If (NombreClave='') Or (NombreExec='') Then
     Exit;
   If AppInReg Then
     Exit;
   Clave:='Software\Microsoft\Windows\CurrentVersion\Run';
   If ProximaVez Then Clave := Clave+'Once';
   Reg:=TRegistry.Create;
   If Not(Usuario) Then Reg.RootKey := HKEY_LOCAL_MACHINE;
   If Not(Reg.KeyExists(Clave)) Then
     Begin
        Reg.Free;
        Exit;
     End;
   Reg.OpenKey(Clave,False);
   Reg.WriteString(NombreClave,NombreExec);
   Reg.Free;
   Result:=True;
 End;

 {==============================================================================}
 Function TBootExec.DelAppReg : Boolean;

 Var
   Reg     : TRegistry;
   RegInfo : TRegDataInfo;
   Clave   : string;
   Valores : TStringList;
   I       : integer;

 Begin
   Result:=False;
   If Not(AppInReg) Then
     Exit;
   If (NombreClave='') Or (NombreExec='') Then
     Exit;
   Clave:='Software\Microsoft\Windows\CurrentVersion\Run';
   If ProximaVez Then Clave := Clave+'Once';
   Reg:=TRegistry.Create;
   If Not(Usuario) Then Reg.RootKey := HKEY_LOCAL_MACHINE;
   If Not(Reg.KeyExists(Clave)) Then
     Begin
        Reg.Free;
        Exit;
     End;
   Reg.OpenKey(Clave,False);
   Valores := TStringList.Create;
   Reg.GetValueNames(Valores);//Obtenemos una lista de los Nombres de los valores de la clave
   For I:=0 To (Valores.Count-1) Do
     Begin
       If Reg.GetDataInfo( Valores[I], RegInfo) Then
         Begin
           If (RegInfo.RegData = rdString) Then
             Begin
               If Lowercase(NombreExec)=LowerCase( Reg.ReadString(Valores[I]) ) Then
                 Begin
                   Reg.DeleteValue( Valores[I] );
                   Result:=True;
                 End;
             End;
         End;
     End;
   Valores.Free;
   Reg.Free;
 End;

 {==============================================================================}
 Procedure Register;

 Begin
   RegisterComponents('LabGalia', [TBootExec]);
 end;

 {==============================================================================}
 END.



Ejemplos de utilización del componente si lo has depositado en tu form:

Saber si existe un programa en esa clave del registro:



 BootExec1.NombreEjecutable:='Notepad.exe';
 If BootExec1.AppInReg Them
    ShowMessage('si/yes')
   Else
     ShowMessage('NO');



Instalar un determinado programa en el registro en la clave que ya sabemos:



 BootExec1.NombrePrograma:='Block de Notas';
 BootExec1.NombreEjecutable:='C:\windows\Notepad.exe';
 BootExec1.SoloUnaVez:=False;{queremos que se ejecute siempre}
 BootExec1.SoloUsuario:=False;{que se ejecute con cualquier usuario}
 If BootExec1.AddAppReg Then
    ShowMessage('Ok, se ha instalado correctamente')
   Else
    ShowMessage('NO, Error en la instalación, posiblemente ya esté instalado...');



Desinstalar un determinado programa del registro en la clave que ya sabemos:



 BootExec1.NombreEjecutable:='Notepad.exe';
 If BootExec1.DelAppReg Then
    ShowMessage('Ok, se ha Desinstalado correctamente')
   Else
    ShowMessage('NO, Error en la Desinstalación, posiblemente ya fuese desinstalado...');




Enviado por: Radikal

Puestos a encapsular, yo lo he hecho en una clase, no en un componente, lista para ser usada en runtime.
He añadido su propia clase de excepciones para poderlas discriminar cuando se utilice.

Aqui está, graba el texto de la unit y la grabas en un fichero llamado BootExec.pas :

 unit BootExec;

 interface

 uses Classes, Windows, SysUtils, Registry;


 type
   EBootExecError = class(Exception);

   TBootExec = class

   private
     FProgramName,
     FExeName            : string;

     FRunOnce,
     FCurrentUser        : boolean;

     Registro            : TRegistry;
     Clave               : string;
     Valores             : TStringList;

     function  GetValueNameOfAValue( Value: string): string;
     procedure OpenCorrectKey;
   public
     constructor  Create;
     destructor   Destroy; override;
     function     IsInBoot : boolean;
     function     Add: boolean;
     function     Delete: boolean;
   published

     //Propiedades...
     property ProgramName        : string  read FProgramName write FProgramName;
     property ExeName            : string  read FExeName     write FExeName;
     property RunOnce            : boolean read FRunOnce     write FRunOnce;
     property CurrentUser        : boolean read FCurrentUser write FCurrentUser;

   end;


 implementation


 procedure TBootExec.OpenCorrectKey;
 {
   Abre la clave del registro adecuada segun las propiedades
   RunOnce y CurrentUser
 }
 begin
   Clave:='Soxxftware\Microsoft\Windows\CurrentVersion\Run';
   if FRunOnce then Clave := Clave+'Once';

   //Seleccionamos HKEY_LOCAL_MACHINE o HKEY_CURRENT_USER
   if FCurrentUser then Registro.RootKey :=HKEY_CURRENT_USER else Registro.RootKey := HKEY_LOCAL_MACHINE;

   //Abrimos la clave en cuestión:
   if NOT Registro.OpenKey(Clave,FALSE) then raise EBootExecError.create( 'BootExec Error: No se pudo abrir la clave '+
                                                                          Clave +' del registro de windows' );
 end;

 function TBootExec.GetValueNameOfAValue( Value: string ): string;
 {
  Si la clave abierta de Registro contiene un Nombre de Valor de tipo string cuyo
  contenido coincide con 'Value', la funcion devuelve dicho Nombre de Valor.
  Si no existe, devuelve una cadena vacia ('')
 }
 var
   RegInfo : TRegDataInfo;
   n       : integer;
 begin
   Result:='';  //Por defecto, no encontrada...

   //Vaciamos la lista de valores
   Valores.Clear;

   //Obtenemos una lista de los Nombres de los valores de la clave en curso
   Registro.GetValueNames(Valores);

   //Comprobamos si esos valores son string, si lo son, los leemos, sino, lo borramos de la lista:
   for n:=0 to Pred(Valores.Count) do begin
     //Comprobamos si se trata de un valor string:
     If Registro.GetDataInfo( Valores[n], RegInfo) then begin
       if (RegInfo.RegData = rdString) then begin
          if Lowercase(Value)=LowerCase( Registro.ReadString(Valores[n]) ) then begin
            Result:=Valores[n];
            Break;
          end;
       end;
     end;
   end; //for n
 end;

 constructor TBootExec.Create;
 begin
   //Que se creen las cosillas del ancestro...
   inherited Create;

   //Y ahora las nuestras:
   FProgramName:='';
   FExeName:='';
   FRunOnce:=FALSE;
   FCurrentUser:=FALSE;

   Registro:=TRegistry.Create;
   Valores :=TStringList.Create;
 end;

 destructor TBootExec.Destroy;
 begin
   //Liberamos nuestras cosillas:
   Valores.Free;
   Registro.Free;


   //Y que se destruyan las cosillas del ancestro...
   inherited Destroy;
 end;

 function  TBootExec.IsInBoot: boolean;
 begin
   //Por defecto, no está
   Result:=FALSE;

   if FExeName='' then raise EBootExecError.create( 'BootExec Error: Debe dar un valor a ExeName '+
                                                    ' para usar el método Add' );

   OpenCorrectKey;

   //Si hay un valor que contenga el ExeName, devolvemos true
   if GetValueNameOfAValue(FExeName)<>'' then Result:=TRUE;

   Registro.CloseKey;
 end;

 function TBootExec.Add : boolean;
 {
     COMETIDO DEL METODO:
       Añade un programa en el registro de Windows, para que se ejecute cuando Windows arranque.
       Se puede seleccionar que se arranque siempre o sólo una vez en el siguiente arranque y tambien
       si ha de ejecutarse en cada arranque de máquina o bien cuando el usuario en curso abra una sesion
       Lo coloca en la clave adecuada, en funcion de las propiedades RunOnce y CurrentUser
 }
 begin
   Result:=FALSE;

   OpenCorrectKey;

   //Escribimos el valor para que se arranque el programa especificado:
   Registro.WriteString(FProgramName,FExeName);

   //Cerramos la clave
   Registro.CloseKey;

   //Si hubiera habido una excepcion en OpenCorrectKey, no llegaría hasta aqui...
   Result:=TRUE;
 end;

 function TBootExec.Delete: boolean;
 var
   ElValor : string;
 begin
   Result:=FALSE;

   if FExeName='' then raise EBootExecError.create( 'BootExec Error: Debe dar un valor a ExeName '+
                                                    ' para usar el método Delete' );

   OpenCorrectKey;

   //Si hay un valor que contenga el ExeName, lo borramos, sino, no hacemos nada...
   ElValor:=GetValueNameOfAValue(FExeName);
   if ElValor<>'' then begin Registro.DeleteValue(ElValor); Result:=TRUE; end;

   Registro.CloseKey;
 end;

 end.



Y aqui van unos cuantos ejemplos de su utilización (no olvides añadir BootExec en tu linea uses)

  //Ejemplos de utilización de la clase:

   //Sin controlar errores:

   //Saber si el c:\windows\Notepad.exe está en el arranque
   //de la máquina:
   BootExec1:=TBootExec.Create;
   try
      with BootExec1 do begin
        ExeName:='c:\windows\notepad.exe';
        RunOnce:=FALSE;
        CurrentUser:=FALSE;
        if IsInBoot then ShowMessage('Si, está / Yes it is')
                    else ShowMessage('No, no está / No, it is not');
      end;
   finally
     BootExec1.Free;
   end;

   //Controlando los posibles errores a traves de excepciones:


   //Saber si el c:\windows\Notepad.exe está en el arranque
   //de la máquina:
   BootExec1:=TBootExec.Create;
   try
      BootExec1.ExeName:='c:\windows\notepad.exe';
      BootExec1.RunOnce:=FALSE;
      BootExec1.CurrentUser:=FALSE;
      if BootExec1.IsInBoot then ShowMessage('Si, está / Yes it is')
                            else ShowMessage('No, no está / No, it is not');

   finally
     BootExec1.Free;
   end;


   //Poner el notepad en el proximo arranque de la maquina:
   BootExec1:=TBootExec.Create;
   try
      BootExec1.ProgramName:='Block de Notas';
      BootExec1.ExeName:='c:\windows\notepad.exe';
      BootExec1.RunOnce:=TRUE;
      BootExec1.CurrentUser:=FALSE;
      try
        if BootExec1.Add then ShowMessage('El programa fué añadido al próximo arranque de Windows');
      except
        //Aqui si hubo algun problema al añadirlo:
        on e: EBootExecError do begin
          ShowMessage( 'Hubo algun problema al intentar añadir el programa al arranque...'+
                       'El mensaje de error fué: '+ e.Message );
        end; //on EBootExecError
      end;

   finally
     BootExec1.Free;
   end;


   //Quitar el notepad del proximo arranque de la maquina:
   BootExec1:=TBootExec.Create;
   try
      BootExec1.ProgramName:='Block de Notas';
      BootExec1.ExeName:='c:\windows\notepad.exe';
      BootExec1.RunOnce:=TRUE;
      BootExec1.CurrentUser:=FALSE;
      try
        if BootExec1.Delete then ShowMessage('El programa fué quitado del próximo arranque de Windows');
      except
        //Aqui si hubo algun problema al añadirlo:
        on e: EBootExecError do begin
          ShowMessage( 'Hubo algun problema al intentar añadir el programa al arranque...'+
                       'El mensaje de error fué: '+ e.Message );
        end; //on EBootExecError
      end;

   finally
     BootExec1.Free;
   end;