TN038: MFC/OLE IUnknown реалізації

У центрі OLE 2 є "OLE компонент об'єктної моделі", або com. COM визначає стандарт для об'єктів, як співпраця спілкуватися один з одним. Це включає в себе відомості про те, що "Об'єкт", що виглядає як, у тому числі як методи направили на об'єкті. COM також визначає базовий клас, з якої походять всі COM сумісних класів. Цей базовий клас є IUnknown. Хоча інтерфейс IUnknown називають клас C++, COM, не характерні для будь-якої однієї мови — це можуть бути реалізовані в C, ПАСКАЛЬ або будь-яку мову, який підтримує двійкові макет COM-об'єкта.

OLE відноситься до всіх класів, отриманих від IUnknown як "інтерфейси". Це важлива відмінність, оскільки "інтерфейс" такі, як IUnknown , що несе в собі не реалізації. Він просто визначає протокол, за допомогою яких об'єкти спілкуватися, не специфіки ті реалізаціях, що робити. Це розумно для системи, що дозволяє для максимальної гнучкості. Це робота MFC, реалізувати поведінки за промовчанням для програм MFC/c + +.

Зрозуміти MFC в реалізації IUnknown ви повинні спочатку зрозуміти, що таке цей інтерфейс. Спрощена версія IUnknown визначено нижче:

 клас IUnknown
{
готелю:
 nbsp;  Віртуальний HRESULT-QueryInterface(REFIID iid, void** ppvObj) = 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 ніколи не член змінні, оголошені в інтерфейсі, і всі методи були оголошені як чисто віртуальний. Наприклад,

клас IPri&ntInterface: Громадська IUnknown
{
готелю:
 nbsp;  Віртуальний недійсним 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();
    Віртуальний недійсним 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;  Віртуальний недійсним 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_ (порожнечу, EditObject)();
    END_INTERFACE_PART(EditObj)

BEGIN_INTERFACE_PART (PrintObj, IPrintInterface)
        STDMETHOD_ (порожнечу, PrintObject)();
    END_INTERFACE_PART(PrintObj)
}

Вище декларації створює клас, отриманих від CCmdTarget. DECLARE_INTERFACE_MAP макрос рамках говорить, що цей клас буде мати власний інтерфейс карти. Крім того, BEGIN_INTERFACE_PART і END_INTERFACE_PART макроси визначити вкладених класи, у цьому випадку з іменами, CEditObj і CPrintObj (X використовується тільки для того, щоб відрізняти вкладених класи від глобального заняття, які починаються з «C» і інтерфейс заняття, які починаються з «Я»). Створення двох вкладених членів цих класів: m_CEditObj та m_CPrintObj, відповідно. Макроси автоматично оголосити AddRef, релізі QueryInterface функції; Ви тільки заявляємо функції для цього інтерфейсу: EditObject і PrintObject (OLE макрос, STDMETHOD є використовується такий так, що _stdcall та віртуальний ключові слова надані в разі потреби для цільову платформу).

Щоб реалізувати інтерфейс карти для цього класу:

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)
    повернення pThis (HRESULT) - > ExternalQueryInterface (& iid, ppvObj);
}

недійсними далеко ЕКСПОРТУВАТИ CEditPrintObj::XEditObj::EditObject()
{
    METHOD_PROLOGUE (CEditPrintObj, EditObj)
    / / код "Змінити" об'єкт, все це означає, що...
}

Впровадження CEditPrintObj::CPrintObj, буде схожа на вище визначення для CEditPrintObj::CEditObj. Хоча можна створити макрос, який може бути використаний для автоматичного створення цих функцій (справді, раніше в розвитку MFC/OLE так було), стає важко встановити точки перерви, коли макрос генерує більше одного рядка коду. З цієї причини цей код розгорнуте вручну.

За допомогою рамках реалізації повідомлення карти там є цілий ряд речей, які не були необхідні, щоб зробити:

Крім того, в рамках використовує карти повідомлення всередині країни. Це дає змогу отримати з рамках клас, сказати 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-об'єкта, який підтримує агрегування і (2) впровадження об'єкта, які можуть бути зібрані інший. Ці можливості можуть бути передано як "за допомогою агрегатних об'єкт" і "зробити об'єкт aggregatable". MFC підтримує як.

За допомогою агрегатних об'єкта

Щоб використати об'єкт сукупності, там має бути якимось чином зв'язати сукупності на QueryInterface механізму. Іншими словами, сукупний об'єкт повинен вести себе як ніби це рідні частиною вашого об'єкта. Так як це краватка в інтерфейс MFC, карта механізм? На додаток до INTERFACE_PART макрос, де вкладений об'єкт відображається на IID, ви можете також оголосити об'єкта агрегатні як частина вашого класу CCmdTarget , отриманих. Для цього використовується INTERFACE_AGGREGATE макрос. Це дає змогу вказати член мінлива (який повинен бути вказівник на IUnknown або отриманих клас), яка повинна бути інтегрована в інтерфейс карта механізм. Якщо вказівник миші не NULL коли називається CCmdTarget::ExternalQueryInterface , рамках буде автоматично дзвінок об'єкт агрегатні функції-члени QueryInterface , якщо IID запит не є одним з рідного IIDs підтримується сам об'єкт 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 стане очевидною, коли обговорювали створення aggregatable об'єктів.

Цей метод дасть ваш об'єкт всіх інтерфейсів, що сукупний об'єкт підтримує плюс її рідному інтерфейсів. Якщо потрібно лише частину інтерфейсів, що підтримує сукупність, ви можете змінити CCmdTarget::GetInterfaceHook. Це дозволить вам дуже низький рівень hookability, подібні до QueryInterface. Звичайно ви хочете, щоб всі інтерфейси, що підтримує сукупність.

Прийняття об'єкта реалізація Aggregatable

Для об'єкта буде aggregatable реалізація AddRef, релізі QueryInterface необхідно делегувати "контрольний невідомо". Іншими словами, для того, щоб бути частиною об'єкта, його необхідно делегувати AddRef, релізі QueryInterface інший об'єкт, також походить від IUnknown. Цей «контрольний невідомо» надається до об'єкта під час його, він надається впровадженню COleObjectFactory. Впровадження цього здійснює невеликою кількістю накладних витрат і в деяких випадках не є бажаним, тому MFC робить це необов'язково. Щоб об'єкт буде aggregatable, ви називаєте CCmdTarget::EnableAggregation від об'єкта конструктора.

Якщо об'єкт також використовує агрегати, ви також повинні бути обов'язково проходити правильні "контрольний невідомо» агрегатні об'єктів. Зазвичай цей IUnknown вказівник передається до об'єкта під час сукупність. Наприклад, параметр pUnkOuter є "контрольний невідомих" для об'єктів, створених з CoCreateInstance. Правильний "контроль невідомого" вказівник можна отримати за номером CCmdTarget::GetControllingUnknown. Значення, що повернувся з цієї функції, однак, це не дійсні під час Конструктор. З цієї причини він запропонував створити ваш агрегати тільки в заміщенням CCmdTarget::OnCreateAggregates, де значення з GetControllingUnknown є надійним, навіть якщо створений з реалізації COleObjectFactory.

Важливо також, що об'єкт маніпулювати кількість правильних посилань під час додавання або звільнення штучних кількість посилань. Щоб переконатися, що у цьому випадку, завжди викликати ExternalAddRef і ExternalRelease , замість того, щоб InternalRelease і InternalAddRef. Це рідкісний для виклику InternalRelease або InternalAddRef на клас, який підтримує агрегації.

Довідкові матеріали

Розширене використання OLE, наприклад, визначення інтерфейсів, свій власний або зміна в рамках впровадження OLE інтерфейсів вимагає використання основний механізм карта інтерфейс.

У цьому розділі описано кожний макрос і API, що використовується для здійснення цих додаткових функцій.

CCmdTarget::EnableAggregation — Опис функції

недійсними EnableAggregation();

Примітка   Викликано цю функцію в конструкторі похідних класів, якщо ви хочете підтримати агрегації OLE для об'єктів цього типу. Це готує спеціальні реалізації IUnknown, що потрібно для aggregatable об'єкти.

CCmdTarget::ExternalQueryInterface — Опис функції

DWORD ExternalQueryInterface (конст недійсними ДАЛЕКИЙ * lpIID, LPVOID ДАЛЕКОГО * 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 необхідно визначити інтерфейс карта виконання файлу (.CPP) з 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