TN038: Осуществление IUnknown MFC/OLE

В основе OLE 2 является «OLE объектная модель компонентов», или COM. COM определяет стандарт для объектов, как сотрудничающих общаться друг с другом. Это включает сведения о какой «объект» выглядит, включая как методы, направляются на объекте. COM определяет базовый класс, производными от которого все классы COM совместимость. Этот базовый класс — IUnknown. Хотя интерфейс IUnknown передается как класс C++, COM характерно не только для одного языка, он может осуществляться в C, PASCAL или любой другой язык, который может поддерживать размещение объекта COM.

OLE, касается всех классов, производных от IUnknown , как "интерфейсы". Это важное различие, с «интерфейс», такие как IUnknown несет с нет реализации. Он просто определяет протокол, в котором объекты общаться, не особенности того, что делают эти реализаций. Это разумно, системы, которая обеспечивает максимальную гибкость. Это работа MFC для реализации поведения по умолчанию для программ MFC/C++.

Чтобы понять MFC в осуществление IUnknown вы должны сначала понять, что такое этот интерфейс. Упрощенная версия IUnknown определяется ниже:

 класс IUnknown
{
общественности:
 nbsp;  виртуальный QueryInterface(REFIID iid, void** ppvObj) HRESULT = 0;
    виртуальный ULO&NG AddRef() = 0;
    виртуальный ULONG Release() = 0;
}

Примечание   Некоторые необходимые вызывающий Конвенции такие сведения, как __stdcall остаются за иллюстрации.

Функции-члены AddRef и релиз управления управление памятью объекта. COM использует схему подсчета ссылок для объектов. Объект не ссылается непосредственно, как в C++. Вместо этого объекты COM всегда ссылки на через указатель. Чтобы освободить объект, когда владелец делается с его помощью освободить члена объекта называется (в противовес с помощью оператора delete, как это будет сделано для традиционного C++ объекта). Механизм подсчета ссылок позволяет несколько ссылок на один объект для управления. Реализация AddRef и выпуска ведется свой счетчик ссылок на объект-объект не удаляется до тех пор, пока его счетчик ссылок достигнет нуля.

Достаточно простой с точки зрения реализации AddRef и выпуска . Здесь будет тривиальным осуществление:

ULO&NG CMyObj::AddRef() {nbsp;  возвращение ++ m_dwRef; 
}

ULONG CMyObj::Release() {если (--m_dwRef == 0) {}
        удалить это; 
        Возвращает 0;
    }
    возвращение m_dwRef;
}

Функция-член QueryInterface немного более интересно. Как вы можете себе представить, это не очень интересно получить объект которого только функции-члены являются AddRef и релиз -было бы неплохо рассказать объект, который требуется выполнять больше задач, чем обеспечивает IUnknown . Вот где QueryInterface полезным. Это позволяет получать различные «интерфейс» на тот же объект. Эти интерфейсы обычно являются производными от IUnknown и добавить дополнительную функциональность путем добавления новых функций-членов. COM-интерфейсы никогда не имеют переменные-члены, объявленные в интерфейсе, и все функции-члены объявляются как чистая virtual. Например,

класс IPri&ntInterface: государственные IUnknown
{
общественности:
 nbsp;  виртуальный void PrintObject() = 0;
}

Чтобы получить IPrintInterface если у вас только IUnknown, вызовите IUnknown::QueryInterface с помощью IID IPrintInterface. IID — 128-битное число, которое однозначно определяет интерфейс. Есть IID для каждого интерфейса, вы или OLE определяют. Если панк — это указатель на объект IUnknown , код, чтобы получить IPrintInterface из него может быть

IPrintInterface * pPrint = NULL;
Если (панк gt;QueryInterface(IID_IPrintInterface, (void**) и pPrint) == NOERROR)
{
    pPrint - > PrintObject();
    pPrint - > Release();   
        / / выпуск указателя, полученных через QueryInterface
}

Это кажется довольно простым, но как бы реализовать объект, поддерживающий интерфейс IPrintInterface и IUnknown ? В данном случае это просто, так как IPrintInterface происходит непосредственно от IUnknown , осуществляя IPrintInterface, автоматически поддерживается IUnknown . Например:

 класс CPrintObj: государственные CPrintInterface
{
 nbsp;  Виртуальная HRESULT QueryInterface(REFIID iid, void** ppvObj);
    виртуальный ULO&NG AddRef();
    виртуальный ULONG Release();
    виртуальный void PrintObject();
}

Реализации AddRef и релиз будет полностью совпадать, как реализовано выше. CPrintObj::QueryInterface будет выглядеть примерно следующим образом

HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
{
 nbsp;  Если (iid == IID_IUnknown || iid == IID_IPrintInterface)
    {
        * ppvObj = это;
        AddRef();
        возвращение &NOERROR;
    }
    возвращение ResultFromScode(E_NOINTERFACE);
}

Как вы можете видеть, если будет признана идентификатор интерфейса (IID), возвращается указатель на объект; в противном случае возникает ошибка. Также Обратите внимание, что успешный QueryInterface приводит к подразумеваемых AddRef. Конечно вы также должны выполнять CEditObj::Print. Это просто потому, что IPrintInterface взята непосредственно из интерфейса IUnknown . Однако если вы хотите поддержать два разных интерфейсов, оба от IUnknown, учитывать следующее.

класс IEditI&nterface: государственные IUnkown
{
общественности:
 nbsp;  виртуальный void EditObject() = 0;
}

Хотя существует ряд различных способов реализации класса, IEditInterface и IPrintInterface, в том числе с использованием C++ множественное наследование, эта записка будет сосредоточена на использовании вложенных классов для реализации этой функции.

класс CEditPrintObj
{
общественности:
 nbsp;  CEditPrintObj();

HRESULT QueryInterface(REFIID iid, void**);
    ULO&NG AddRef();
    ULONG Release();
    DWORD m_dwRef;

класс CPrintObj: государственные IPrintInterface
    {
    общественности:
        CEditPrintObj * m_pParent;
        Виртуальная HRESULT QueryInterface(REFIID iid, void** ppvObj);
        виртуальный ULONG AddRef();
        виртуальный ULONG Release();
    } m_printObj;

класс CEditObj: государственные IEditInterface
    {
    общественности:
        CEditPrintObj * m_pParent;
        виртуальный ULONG QueryInterface(REFIID iid, void** ppvObj);
        виртуальный ULONG AddRef();
        виртуальный ULONG Release();
    } m_editObj;
}

Ниже приведены все реализации:

CEditPrintObj::CEditPrintObj()
{
 nbsp;  m_editObj.m_pParent = это;
    m_printObj.m_pParent = это;
}

ULONG CEditPrintObj::AddRef() {возвращение ++ m_dwRef;
}

CEditPrintObj::Release()
{
    Если (--m_dwRef == 0)
    {
        удалить это;
        Возвращает 0;
    }
    возвращение m_dwRef;
}

HRESULT CEditPrintObj::QueryInterface(REFIID iid, void** ppvObj)
{
    Если (iid == IID_IUnknown || iid == IID_IPrintInterface)
    {
        * ppvObj = & m_printObj;
        AddRef();
        возвращение NOERROR;
    }
    иначе если (iid == IID_IEditInterface)
    {
        * ppvObj = & m_editObj;
        AddRef();
        возвращение NOERROR;
    }
    возвращение ResultFromScode(E_NOINTERFACE);
}

ULONG CEditPrintObj::CEditObj::AddRef() {возвращение m_pParent - > AddRef(); 
}

ULONG CEditPrintObj::CEditObj::Release() {возвращение m_pParent - > Release(); 
}

(HRESULT) CEditPrintObj::CEditObj::QueryInterface
    REFIID iid, пустота ** ppvObj) {возвращение m_pParent - > QueryInterface (iid, ppvObj); 
}

ULONG CEditPrintObj::CPrintObj::AddRef() {возвращение m_pParent - > AddRef(); 
}

ULONG CEditPrintObj::CPrintObj::Release() {возвращение m_pParent - > Release(); 
}

(HRESULT) CEditPrintObj::CPrintObj::QueryInterface
    REFIID iid, пустота ** ppvObj) {возвращение m_pParent - > QueryInterface (iid, ppvObj); 
}

Обратите внимание, что большая часть реализации IUnknown помещен в класс CEditPrintObj , а не дублирования кода в CEditPrintObj::CEditObj и CEditPrintObj::CPrintObj. Это уменьшает объем кода и позволяет избежать ошибок. Ключевой момент здесь заключается том, что с помощью интерфейса IUnknown можно вызывать QueryInterface для получения любого интерфейса, которые могут поддерживать объект, и от каждого из этих интерфейсов можно сделать то же самое. Это означает, что все функции QueryInterface , доступные из каждого интерфейса должен вести себя так же. Для того чтобы эти внедренных объектов для вызова реализации в объекте «внешних», бэк указатель — используется (m_pParent). Указатель m_pParent инициализируется во время CEditPrintObj конструктор. Затем будет осуществлять CEditPrintObj::CPrintObj::PrintObject и CEditPrintObj::CEditObj::EditObject, а. Совсем немного кода был добавлен для добавления одну особенность — возможность редактировать объект. К счастью, это довольно необычная для интерфейсов иметь только один член функции (хотя это произойдет), и в этом случае, EditObject и PrintObject будут обычно объединены в один интерфейс.

Это много объяснений и много кода для такого простого сценария. Классы MFC/OLE предоставляют более простую альтернативу. Реализации MFC использует технику, подобно тому как завернутые сообщения Windows с схемы сообщений. Этот объект называется Интерфейс карты и обсуждается в следующем разделе.

Карты интерфейса MFC

MFC/OLE включает в себя осуществление «Интерфейс карты» аналогичны "MFC"Сообщение карты"карты и диспетчеризации" в концепции и осуществления. Основные черты карты интерфейса MFC:

Кроме того интерфейс карты поддерживают следующие дополнительные функции:

Для получения дополнительных сведений о агрегации приведена в справочнике программиста OLE.

Карта поддержки интерфейса MFC коренится в классе CCmdTarget . CCmdTarget "есть а" справочные графа, а также всех функций-членов, связанные с осуществлением IUnknown (количество ссылок, например находится в CCmdTarget). Для создания класса, который поддерживает OLE COM, производным от CCmdTarget и использовать различные макросы, так и функции-члены CCmdTarget для реализации желаемых интерфейсов. Реализация MFC использует вложенные классы для определения каждой реализации интерфейса так же, как в примере выше. Это стало проще с стандартной реализации IUnknown, а также ряд макросов, ликвидировать некоторые из повторяющегося кода.

Основы интерфейса карты

Для реализации класса с помощью интерфейса MFC карты выполните следующие действия:

  1. Класс производный прямо или косвенно от CCmdTarget.

  2. Использовать функцию DECLARE_INTERFACE_MAP в определении производного класса.

  3. Для каждого интерфейса вы хотите поддерживать, используйте макросы BEGIN_INTERFACE_PART и END_INTERFACE_PART в определении класса.

  4. В файле реализации используйте макросы BEGIN_INTERFACE_MAP и END_INTERFACE_MAP для определения класса интерфейса карты.

  5. Для каждого IID поддерживается используйте макрос INTERFACE_PART между BEGIN_INTERFACE_MAP и END_INTERFACE_MAP макросы для сопоставления этой IID конкретную "часть" класса.

  6. Осуществления каждой из вложенных классов, которые представляют интерфейсов, поддерживаемых.

  7. Использовать макрос METHOD_PROLOGUE для доступа к родительской CCmdTarget-производный объект.

  8. AddRef, QueryInterface и выпускаможно делегировать CCmdTarget осуществление этих функций, (ExternalAddRef, ExternalReleaseи ExternalQueryInterface).

В CPrintEditObj примере выше может осуществляться следующим:

класс CPrintEditObj: государственные CCmdTarget
{
общественности:
 nbsp;  / / членов данных и функции-члены для CPrintEditObj перейдите сюда

/ / Интерфейса карты
Охраняемые:
    DECLARE_I&NTERFACE_MAP()

BEGIN_INTERFACE_PART (EditObj, IEditInterface)
        STDMETHOD_ (void, EditObject)();
    END_INTERFACE_PART(EditObj)

BEGIN_INTERFACE_PART (PrintObj, IPrintInterface)
        STDMETHOD_ (void, PrintObject)();
    END_INTERFACE_PART(PrintObj)
}

Выше Декларация создает класс, производный от CCmdTarget. Макрос DECLARE_INTERFACE_MAP рассказывает рамки, что этот класс будет иметь пользовательский интерфейс карты. Кроме того BEGIN_INTERFACE_PART и END_INTERFACE_PART макросы определить вложенные классы, в данном случае с именами CEditObj и CPrintObj (X используется только для различения вложенные классы от глобальных классов, начинающихся с "C" и интерфейс классов, которые начинаются с "I"). Создаются два вложенных члены этих классов: m_CEditObj и m_CPrintObj, соответственно. Макросы автоматически объявить AddRef, выпускаи QueryInterface функций; Поэтому только объявлении функции для этого интерфейса: EditObject и PrintObject (OLE STDMETHOD — использовать макрос такие таким образом, чтобы указывая и виртуальных ключевые слова предоставляются при необходимости для целевой платформы).

Для реализации интерфейса карты для этого класса:

BEGI&N_INTERFACE_MAP (CPrintEditObj, CCmdTarget)
 nbsp;  INTERFACE_PART (CPrintEditObj, IID_IPrintInterface, PrintObj)
    INTERFACE_PART (CPrintEditObj, IID_IEditInterface, EditObj)
END_INTERFACE_MAP()

Это соединяет IID_IPrintInterface IID с m_CPrintObj и IID_IEditInterface с m_CEditObj соответственно. Реализация CCmdTarget QueryInterface (CCmdTarget::ExternalQueryInterface) использует эту карту для возврата указатели к m_CPrintObj и m_CEditObj при запросе. Нет необходимости включать запись для IID_IUnknown; рамки будет использовать первый интерфейс на карте (в данном случае m_CPrintObj) когда испрашивается IID_IUnknown.

Несмотря на то, что BEGIN_INTERFACE_PART макрос автоматически объявляется AddRef, выпуска и функции QueryInterface для вас, все еще необходимо для их осуществления:

ULONG ДАЛЬНЕГО экспорта CEditPrintObj::XEditObj::AddRef()
{
 nbsp;  METHOD_PROLOGUE (CEditPrintObj, EditObj)
    возвращение pThis - > ExternalAddRef();
}

ULONG, Дальний экспорт CEditPrintObj::XEditObj::Release()
{
    METHOD_PROLOGUE (CEditPrintObj, EditObj)
    возвращение pThis - > ExternalRelease();
}

HRESULT далеко экспорта () CEditPrintObj::XEditObj::QueryInterface
    REFIID iid, недействительным FAR ** FAR ppvObj)
{
    METHOD_PROLOGUE (CEditPrintObj, EditObj)
    возвращение (HRESULT) pThis - > ExternalQueryInterface (& iid, ppvObj);
}

void CEditPrintObj::XEditObj::EditObject() далеко экспорта
{
    METHOD_PROLOGUE (CEditPrintObj, EditObj)
    / / код «Edit» объект, какой это означает...
}

Реализация для CEditPrintObj::CPrintObj, будет аналогичен выше определений для CEditPrintObj::CEditObj. Хотя можно было бы создать макрос, который можно было использовать для автоматического создания этих функций (на самом деле, ранее в MFC/OLE развития это было), то становится трудно для задания точек останова, когда макрос создает более чем одной строки кода. По этой причине этот код будет расширен вручную.

С помощью реализации framework сообщения есть карты являются несколько вещей, которые не были необходимыми для этого:

Кроме того она используется схемы сообщений внутри страны. Это позволяет вам получить от класса framework говорят COleServerDoc, который уже поддерживает некоторые интерфейсы и обеспечивает замены или дополнения в интерфейсы, предоставляемые средой. Это позволило тем фактом, что рамки полностью поддерживает наследование интерфейса карты от базового класса — это причина, почему BEGIN_INTERFACE_MAP принимает в качестве второго параметра имя базового класса.

Примечание   Как правило невозможно повторно использовать выполнения встроенных реализаций MFC интерфейсов OLE, наследование встроенных специализация этого интерфейса в MFC версии. Это не представляется возможным потому, что использование макросов METHOD_PROLOGUE для того чтобы получить доступ к содержащий CCmdTarget-производный объект подразумевает исправлено смещение внедренного объекта от CCmdTarget-производный объект. Это означает, к примеру, нельзя получить встроенного XMyAdviseSink от реализации MFC в COleClientItem::XAdviseSink, потому что XAdviseSink опирается на время в определенных смещение от верхней части объекта COleClientItem.

Можно однако, делегировать реализации MFC для всех функций, который MFC по умолчанию. Это делается в MFC из IOleInPlaceFrame (XOleInPlaceFrame) в COleFrameHook классе реализации (он делегирует m_xOleInPlaceUIWindow для многих функций). Эта конструкция была выбрана для сокращения времени выполнения размер объектов, которые реализуют множество интерфейсов; Это устраняет необходимость для бэк указателя (например, способ m_pParent использовался в предыдущем разделе).

Агрегирование и интерфейс карты

В дополнение к поддержке автономных объектов COM, MFC также поддерживает агрегирование. Агрегации, само по себе является слишком сложной темой обсудить здесь; обратитесь в справочнике программиста OLE для получения дополнительной информации о статистической обработки. Эта записка будет просто описывают поддержку для агрегирования, встроенный в рамки и интерфейс карты.

Существует два способа использования статистической обработки: (1) с помощью объекта COM, который поддерживает агрегирование и 1 (2) реализация объекта, могут быть вычислены с другой. Эти возможности могут именоваться «с использованием совокупных объект» и «сделать объект комбинируемого». MFC поддерживает оба.

С помощью объекта совокупного

Чтобы использовать совокупный объект, необходимо каким-то образом связать агрегата в механизм QueryInterface. Другими словами совокупные объект должны вести себя, как будто это родной частью вашего объекта. Так как этот галстук в интерфейс MFC карта механизм? В дополнение к INTERFACE_PART макрос, где вложенного объекта сопоставляется с IID, можно также объявить объект совокупного как часть вашего CCmdTarget производного класса. Для этого используется макрос INTERFACE_AGGREGATE . Это позволяет вам указывать переменную-член (который должен быть указатель IUnknown или производного класса), который должен быть интегрированы в интерфейс карты механизм. Если указатель мыши не NULL при вызове CCmdTarget::ExternalQueryInterface , рамки автоматически вызывает функцию-член QueryInterface совокупные объекта, если IID не является одним из родной s IID, поддерживаемых сам объект CCmdTarget.

Чтобы использовать макрос INTERFACE_AGGREGATE, выполните следующие действия:

  1. Объявите переменную-член ( IUnknown *) который будет содержать указатель на совокупные объект.

  2. Включить макрос INTERFACE_AGGREGATE в вашей карты интерфейса, которая относится к переменной-члену по имени.

  3. В определенный момент (обычно во время CCmdTarget::OnCreateAggregates) инициализируйте переменную-член для что-то отличное от NULL.

Например,

класс CAggrExample: государственные CCmdTarget
{
общественности:
 nbsp;  CAggrExample();

Охраняемые:
    LPUNKNOWN m_lpAggrInner;
    виртуальный BOOL OnCreateAggregates();

DECLARE_INTERFACE_MAP()
    / / Здесь могут использоваться макросы часть «родной» интерфейс
};

CAggrExample::CAggrExample()
{
    m_lpAggrInner = NULL;
}

BOOL CAggrExample::OnCreateAggregates()
{
    / / соединять агрегат с правильным контролирующих неизвестно
    m_lpAggrInner = CoCreateInstance (CLSID_Example,
        GetControllingUnknown(), CLSCTX_INPROC_SERVER,
        IID_IUnknown, (LPVOID *) & m_lpAggrInner);
    Если (m_lpAggrInner == NULL)
        вернуть значение FALSE;
    / / при необходимости, создавать другие статистические объекты
    Возвращает значение TRUE;
}

BEGIN_INTERFACE_MAP (CAggrExample, CCmdTarget)
    / / записи родной «INTERFACE_PART» вы можете ознакомиться здесь
    INTERFACE_AGGREGATE (CAggrExample, m_lpAggrInner)
END_INTERFACE_MAP()

m_lpAggrInnerИнициализируется в конструкторе значение NULL. Рамки проигнорирует переменную-член NULL в реализации по умолчанию QueryInterface. OnCreateAggregates это хорошее место, чтобы фактически создать статистические объекты. Вам придется явно вызывать его, если вы создаете объект вне хода MFC COleObjectFactory. Причины создания агрегатов в CCmdTarget::OnCreateAggregates , а также использование CCmdTarget::GetControllingUnknown станут очевидными при создании комбинируемых объектов.

Эта технология даст ваш объект все интерфейсы, которые поддерживает итоговые объект плюс его интерфейсы. Если требуется только подмножество интерфейсов, поддерживаемых агрегат, можно переопределить CCmdTarget::GetInterfaceHook. Это позволяет вам очень низкий уровень hookability, подобно QueryInterface. Обычно вы хотите все интерфейсы, Поддерживаемые агрегат.

Сделать объект осуществление комбинируемого

Для объекта быть комбинируемыми осуществление AddRef, QueryInterface и выпусканеобходимо делегировать "контрольный неизвестно". Другими словами для того чтобы быть частью объекта, он должен делегировать AddRef, QueryInterface и выпускана другой объект, производный от IUnknown. Этот «контрольный неизвестно» содержится на объект при его создании, то есть, он — осуществлением COleObjectFactory. Выполнение этой содержит небольшое количество накладных расходов, а в некоторых случаях не является желательным, поэтому MFC делает это необязательно. Чтобы объект быть комбинируемыми, CCmdTarget::EnableAggregation вызывается из конструктора объекта.

Если объект использует агрегатов, вы также должны быть уверены пройти правильную «контрольный неизвестно» совокупные объектам. Обычно этот указатель IUnknown передается объекту при создании агрегата. Например параметр pUnkOuter — «контрольный неизвестно» для объектов, созданных с CoCreateInstance. Правильный «управление неизвестного» указатель можно получить путем вызова CCmdTarget::GetControllingUnknown. Значение, возвращаемое из этой функции, однако, не допускается в конструктор. По этой причине предлагается создать ваши агрегаты только в переопределении CCmdTarget::OnCreateAggregates, где возвращаемое значение GetControllingUnknown является надежным, даже если создан от реализации COleObjectFactory.

Важно также и то, что объект манипулировать счетчик правильных ссылок при добавлении или выпуска счетчики искусственных ссылок. Чтобы убедиться, что это так, всегда вызывайте ExternalAddRef и ExternalRelease вместо того, InternalRelease и InternalAddRef. Это редко называть InternalRelease или InternalAddRef в классе, который поддерживает агрегирование.

Справочный материал

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

В этом разделе обсуждаются API, который используется для реализации этих дополнительных функций и каждый макрос.

CCmdTarget::EnableAggregation — Описание функции

void EnableAggregation();

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

CCmdTarget::ExternalQueryInterface — Описание функции

DWORD ExternalQueryInterface (const недействительным FAR * lpIID, LPVOID FAR * ppvObj);

lpIID

Указатель далеко IID (первый аргумент QueryInterface)

ppvObj

Указатель на IUnknown (второй аргумент QueryInterface)

Примечание   Эта функция вызывается в вашей реализации IUnknown для каждого интерфейса класс реализует. Эта функция обеспечивает стандартный данными реализацию QueryInterface, основанный на карте интерфейса вашего объекта. Необходимо привести возвращаемое значение к HRESULT. Если объект является агрегатом, эта функция будет вызывать «Контрольный IUnknown» вместо того, чтобы с помощью локального интерфейса.

CCmdTarget::ExternalAddRef — Описание функции

DWORD ExternalAddRef();

Примечание   Эта функция вызывается в реализации IUnknown::AddRef для каждого интерфейса класс реализует. Возвращаемое значение является новый счетчик ссылок на объект CCmdTarget. Если объект является агрегатом, эта функция будет вызывать «Контрольный IUnknown» вместо того, чтобы манипулировать счетчик местной ссылок.

CCmdTarget::ExternalRelease — Описание функции

DWORD ExternalRelease();

Примечание   Эта функция вызывается в вашей реализации IUnknown::Release для каждого интерфейса класс реализует. Возвращаемое значение указывает новый счетчик ссылок на объект. Если объект является агрегатом, эта функция будет вызывать «Контрольный IUnknown» вместо того, чтобы манипулировать счетчик местной ссылок.

DECLARE_INTERFACE_MAP — Описание макроса

DECLARE_INTERFACE_MAP

Примечаниеnbsp;  Используйте этот макрос в любом классе, производных от CCmdTarget , которые будут иметь интерфейс карты. Используется во многом так же, как DECLARE_MESSAGE_MAP. Этот макрос вызов должен быть помещен в определение класса, обычно в верхнем колонтитуле (.H) файл. Класс с DECLARE_I&NTERFACE_MAP необходимо определить интерфейс карты в файл реализации (.НПК) с BEGIN_INTERFACE_MAP и END_INTERFACE_MAP макросы.

BEGIN_INTERFACE_PART и END_INTERFACE_PART — описания макросов

BEGIN_INTERFACE_PART (localClass, iface);

END_INTERFACE_PART (localClass)

localClass

Имя класса, реализующего интерфейс

iface

Имя интерфейса, который реализует этот класс

Примечаниеnbsp;  Для каждого интерфейса, который будет реализовать класс необходимо иметь пару BEGI&N_INTERFACE_PART и END_INTERFACE_PART . Эти макросы определяют местные производный класс от интерфейса OLE, определяемые как встроенного переменной–члена этого класса. Члены AddRef, выпускаи QueryInterface для объявления автоматически. Вы должны включать объявления для других функций-членов, которые являются частью осуществляемой интерфейса (эти объявления размещаются между BEGIN_INTERFACE_PART и END_INTERFACE_PART макросы).

Аргумент iface — интерфейс OLE, который необходимо реализовать, например IAdviseSink, или IPersistStorage (или ваш собственный пользовательский интерфейс).

Аргумент localClass представляет имя локального класса, которые будут определены. ' X' начало списка будут автоматически на имя. Этот именования используется для избежания столкновения с глобальных классов с таким же названием. Кроме того имя внедренного члена, совпадает с именем localClass , за исключением его префиксом 'm_x'.

Например:

BEGI&N_INTERFACE_PART (MyAdviseSink, IAdviseSink)
 nbsp; STDMETHOD_(void,OnDataChange) (LPFORMATETC, LPSTGMEDIUM);
   STDMETHOD_(void,OnViewChange) (DWORD, ДЛИННЫЕ);
   STDMETHOD_(void,OnRename)(LPMONIKER);
   STDMETHOD_(void,OnSave)();
   STDMETHOD_(void,OnClose)();
END_INTERFACE_PART(MyAdviseSink)

определить местные класс с именем XMyAdviseSink, от IAdviseSink, и членом класса, в котором он объявлен под названием m_xMyAdviseSink.Note:

Примечание   Строки, начинающиеся с STDMETHOD_ по существу копируются из OLE2.H и слегка модифицированные. Их копирования с OLE2.H можно уменьшить количество ошибок, которые трудно решить.

BEGIN_INTERFACE_MAP и END_INTERFACE_MAP — описания макросов

BEGIN_INTERFACE_MAP (theClass, baseClass)

END_INTERFACE_MAP

theClass

Класс, в котором карта интерфейса должен быть определен

baseClass

Класс, из которого theClass является производным от.

Замечания: Макросы BEGIN_INTERFACE_MAP и END_INTERFACE_MAP используются в файле реализации для фактически определения интерфейса. Для каждого интерфейса, реализованного есть один или несколько вызовов макрос INTERFACE_PART . Для каждой совокупности, используемый классом есть один вызов макроса INTERFACE_AGGREGATE.

INTERFACE_PART — Описание макроса

INTERFACE_PART (theClass, iid, localClass)

theClass

Имя класса, который содержит интерфейс карты.

iid

IID , который должен быть сопоставлен встроенного класса.

localClass

Имя локального класса (менее 'X')

Примечаниеnbsp;  Этот макрос используется между BEGI&N_INTERFACE_MAP макро- и END_INTERFACE_MAP макрос для каждого интерфейса, который будет поддерживать ваш объект. Это позволяет сопоставить IID для члена класса, theClass и localClass. «m_x» будут автоматически добавлены к localClass . Обратите внимание, что более чем одной IID могут быть связаны с одним членом. Это очень полезно, когда вы только «наиболее полученных» интерфейс и желаем предоставлять все промежуточные интерфейсы. Хорошим примером этого является интерфейс IOleInPlaceFrameWindow . Его иерархия выглядит следующим образом:

IU&nknown
 nbsp;  IOleWindow
        IOleUIWindow
            IOleInPlaceFrameWindow

Если объект реализует IOleInPlaceFrameWindow, клиент может QueryInterface по любому из этих интерфейсов: IOleUIWindow, IOleWindowили IUnknown, кроме "наиболее производный" интерфейса IOleInPlaceFrameWindow (тот, на самом деле реализации). Для обработки этого можно использовать более одного INTERFACE_PART макрос для сопоставления каждого базовый интерфейс интерфейс IOleInPlaceFrameWindow

в файле определения класса:

BEGIN_INTERFACE_PART (CMyFrameWindow, IOleInPlaceFrameWindow)

в файл реализации класса:

BEGI&N_INTERFACE_MAP (CMyWnd, CFrameWnd)
 nbsp;  INTERFACE_PART (CMyWnd, IID_IOleWindow, MyFrameWindow)
    INTERFACE_PART (CMyWnd, IID_IOleUIWindow, MyFrameWindow)
    INTERFACE_PART (CMyWnd, IID_IOleInPlaceFrameWindow, MyFrameWindow)
END_INTERFACE_MAP

Рамки заботится о IUnknown, так как всегда требуется.

INTERFACE_PART — Описание макроса

INTERFACE_AGGREGATE (theClass, theAggr)

theClass

Имя класса, который содержит интерфейс карты,

theAggr

Имя переменной-члена, который должен быть агрегированы.

Примечаниеnbsp;  Этот макрос используется рассказать рамки, что класс использует совокупный объект. Оно должно располагаться между BEGI&N_INTERFACE_PART и END_INTERFACE_PART макросов. Совокупные объект — это отдельный объект, производный от IUnknown. Используя статистическое значение и INTERFACE_AGGREGATE макрос, вы можете сделать все интерфейсы совокупные поддерживает непосредственно поддерживаться объектом. Аргумент theAggr — это просто имя переменной-члена класса, который является производным от IUnknown (прямо или косвенно). Все макросы INTERFACE_AGGREGATE должны следовать все INTERFACE_PART макросы при помещении в карте интерфейса.

Технические примечания по номеру |nbsp; Технические примечания по категориям

Index