END_CONNECTION_MAP()
Затем добавьте в конструктор нашего класса вызов функции EnableConnections. Эта функция является недокументированной функцией класса CCmdTarget, однако если вы не вызовете её из конструктора класса, работающего с Connection point и являющегося потомком CCmdTarget, то у вас ничего не получится.
CMyInterface::CMyInterface() {
EnableAutomation();
EnableConnections();
// To keep the application running as long as an OLE automation
// object is active, the constructor calls AfxOleLockApp.
AfxOleLockApp();
}
Сохраните редактируемый файл и постройте наш проект. Если вы делали все правильно, то не должно быть ни ошибок, ни предупреждений. На данный момент у нас готов основной каркас. Займемся реализацией непосредственно самих функций. Однако сначала я хотел бы обратить ваше внимание на следующий факт. Я думаю, ни для кого не секрет, что COM-сервер может иметь сразу нескольких клиентов. Может случиться так, что этот сервер должен посылать событие клиентам в ответ на какое-либо действие пользователя. Например, сервер имеет графический интерфейс, и когда пользователь выбирает меню Файл, сервер должен уведомить ВСЕХ ЗАИНТЕРЕСОВАННЫХ клиентов об этом. Естественно возникает 2 вопроса:
1. Каким образом сервер сможет послать событие сразу всем клиентам.
2. Как определить, какой клиент заинтересован в получении событий, а какой нет?
Начнем со второго вопроса. Для этих целей интерфейс IConnectionPoint предусматривает специальные методы подписки на события Advise и Unadvise. С помощью первого из них клиент сообщает серверу, что он желает получать уведомления относительно какого-либо события, а вторая функция, наоборот, сообщает серверу, что данный клиент больше в таких сообщениях не нуждается. Соответственно, сервер должен иметь некий список, в который он заносит клиентов, подписанных на те или иные сообщения. И из которого он потом будет удалять отписавшихся клиентов. Таким образом, когда серверу нужно будет послать некое событие клиентам, то он в цикле пробежится по этому списку и отправит сообщения всем заинтересованным клиентам. Это и есть ответ на первый вопрос. Теперь приведем процедуру, которая реализует все выше сказанное. Вставьте её код в файл MyInterface.cpp а также не забудьте объявить её в MyInterfcae.h.
void CMyInterface::FireEvent() {
const CPtrArray* pConnections=m_xObjCP.GetConnections();
int nConnections=pConnections->GetSize();
for (int i=0; i
IDispatch* pClient=(IDispatch*)(pConnections->GetAt(i));
if (pClient) {
VARIANT varResult;
DISPPARAMS disp={0,0,0,0};
HRESULT hr = pClient->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
}
Итак, что же мы имеем? Скажу сразу, что MFC сильно облегчила нам жизнь. Здесь const CPtrArray* pConnections=m_xObjCP.GetConnections();мы объявляем указатель на CPtrArray и присваиваем ему значение полученное из m_xObjCP.GetConnections(). Вот и все. Теперь мы имеем указатель на список всех наших потенциальных клиентов. Объект m_xObjCP поддерживается средствами CCmdTarget и самостоятельно, «без нашего участия» заносит в список подписавшихся и удаляет из него отписавшихся клиентов. Дальше все просто: мы перебираем в цикле всех наших клиентов и с помощью метода Invoke им события.
Еще раз напомню: не забудьте добавить описание этой функции в наш класс. А теперь измените тело функции FireMyEvent, как показано ниже.
void CMyInterface::FireMyEvent() {
FireEvent();
}
Таким образом, мы заставим метод сгенерировать событие. Сохраните все сделанные вами изменения и постройте проект. Ошибок быть не должно. После чего найдите полученную DLL и с помощью утилиты regsvr32.exe (или любого другого инструмента, способного вызвать функцию DllRegisterServer) зарегистрируйте её в вашей операционной системе. На этом с сервером все!
Часть 3. Реализация клиента.
Программа-пример Client
Теперь напишем клиента. Выполните пункты меню File->New и заполните опции согласно рисунку 8.
Рисунок 8
Обратите внимание на папки, куда я помещаю проекты клиента и сервера. Они оба должны находиться в одном каталоге. Жмите Ок, и в появившемся мастере выберите опцию создания диалогового приложения, см. рисунок 9, после чего жмите Finish.
Рисунок 9
Отредактируйте диалоговую форму. Чтобы она приняла вид, как на рисунке 10.
Рисунок 10
Читать дальше