Статьи Королевства Дельфи

       

Рабочий пример


Ну, теперь - о главном. Вниманию уважаемой публики предлагается простой модуль с иерархией объектов, реализующих вышеописанные методы нотификации.

Для удобства использования серверами, находящимися в DLL, и экспортирующими только функции (не классы), необходимые клиенту определения вынесены в отдельный unit:

(********************************************************************* * Notifier object definitions * *********************************************************************) unit NotifyDef; interface uses Windows; const tnEvent = 0; // Use kernel object Event (SetEvent) tnThreadMsg = 1; // Use message to thread ID (PostThreadMessage) tnWinMsg = 2; // Use message to window HWND (PostMessage) tnCallBack = 3; // Asynchronous call user function TNotifierProc tnCallEvent = 4; // Asynchronous call object event handler TNotifierEvent type TNotifierProc = procedure(Owner: THandle; Msg,UserParam : dword); TNotifierEvent = procedure(Sender : TObject; Msg,UserParam : dword) of object; implementation end.

Для создания объекта нотификатора заданного типа сервер может использовать функцию (см. модуль ):

function MakeNotifier(hEventObj,hSender : THandle; EventType : byte; MsgID,UserParam : dword) : TNotify;

Описание параметров ПараметрНазначение Значение, использование в способах нотификации Событие Сообщение потоку Сообщение окну Процедура клиента
hEventObj Хэндл низкоуровнего объекта, используемого для нотификации хэндл события - результат вызова CreateEvent ID потока (можно узнать GetCurrentThreadID) хэндл окна адрес процедуры
hSender Условный хэндл объекта сервера - то, что сервер хочет сообщить о себе не используется TMessage.LParam TMessage.LParam Owner в TNotifierProc
EventType Тип объекта нотификатора - см. константы в модуле tnEvent tnThreadMsg tnWinMsg tnCallBack
MsgID Идентификатор сообщения не используется TMessage.Msg TMessage.Msg Msg в TNotifierProc
UserParam Пользовательский параметр не используется TMessage.WParam TMessage.WParam UserParam в TNotifierProc
Собственно, параметры hSender,MsgID,UserParam могут быть заряжены произвольными данными на усмотрение программиста, нотификаторы не используют их для своих нужд.


Нотификатор типа "асинхронный вызов обработчика события" (tnCallEvent) нельзя создать через функцию MakeNotifier - требуется явный вызов конструктора. Это связано с тем, что адрес TNotifierEvent нельзя привести к четырехбайтному типу THandle. Параметры конструктора аналогичны параметрам MakeNotifier при EventType=tnCallback.

Далее приводится собственно текст юнита реализации библиотеки нотификаторов.

(****************************************************************************** * The Collection of Notifier objects. * ******************************************************************************) unit Notify; interface uses Windows,NotifyDef; type TNotify = class protected hNotify : THandle; hOwner : THandle; Message, UParam : dword; public constructor Create(hEventObj : THandle); procedure Execute; virtual; property Owner : THandle read hOwner write hOwner; property Param : dword read UParam write UParam; end; TThreadNotify = class(TNotify) public constructor Create(hEventObj,hSender : THandle; MsgID,UserParam : dword); procedure Execute; override; end; TWinNotify = class(TThreadNotify) public procedure Execute; override; end; TCallBackNotify = class(TThreadNotify) public procedure Execute; override; end; TCallEventNotify = class(TThreadNotify) private fOnNotify : TNotifierEvent; public constructor Create(hEventObj : TNotifierEvent; hSender : THandle; MsgID,UserParam : dword); property OnNotify : TNotifierEvent read fOnNotify write fOnNotify; procedure Execute; override; end; function MakeNotifier(hEventObj,hSender : THandle; EventType : byte; MsgID,UserParam : dword) : TNotify; implementation function MakeNotifier(hEventObj,hSender : THandle; EventType : byte; MsgID,UserParam : dword) : TNotify; begin case EventType of tnEvent : result := TNotify.Create(hEventObj); tnThreadMsg : result := TThreadNotify.Create(hEventObj, hSender, MsgID, UserParam); tnWinMsg : result := TWinNotify.Create(hEventObj, hSender, MsgID, UserParam); tnCallBack : result := TCallBackNotify.Create(hEventObj, hSender, MsgID, UserParam); else result := nil; end; end; (*** TNotify ***) constructor TNotify.Create(hEventObj : THandle); begin hNotify := hEventObj; end; procedure TNotify.Execute; begin SetEvent(hNotify); end; (*** TThreadNotify ***) constructor TThreadNotify.Create(hEventObj,hSender : THandle; MsgID,UserParam : dword); begin inherited Create(hEventObj); Owner := hSender; Message := MsgID; UParam := UserParam; end; procedure TThreadNotify.Execute; begin PostThreadMessage(hNotify, Message, UParam, hOwner); end; (*** TWinNotify ***) procedure TWinNotify.Execute; begin PostMessage(hNotify, Message, UParam, hOwner); end; (*** TCallbackNotify ***) procedure TCallbackNotify.Execute; begin TNotifierProc(hNotify)(hOwner, Message, UParam); end; (*** TCalleventNotify ***) constructor TCalleventNotify.Create(hEventObj : TNotifierEvent; hSender : THandle; MsgID,UserParam : dword); begin OnNotify := hEventObj; Owner := hSender; Message := MsgID; UParam := UserParam; end; procedure TCalleventNotify.Execute; begin if assigned(OnNotify) then OnNotify(TObject(Owner), Message, UParam); end; end.
Порядок работы очень прост. Сервер инициализирует экземпляр нужного типа, воспользовавшись функцией MakeNotifier или прямым вызовом конструктора. Виртуальный метод TNotify.Execute реализует заданный способ нотификации, именно его сервер вызывает, когда нужно выполнить извещение клиента.

Эта библиотечка родилась вследствие практической необходимости как результат обобщения наработок на данную тему. Теперь, создавая серверный модуль, я снабжаю его этим набором нотификаторов, чтобы он мог предоставить клиенту свободный выбор способа извещения.

Практическим примером использования объектов-нотификаторов является таймерный менеджер, которому будет посвящена следующая статья под названием "".


Специально для


Содержание раздела