Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Статьи о программировании и не только Сделай сам: Управление автозагрузкой


Сайт рассылки

Продолжаем серию "Сделай сам", посвящённую практическому применению Delphi. На этот раз мы поговорим о такой важной составляющей жизни нашего компьютера, как автозагрузка. При загрузке Windows могут запускаться самые разные приложения: от системной панели (вы её можете узнать по характерным для неё часам) до программы оптимизации реестра.
 Все мы любим устанавливать новые программы. А некоторые из них, дабы мы с ними никогда не расставались, втихую прописывают себя в автозагрузку. Вот и получается, что со временем Windows загружается всё дольше и дольше. А всё потому, что с ней за компанию запускаются различные "удобняшки", антивирусы (а иногда и их анти-сородичи) и т.п.
 Вывод из всего вышесказанного: время от времени нужно проводить "зачистку" в автозагрузке. Продвинутыми пользователями это делается при помощи редактора реестра и Блокнота, а все остальные используют специальные программы. Давайте посмотрим, что нам предлагает Windows для управления автозагрузкой. После недолгих поисков была найдена программа MsConfig (лежит она в каталоге …\Windows\System). MsConfig позволяет просматривать список файлов, запускающихся вместе с Windows и удалять элементы из автозагрузки с возможностью восстановления. Программа обрабатывает файл Win.ini, папку "Автозагрузка" и следующие ключи реестра:  HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Run,  HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run и  HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices.
Теперь, когда есть с чем сравнить, сделаем свою программу для управления автозагрузкой. Вот что наше творение будет уметь делать к концу статьи:
1) Всё, что умеет MsConfig, за исключением восстановления удалённых из автозагрузки файлов;
2) Добавлять новые файлы в автозагрузку и изменять пути к существующим;
3) Обрабатывать большее количество ключей реестра, чем MsConfig. 

Теперь немного теоретических сведений:
1) В Win.ini есть два параметра: Load и Run. Все файлы, имена которых записаны в этих параметрах через пробел, будут загружаться при старте Windows. А значит, в именах файлов не должно быть пробелов. Этого легко добиться при помощи функции sysutils.ExtractShortPathName (filename).
2) В реестре есть "автозагрузочные" ключи с одинаковыми названиями: Run и RunOnce. Одна пара находится в разделе  HKEY_LOCAL_MACHINE, а другая – в  HKEY_CURRENT_USER. В связи с этим, в нашей программе будем осуществлять переход между разделами при помощи двух компонентов  TradioButton (см. рис. 1). 


Создайте в Delphi новый проект и поместите на форму  PageControl1:TpageControl. Затем на этот компонент поместите  ListView1:TlistView. После этого на форму поместите следующие компоненты:  ToolBar1:TtoolBar, ImageList1:TimageList, OpenDialog1:TopenDialog, RadioButton1:TradioButton и RadioButton2:TradioButton. Теперь выделите  PageControl1 и нажмите правую клавишу мыши. Из появившегося меню выберите пункт  New Page. После этого на компоненте должна появиться новая страница. Создайте, таким образом, ещё четыре страницы и дайте каждой название (свойство  Caption): 1 – Run, 2 – RunOnce, 3 – RunServices, 4 – RunServicesOnce, 5 – Win.ini. Каждая страница будет отвечать за определённый ключ реестра, либо за файл Win.ini. Теперь выделите  ListView1 и, при помощи свойства  Columns, создайте две колонки с названиями (свойство  Caption)  Имя и  Путь соответственно, также для каждой колонки установите свойству  Autosize значение  True. После этого измените значения свойства  ViewStyle на  vsReport. Затем сделайте активным компонент  ToolBar1 и создайте на нём четыре кнопки. Для каждой свойству  ShowHint (показывать подсказку) установите значение true (истина), а в свойство  Hint запишите эти самые подсказки, которые будут появляться при наведении указателя мыши на ту или иную кнопку: 1 – Добавить файл, 2 – Изменить путь, 3 – Удалить файл, 4 – Автозагрузка. На кнопки, при помощи  ImageList1, можно поместить иконки (см. рисунок 1). Чтобы сделать это, выполните следующие действия: кликните двойным щелчком по компоненту  ImageList1, при помощи кнопки “Add…” добавьте в компонент нужные значки (каждый значок будет помещён под своим номером), выделите компонент  ToolBar1 и в свойстве  Images выберите компонент  ImageList1. После этого нужно в свойстве  ImageIndex каждой кнопки выбрать номер понравившегося значка. Теперь приведите вашу форму к виду, подобному на форму, изображённую на рисунке 1.
На этом внешнее оформление программы завершено, а значит, пора заняться непосредственно программированием. Для начала в разделе  Uses подключите два модуля:  Registry (для работы с реестром) и  IniFiles (для работы с Ini-файлами). После этого нужно объявить несколько глобальных переменных:
var
 …
 ActIndex: Integer; //индекс активной страницы
 Appini: TIniFile; //для работы с Ini-файлами
 key: Cardinal; //текущий ключ реестра
 path: String; //путь к файлу
 reg: TRegistry; //для работы с реестром
 i: Integer; //используется в циклах
 pathfile: String;
 Value, Load, Run: TStringList; //списки файлов автозагрузки
 ListItem:TListItem; //для работы с компонентом ListView1

Затем запишите процедуру, которая будет из строки извлекать пути к файлам, разделённые пробелами, и помещает их в список. Позже эта процедура будет востребована.
procedure ExtractFilenames(s: String;FileNames: String;qw: TStrings);
begin
 {если найдены два пробела, то удаляем один из них}
 i := pos(' ', filenames);
 while (i <> 0)  do
 begin
   delete(filenames, i, 1);
   i := pos(' ', filenames);
 end;
 i := pos(' ', filenames);
 {добавляем в список qw все файлы из строки}
 while (i<>0)  do
 begin
   qw.Add(copy(Filenames, 1, i-1));
   delete(filenames, 1, i);
   i := pos(' ', filenames);
 end;
 qw.Add(filenames);
end;

Для обработки события OnShow компонента TabSheet1 (мы её назвали "Run") запишите следующую процедуру:

procedure TForm1.TabSheet1Show(Sender: TObject);
begin
 //очищаем ListView1
 ListView1.Items.Clear;
 //создаём объект для работы с реестром
 reg := TRegistry.Create;
 //будем работать в ключе хранящемся в переменной Key
 reg.RootKey := Key;
 {открываем ключ, в котором содержатся имена файлов загружаемых при каждом старте Windows и записываем эти в ListBox1}
 reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Run', False);
 reg.GetValueNames(value);
 for i := 0  to value.Count-1  do
 with ListView1 do
 begin
   ListItem := Items.Add;
   ListItem.Caption :=Value.Strings[i];
   ListItem.SubItems.Add(reg.ReadString(Value.Strings[i]));
 end;
 //освобождаем память, выделенную под объект reg
 reg.Free;
end;

Процедура события OnShow компонента TabSheet2:
Всё то же самое, только открываем другой ключ реестра:
...
 reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunOnce', False);
...
Обработка события OnShow компонента TabSheet3:
То же, что и в предыдущих процедурах, но открываем ключ реестра, в котором хранятся имена сервисов, которые запускаются вместе с Windows:
...
 reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunServices', False);
...
Обработка события OnShow компонента TabSheet4:
Открываем ключ реестра, в котором хранятся имена сервисов, которые запустятся только один раз при ближайшей перезагрузки Windows:
...
 reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunServicesOnce', False);
...

Процедура обработки события OnShow компонента TabSheet5:

procedure TForm1.TabSheet5Show(Sender: TObject);
begin
 ListView1.Items.Clear;
 load.Clear;
 run.Clear;
 //получаем доступ к файлу Win.ini
 AppIni := TIniFile.Create('Win.INI');
 //читаем пути к файлам из строки Load
 path := appini.ReadString('windows', 'Load', '');
 //удаляем все ведущие пробелы
 while (path[1]= ' ')  do
 delete(path, 1, 1);
 //записываем пути к файлам в список Load
 if (path <> '')  then
 ExtractFileNames('Load', path, Load);
 {теперь всё это повторяем со строкой “Run” и записываем их в список Run}
 path := appini.ReadString('windows','Run', 'error');
 while (pos(' ', path) = 1)  do
 delete(path, 1, 1);
 if (path <> '')  then
 ExtractFileNames('Run',path,Run);
 AppIni.Free;
 {отображаем пути ко всем файлам из списков Run и Load в ListView1}
 for i:=0  to Load.Count-1  do
 with ListView1  do
 begin 
   ListItem := Items.Add;
   ListItem.Caption :='Load';
   ListItem.SubItems.Add(Load.Strings[i]);
 end;
 for i:=0  to Run.Count-1  do
   with ListView1  do
   begin
     ListItem := Items.Add;
     ListItem.Caption :='Run';
     ListItem.SubItems.Add(Run.Strings[i]);
   end;
end;

Обработка события OnClick компонента RadioButton1:
procedure TForm1.RadioButton1Click(Sender: TObject);
begin
 {если текущий ключ не HKEY_LOCAL_MACHINE, то делаем его активным и, если нужно, обновляем информацию в ListBox1}
 if Key<>windows.HKEY_LOCAL_MACHINE  then
 begin
   key := Windows.HKEY_LOCAL_MACHINE;
   if PageControl1.ActivePageIndex<2 then
     PageControl1.ActivePage.OnShow(self);
 end;
end;

Обработка события OnClick компонента RadioButton1:
procedure TForm1.RadioButton2Click(Sender: TObject);
begin
 {если текущий ключ не HKEY_CURRENT_USER, то делаем его активным и, если нужно, обновляем информацию в ListBox1}
 if Key<>windows.HKEY_CURRENT_USER  then
 begin
   key := Windows.HKEY_CURRENT_USER;
   if PageControl1.ActivePageIndex<2 then
     PageControl1.ActivePage.OnShow(self);
 
end;
end;

После этого создайте новую форму и поместите на неё кнопку Tbutton, и два компонента TradioButton (рис. 2).

Запишите обработку события нажатия на кнопку:
procedure TForm2.Button1Click(Sender: TObject);
var
 FName: String;
begin
 {преобразуем имя выбранного файла в краткий формат}
 FName := sysutils.ExtractShortPathName(form1.opendialog1.filename);
 {записываем в выбранную константу имя файла после пробела, также отображаем добавленный файл в окне нашей программы}
 if form2.RadioButton1.Checked  then
   path := 'Load'
 else   path:='Run';
 AppIni := TIniFile.Create('Win.INI');
 AppIni.writeString('windows', path, appini.readstring('windows', path, '') + ' ' + FName);
 AppIni.Free;
 with form1.ListView1  do
 begin
   ListItem := Items.Add;
   ListItem.Caption := path;
   ListItem.SubItems.Add(FName);
 end;
 form2.hide;
 form1.show;
end;

Теперь запишите обработку нажатия кнопки New, при помощи которой можно добавить новый файл в автозагрузку:
procedure TForm1.ToolButton1Click(Sender: TObject);
begin
 {если выбран файл, который нужно добавить, то продолжаем}
 if OpenDialog1.Execute  then
 {если активна страница с ключами реестра то добавляем файл в реестр, иначе – в Win.ini}
 if PageControl1.ActivePageIndex<4 then
 begin
   reg := Tregistry.Create;
   if PageControl1.ActivePageIndex<2 then
     reg.RootKey := key
   else
     reg.RootKey:=windows.HKEY_LOCAL_MACHINE;
   case PageControl1.ActivePageIndex  of
     0: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Run', False);
     1: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunOnce', False);
     2: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunServices', False);
     3: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunServicesOnce', False);
   end;
   //просим ввести имя константы для нового файла
   path := inputbox('Введите имя константы', '', Extractfilename OpenDialog1.filename));
   {если имя не введено, то вместо него записываем имя добавляемого файла}
   if path=''  then
   path := Extractfilename(OpenDialog1.filename);
   pathfile := ExtractShortPathName(OpenDialog1.filename);
   reg.WriteString(path, pathfile);
   reg.CloseKey;
   reg.Free;
   with ListView1  do
   begin
     ListItem := Items.Add;
     ListItem.Caption :=path;
     ListItem.SubItems.Add(pathfile);
   end;
 end  else
 {если нужно добавить файл в Win.ini, то вызываем форму 2}
 form2.show;
end;

 

Нажатие кнопки "Изменить":
procedure TForm1.ToolButton2Click(Sender: TObject);
var
 Temp: String;
 Results: String;
begin
 {если выбран новый файл для константы, то продолжаем}
 if ListView1.ItemFocused.Selected  then
 if opendialog1.Execute  then
 begin
 {получаем индекс активной константы}
 ActIndex := ListView1.ItemFocused.Index;
 {преобразовываем имя выбранного файла в короткий формат}
 results := ExtractShortPathName(OpenDialog1.filename);
 {теперь записываем в константу новый файл}
 if PageControl1.ActivePageIndex<4  then
 begin
   reg := TRegistry.Create;
   if PageControl1.ActivePageIndex<2  then
     reg.RootKey := key
   else
     reg.RootKey:=windows.HKEY_LOCAL_MACHINE;
   case PageControl1.ActivePageIndex  of
     0: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Run', False);
     1: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunOnce', False);
     2: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunServices', False);
     3: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunServicesOnce', False);
   end;
   reg.WriteString(listview1.Items.Item[ActIndex].Caption,results);
   reg.CloseKey;
   reg.Free; 
 end
 else
 begin
   AppIni:=TIniFile.Create('Win.INI');
   path := appini.readstring('windows',listview1.Items.Item[ActIndex].Caption,'error');
   temp := ListView1.Items.Item[actindex].SubItems.Strings[0];
   i := pos(temp,path);
   if i<>0  then
   begin
     delete(path, i, length(temp));
     path := path + ' ' + results;
     appini.writeString('windows',listview1.Items.Item[ActIndex].Caption, path);
     AppIni.Free;
   end;
 end;
 ListView1.Items.Item[actindex].SubItems.Strings[0] := Results;
 end;
end;

Нажатие кнопки "Удалить":
procedure TForm1.ToolButton3Click(Sender: TObject);
var
 temp: String;
begin
 {если пользователь уверен в своём решении, то удаляем выбранный файл из автозагрузки}
 if ListView1.ItemFocused.Selected  then
 if messagedlg('Вы уверены?', mtConfirmation, [mbYes,mbNo], 0) = mryes  then
 begin
 ActIndex := ListView1.ItemFocused.Index;
 if PageControl1.ActivePageIndex<4  then
 begin
   reg:=Tregistry.Create;
   if PageControl1.ActivePageIndex < 2  then reg.RootKey:=key
   else
     reg.RootKey:=windows.HKEY_LOCAL_MACHINE;
   case PageControl1.ActivePageIndex  of
     0: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\Run', False);
     1: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunOnce', False);
     2: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunServices', False);
     3: reg.OpenKey('Software\Microsoft\Windows\CurrentVersion\RunServicesOnce', False);
   end;
   reg.DeleteValue(listview1.Items.Item[ActIndex].Caption);
   reg.CloseKey;
   reg.Free; 
 end  else
 begin
   AppIni := TIniFile.Create('Win.INI');
   path := AppIni.readstring('windows', listview1.Items.Item[ActIndex].Caption, 'error');
   temp := ListView1.Items.Item[actindex].SubItems.Strings[0];
   i := pos(temp,path);
   if (i<>0)  then 
   begin
     delete(path,i,length(temp)); 
     appini.writeString('windows',listview1.Items.Item[ActIndex].Caption, path);
     AppIni.Free;
   end;
 end;
 ListView1.Items.Item[actindex].Delete;
 end;
end;

Нажатие на кнопку "Автозагрузка":
procedure TForm1.ToolButton4Click(Sender: TObject);
var
 Auto: String;
begin
 reg:=TRegistry.Create(windows.key_Read);
 reg.RootKey:=HKEY_USERS;
 reg.OpenKey('.DEFAULT\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders', False);
 {читаем из реестра путь к папке "Автозагрузка" и открываем её}
 Auto:='Explorer '+reg.ReadString('Startup');
 reg.Free;
 winexec(pchar(Auto),SW_ShowNormal);
end;

Теперь добавим в программу пару штрихов.
Выделите компонент  ListView1 и для события  OnDblClick (при двойном щелчке мышью) выберите процедуру  ToolButton2Click, а для события  OnKeyDown (при нажатии клавиши) запишите следующее:
procedure TForm1.ListView1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
 if key=VK_DELETE  then form1.ToolButton3.OnClick(self);
end;

 В итоге, при нажатии кнопки Delete, выбранный файл будет удалён, а при двойном щелчке мыши будет предложено заменить этот файл другим.
 Вот и всё. Предложения по поводу тем следующих статей этого цикла присылайте мне на e-mail.

Иван Ширко
ishyrko@gmail.com

при использовании материалов данной рассылки ссылка на Статьи о программировании и не только обязательна


В избранное