logo search
Программирование в среде Delphy / Программирование в среде Delphi

25.1. Обмен сообщениями

Посылка сообщений – это естественный способ связи между программами в Windows. В Delphi все участники обмена должны быть наследниками класса TWinControl, т.е. окнами, у которых есть свои номера или дискрипторы. Следующий пример показывает, как найти запущенное приложение c главным окном Server:

Var Svrh:THandle;

Begin

Svrh:=FindWindow(nil, ’Server’);

If Svrh=0 then ShowMassage(’Сервер не найден’);

Передать сообщение окну можно с помощью функции

Function SendMessage(Hwnd:HWND; Msg:Cardinal; WParam, LParam:Integer):LongBool;

Здесь Hwnd – номер окна, Msg – код команды, WParam и LParam – параметры, которые передаются окну. Эта функция ожидает окончания обработки переданного сообщения и возвращает его результат. Другая функция PostMessage имеет такие же параметры, но она не ждет окончания обработки посланного сообщения, а лишь сообщает о том, смогла ли она поставить сообщение в очередь.

Для создания обработчика Windows сообщений нужно в классе объявить метод с директивой message и указать номер обрабатываемой команды. Как видно из списка параметров функции посылки сообщения, каждому окну может быть передано не более 8 байт информации. Для передачи большего количества информации можно использовать команду WM_COPYDATA.

Рассмотрим пример создания сервера с именем Server, который каждому клиенту посылает информацию о текущем времени на сервере. В примере используются следующие типы:

TMsg = packed record // Тип сообщения

hwnd: HWND; // Указатель на окно, которому посылается сообщение

message: UINT; // Код сообщения

wParam: WPARAM; // W параметр

lParam: LPARAM; // L параметр

time: DWORD; // Время посылки сообщения

pt: TPoint; // Координаты мыши в момент отправки сообщения

end;

TCopyDataStruct= record // Структура передаваемых данных

dwData: Integer; // Прямо передаваемые 4 байта

cbData: Integer; // Длина передаваемых данных

lpData: Pointer; // Указатель на начало передаваемых данных

end;

Текст примера:

// Текст файла проекта сервера

Program server;

Uses Forms, windows,

userver in 'userver.pas' {Form1}, // Включение в проект модуля Userver

Udata1 in 'Udata1.pas' {DataModule1: TDataModule};

// Подключение модуля данных

Type TNewObject=class // Объявляем новый класс

// Определяем классовый обработчик сообщений для сервера

class procedure AppMsgHandler(var Msg:TMsg; var Handled:Boolean);

end;

{$R *.res}

class procedure TNewObject.AppMsgHandler;

var i:Integer;

ClientWnd:Thandle;

Begin

ClientWnd:=THandle(Msg.WParam); // Получаем номер окна клиента

if Msg.message=WM_ST then Begin

for i:=0 to MaxClient-1 do Begin

if TimeClientList[i]=0 then Begin

TimeClientList[i]:=ClientWnd;

// Запоминаем номер окна в списке клиентов

Handled:=True;

exit;

end;

end;

end;

if Msg.Message=WM_UT then Begin

for i:=0 to MaxClient-1 do Begin

if TimeClientList[i]=ClientWnd then Begin

// Удаляем клиента из списка

TimeClientList[i]:=0;

Handled:=True;

exit;

end;

end;

end;

end;

var i:Integer;

begin

// Очищаем список клиентов

for i:=0 to MaxClient-1 do TimeClientList[i]:=0;

// Регистрируем в системе новые коды сообщений для окон

// Код соединения с сервером

WM_ST:=RegisterWindowMessage('WM_ST');

// Код отсоединения

WM_UT:=RegisterWindowMessage('WM_UT');

Application.Initialize;

// Определяем обработчик Windows сообщения для сервера

Application.OnMessage:=TNewObject.AppMsgHandler;

// Создаем формы

Application.CreateForm(TForm1, Form1);

Application.CreateForm(TDataModule1, DataModule1);

// Запускаем обработчик сообщений сервера

Application.Run;

end.

// Текст модуля данных

Unit Udata1;

interface

uses SysUtils, Classes;

type

TDataModule1 = class(TDataModule)

end;

// Определяем глобальные переменные и константы сервера

var

DataModule1: TDataModule1;

WM_ST,WM_UT:THAndle;

const maxclient=64; // Максимальное число клиентов

var TimeClientList:Array[0..maxclient] of integer;

implementation

{$R *.dfm}

end.

// Текст модуля формы сервера

Unit userver;

interface

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls,Udata1;

Type

TForm1 = class(TForm)

Timer1: TTimer;

procedure Timer1Timer(Sender: TObject);

end;

var

Form1: TForm1;

implementation

{$R *.dfm}

// Метод обработки тиков таймера сервера

Procedure TForm1.Timer1Timer(Sender: TObject);

var dt:TDateTime;

i:Integer;

cds:TCopyDataStruct; // Структура передаваемых данных

begin

dt:=Now; // Определяем текущее время

cds.cbData:=sizeof(dt); // Запоминаем длину передаваемых данных

cds.lpData:=@dt; // Запоминаем указатель на передаваемые данные

for i:=0 to MaxClient-1 do Begin

if TimeClientList[i]<>0 then

// Посылаем данные всем зарегистрированным клиентам

SendMessage(TimeClientList[i],WM_COPYDATA,Self.Handle,

LongInt(@cds));

end;

end;

end.

// Текст модуля формы клиента

Unit Uclient1;

interface

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Buttons;

Type

TForm1 = class(TForm)

SpeedButton1: TSpeedButton;

Label1: TLabel;

Label2: TLabel;

procedure SpeedButton1Click(Sender: TObject);

procedure FormCreate(Sender: TObject);

private

// Метод обработки сообщения WM_COPYDATA для клиента

procedure WMCopyData(var msg:TMessage);message WM_COPYDATA;

end;

var

Form1: TForm1;

WM_ST,WM_UT:THandle;

implementation

{$R *.dfm}

// Текст метода обработки сообщения WM_COPYDATA

Procedure TForm1.WMCopyData(var msg:TMessage);

var dt:TDateTime;

Begin

if PCopyDataStruct(msg.LParam)^.lpData <> nil then Begin

dt:=TDateTime(PCopyDataStruct(msg.LParam)^.lpData^);

// Выводим на форму клиента врямя, переданное сервером

Label2.Caption:=TimetoStr(dt);

end;

end;

Procedure TForm1.SpeedButton1Click(Sender: TObject);

var ServerHandle:THandle;

begin

// Получаем номер окна сервера

ServerHandle:=FindWindow(nil,'server');

if ServerHandle<>0 then Begin

if SpeedButton1.Down then Begin

// Посылаем серверу сообщение для установления с ним соединения

PostMessage(ServerHandle,WM_ST,Integer(Self.Handle),0);

SpeedButton1.Caption:='Соединение есть!';

end

else Begin

// Посылаем серверу сообщение о прекращении с ним связи

PostMessage(ServerHandle,WM_UT,Integer(Self.Handle),0);

SpeedButton1.Caption:='Connect';

Label2.Caption:='';

end;

end;

end;

Procedure TForm1.FormCreate(Sender: TObject);

Begin

// Регистрируем в системе новые коды сообщений со стороны клиента

WM_ST:=RegisterWindowMessage('WM_ST');

WM_UT:=RegisterWindowMessage('WM_UT');

end;

end.

Вид окна клиента может быть следующим:

Рис.25.1. Вид формы клиента