Шаг 179.
Среда программирования Visual C++.
Анализ кода ATL COM-компонента. Функции глобальной точки входа

    На этом шаге мы рассмотрим содержимое файла EncodeServer.cpp.

    На вкладке ClassView рабочей области есть узел Globals, развернув который, Вы увидите несколько глобальных функций (с префиксом Dll) и один глобальный объект _Module.


Рис.1. Вкладка ClassView

    Эти элементы находятся файле EncodeServer.cpp, они добавлены в проект мастером ATL COM AppWizard для предоставления функций точки входа, экспортируемых из DLL и вызываемых из СОМ и других системных утилит. Вот какой код находится в файле EncodeServer.cpp:

#include "stdafx.h"
#include "resource.h"
#include <initguid.h>
#include "EncodeServer.h"

#include "EncodeServer_i.c"
#include "Encoder.h"


CComModule _Module;

BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_Encoder, CEncoder)
END_OBJECT_MAP()

/////////////////////////////////////////////////////////////////////////////
// Точка входа в DLL

extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        _Module.Init(ObjectMap, hInstance, &LIBID_ENCODESERVERLib);
        DisableThreadLibraryCalls(hInstance);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
        _Module.Term();
    return TRUE;    // ok
}

/////////////////////////////////////////////////////////////////////////////
// Здесь проверяем, может ли OLE выгрузить нашу DLL 

STDAPI DllCanUnloadNow(void)
{
    return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// Возвращает фабрику классов для создания объекта нужного типа

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
    return _Module.GetClassObject(rclsid, riid, ppv);
}

/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer помещает записи в реестр
// (регистрирует сервер) 

STDAPI DllRegisterServer(void)
{
    // registers object, typelib and all interfaces in typelib
    return _Module.RegisterServer(TRUE);
}

/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer удаляет записи из реестра
//  (удаляет регистрационную запись сервера)

STDAPI DllUnregisterServer(void)
{
    return _Module.UnregisterServer(TRUE);
}

    В первой половине файла находится объявление объекта _Module класса CComModule. В классе CComModule реализован модуль СОМ-сервера, позволяющий клиенту запрашивать его компоненты. ССоmModule поддерживает как внешние модули, так и модули, встраиваемые в процесс. Внешние серверы (расположенные в ЕХЕ-файлах) используют объект, реализующий особые функции приложения и являющийся производным от CComModule.

    Экземпляр класса CComModule имеет таблицу, называемую картой объекта (object map), которая хранит набор определений объекта. Внутренние механизмы карты объекта создают и поддерживают массив структур _ATL_OBJMAP_ENTRY, которые содержат информацию, используемую каркасом для:

    Макрос OBJECT_ENTRY помещается в карте каждого СОМ-объекта данной DLL. Ему передаются два параметра. Первый из них - это GUID, уникальный идентификатор СОМ-объекта, а второй - имя реализующего его класса. На основе этих сведений макрос создает для указанного объекта соответствующую запись _ATL_OBJMAP_ENTRY.

    При загрузке DLL в ответ на клиентский запрос СОМ вызывает функцию DllGetClassObject(), которая в свою очередь для вызова фабрики классов указанного объекта обращается к ССоmModule::GetClassObject() - функции базового класса, находящейся в глобальном объекте _Module. CComModule::GetClassObject() обращается к таблице в карте объекта и получает указатель на метод CreateInstance() фабрики классов. С помощью этого указателя GetClassObject() создает СОМ-объект, выполняет его функцию QueryInterface() и возвращает в СОМ указатель на интерфейс.

    В серверах, находящихся в ЕХЕ-файлах, Dll-функции не реализованы; вместо этого при запуске вызывается СОМ-функция CoRegisterClassObject() для каждой реализованной в ней фабрики классов. Указатели на фабрики классов кэшируются во внутренней таблице. Функции DllRegisterServer() и DllUnregisterServer() реализуют саморегистрирующийся СОМ-объект, встраиваемый в процесс. Программы типа консольной утилиты RegSvr32.exe способны вызывать их для добавления в реестр или удаления из него сведений о СОМ-объекте. Информацию о том, какие действия нужно предпринять - добавить или удалить записи, ЕХЕ-серверы получают из параметров командной строки: RegServer или UnregServer соответственно. И ЕХЕ, и DLL в конце концов обращаются к функциям CComModule::RegisterServer() и CComModule::UnregisterServer(). Задача этих функций - регистрация или дерегистрация всех объявленных в карте объектов на основе информации из сценария реестра.

    На следующем шаге мы рассмотрим сценарий реестра.




Предыдущий шаг Содержание Следующий шаг