КОМПЬЮТЕРНЫЕ КУРСЫ "ПОИСК"
[Главная страница] [Delphi] [Контакты]
Организация обмена данными между приложениями, а именно между процессами этих приложений, является достаточно трудоемкой задачей. Архитектура Win32 подразумевает максимальную изоляцию выполняющихся приложений друг от друга. Каждое приложение исполняется в своем виртуальном адресном пространстве, которое изолировано и не имеет доступа к памяти других процессов приложений. Но довольно часто возникает необходимость передачи данных из одного выполняющегося процесса в другой. Это вызвано тем, что функциональные приложения и пакеты программ исполняются не в одном процессе, поэтому для нормальной работы используются основные возможности межпроцессного взаимодействия. Наиболее простым, понятным, но не всегда удобным является передача данных с использованием сообщения WMCOPYDATA. Также для передачи данных между приложениями широко используются проецируемые в память файлы (Mapping Files). Существуют и такие высокоуровневые средства, как буфер обмена или технология СОМ.
Сообщение WM_COPYDATA позволяет приложениям копировать данные между их адресными пространствами. Для передачи сообщения должна использоваться функция синхронной отправки сообщения SendMessage, а не PostMessage, которая асинхронным образом передает сообщение. Данные, предназначенные для передачи, не должны содержать указателей или других ссылок на объекты, недоступные для программы, принимающей эти данные.
Итак, приступим к созданию приложения, демонстрирующего работу WM_COPYDATA. Для создания хорошего примера потребуется создать два приложения. Первое будет отправлять данные (например, строку текста), другое приложение будет их получать. На главной форме первого приложения помещаем элемент управления TextBox, в который будет записываться передаваемая строка, и кнопку, нажатие которой инициирует передачу данных. Для второго приложения достаточно элемента для отображения текстовой информации типа Label. Перейдем к рассмотрению исходных текстов созданных приложений.
Рис. 1. Вид приложений посылки и получения строки
Мы будет посылать сообщение окну, и сообщений может быть различное количество, поэтому для уникальной идентификации операции введем специальную константу:
const CMD_SETLABELTEXT = 1; //Задаем ID команды
На форме находится кнопка отправки данных другому приложению, ее обработчик выглядит еледующим образом (листинг 1).
Листинг 1. Отправка данных другому приложению
procedure TForm1.btnSendClick(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, AnsiString(StringEdit.Text)); //Отсылаем сообщение в окно с заголовком StringReceiver SendMessage(FindWindow(nil, 'StringReceiver'), WM_COPYDATA, Handle, Integer(@CDS)); finally //Высвобождаем буфер FreeMem(CDS.lpData, CDS.cbData); end; end;
Подробного комментария данный листинг не требует. Обратите лишь внимание на вызов функции SendMessage, которая использует FindWindow для задания одного из своих параметров. Процедура FindWindow в случае успешного выполнения возвращает HWND окна, заголовок которого задается в параметре этой функции (строка StringReciever из предыдущего примера). Синхронная отправка сообщения VM_COPYDATA с набором данных, которые помещены в структуру CDS, осуществляется вызовом SendMessage.
Рассмотрим второе приложение, которое принимает строку и отображает ее в надписи (Label). Для начала в блок объявления помещаем обработчик сообщения и объявляем само сообщение WM_COPYDATA:
type TForm1 = class(TForm) LabelStr: TLabel; private //Обработчик сообщения WM_COPYDATA procedure WMCopyData(var MessageData: TWMCopyData); message WM_COPYDATA;
Как и в случае первого приложения, нам необходима константа, которая будет идентифицировать тип операции:
const CMD_SETLABELTEXT = 1;
Далее рассмотрим тело функции обработчика сообщения WM_COPYDATA (листинг 2).
Листинг 2. Обработка сообщения WM_COPYDATA
procedure TForm1.WMCopyData(var MessageData: TWMCopyData); begin //Устанавливаем свойства метки, если заданная команда совпадает if MessageData.CopyDataStruct.dwData = CMD_SETLABELTEXT then begin //Устанавливаем текст из полученных данных LabelStr.Caption := PAnsiChar((MessageData.CopyDataStruct.lpData)); MessageData.Result := 1; end else MessageData.Result := 0; end;
Если окну второго приложения, которое носит название StringReciver (получатель строки), приходит сообщение WM_COPYDATA, то происходит вызов WMCopyData. В качестве параметра эта процедура получает структуру данных МеssageData типа TWMCopyData, содержащую идентификатор операции и данные (передаваемую строку). После проверки типа операции в случае совпадения его с константой CMD_SETLABELTEXT полученные данные преобразуются в строку. Преобразование происходит при помощи функции PAnsiChar. Полученная строка устанавливается в качестве заголовка для меткие именем LabelStr. Затем полю Result структуры MessageData присваивается значение 1 или 0, в зависимости от успеха операции.
Таким образом, для передачи данных (строки) записываем передаваемую строку в текстовое поле первой формы и нажимаем кнопку Отправить. Результат работы приложений можно увидеть на рис. 1.
Необходимо добавить, что передача данных посредством сообщения WM_COPYDATA является удобным и простым способом. Но WM_COPYDATA можно передавать только функцией SendMessage, и это является существенным недостатком такого метода. SendMessage «замораживаете работу приложения-отправителя, поэтому такой способ применяется для передачи небольших объемов данных, которые не требуют сложной обработки на стороне программы-приемника. К тому же на использование WM_COPYDATA налагаются некоторые существенные ограничения, о которых говорилось выше.
Исходный код проекта здесь. Выполнен на Delphi XE.