Шрифт:
Интервал:
Закладка:
begin
temp := item;
while temp.Parent <> nil do
begin
path := temp.Text + '\' + path;
temp := temp.Parent;
end;
GetKeyPath := path;
end;
Аналогичным образом, даже проще, определяется дескриптор корневого раздела определенной ветви реестра: для этого нужно просто добраться до корня ветви дерева и прочитать значение поля Data корневого элемента (листинг 7.27).
...Листинг 7.27.
Определение дескриптора корневого раздела ветви
function GetRootKey(item: TTreeNode): HKEY;
var
temp: TTreeNode;
begin
temp := item;
while temp.Parent <> nil do
temp := temp.Parent;
GetRootKey := HKEY(temp.Data);
end;
При выделении элемента дерева происходит отображение параметров соответствующего раздела в списке в правой части формы. Как заполнять список, представлено в листинге 7.28.
...Листинг 7.28.
Составление списка параметров раздела реестра
procedure TForm1.keysChange(Sender: TObject; Node: TTreeNode);
var
reg: TRegistry;
valueItem: TListItem;
item: TTreeNode;
valueNames: TStrings;
i: Integer;
begin
item := keys.Selected;
if item <> nil then
begin
//Зачитаем содержимое выбранного раздела в ListView (values)
values.Clear;
reg := TRegistry.Create();
reg.RootKey := GetRootKey(item);
if reg.OpenKeyReadOnly(GetKeyPath(item)) then
begin
valueNames := TStringList.Create();
//Получение списка названий параметров
reg.GetValueNames(valueNames);
//Добавление каждого параметра в список
for i := 0 to valueNames.Count – 1 do
begin
valueItem := values.Items.Add();
if valueNames[i] = '' then
valueItem.Caption := '<По умолчанию>'
else
valueItem.Caption := valueNames[i];
//Получение типа и значения параметра
case reg.GetDataType(valueNames[i]) of
rdUnknown:
valueItem.SubItems.Add('Неизвестно');
rdString, rdExpandString:
begin
valueItem.SubItems.Add('Строка');
valueItem.SubItems.Add(reg.ReadString(valueNames[i]));
end;
rdInteger:
begin
valueItem.SubItems.Add('Число');
valueItem.SubItems.Add(IntToStr(
reg.ReadInteger(valueNames[i])));
end;
rdBinary:
valueItem.SubItems.Add('Двоичные данные');
end;
end;
valueNames.Free();
reg.CloseKey();
end;
reg.Free();
end;
end;
Процедура, приведенная в листинге 7.28, не считывает значения двоичных параметров. Так сделано для упрощения этого и так громоздкого фрагмента кода. В считывании значений двоичных параметров на самом деле нет ничего сложного: нужно лишь заранее определить размер данных (метод GetDataSize) и создать буфер соответствующего размера.
Глава 8 Обмен данными между приложениями
• СообщениеWM_COPYDATA
• Использованиебуфераобмена
• Проецируемыевпамятьфайлы
Организация обмена данными между приложениями, а именно между процессами этих приложений, является достаточно трудоемкой задачей. Архитектура Win32 подразумевает максимальную изоляцию выполняющихся приложений друг от друга. Каждое приложение исполняется в своем виртуальном адресном пространстве, которое изолировано и не имеет доступа к памяти других процессов приложений. Но довольно часто возникает необходимость передачи данных из одного выполняющегося процесса в другой. Это вызвано тем, что функциональные приложения и пакеты программ исполняются не в одном процессе, поэтому для нормальной работы используются основные возможности межпроцессного взаимодействия. Наиболее простым, понятным, но не всегда удобным является передача данных с использованием сообщения WM_COPYDATA. Также для передачи данных между приложениями широко используются проецируемые в память файлы (Mapping Files). Существуют и такие высокоуровневые средства, как буфер обмена или уже рассмотренная технология СОМ. Перечисленные способы будут подробно рассматриваться в этой главе. За рамки этой книги выходит рассмотрение способа передачи данных через каналы (трубы, или Pipe), который считается устаревшим и по этой причине не вызывает интереса.
8.1. Сообщение WM_COPYDATA
Сообщение WMCOPYDATA позволяет приложениям копировать данные между их адресными пространствами. Для передачи сообщения должна использоваться функция синхронной отправки сообщения SendMessage, а не PostMessage, которая асинхронным образом передает сообщение. Данные, предназначенные для передачи, не должны содержать указателей или других ссылок на объекты, недоступные для программы, принимающей эти данные. Рассмотрим параметры, передаваемые с сообщением WM_COPYDATA:
...//дескриптор передающего окна
wParam = (WPARAM) (HWND) hwnd;
//указатель на структуру с данными
lParam = (LPARAM) (PCOPYDATASTRUCT) pcds;
На использование сообщения налагаются следующие ограничения:
• данные, которые будут приняты, должны быть только для чтения, так как изменение структуры с данными может привести к непредсказуемым последствиям;
• если приложению, получающему данные, требуется использовать их после возврата из обработчика WMCOPYDATA, оно должно скопировать их в локальный буфер.
Итак, приступим к созданию приложения, демонстрирующего работу WM_COPYDATA Для создания хорошего примера потребуется создать два приложения. Первое будет отправлять данные (например, строку текста), другое приложение будет их получать. На главной форме первого приложения помещаем элемент управления TextBox, в который будет записываться передаваемая строка, и кнопку, нажатие которой инициирует передачу данных. Для второго приложения достаточно элемента для отображения текстовой информации типа Label. Перейдем к рассмотрению исходных текстов созданных приложений.
Мы будет посылать сообщение окну, и сообщений может быть различное количество, поэтому для уникальной идентификации операции введем специальную константу:
...const
CMD_SETLABELTEXT = 1; // Задаем ID команды
На форме находится кнопка отправки данных другому приложению, ее обработчик выглядит следующим образом (листинг 8.1).
...Листинг 8.1.
Отправка данных другому приложению
procedure TDataSender.bnSendClick(Sender: TObject);
var
CDS: TCopyDataStruct;
begin
//Устанавливаем тип команды
CDS.dwData := CMD_SETLABELTEXT;
//Устанавливаем длину передаваемых данных
CDS.cbData := Length(StringEdit.Text) + 1;
//Выделяем память буфера для передачи данных
GetMem(CDS.lpData, CDS.cbData);
try
//Копируем данные в буфер
StrPCopy(CDS.lpData, StringEdit.Text);
// Отсылаем сообщение в окно с заголовком StringReciever
SendMessage(FindWindow(NIL, 'StringReciever'),
WM_COPYDATA, Handle, Integer(@CDS));
Finally
//Высвобождаем буфер
FreeMem(CDS.lpData, CDS.cbData);
end;
end;
Подробного комментария данный листинг не требует. Обратите лишь внимание на вызов функции SendMessage, которая использует FindWindow для задания одного из своих параметров. Процедура FindWindow в случае успешного выполнения возвращает HWND окна, заголовок которого задается в параметре этой функции (строка StringReciever из предыдущего примера). Синхронная отправка сообщения WM_COPYDATA с набором данных, которые помещены в структуру CDS, осуществляется вызовом SendMessage.
Рассмотрим второе приложение, которое принимает строку и отображает ее в надписи ( Label). Для начала в блок объявления помещаем обработчик сообщения и объявляем само сообщение WM_COPYDATA:
...type
TStringReciever = class(TForm)
LabelStr: TLabel;
private
//Обработчик сообщения WM_COPYDATA
procedure WMCopyData(var MessageData: TWMCopyData);
message WM_COPYDATA;
Как и в случае первого приложения, нам необходима константа, которая будет идентифицировать тип операции:
...const
CMD_SETLABELTEXT = 1;
Далее рассмотрим тело функции обработчика сообщения WM_COPYDATA (листинг 8.2).
...Листинг 8.2.
Обработка сообщения WM_COPYDATA
procedure TStringReciever.WMCopyData(var MessageData: TWMCopyData);
begin
//Устанавливаем свойства метки, если заданная команда совпа-
дает
if MessageData.CopyDataStruct.dwData = CMD_SETLABELTEXT then
begin
//Устанавливаем текст из полученных данных
LabelStr.Caption := PChar(MessageData.CopyDataStruct.lpData);
MessageData.Result := 1;
end else
MessageData.Result := 0;
end;
Если окну второго приложения, которое носит название StringReciver (получатель строки), приходит сообщение WM_COPYDATA, то происходит вызов WMCopyData. В качестве параметра эта процедура получает структуру данныхМеБ sage Data типа TWMCopyData, содержащую идентификатор операции и данные (передаваемую строку). После проверки типа операции в случае совпадения его с константой CMD_SETLABELTEXT полученные данные преобразуются в строку. Преобразование происходит при помощи функции PChar. Полученная строка устанавливается в качестве заголовка для метки с именем LabelStr. Затем полю Result структуры MessageData присваивается значение 1 или 0, в зависимости от успеха операции.
Таким образом, для передачи данных (строки) записываем передаваемую строку в текстовое поле первой формы и нажимаем кнопку Отправить. Результат работы приложений можно увидеть на рис. 8.1.
Рис. 8.1. Вид приложений посылки и получения строки
Необходимо добавить, что передача данных посредством сообщения WM_COPYDATA является удобным и простым способом. Но WMCOPYDATA можно передавать только функцией SendMessage, и это является существенным недостатком такого метода. SendMessage «замораживает» работу приложения-отправителя, поэтому такой способ применяется для передачи небольших объемов данных, которые не требуют сложной обработки на стороне программы-приемника. К тому же на использование WMCOPYDATA налагаются некоторые существенные ограничения, о которых говорилось выше.
- Тонкости реестра Windows Vista. Трюки и эффекты - Роман Клименко - Программы
- Google Таблицы. Это просто. Функции и приемы - Евгений Намоконов - Программы
- 200 лучших программ для Linux - Сергей Яремчук - Программы
- Защита вашего компьютера - Сергей Яремчук - Программы
- Видеосамоучитель монтажа домашнего видео в Adobe Premiere Pro CS3 - Александр Днепров - Программы