Мы переехали

Новый адрес - http://delphiblog.ru

понедельник, 28 января 2008 г.

Сделай сам: IE и Delphi – вместе веселее!

    Сегодня мы займёмся самым популярным web-браузером в мире – Internet Explorer'ом. Кто-то обожает эту программу, кто-то терпеть её не может, но, как ни крути, пока что ни один конкурент IE не может приблизиться к нему по возможностям (не считая, конечно, браузеров, построенных на движке IE). Итак, что мы будем делать с IE? Да ничего страшного… Мы просто научимся управлять им так же, как и любым другим окном. Для закрепления полученных знаний сделаем программу для управления IE при помощи горячих клавиш. Для пущего эффекта добавим иконку программы на Системную панель (SysTray). Итак, поехали…
Первым делом разберёмся с двумя приёмами программирования, которые мы будем использовать и в последующих статьях данного цикла:
1) Как работать с "горячими" клавишами?
2) Как добавить свой значок на Системную Панель (SysTray, можно узнать по характерным для неё часикам)?
На первый вопрос я уже дал частичный ответ в статье Сделай сам: "Вскрывалка паролей", но нам нужно копнуть немного глубже, а второй вопрос мы ещё вообще не затрагивали.

Работа с "горячими" клавишами
Для работы с "горячими" клавишами вполне достаточно использования лишь двух функций:

1) Регистрирует "горячие" клавиши:
BOOL RegisterHotKey(
    HWND hWnd, // этому окну придёт уведомление о нажатии комбинации клавиш
    int id, // идентификатор "горячих" клавиш
    UINT fsModifiers, // должны ли быть нажаты клавиши Ctrl, Shift, Alt или Win
    UINT vk // код клавиши, на которую мы будем реагировать
);
2) Удаляет "горячие" клавиши
BOOL UnregisterHotKey(
    HWND hWnd, // окно, ассоциированное с "горячими" клавишами
    int id // идентификатор "горячих" клавиш
);

  Всё бы ничего, да вот при работе с "горячими" клавишами из DLL (динамически подключаемой библиотеки) могут возникнуть проблемы с идентификаторами. Чтобы этого избежать следует использовать функцию GlobalAddAtom, которая возвратит нам уникальный идентификатор (атом) требуемого формата. После завершения работы с "горячими" клавишами атом нужно удалить при помощи функции GlobalDeleteAtom. Работу с атомами мы рассмотрим в одной из следующих статей, где будем использовать DLL.
Помещение своей иконки в SysTray
Бывают такие программы, которые постоянно должны быть активны в системе. Они довольно часто помещают свой значок на Системную панель, чтобы не надоедать пользователю присутствием своего окна и в то же время оставить возможность "достучаться" до программы. Для управления иконкой на Системной панели используется функция
Shell_NotifyIcon(dwMessage: DWORD; lpData: PNotifyIconData): BOOL;
dwMessage – сообщение, которое мы посылаем Панели задач, может принимать следующие значения: NIM_ADD – добавить новую иконку, NIM_DELETE – удалить иконку, NIM_MODIFY – изменить иконку.
lpData – указатель на структуру NotifyIconData, которая состоит из следующих полей:
cbSize: DWORD;
Wnd: HWND;
uID: UINT;
uFlags: UINT;
uCallbackMessage: UINT;
hIcon: HICON;
szTip: array [0..63] of AnsiChar;
Пояснения:
cbSize – размер структуры;
Wnd – идентификатор окна, которое будет получать сообщения, ассоциированные с иконкой;
uID – идентификатор иконки, который мы сами ей назначаем;
uFlags – комбинация из трёх флагов, которая обозначает, какие поля структуры мы хотим заполнить: NIF_ICON (хотим заполнить поле hIcon), NIF_MESSAGE (поле uCallbackMessage), NIF_TIP (поле szTip).
uCallbackMessage – определяемый нами идентификатор сообщения, ассоциированного с иконкой;
hIcon – идентификатор иконки;
szTip – текст подсказки к иконке, которая появляется при наведении на неё курсора мышки.
Пример использования функции Shell_NotifyIcon вы найдёте в коде нашей сегодняшней программы.

Настала пора приступить к созданию программы. Она будет выполнять две полезные функции:
1) Закрытие всех окон IE;
2) Переход "Вперёд\Назад" в коллекции некоторых объектов. Всё дело в том, что часто при просмотре какого-либо форума или галереи картинок, ссылки имеют вид "http://anysite/forum.php?page=2". Т.е мы находимся на второй странице форума. Если мы заменим цифру на '1', то попадём на предыдущую страницу, на '3' – на следующую. Примерно по такому принципу мы организуем Переход "Вперёд\Назад".

Закрытие всех окон IE
Предлагаю два способа реализации функции закрытия всех окон IE.
Способ I
Последовательно ищем окна Internet Explorer'a и закрываем их:
procedure CloseAllIE_1;
var
  ie: HWND;
begin
  //ищем окно IE
  ie := FindWindow('IEFrame', nil);
  //пока найдено окно IE…
  while (ie<>0) do
  begin
    //…закрываем его
    postmessage(ie, WM_CLOSE, 0, 0);
    //ищем следующее
    ie := FindWindow('IEFrame', nil);
  end;
end;

Способ II
Перебираем все родительские окна в системе и, если увидели окно IE, то закрываем его. Таким образом, мы совершаем только один проход по окнам, а значит, работает этот способ намного быстрее предыдущего.
procedure CloseAllIE_2;
//эта функция будет применяться к каждому окну
functionCloseIE (Wnd: HWND): boolean; stdcall;
var
  winclass: array [0..255] of char;
begin
  //получаем класс окна
  GetClassName (Wnd, WinClass, sizeof(WinClass));
  //если у нас окно IE, то закрываем его
  if (WinClass='IEFrame') then
  PostMessage (Wnd, WM_CLOSE, 0, 0);
  //принимаем следующее окно
  CloseIE := true;
end;
begin
//перебираем все родительские окна, указывая,
//какой функцией будем их обрабатывать
  EnumWindows(@CloseIE, 0);
end;

Переход "Вперёд\Назад"
Разделим нашу задачу на три составляющие:
1) Получить адрес (URL) текущей странички IE;
2) Увеличить (уменьшить) последнее число адреса на единицу;
3) Записать изменённый адрес в окно IE и заставить браузер перейти по нему.

Пункт 1: получить адрес текущей странички
Окно IE, как и любое порядочное окно, содержит множество дочерних окон (всякие там кнопочки, поля ввода, надписи и т.д.). В одном из таких окон содержится URL странички. После недолгого изучения иерархии окон в IE при помощи специальной программы, добраться до адреса совсем несложно. Следующая функция возвращает идентификатор поля ввода (класс 'Edit'), в котором содержится URL:

function FindEdit(var h:hwnd):boolean;
var
  wclass: array[0..255] of char;
begin
  //получаем идентификатор и класс "верхнего" окна
  h := getforegroundwindow;
  getclassname(h, wclass, sizeof(wclass));
  //если это окно IE, то "распутываем" иерархию дочерних окон
  if (wclass='IEFrame') then
  begin
    h := findwindowex(h, 0, 'WorkerA', nil);
    h := findwindowex(h, 0, 'ReBarWindow32', nil);
    h := findwindowex(h, 0, 'ComboBoxEx32', nil);
    h := findwindowex(h, 0, 'ComboBox', nil);
    h := findwindowex(h, 0, 'Edit', nil);
    result := true;
  end else
    result := false;
end;

После того, как мы добрались до поля ввода, в котором хранится адрес странички, извлечём его при помощи следующей функции:
function GetText(WindowHandle: hwnd): String;
var
  txtLength: Integer;
  buffer: String;
begin
  //Узнаём длину текста
  TxtLength := SendMessage(WindowHandle, WM_GETTEXTLENGTH, 0, 0);
  if (txtlength>0) then
  begin
    txtlength := txtlength + 1;
    setlength (buffer, txtlength);
    //записываем текст окна в buffer
    sendmessage(WindowHandle, wm_gettext, txtlength, longint(@buffer[1]));
    result := buffer;
  end else result := '';
end;

Таким образом, чтобы узнать текущий адрес в IE, достаточно применить эти две функции:

FindEdit(h);
Adress := GetText(h);

Пункт 2: Увеличить (уменьшить) последнее число адреса на единицу
Здесь нам потребуется только умение оперировать со строками и знание основ арифметики.
//увеличение последнего числа в строке s
function IncURL(s:string): String;
const
  num = ['0'..'9'];
var
  i,  j, cnt: word;
  plus, ch: byte;
  code: integer;
  s1: string;
begin
  i := length(s);
  plus := 0;
  //ищем первую цифру с конца
  while (i>0) and not(s[i] in num) do
    dec(i);
  //если нашли…
  if (i<>0) then
  begin
    //считаем количество девяток, которыми кончается число
    cnt := 0;
    while (i>0) and (s[i]='9') do
    begin
      dec(i);
      inc(cnt);
    end;
    if (i=0) or not( s[i] in num) then
    begin
      ch := 0;
    {если число сплошь состоит из девяток, то мы должны первой цифрой сделать '1' и заменить все девятки на нули}
      if not(s[i] in num) then
        plus := 1;
    end else
      val(s[i], ch, code);
    inc(ch);
    str(ch, s1);
    if (cnt>0) then
      //заменяем последние девятки на нули
      for j := 1 to cnt do
        s1 := s1 + '0';
    //составляем итоговую строку
    s := copy(s, 1, i-1+plus)+s1+copy(s, i+cnt+1, length(s)-i-cnt);
  end;
  result := s;
end;

//уменьшение последнего числа в строке s
function DecURL(s:string):string;
const
  num = ['0'..'9'];
var
  i, j, cnt: word;
  minus, ch: byte;
  code: integer;
  s1: string;
begin
  i := length(s);
  minus := 0;
  //ищем последнюю цифру в строке
  while (i>0) and not (s[i] in num) do
    dec(i);
  if (i<>0) then
  begin
    cnt := 0;
    //считаем количество нулей
    while (i>0) and(s[i]='0') do
    begin
      dec(i);
      inc(cnt);
    end;
    if (i>0) and (s[i] in num) then
    begin
      val(s[i],ch,code);
      dec(ch);
      if (ch=0) and (i>0) and not(s[i-1] in num) then
        s1 := ''
      else
        str(ch, s1);
      if (cnt>0) then
        //заменяем последние нули на девятки
        for j := 1 to cnt do
          s1 := s1 + '9';
      //составляем итоговый URL
      s := copy(s, 1, i-1-minus) + s1 + copy(s, i+cnt+1, length(s)-i-cnt);
    end;
  end;
  result := s;
end;

Пункт 3: записать изменённый адрес в окно IE и заставить браузер перейти по нему.
Для выполнения третьей части задачи нужно просто послать полю ввода два сообщения:

//"вводим" изменённый адрес
SendMessage(h, WM_SETTEXT, 0, longint(Pchar(s)));
//"нажимаем" клавишу "Ввод" (Enter)
SendMessage(h, WM_KEYDOWN, VK_RETURN, 0);


Теперь соберём эти три пункта в нужные нам процедуры:
//переход "Вперёд"
procedure NextPage;
var
  s: String;
  h: HWnd;
begin
  if FindEdit(h) then
  begin
    //получаем URL
    s := gettext(h);
    delete(s, length(s), 1);
    //увеличиваем последнее число на единицу
    s := IncURL(s);
    //записываем новый URL
    SendMessage(h, WM_SETTEXT, 0, longint(Pchar(s)));
    //нажимаем клавишу "Ввод"
    SendMessage(h, WM_KEYDOWN, VK_RETURN, 0);
  end;
end;

//переход "Вперёд"
procedure PrevPage;
var
  s: String;
  h: HWnd;
begin
  if FindEdit(h) then
  begin
    s := string(gettext(h));
    delete(s, length(s), 1);
    s := DecURL(s);
    SendMessage(h, WM_SETTEXT, 0, longint(Pchar(s)));
    SendMessage(h, WM_KEYDOWN, VK_RETURN, 0);
  end;
end;

Все основные процедуры нашей программы готовы, теперь настало время сделать для них оболочку. Создайте новый проект и поместите на форму один-единственный компонент – PopupMenu1:TPopupMenu1. В нём должен быть один пункт – "Выход". Процедура при выборе этого пункта:
procedure TForm1.ExitClick(Sender: TObject);
begin
  //завершаем работу программы
  halt;
end;

Добавьте к списку подключаемых модулей (раздел Uses) модуль ShellApi. Объявите константу

const
  WM_ICONTRAY = wm_user + 1;

Этим мы определили сообщение, которое будем получать от иконки в SysTray.
В раздел Private добавьте три строчки:

//информация о нашей иконке
TrayIconData: TNotifyIconData;
//эта процедура будет обрабатывать поступающие от иконки сообщения
procedure TrayMessage (var Msg: TMessage); message WM_ICONTRAY;
//процедура обработки нажатия "горячих" клавиш
procedure hotykey(var msg:TWMHotkey); message WM_HOTKEY;

Запишите процедуру для события OnCreate формы:
procedure TForm1.FormCreate(Sender: TObject);
begin
  //заполняем информацию об иконке
  with TrayIconData do
  begin
    cbSize := SizeOf(TrayIconData);
    Wnd := Handle;
    uID := 0;
    uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
    uCallbackMessage := WM_ICONTRAY;
    hIcon := application.icon.handle;
    szTip := 'My TrayIcon!';
  end;
  //добавляем иконку в SysTray
  Shell_NotifyIcon(NIM_ADD, @TrayIconData);
  //регистрируем "горячие" клавиши Alt+P
  RegisterHotKey(handle, 1,.MOD_Alt, 80);
  //регистрируем "горячие" клавиши Alt+Q
  RegisterHotKey(handle, 2,.MOD_Alt, 81);
  //регистрируем "горячие" клавиши Alt+R
  RegisterHotKey(handle, 3,.MOD_Alt, 82);
end;

Теперь процедура при уничтожении формы:
procedure TForm1.FormDestroy(Sender: TObject);
begin
  //удаляем иконку
  ShellApi.Shell_NotifyIcon(NIM_DELETE, @TrayIconData);
  //удаляем "горячие" клавиши
  UnRegisterHotKey(handle, 1);
  UnRegisterHotKey(handle, 2);
  UnRegisterHotKey(handle, 3);
end;

//обработка сообщений от иконки
procedure TForm1.TrayMessage(var Msg: TMessage);
var
  p: TPoint;
begin
  case Msg.lParam of
  //если нажата правая кнопка мыши,
    WM_RBUTTONDown, WM_RBUTTONDBLCLK:
    begin
      SetForegroundWindow(handle);
      GetCursorPos(p);
      //то показываем наше меню в текущей позиции курсора
      popupmenu1.Popup(p.x,p.y);
    end;
  end;
end;

//нажатие на "горячие" клавиши
procedure TForm1.hotykey(var msg:TWMHotkey);
var
  n: Integer;
begin
  n := msg.HotKey;
  //если нажали Alt+P, то закрываем все окна IE
  if (n=1) then CloseAllIE_2;
  else
    //если нажали Alt+Q, то переход "Вперёд"
    if (n=2) then NextPage
    else
      //если нажали Alt+R, то переход "Назад"
      if (n=3) then PrevPage;
end;

На этом создание программы, которая расширяет функциональность браузера Internet Explorer, завершено. Мы научились:
1) работать с "горячими" клавишами;
2) помещать иконку на Системную панель;
3) работать с сообщениями и окнами.
На сегодня всё.

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


Читать дальше >>

среда, 9 января 2008 г.

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

Продолжаем серию "Сделай сам", посвящённую практическому применению 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<2end;
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<2then
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


Читать дальше >>