Читать интересную книгу Delphi. Трюки и эффекты - Валерий Борисок

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 34 35 36 37 38 39 40 41 42 ... 59

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 налагаются некоторые существенные ограничения, о которых говорилось выше.

1 ... 34 35 36 37 38 39 40 41 42 ... 59
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Delphi. Трюки и эффекты - Валерий Борисок.

Оставить комментарий