Здравствуйте, Евгений Щербатов, Вы писали:
>Статья посвящена реализации механизма self-unregistration в СОМ-серверах, созданных на базе библиотеки MFC.
Интересная картина с регистрацией SDI (MDI) сервера.
При создании проекта Вы требуете установит галогку Automation в аппвизарде. Вам эта галочка нужна для инициализации СОМ. В случае с SDI галочка, как известно, делает из класса CDocument сервер автоматизации. Вы предлагаете и в SDI добавить еще классы-сервера, как для DLL. А я вот задумался, зачем добавлять еще классы-сервера, если CDocument и так уже сервер. Стал смотреть, как устроен COleTemplateServer.
COleObjectFactory::UpdateRegistryAll() вызывает у всех фабрик UpdateRegistry(BOOL).
Логично было бы предполочить, что COleTemplateServer::UpdateRegistry(BOOL) регистрирует CDocument как сервер. На деле не совсем так. В COleTemplateServer введена дополнительная функция void UpdateRegistry(OLE_APPTYPE, LPCTSTR*, LPCTSTR*) и мастер прописывает известную регистрацию:
m_server.UpdateRegistry(OAT_DISPATCH_OBJECT);
COleObjectFactory::UpdateRegistryAll();
UpdateRegistry(OLE_APPTYPE, LPCTSTR*, LPCTSTR*) в конечном итоге вызывает AfxOleRegisterServerClass, как и UpdateRegistry(BOOL). Получается, при регистрации CDocument AfxOleRegisterServerClass вызывается дважды.
Описанные вещщи меня насторожили. Еще больше меня насторожил предлагаемый способ un-регистрации:
if( cmdInfo.m_nShellCommand == CCommandLineInfo::AppUnregister )
{
m_server.UpdateRegistry(OAT_DISPATCH_OBJECT);
COleObjectFactory::UpdateRegistryAll(FALSE);
}
Получается, что при un-регистрации CDocument
еще раз регистрируется, а потом уж un-регистрируется. Как-то корявенько...
В COleTemplateServer UpdateRegistry(BOOL) не переопределена. Далее, проверив исходники CDocument и не найдя там макросов DECLARE_OLECREATE_EX и IMPLEMENT_OLECREATE_EX, я, грешным делом, подумал, что для CDocument un-регистрация не выполнится. Я проверил с помошью regedit. Очень удивился, когда регистрация исчезла
.
Оказывается, в CWinApp::ProcessShellCommand есть строки:
//...
// If we've been asked to unregister, unregister and then terminate
case CCommandLineInfo::AppUnregister:
{
UnregisterShellFileTypes();
BOOL bUnregistered = Unregister();
// ...
Далее, в CWinApp::Unregister():
//...
POSITION pos = GetFirstDocTemplatePosition();
while (pos != NULL)
{
CDocTemplate* pTempl = GetNextDocTemplate(pos);
if (pTempl != NULL)
pTempl->OnCmdMsg(0, CN_OLE_UNREGISTER, NULL, NULL);
}
//...
В конечном итоге вызывается
BOOL COleTemplateServer::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
BOOL bReturn;
if (nCode == CN_OLE_UNREGISTER)
bReturn = Unregister();
else
bReturn = COleObjectFactory::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
return bReturn;
}
В COleTemplateServer::OnCmdMsg стоит вызов
невиртуальной Unregister, которая и удаляет соответствующие записи из реестра. Что интересно, что Unregister есть и в COleObjectFactory и ничего не делает.
Почему в COleTemplateServer не переопределили UpdateRegistry(BOOL), а вместо этого переопределили OnCmdMsg с такими хитрыми условиями, для меня остается загадкой...
Такое впечатление, что механизм регистрации и un-регистрации делали последовательно несколько человек, как в том мультике про письмо из Простоквашина.