Поделиться через


Класс CComObjectRootEx

Этот класс предоставляет методы для обработки управления счетчиками ссылок объектов для негрегатированных и агрегированных объектов.

Синтаксис

template<class ThreadModel>
class CComObjectRootEx : public CComObjectRootBase

Параметры

ThreadModel
Класс, методы которого реализуют нужную модель потоковой обработки. Вы можете явно выбрать модель потоков, задав ThreadModel значение CComSingleThreadModel, CComMultiThreadModel или CComMultiThreadModelNoCS. Вы можете принять модель потока по умолчанию сервера, задав ThreadModel значение CComObjectThreadModel или CComGlobalsThreadModel.

Участники

Методы

Function Description
CComObjectRootEx Конструктор.
InternalAddRef Увеличивает число ссылок для негрегатированного объекта.
InternalRelease Уменьшает число ссылок для негрегатированного объекта.
Заблокировать Если модель потока многопоточной, получает владение критически важным объектом раздела.
Отпирать Если модель потока многопоточной, освобождает право владения критически важным объектом раздела.

Методы CComObjectRootBase

Function Description
FinalConstruct Переопределите в классе для выполнения любой инициализации, необходимой для объекта.
FinalRelease Переопределите в классе для выполнения любой очистки, требуемой объектом.
OuterAddRef Увеличивает число ссылок для агрегированного объекта.
OuterQueryInterface Делегирует внешний IUnknown объект агрегированного объекта.
Внешнийrelease Уменьшает количество ссылок для агрегированного объекта.

Статические функции

Function Description
InternalQueryInterface Делегирует IUnknown негрегатный объект.
ObjectMain Вызывается во время инициализации модуля и завершения производных классов, перечисленных на карте объектов.

Элементы данных

Элемент данных Description
m_dwRef С m_pOuterUnknown, частью объединения. Используется, если объект не агрегируется для хранения количества AddRef ссылок и Release.
m_pOuterUnknown С m_dwRef, частью объединения. Используется, когда объект агрегируется для хранения указателя на внешний неизвестный объект.

Замечания

CComObjectRootEx обрабатывает управление счетчиками ссылок объектов как для негрегатированных, так и агрегированных объектов. Он содержит счетчик ссылок на объекты, если объект не агрегируется, и содержит указатель на внешний неизвестный, если объект агрегируется. Для агрегированных объектов CComObjectRootEx методы можно использовать для обработки сбоя построения внутреннего объекта, а также для защиты внешнего объекта от удаления при освобождении внутренних интерфейсов или удалении внутреннего объекта.

Класс, реализующий COM-сервер, должен наследоваться от CComObjectRootEx CComObjectRoot.

Если определение класса указывает макрос DECLARE_POLY_AGGREGATABLE , ATL создает экземпляр CComPolyObject<CYourClass> при IClassFactory::CreateInstance вызове. Во время создания проверяется значение внешнего неизвестного. Если значение NULL, IUnknown реализуется для негрегатированного объекта. Если внешний неизвестный не имеет значения NULL, IUnknown реализуется для агрегированного объекта.

Если класс не задает макрос DECLARE_POLY_AGGREGATABLE, ATL создает экземпляр CAggComObject<CYourClass> для агрегированных объектов или экземпляр для CComObject<CYourClass> негрегатированных объектов.

Преимущество использования CComPolyObject заключается в том, что вы избегаете использования как CComAggObject в модуле, так и CComObject в модуле для обработки агрегированных и негрегатированных случаев. Один CComPolyObject объект обрабатывает оба случая. Поэтому в модуле существует только одна копия vtable и одна копия функций. Если vtable большой, это может значительно уменьшить размер модуля. Тем не менее, если ваша vtable небольшая, использование CComPolyObject может привести к немного большему размеру модуля, так как он не оптимизирован для агрегированного или негрегатированного объекта, как и CComObjectCComAggObject .

Если объект агрегирован, IUnknown реализуется CComAggObject или CComPolyObject. Эти классы делегироватьQueryInterfaceAddRef, а также вызывать CComObjectRootEx"sOuterQueryInterface" OuterAddRefи Release OuterRelease пересылать внешние неизвестные. Как правило, вы переопределяете CComObjectRootEx::FinalConstruct в классе, чтобы создать все агрегированные объекты и переопределить CComObjectRootEx::FinalRelease их, чтобы освободить все агрегированные объекты.

Если объект не агрегирован, IUnknown реализуется CComObject или CComPolyObject. В этом случае вызовы QueryInterfaceAddRefRelease и делегированы CComObjectRootExдля операций InternalQueryInterface, InternalAddRefа также InternalRelease для выполнения фактических операций.

Требования

Заголовок: atlcom.h

CComObjectRootEx::CComObjectRootEx

Конструктор инициализирует число ссылок до 0.

CComObjectRootEx();

CComObjectRootEx::FinalConstruct

Этот метод можно переопределить в производном классе, чтобы выполнить любую инициализацию, необходимую для объекта.

HRESULT FinalConstruct();

Возвращаемое значение

Возвращает S_OK при успешном выполнении или одном из стандартных значений HRESULT.

Замечания

По умолчанию CComObjectRootEx::FinalConstruct просто возвращается S_OK.

Есть преимущества для выполнения инициализации FinalConstruct вместо конструктора класса:

  • Невозможно вернуть код состояния из конструктора, но вы можете вернуть HRESULT с FinalConstructпомощью возвращаемого значения. Когда объекты класса создаются с помощью фабрики стандартных классов, предоставляемой ATL, это возвращаемое значение распространяется обратно на COM-клиент, что позволяет предоставить им подробные сведения об ошибках.

  • Нельзя вызывать виртуальные функции через механизм виртуальной функции из конструктора класса. Вызов виртуальной функции из конструктора класса приводит к статически разрешенным вызовом функции, так как она определена в этой точке в иерархии наследования. Вызовы чистых виртуальных функций приводят к ошибкам компоновщика.

    Класс не является самым производным классом в иерархии наследования— он зависит от производного класса, предоставленного ATL, для предоставления некоторых функций. Существует хороший шанс, что инициализация потребуется использовать функции, предоставляемые этим классом (это, безусловно, верно, когда объекты класса должны агрегировать другие объекты), но конструктор в классе не имеет способа доступа к этим функциям. Строительный код класса выполняется до полного построения самого производного класса.

    Однако вызывается сразу после полного создания самого производного класса, FinalConstruct что позволяет вызывать виртуальные функции и использовать реализацию подсчета ссылок, предоставляемую ATL.

Пример

Как правило, переопределите этот метод в классе, производном от CComObjectRootEx создания агрегированных объектов. Например:

class ATL_NO_VTABLE CMyAggObject :
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CMyAggObject, &CLSID_MyAggObject>,
   public IDispatchImpl<IMyAggObject, &IID_IMyAggObject, &LIBID_NVC_ATL_COMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
   DECLARE_GET_CONTROLLING_UNKNOWN()
   HRESULT FinalConstruct()
   {
      return CoCreateInstance(CLSID_MyCustomClass, GetControllingUnknown(), 
         CLSCTX_ALL, IID_IUnknown, (void**)&m_pMyCustomClass);
   }

   IMyCustomClass* m_pMyCustomClass;

   // Remainder of class declaration omitted.

Если конструкция завершается ошибкой, можно вернуть ошибку. Макрос можно также использовать DECLARE_PROTECT_FINAL_CONSTRUCT для защиты внешнего объекта от удаления, если во время создания внутренний агрегированный объект увеличивает число ссылок, а затем уменьшает количество счетчиков до 0.

Ниже приведен типичный способ создания агрегата:

  • IUnknown Добавьте указатель на объект класса и инициализируйте его значение NULL в конструкторе.

  • Переопределите FinalConstruct для создания агрегата.

  • IUnknown Используйте указатель, определенный как параметр, на макрос COM_INTERFACE_ENTRY_AGGREGATE.

  • Переопределите FinalRelease , чтобы освободить IUnknown указатель.

CComObjectRootEx::FinalRelease

Этот метод можно переопределить в производном классе, чтобы выполнить любую очистку, необходимую для объекта.

void FinalRelease();

Замечания

По умолчанию ничего CComObjectRootEx::FinalRelease не делает.

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

CComObjectRootEx::InternalAddRef

Увеличивает число ссылок негрегатированного объекта на 1.

ULONG InternalAddRef();

Возвращаемое значение

Значение, которое может быть полезно для диагностика и тестирования.

Замечания

Если модель потока многопоточная, InterlockedIncrement используется для предотвращения одновременного изменения количества ссылок несколькими потоками.

CComObjectRootEx::InternalQueryInterface

Извлекает указатель на запрошенный интерфейс.

static HRESULT InternalQueryInterface(
    void* pThis,
    const _ATL_INTMAP_ENTRY* pEntries,
    REFIID iid,
    void** ppvObject);

Параметры

pThis
[in] Указатель на объект, содержащий com-карту интерфейсов, предоставляемых QueryInterface.

PEntries
[in] Указатель на структуру, которая обращается к _ATL_INTMAP_ENTRY карте доступных интерфейсов.

iid
[in] Идентификатор GUID запрашиваемого интерфейса.

ppvObject
[out] Указатель на указатель интерфейса, указанный в iid или NULL, если интерфейс не найден.

Возвращаемое значение

Одно из стандартных значений HRESULT.

Замечания

InternalQueryInterface обрабатывает интерфейсы только в таблице сопоставлений COM. Если объект агрегирован, InternalQueryInterface не делегирует внешнему неизвестному объекту. Интерфейсы можно ввести в таблицу карты COM с помощью макроса COM_INTERFACE_ENTRY или одного из его вариантов.

CComObjectRootEx::InternalRelease

Уменьшает число ссылок негрегатированного объекта на 1.

ULONG InternalRelease();

Возвращаемое значение

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

Замечания

Если модель потока многопоточная, InterlockedDecrement используется для предотвращения одновременного изменения количества ссылок несколькими потоками.

CComObjectRootEx::Lock

Если модель потока многопоточной, этот метод вызывает функцию API Win32 EnterCriticalSection, которая ожидает, пока поток не сможет взять на себя ответственность за критически важный объект раздела, полученный через частный член данных.

void Lock();

Замечания

Когда защищенный код завершит выполнение, поток должен вызвать Unlock освобождение владения критически важным разделом.

Если модель потоков является однопоточной, этот метод ничего не делает.

CComObjectRootEx::m_dwRef

Часть объединения, которая обращается к четырем байтам памяти.

long m_dwRef;

Замечания

С m_pOuterUnknownчастью объединения:

union {
    long m_dwRef;
    IUnknown* m_pOuterUnknown;
};

Если объект не агрегирован, количество ссылок, доступ к которым осуществляется AddRef и Release хранится в m_dwRef. Если объект агрегирован, указатель на внешний неизвестный хранится в m_pOuterUnknown.

CComObjectRootEx::m_pOuterUnknown

Часть объединения, которая обращается к четырем байтам памяти.

IUnknown*
    m_pOuterUnknown;

Замечания

С m_dwRefчастью объединения:

union {
    long m_dwRef;
    IUnknown* m_pOuterUnknown;
};

Если объект агрегирован, указатель на внешний неизвестный хранится в m_pOuterUnknown. Если объект не агрегирован, количество ссылок, доступ к которым AddRef осуществляется и Release хранится в m_dwRef.

CComObjectRootEx::ObjectMain

Для каждого класса, указанного на карте объектов, эта функция вызывается один раз при инициализации модуля и снова при завершении.

static void WINAPI ObjectMain(bool bStarting);

Параметры

bStarting
[out] Значение равно TRUE, если класс инициализирован; в противном случае ЗНАЧЕНИЕ FALSE.

Замечания

Значение параметра bStarting указывает, инициализируется ли модуль или завершается. Реализация по умолчанию ничего не делает, но эту функцию ObjectMain можно переопределить в классе, чтобы инициализировать или очистить ресурсы, которые необходимо выделить для класса. Обратите внимание, что ObjectMain вызывается перед запросом любых экземпляров класса.

ObjectMain вызывается из точки входа библиотеки DLL, поэтому тип операции, которую может выполнять функция точки входа, ограничен. Дополнительные сведения об этих ограничениях см. в библиотеках DLL и поведении библиотеки времени выполнения Visual C++ и dllMain.

Пример

class ATL_NO_VTABLE CMyApp :
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CMyApp, &CLSID_MyApp>,
   public IMyApp
{
public:
   CMyApp()
   {
   }

   static void WINAPI ObjectMain(bool bStarting)
   {
      if (bStarting)
         ;// Perform custom initialization routines
      else
         ;// Perform custom termination routines
   }

   // Remainder of class declaration omitted.

CComObjectRootEx::OuterAddRef

Увеличивает число ссылок внешнего неизвестного агрегата.

ULONG OuterAddRef();

Возвращаемое значение

Значение, которое может быть полезно для диагностика и тестирования.

CComObjectRootEx::OuterQueryInterface

Извлекает косвенный указатель на запрошенный интерфейс.

HRESULT OuterQueryInterface(REFIID iid, void** ppvObject);

Параметры

iid
[in] Идентификатор GUID запрашиваемого интерфейса.

ppvObject
[out] Указатель на указатель интерфейса, указанный в iid или NULL, если агрегат не поддерживает интерфейс.

Возвращаемое значение

Одно из стандартных значений HRESULT.

CComObjectRootEx::OuterRelease

Уменьшает количество ссылок внешнего неизвестного агрегата.

ULONG OuterRelease();

Возвращаемое значение

В сборках, отличных от отладки, всегда возвращается значение 0. В отладочных сборках возвращает значение, которое может быть полезно для диагностика или тестирования.

CComObjectRootEx::Unlock

Если модель потока многопоточной, этот метод вызывает функцию API Win32 LeaveCriticalSection, которая освобождает владение критически важным объектом раздела, полученным через член частных данных.

void Unlock();

Замечания

Чтобы получить владение, потоку необходимо вызвать Lock. Каждому вызову требуется соответствующий вызов Lock для Unlock освобождения владения критически важным разделом.

Если модель потоков является однопоточной, этот метод ничего не делает.

См. также

Класс CComAggObject
Класс CComObject
Класс CComPolyObject
Общие сведения о классе