Менеджер программ (Program Manager) знаком многим из тех, кто
работал в Windows ещё в незапамятные времена. Сейчас, когда в Windows появился
Проводник, менеджер программ ушёл на второй план и исользуется сейчас, в
основном, с одной-единственной целью - создавать группы программ во время
инсталляции. :)
Менеджер программ может быть сервером DDE-соединения. Если вы
ничего не знаете о DDE - не беспокойтесь: всё, что нам потребуется, вы
прочитаете в этой статье ниже.
Для работы с DDE-серверами мы будем
использовать компонент DdeClientConv, который находится на закладке
System панели компонентов.
Что такое DDE? DDE (Dynamic Data Excahnge) - это устаревшая
технология, которая использовалась давным давно для передачи данных между
программами (сейчас для этих целей используется OLE). Передача данных в DDE
производится через соединения. Программа-клиент устанавливает
соединение с программой-сервером, передаёт/принимает данные и разрывает
соединение.
Применительно к нашей задаче, менеджер программ будет выступать
в роли DDE-сервера, а программа инсталляции - в роли DDE-клиента. DDE
предоставляет двухуровневую схему связи с сервером: для её установления клиенту
необходимо указать имя сервера и имя сервиса (topic), который
клиент хочет у сервера запросить. Для больших и толстых серверов, имя сервиса
является насущной необходимость, для маленьких и простых - непонятным
параметром, необходимость которого очень трудно объяснить.
Менеджер программ - простая и маленькая
программа, поэтому имя сервиса у неё совпадает с именем сервера. Поместим на
форму компонент DdeClientConv и настроим его в инспекторе объектов.
Свойства DDEService и DDETopic должны быть
установлены в PROGMAN. Свойство ConnectionMode переключите в
ddeManual -устанавливать и разрывать соединение мы будем вручную. Почему?
Одним из правил, которых я придерживаюсь, является правило не кушать ресурсы
без необходимости. Я создаю объекты в программах сразу перед тем, как они
мне понадобятся; выделяю память непосредственно перед операторами, её
использующими; и открываю файл, только тогда, когда уже готов его читать.
Зачастую. :) Именно поэтому открывать соединение с менеджером программ я
предлагаю только тогда, когда вся остальная работа уже выполнена.
Хорошо. Будем считать, это было лирическое отступление и
вернёмся к нашим баранам. Может оказаться, что у нас под рукой нет подходящей
формы для того, чтобы поместить на неё DdeClientConv. В этом случае можно
создавать компонент DdeClientConv вручную: var DdeClientConv:
TDdeClientConv; begin DdeClientConv :=
TDdeClientConv.Create(nil); with DdeClientConv
do begin ConnectMode := ddeManual; DDEService :=
'PROGMAN'; DDETopic := 'PROGMAN'; . .
. Free; end; end;
Перед тем, как что-то сделать с сервером, вы должны вызвать
метод OpenLink (установить соединение), а после работы - CloseLink
(соответственно, разорвать).
Помимо приёма и передачи данных, DDE-сервер может выполнять
команыды клиента. Всё очень просто: мы передаём серверу строку, говорим, что
это команда - и он её исполняет.
Методы ExecuteMacro или ExecuteMacroLines
компонента DdeClientConv передают серверу команду (и команды,
соответственно) для выполнения. Команды менеджера программ заключаются в
квадратные скобки, и выглядят приблизительно так:
[CreateGroup("SomeTools",0)] [ShowGroup("Стандартные")]
[AddItem("c:\windows\notepad.exe")]
Эти команды мы подробнее рассмотрим ниже, а перед этим
остановимся ещё на одном важном моменте работы с менеджером программ - получении
информации о текущем состоянии дел. Что нас может интересовать? Какие группы уже
созданы, какие элементы находятся в этих группах...
Обратите внимание, что этой информацией мы можем и пренебречь -
для того, чтобы создать группу, нам вовсе не требуется знать, какие группы уже
созданы.
Пример показывает, как можно прочитать список групп из
менеджера программ: var GroupList:
TStringList; begin GroupList := TStringList.Create; . .
. GroupList.Text := String(DdeClientConv.RequestData('Groups')); . .
. GroupList.Free; end; После выполнения этой строчки, в
GroupList появится список доступных групп.
- Примечание:
- Если вы работаете под NT, возможно, вас волнует вопрос, как прочитать список
групп из общедостуной части меню Программы. Для этого необходимо
воспользоваться чем-то, что не является менеджером программ. Как это сделать, я
расскажу чуть ниже.
Прочитав список групп, мы можем прочитать содержимое любой
группы из этого списка (например, первой): var GroupList:
TStringList; ItemList: TStringList; begin GroupList :=
TStringList.Create; ItemList := TStringList.Create; . .
. GroupList.Text :=
String(DdeClientConv.RequestData('Groups')); ItemList.Text :=
String(DdeClientConv.RequestData(PChar(GroupList[0]))); . .
. ItemList.Free; GroupList.Free; end; Менеджер программ
возвращает в первой строке название группы (в кавычках), имя файла группы (с
расширением .GRP) и количество элементов в группе. Всё это разделяется
запятыми. Далее идёт информация об элементах: командная строка (в кавычках),
каталог по умолчанию, иконка, позиция в группе (по горизонтали и вертикали),
номер иконки, клавиши быстрого доступа (в целочисленном виде) и флаг
"свернуть при запуске".
Вот содержимое группы Стандартные:
"Стандартные",C:\WINDOWS\ГЛАВНО~1\
ПРОГРА~1\СТАНДА~1,7,1 "Таблица
символов","C:\WINDOWS\CHARMAP.EXE",,
C:\WINDOWS\CHARMAP.EXE,416,32,0,0,0 "Текстовый редактор
WordPad","C:\PROGRA~1\ACCESS~1\WORDPAD.EXE",,
C:\PROGRA~1\ACCESS~1\WORDPAD.EXE,352,32,0,0,0 "Просмотр
рисунков","C:\WINDOWS\WANGIMG.EXE",,
C:\WINDOWS\WANGIMG.EXE,288,32,0,0,0 "Калькулятор","C:\WINDOWS\CALC.EXE",,
C:\WINDOWS\CALC.EXE,224,32,0,0,0 "Графический редактор
Paint","C:\PROGRA~1\ ACCESS~1\MSPAINT.EXE",,
C:\PROGRA~1\ACCESS~1\MSPAINT.EXE,160,32,0,0,0 "Интерактивная
регистрация","C:\WINDOWS\ SYSTEM\REGWIZ.EXE /i
software\microsoft\windows\currentversion",,
C:\WINDOWS\SYSTEM\REGWIZ.EXE,96,32,0,0,0 "Блокнот","C:\WINDOWS\NOTEPAD.EXE",,
C:\WINDOWS\NOTEPAD.EXE,32,32,0,0,0
По большому счёту, нам эта информация не потребуется. Но, может
быть, вы захотите заменить один из элементов группы во время инсталляции - в
этом случае, конечно, надо знать, что изменять.
Далее я опишу способ создать группу и элемент в группе.
var Commands: TStringList; begin . . . Commands :=
TStringList.Create; Commands.Add('[CreateGroup("Нестандартные",0)]'); Commands.Add('[ShowGroup("Нестандартные",1,0)]'); Commands.Add('[AddItem("c:\windows\notepad.exe","Блокнот")]'); DdeClientConv.ExecuteMacroLines(Commands,
False); Commands.Free; . . . end; В приведённом примере мы
создаём группу Нестандартные (в пику группе Стандартные). Далее,
мы показываем её (без этого добавление элемента не будет работать - ох, как я с
этим намучился в своё время!). Наконец, добавляем Блокнот в эту группу,
присваивая ему имя "Блокнот" (оригинально, не правда ли?). Важным
здесь является то, что, во-первых, команды менеджеру программ заключаются в
квадратные скобки, и, во-вторых, параметры команды, содержащие пробелы и прочие
нестандартные символы, заключаются в кавычки. Ну, и, если вы вызываете несколько
команд сразу, пользуйтесь методом ExecuteMacroLines вместо нескольких
вызовов ExecuteMacro.
Полный список команд плюс описание вы найдёте в файле
win32.hlp. Здесь я приведу только их список, чтобы вы знали, что искать:
CreateGroup, ShowGroup, DeleteGroup, Reload, AddItem, ReplaceItem, DeleteItem и
ExitProgman.
Я написал утилиту, которая позволит вам поиграться с менеджером
программ. Для того, чтобы создать, показать или удалить группу программ,
введите название группы в поле ввода Группа (или выберите её в списке) и
нажмите соответствующую кнопку.
Та же самая техника работает и для элементов группы - если вы
хотите добавить новый элемент, введите название программы и имя файла в
соответствующих полях ввода перед тем, как нажать кнопку Создать.
Может быть это не самая сложная программа из тех, которые я
написал, но она (а) доступна в исходниках и (б) позволяет
"почувствовать", как работает менеджер программ.
Теперь перейдём ко второму способу работать с группами
программ - через интерфейсы, предоставляемые Проводником.
|