Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект лекций РСОИ.doc
Скачиваний:
20
Добавлен:
04.11.2018
Размер:
1.93 Mб
Скачать

2.10.3. Підключення множини клієнтів до сервера

У програмному коді сервера, що існує зараз, є недолік. Незважаючи на те, що для обслуговування множини клієнтів можна запустити єдиний екземпляр застосунка-сервера, цей сервер зможе згенерувати події тільки для першого підключеного клієнта. А цього не досить.

Щоб усунути цей недолік, доведеться внести корективи як у програмний код сервера, так і у програмний код застосунка-клієнта.

Спочатку, необхідно змінити метод Initialize, який повинен мати такий вигляд:

procedure TEventIntf.Initialize;

begin

inherited Initialize;

FConnectionPoints := TConnectionPoints.Create(Self);

if AutoFactory.EventTypeInfo <> nil then FConnectionPoints. CreateConnectionPoint(AutoFactory.EventIID, ckMulti, EventConnect);

end;

Зверніть увагу на те, що змінено передостанній параметр методу CreateConnectionPoint. Замість значення ckSingle тепер використовується ckMulti. Це забезпечить серверу можливість пам’ятати про всіх клієнтів, які підключені до нього у цей момент.

Так, коли сервер може відстежувати багато паралельних підключень, необхідно організувати перегляд по черзі всіх активних підключень. Для цього скористаймося лічильником (нумератором), яким володіє інтерфейс IConnectionPointContainer. Для звернення до цього лічильника можна скористатися функцією, що подібна до тої, яка наведена нижче:

function TEventIntf.GetEnumerator: IEnumConnections;

var

Container: IConnectionPointContainer;

ConnectionPoint: IConnectionPoint;

begin

OleCheck(QueryInterface (IConnectionPointContainer, Container));

OleCheck(Container.FindConnectionPointAutoFactory.EventIID, ConnectionPoint));

ConnectionPoint.EnumConnections(Result);

end;

Після того, як дані від лічильника підключень вже отримані, необхідно для кожного підключення збудити подію. Нижче наведено скорегований програмний код процедури обробки події, яка підтримує множину підключень.

procedure TEventIntf.SendText(const Text: WideString);

var

Enum: IEnumConnections;

ConnectData: TConnectData;

Fetched: Cardinal;

begin

Enum := GetEnumerator;

if Enum <> nil then

begin

while Enum.Next(1, ConnectData, @Fetched) = S_OK do

if ConnectData.pUnk <> nil then

(ConnectData.pUnk as IEventIntfEvents).OnText(Text);

end;

end;

Останння зміна, яку необхідно внести у програму сервера, має забезпечити реєстрацію сервера у таблиці виконуваних об’єктів Windows. Для цього у кінець коду методу Initialize необхідно додати рядок:

RegisterActiveObject (self as IUnknown, CLASS_EventIntf, ACTIVEOBJECT_WEAK, FObjectID);

Визначення цієї функції має вигляд:

function RegisterActiveObject(unk: IUnknown; const clsid: TCLSID; dwFlags: Longint; out dwRegister: Longint): HResult; stdcall;

Згідно з визначенням останній параметр (у прикладі, що подано вище, цей параметр має назву FObjectID) має бути глобальною змінною типу Longint. Після виконання функції цей параметр буде містити значення ідентифікатора сервера у таблиці виконуваних об’єктів.

Щоб видалити елемент, що відповідає серверу, з таблиці виконуваних об’єктів Windows, необхідно створити метод Destroy і включити до нього виклик функції RevokeActiveObject:

RevokeActiveObject(FObjectID, nil);

На цьому зміни у програмі сервера, покликані забезпечити нормальну взаємодію з множиною клієнтів, обмежуються.

На стороні клієнта потрібно внести зміни в код методу FormCreate, після чого він повинен виглядати, як наведено нижче:

procedure TForm1.FormCreate(Sender: TObject);

var

Obj: IUnknown;

begin

GetActiveObject(CLASS_EventIntf, nil, Obj);

if Obj <> nil then

//F – це глобальна змінна типу IEventIntf

F := Obj as IEventIntf

else

F := CoEventIntf.Create;

EventIntf1.Connect(F, IEventIntfEvents);

//або EventIntf1.ConnectTo(F, IEventIntfEvents);

end;

Функція GetActiveObject шукає активізований екземпляр сервера автоматизації EventSrv. Якщо такий знайдеться, він і буде надалі використовуватися клієнтом. Якщо ж жодного активного екземпляра сервера знайти не вдасться, метод CoEventIntf.Create створить новий екземпляр.