Udostępnij za pośrednictwem


TN038: Wdrożenie IUnknown MFC/OLE

[!UWAGA]

Następujące Uwaga techniczna została zaktualizowana, ponieważ najpierw została uwzględniona w dokumentacji online.W rezultacie niektóre procedur i tematów może być nieaktualne lub nieprawidłowe.Najnowsze informacje zaleca się wyszukać temat zainteresowanie Indeks dokumentacji online.

Istotą OLE 2 jest "OLE Component Object Model" lub modelu COM.W modelu COM zdefiniowano standard obiektów jak współpracujący komunikować się ze sobą.Obejmuje to szczegóły, jakie "obiekt" wygląda, tym jak wysyłane są metody obiektu.COM definiuje również klasy bazowej, pochodną wszystkich klas zgodne COM.Jest to klasa podstawowa IUnknown.Chociaż IUnknown interfejsu jest określone jako klasa C++, COM nie jest specyficzne dla dowolnego jednego języka — może być implementowana w C PASCAL lub w innym języku, który może obsługiwać binarnych układ obiektu COM.

OLE odnosi się do wszystkich klas pochodnych IUnknown jako "Interfejsy". Jest to ważne rozróżnienie od "interfejsu" takie jak IUnknown niesie ze sobą nie wykonania.Po prostu definiuje protokół, przez które komunikację obiektów, nie charakterystykę tych implementacje zrobić.Jest to uzasadnione dla systemu, który umożliwia maksymalną elastyczność.To zadanie MFC firmy implementują domyślne zachowanie programów MFC/C++.

Zrozumienie wykonania MFC firmy IUnknown należy najpierw zrozumieć ten interfejs jest.Uproszczona wersja IUnknown jest określone poniżej:

class IUnknown
{
public:
    virtual HRESULT QueryInterface(REFIID iid, void** ppvObj) = 0;
    virtual ULONG AddRef() = 0;
    virtual ULONG Release() = 0;
};

[!UWAGA]

Niektóre niezbędne konwencja wywołania szczegóły, takie jak __stdcall są opuszczony na tej ilustracji.

AddRef i wersji Członkowskich funkcje kontroli Zarządzanie pamięcią obiektu.COM używa schematu liczenia odwołania do śledzenia obiektów.Nigdy nie odwołań do obiektu bezpośrednio, jak w języku C++.Zamiast tego obiekty COM są zawsze odwoływać za pomocą wskaźnika.Zwolnienie obiektu, gdy właściciel jest wykonywane przy użyciu jego, obiekt Zwolnij Członkowskich nazywa się (w przeciwieństwie do użycia operatora delete, jak będzie wykonywane dla tradycyjnych obiektu C++).Wiele odwołań do jednego obiektu umożliwia odwołanie liczydło zarządzane.Implementacja AddRef i wersji przechowuje licznika odwołań do obiektu — obiekt nie jest usuwany, dopóki jego licznika odwołań osiągnie zero.

AddRefi wersji są dość proste, z punktu widzenia realizacji.Oto trivial implementacji:

ULONG CMyObj::AddRef() 
{ 
    return ++m_dwRef; 
}

ULONG CMyObj::Release() 
{ 
    if (--m_dwRef == 0) 
    {
        delete this; 
        return 0;
    }
    return m_dwRef;
}

QueryInterface Funkcji składowej jest nieco bardziej interesującą.Nie jest to bardzo interesujące obiekt, którego jedynym funkcji elementów członkowskich są AddRef i wersji — byłoby dobrze tell obiektu powinny robić więcej niż IUnknown zawiera.Gdzie jest QueryInterface jest przydatna.Pozwala uzyskać inny "interfejs" dla tego samego obiektu.Interfejsy te zwykle są pochodnymi IUnknown i dodać dodatkowe funkcje, dodając nowe funkcje składowe.Interfejsów COM nigdy nie zmienne zadeklarowane w interfejsie, a wszystkie funkcje składowe są deklarowane jako czysty wirtualnych.Na przykład,

class IPrintInterface : public IUnknown
{
public:
    virtual void PrintObject() = 0;
};

Aby uzyskać IPrintInterface jeśli tylko IUnknown, call IUnknown::QueryInterface za pomocą IID z IPrintInterface.IID jest numerem 128-bitowego, który unikatowo identyfikuje interfejs.Istnieje IID dla każdego interfejsu, który lub OLE.Jeśli pUnk jest wskaźnikiem do IUnknown obiektu, kod, aby pobrać IPrintInterface z może być:

IPrintInterface* pPrint = NULL;
if (pUnk->QueryInterface(IID_IPrintInterface, 
    (void**)&pPrint) == NOERROR)
{
    pPrint->PrintObject();
    pPrint->Release();   
        // release pointer obtained via QueryInterface
}

Wydaje się dość proste, ale jak byłoby zaimplementowaniem obiekt, który obsługuje zarówno IPrintInterface i IUnknown interfejsu?W tym przypadku jest proste, ponieważ IPrintInterface pochodzi bezpośrednio z IUnknown — implementując IPrintInterface, IUnknown jest obsługiwana automatycznie.Na przykład:

class CPrintObj : public CPrintInterface
{
    virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
    virtual ULONG AddRef();
    virtual ULONG Release();
    virtual void PrintObject();
};

Implementacje z AddRef i wersji byłoby dokładnie takie same jak te wdrażane powyżej.CPrintObj::QueryInterface wyglądać mniej więcej tak:

HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
{
    if (iid == IID_IUnknown || iid == IID_IPrintInterface)
    {
        *ppvObj = this;
        AddRef();
        return NOERROR;
    }
    return E_NOINTERFACE;
}

Jak widać, jeśli identyfikator interfejsu (IID) jest rozpoznawany, wskaźnik jest zwracana do obiektu; w przeciwnym razie wystąpi błąd.Ponadto należy zauważyć, że pomyślne QueryInterface skutkuje dorozumianych AddRef.Oczywiście również trzeba zaimplementować CEditObj::Print.To proste ponieważ IPrintInterface wynikające bezpośrednio z IUnknown interfejsu.Jednakże jeśli chciał obsługuje dwa interfejsy, zarówno pochodną IUnknown, należy uwzględnić następujące:

class IEditInterface : public IUnkown
{
public:
    virtual void EditObject() = 0;
};

Chociaż istnieje wiele różnych sposobów, aby zaimplementować klasę wspieranie zarówno IEditInterface i IPrintInterface, w tym przy użyciu języka C++ wielokrotne dziedziczenie, Uwaga ta koncentruje się na użycie klas zagnieżdżonych zaimplementować tę funkcję.

class CEditPrintObj
{
public:
    CEditPrintObj();

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

    class CPrintObj : public IPrintInterface
    {
    public:
        CEditPrintObj* m_pParent;
        virtual HRESULT QueryInterface(REFIID iid, void** ppvObj);
        virtual ULONG AddRef();
        virtual ULONG Release();
    } m_printObj;

    class CEditObj : public IEditInterface
    {
    public:
        CEditPrintObj* m_pParent;
        virtual ULONG QueryInterface(REFIID iid, void** ppvObj);
        virtual ULONG AddRef();
        virtual ULONG Release();
    } m_editObj;
};

Wdrożenie całego znajduje się poniżej:

CEditPrintObj::CEditPrintObj()
{
    m_editObj.m_pParent = this;
    m_printObj.m_pParent = this;
}

ULONG CEditPrintObj::AddRef() 
{ 
    return ++m_dwRef;
}

CEditPrintObj::Release()
{
    if (--m_dwRef == 0)
    {
        delete this;
        return 0;
    }
    return m_dwRef;
}

HRESULT CEditPrintObj::QueryInterface(REFIID iid, void** ppvObj)
{
    if (iid == IID_IUnknown || iid == IID_IPrintInterface)
    {
        *ppvObj = &m_printObj;
        AddRef();
        return NOERROR;
    }
    else if (iid == IID_IEditInterface)
    {
        *ppvObj = &m_editObj;
        AddRef();
        return NOERROR;
    }
    return E_NOINTERFACE;
}

ULONG CEditPrintObj::CEditObj::AddRef() 
{ 
    return m_pParent->AddRef(); 
}

ULONG CEditPrintObj::CEditObj::Release() 
{ 
    return m_pParent->Release(); 
}

HRESULT CEditPrintObj::CEditObj::QueryInterface(
    REFIID iid, void** ppvObj) 
{ 
    return m_pParent->QueryInterface(iid, ppvObj); 
}

ULONG CEditPrintObj::CPrintObj::AddRef() 
{ 
    return m_pParent->AddRef(); 
}

ULONG CEditPrintObj::CPrintObj::Release() 
{ 
    return m_pParent->Release(); 
}

HRESULT CEditPrintObj::CPrintObj::QueryInterface(
    REFIID iid, void** ppvObj) 
{ 
    return m_pParent->QueryInterface(iid, ppvObj); 
}

Należy zauważyć, że większość IUnknown realizacji jest umieszczany w CEditPrintObj klasy, a nie kodu w CEditPrintObj::CEditObj i CEditPrintObj::CPrintObj.To zmniejsza ilość kodu i uniknąć błędów.Tutaj kluczową sprawą jest, że z interfejsu IUnknown jest możliwe wywołanie QueryInterface do pobierania jakichkolwiek interfejs może obsługiwać obiektu i z każdego z tych interfejsów jest możliwe zrobić to samo.Oznacza to, że wszystkie QueryInterface funkcje dostępne każdego interfejsu muszą zachowywać się dokładnie tak samo.Aby wywołać wykonania w "obiektu zewnętrznego" tych obiektów back wskaźnik jest używany (m_pParent).Wskaźnik m_pParent jest inicjowany podczas konstruktora CEditPrintObj.Następnie czy zaimplementować, CEditPrintObj::CPrintObj::PrintObject i CEditPrintObj::CEditObj::EditObject, jak również.Całkiem sporo kodu dodano dodać jedną z funkcji — możliwość edycji obiektu.Na szczęście jest dość rzadko stosowane dla interfejsów, które mają tylko funkcja pojedynczego członka (chociaż zdarzyć) i w tym przypadku EditObject i PrintObject byłyby zazwyczaj połączone do jednego interfejsu.

To jest dużo wyjaśnienie i dużo kodu dla prostych scenariusza.Klas MFC/OLE zapewnić prostsze alternatywę.Wdrożenie MFC wykorzystuje technikę podobnie jak wiadomości systemu Windows są pakowane z mapami wiadomości.Instrument ten jest nazywany Mapy interfejsu jest omówiona w następnej sekcji.

Mapy interfejsu MFC

MFC/OLE obejmuje implementacja "Interfejs mapy" podobny "Mapy wiadomości" i "Mapy wysyłki" MFC firmy w koncepcji i wykonanie.Podstawowe funkcje map interfejsu MFC firmy są następujące:

  • Standardowej implementacji IUnknown, zbudowany do CCmdTarget klasy.

  • Konserwacja licznika odwołań, zmodyfikowany przez AddRef i wersji

  • Wdrożenia opartych na danychQueryInterface

Ponadto mapy interfejs obsługuje następujące zaawansowane funkcje:

  • Obsługa tworzenia kumulowalnych obiektów COM.

  • Obsługa przy użyciu obiektów agregacji w implementacji obiektu COM

  • Wdrożenie jest hookable i rozszerzonego

Aby uzyskać więcej informacji o agregacji, zobacz OLE Programmer's Reference.

Obsługa mapę interfejsu MFC firmy jest umieszczone w CCmdTarget klasy.CCmdTarget"ma w" odwołać count, jak również wszystkie funkcje składowe związane z IUnknown realizacji (liczbę odwołań, na przykład jest w CCmdTarget).Aby utworzyć klasy, która obsługuje OLE COM, wynikają są klasy z CCmdTarget i korzystać z makr w różnych jak również funkcji elementów członkowskich z CCmdTarget do wykonania żądanej interfejsów.Wdrożenie MFC firmy używa klas zagnieżdżonych do definiowania każdej implementacji interfejsu, podobnie jak w powyższym przykładzie.Jest to łatwiejsze przy użyciu standardowej implementacji IUnknown, jak również liczbę wyeliminować niektóre powtarzających się kod makra.

Aby zaimplementować klasę przy użyciu interfejsu MFC firmy mapy

  1. Pochodzić klasy bezpośrednio lub pośrednio od CCmdTarget.

  2. Użyj DECLARE_INTERFACE_MAP funkcji w definicji klasy pochodnej.

  3. Dla każdego interfejsu chcesz obsługiwać, użyj BEGIN_INTERFACE_PART i END_INTERFACE_PART makr w definicji klasy.

  4. W pliku implementacji, użyj BEGIN_INTERFACE_MAP i END_INTERFACE_MAP makra, aby zdefiniować mapę interfejsu klasy.

  5. Dla każdego identyfikatora IID obsługiwane, użyj INTERFACE_PART makro między BEGIN_INTERFACE_MAP i END_INTERFACE_MAP makr do mapowania tego IID określonej klasy "części".

  6. Wdrożenie klas zagnieżdżonych, reprezentujące interfejsów, która jest obsługiwana.

  7. Użyj METHOD_PROLOGUE makro dostępu do nadrzędnej, CCmdTarget-uzyskane obiektu.

  8. AddRef, Wersji, i QueryInterface może delegować do CCmdTarget wykonywania tych zadań (ExternalAddRef, ExternalRelease, i ExternalQueryInterface).

W powyższym przykładzie CPrintEditObj można wdrożyć w następujący sposób:

class CPrintEditObj : public CCmdTarget
{
public:
    // member data and member functions for CPrintEditObj go here

// Interface Maps
protected:
    DECLARE_INTERFACE_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)
};

Powyższej deklaracji tworzy klasę pochodną CCmdTarget.DECLARE_INTERFACE_MAP makra informuje ramy tej klasy że mapę interfejs niestandardowy.Ponadto BEGIN_INTERFACE_PART i END_INTERFACE_PART makra Definiowanie klas zagnieżdżonych, w tym przypadku o nazwach CEditObj i CPrintObj (X jest używany tylko do odróżnienia klas zagnieżdżonych klas globalnych, które zaczynają się klasy "C" i interfejsu, które zaczynają się "I").Tworzone są dwa elementy zagnieżdżone tych klas: m_CEditObj i m_CPrintObj, odpowiednio.Makra automatycznie deklarować AddRef, wersji, i QueryInterface funkcje; Dlatego należy zadeklarować tylko funkcje specyficzne dla tego interfejsu: EditObject i PrintObject (makro OLE STDMETHOD jest używane takie tak, aby _stdcall i wirtualnych słowa kluczowe są dostarczane jako właściwe dla platformy docelowej).

Aby zaimplementować mapę interfejsu dla tej klasy:

BEGIN_INTERFACE_MAP(CPrintEditObj, CCmdTarget)
    INTERFACE_PART(CPrintEditObj, IID_IPrintInterface, PrintObj)
    INTERFACE_PART(CPrintEditObj, IID_IEditInterface, EditObj)
END_INTERFACE_MAP()

To łączy IID_IPrintInterface IID z m_CPrintObj i IID_IEditInterface z m_CEditObj odpowiednio.CCmdTarget Wykonania QueryInterface (CCmdTarget::ExternalQueryInterface) używa tej mapy do zwracania wskaźniki do m_CPrintObj i m_CEditObj na żądanie.Nie jest konieczne, zawierać wpis dla IID_IUnknown; ramy użyje pierwszego interfejsu na mapie (w tym przypadku m_CPrintObj) po IID_IUnknown jest wymagane.

Mimo że BEGIN_INTERFACE_PART makro automatycznie zadeklarowane AddRef, wersji i QueryInterface funkcji można nadal trzeba je:

ULONG FAR EXPORT CEditPrintObj::XEditObj::AddRef()
{
    METHOD_PROLOGUE(CEditPrintObj, EditObj)
    return pThis->ExternalAddRef();
}

ULONG FAR EXPORT CEditPrintObj::XEditObj::Release()
{
    METHOD_PROLOGUE(CEditPrintObj, EditObj)
    return pThis->ExternalRelease();
}

HRESULT FAR EXPORT CEditPrintObj::XEditObj::QueryInterface(
    REFIID iid, void FAR* FAR* ppvObj)
{
    METHOD_PROLOGUE(CEditPrintObj, EditObj)
    return (HRESULT)pThis->ExternalQueryInterface(&iid, ppvObj);
}

void FAR EXPORT CEditPrintObj::XEditObj::EditObject()
{
    METHOD_PROLOGUE(CEditPrintObj, EditObj)
    // code to "Edit" the object, whatever that means...
}

Wykonania na CEditPrintObj::CPrintObj, będzie podobna do powyższych definicji dla CEditPrintObj::CEditObj.Chociaż byłoby możliwe utworzyć makro, które można użyć do automatycznego generowania te funkcje (ale wcześniej w rozwoju MFC/OLE to było w przypadku), będzie trudno ustawić punkty przerwania, gdy makro generuje więcej niż jedną linię kodu.Z tego powodu ten kod jest rozwinięty ręcznie.

Za pomocą ramy realizacji mapy wiadomości, istnieje kilka rzeczy, które nie były konieczne:

  • Wdrożenie QueryInterface

  • AddRef wdrożenie i zwolnienia

  • Stwierdzenie każdej z tych metod wbudowanych w obu interfejsach użytkownika

Ponadto ramach wewnętrznie mapy wiadomości.Umożliwia to pochodzi od klasy RAM, powiedz COleServerDoc, który już obsługuje niektóre interfejsy i zapewnia wymianach lub uzupełnienia z interfejsów dostarczanych w ramach.Ta opcja jest włączona przez fakt, że w ramach w pełni obsługuje dziedziczenie z mapy interfejsu z klasy bazowej — dlaczego jest to przyczyna BEGIN_INTERFACE_MAP przyjmuje jako drugi parametr Nazwa klasy podstawowej.

[!UWAGA]

Ogólnie nie jest możliwe ponowne wykonania MFC firmy wbudowanych implementacji interfejsów OLE przez dziedziczenie osadzone specjalizacji tego interfejsu z wersji MFC.Nie jest to możliwe ponieważ wykorzystanie METHOD_PROLOGUE makra, aby uzyskać dostęp do zawierających CCmdTarget-pochodnych obiektu pociąga za sobą ustalone przesunięcie obiektu osadzonego z CCmdTarget-uzyskane obiektu.Nie oznacza to, na przykład, można wyznaczyć osadzony XMyAdviseSink z wdrożenia MFC firmy w COleClientItem::XAdviseSink, ponieważ XAdviseSink korzysta z przesunięciem określonej z góry z COleClientItem obiektu.

[!UWAGA]

Jednakże można przekazać wykonania MFC, wszystkie funkcje, w której MFC firmy domyślne zachowanie.Jest to wykonywane w realizacji MFC IOleInPlaceFrame (XOleInPlaceFrame) w COleFrameHook klasy (przekazuje do m_xOleInPlaceUIWindow dla wielu funkcji).Ten projekt został wybrany do zmniejszenia rozmiaru runtime obiektów, które realizują wiele interfejsów; (takie jak m_pParent sposób został użyty w poprzedniej sekcji), eliminuje potrzebę back wskaźnik.

5hhehwba.collapse_all(pl-pl,VS.110).gifAgregacja i mapy interfejsu

Oprócz obsługi autonomicznych obiektów COM, MFC obsługuje agregacji.Agregacja sam jest zbyt złożona temat dyskutować na miejscu; odnoszą się do OLE Programmer's Reference więcej informacji na temat agregacji.Uwaga ta po prostu opisano obsługę agregacji wbudowana w interfejs i ramy mapy.

Istnieją dwa sposoby używania agregacji: (1) przy użyciu obiektu COM, który obsługuje agregacji i (2) realizacji mogą zostać zagregowane przez inny obiekt.Funkcje te można dalej jako "przy użyciu obiektu agregacji" i "making, obiekt będzie kumulowalnych".MFC obsługuje zarówno.

5hhehwba.collapse_all(pl-pl,VS.110).gifZa pomocą obiektu agregacji

Aby użyć obiektu agregacji tam musi być w jakiś sposób powiązać agregatu do mechanizmu QueryInterface.Innymi słowy obiekt agregacji musi zachowują się tak, jakby jest macierzystym części obiektu.W jaki sposób wiązania do interfejsu MFC firmy mapę mechanizm?Oprócz INTERFACE_PART makro, w przypadku gdy zagnieżdżony obiekt jest mapowany na IID można również zadeklarować agregacji obiektu jako część sieci CCmdTarget klasy.Aby to zrobić, INTERFACE_AGGREGATE makro jest używany.Pozwala określić zmienną (który musi być wskaźnik do IUnknown lub klasy), które ma być zintegrowane z mechanizmu mapę interfejsu.Jeżeli wskaźnik jest nie zerowa, gdy CCmdTarget::ExternalQueryInterface jest wywoływana, ramy będzie automatycznie wywoływać agregacji obiektu QueryInterface Członkowskich działać, jeśli IID żądanie nie jest jednym z macierzystego IIDs obsługiwana przez CCmdTarget samego obiektu.

Aby użyć makra INTERFACE_AGGREGATE

  1. Zadeklarować zmienną ( IUnknown *) zawierający wskaźnik do obiektu agregacji.

  2. Zawiera INTERFACE_AGGREGATE makro w mapie interfejsu odnosi się do zmiennej Członkowskie według nazwy.

  3. W pewnym momencie (zwykle w ciągu CCmdTarget::OnCreateAggregates), Zainicjuj zmienną na inne niż NULL.

Na przykład:

class CAggrExample : public CCmdTarget
{
public:
    CAggrExample();

protected:
    LPUNKNOWN m_lpAggrInner;
    virtual BOOL OnCreateAggregates();

    DECLARE_INTERFACE_MAP()
    // "native" interface part macros may be used here
};

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

BOOL CAggrExample::OnCreateAggregates()
{
    // wire up aggregate with correct controlling unknown
    m_lpAggrInner = CoCreateInstance(CLSID_Example,
        GetControllingUnknown(), CLSCTX_INPROC_SERVER,
        IID_IUnknown, (LPVOID*)&m_lpAggrInner);
    if (m_lpAggrInner == NULL)
        return FALSE;
    // optionally, create other aggregate objects here
    return TRUE;
}

BEGIN_INTERFACE_MAP(CAggrExample, CCmdTarget)
    // native "INTERFACE_PART" entries go here
    INTERFACE_AGGREGATE(CAggrExample, m_lpAggrInner)
END_INTERFACE_MAP()

m_lpAggrInner Jest inicjowana w konstruktorze NULL.Ramy zignoruje zmienną w realizacji domyślnej NULL QueryInterface.OnCreateAggregates jest dobrym miejscem do faktycznie tworzyć obiekty agregacji.Trzeba będzie go jawnie wywołana podczas tworzenia obiektu poza z wykonania MFC COleObjectFactory.Przyczyny utworzenia kruszywa w CCmdTarget::OnCreateAggregates jak również użycie CCmdTarget::GetControllingUnknown staną się widoczne podczas tworzenia obiektów kumulowalnych omówiono.

Ta technika da obiekt, wszystkie interfejsy, które obsługuje agregacji obiektu plus jego macierzyste interfejsy.Jeśli chcesz tylko podzbiór interfejsów, które obsługuje agregacji, można zastąpić CCmdTarget::GetInterfaceHook.Pozwala to bardzo niskiego poziomu hookability, podobne do QueryInterface.Zazwyczaj jest wszystkich interfejsów, które obsługuje agregacji.

5hhehwba.collapse_all(pl-pl,VS.110).gifDokonanie kumulowalnych implementacja obiektu

Dla obiektu być kumulowane, wykonania AddRef, wersji, i QueryInterface musi przekazać "Nieznany kontroli". Innymi słowy, jej część obiektu, to musi przekazać AddRef, wersji, i QueryInterface do innego obiektu, również otrzymanych z IUnknown.To "Nieznany kontroli" jest pod warunkiem, że do obiektu podczas jego tworzenia, oznacza to, że to będzie udostępniane wykonania COleObjectFactory.Implementacja tego prowadzi niewielką ilość narzutów, a w niektórych przypadkach nie jest pożądane, więc MFC czyni to opcjonalny.Aby włączyć obiekt być kumulowane, należy wywołać CCmdTarget::EnableAggregation z konstruktora obiektu.

Jeśli obiekt korzysta również agregatów, również należy upewnić się, że przechodzą prawidłowego "kontrolującego nieznany" do agregacji obiektów.Zazwyczaj to IUnknown wskaźnik jest przekazywana do obiektu, gdy jest tworzona suma.Na przykład parametr pUnkOuter jest "Nieznany kontroli" dla obiektów utworzonych za pomocą CoCreateInstance.Poprawne wskaźnik "kontrolowanie unknown" mogą być pobierane przez wywołanie CCmdTarget::GetControllingUnknown.Wartość zwracana z tej funkcji, jednak nie jest prawidłowe podczas konstruktora.Z tego powodu zalecane jest, tworzenie sieci agregatów tylko w nadpisanie CCmdTarget::OnCreateAggregates, gdzie wartość zwrot z GetControllingUnknown jest wiarygodne, nawet jeśli utworzony z COleObjectFactory wdrożenia.

Jest również ważne, że obiekt manipulować licznika odwołań poprawne, przy dodawaniu lub zwalniania zliczanie odwołań sztuczne.W celu zapewnienia, w przypadku, wywoływanie zawsze ExternalAddRef i ExternalRelease zamiast InternalRelease i InternalAddRef.Rzadko call InternalRelease lub InternalAddRef na klasy, która obsługuje agregacji.

5hhehwba.collapse_all(pl-pl,VS.110).gifMateriał odniesienia

Zaawansowane wykorzystanie OLE, takich jak Definiowanie własnych interfejsów lub przesłanianie ramy realizacji interfejsy OLE wymaga użycia mechanizmu mapę podstawowego interfejsu.

W tej części omówiono każde makro i interfejsów API, który jest używany do wykonania tych zaawansowanych funkcji.

5hhehwba.collapse_all(pl-pl,VS.110).gifCCmdTarget::EnableAggregation — Funkcja opis

void EnableAggregation();

Uwagi

Wywołanie tej funkcji w konstruktorze klasy pochodnej, jeśli chcesz obsługuje agregacji OLE dla obiektów tego typu.Przygotowuje się specjalne implementacji IUnknown, który jest wymagany dla obiektów kumulowalnych.

5hhehwba.collapse_all(pl-pl,VS.110).gifCCmdTarget::ExternalQueryInterface — Funkcja opis

DWORD ExternalQueryInterface( 
   const void FAR* lpIID, 
   LPVOID FAR* ppvObj 
);

Uwagi

5hhehwba.collapse_all(pl-pl,VS.110).gifParametry

  • lpIID
    Wskaźnik far IID (pierwszy argument do metody QueryInterface)

  • ppvObj
    Wskaźnik IUnknown * (drugi argument do metody QueryInterface)

Uwagi

Wywołanie tej funkcji w danej implementacji IUnknown dla każdego interfejsu klasy implementuje.Ta funkcja zapewnia standardowej implementacji sterowanych danymi QueryInterface oparte na mapie interfejsu użytkownika obiektu.Jest zwracana wartość HRESULT oddanych.Obiekt jest zagregowane, ta funkcja wywoła "IUnknown kontroli" zamiast mapy interfejsu lokalnego.

5hhehwba.collapse_all(pl-pl,VS.110).gifCCmdTarget::ExternalAddRef — Funkcja opis

DWORD ExternalAddRef();

Uwagi

Wywołanie tej funkcji w danej implementacji IUnknown::AddRef dla każdego interfejsu klasy implementuje.Wartość zwracana jest nową liczbę odwołań do obiektu CCmdTarget.Jeśli obiekt jest zagregowane, ta funkcja będzie wywoływać "IUnknown kontroli" zamiast manipulowania licznika odwołań lokalnych.

5hhehwba.collapse_all(pl-pl,VS.110).gifCCmdTarget::ExternalRelease — Funkcja opis

DWORD ExternalRelease();

Uwagi

Wywołanie tej funkcji w danej implementacji IUnknown::Release dla każdego interfejsu klasy implementuje.Zwracana wartość wskazuje nowy licznika odwołań do obiektu.Jeśli obiekt jest zagregowane, ta funkcja będzie wywoływać "IUnknown kontroli" zamiast manipulowania licznika odwołań lokalnych.

5hhehwba.collapse_all(pl-pl,VS.110).gifDECLARE_INTERFACE_MAP — Opis makra

DECLARE_INTERFACE_MAP

Uwagi

Użyj tego makra w dowolnej klasy pochodne CCmdTarget będzie mapę interfejsu.W podobny sposób jak DECLARE_MESSAGE_MAP.Wywołania tego makra, należy umieścić w definicji klasy, zwykle w nagłówku (.H) pliku.Klasy z DECLARE_INTERFACE_MAP należy zdefiniować mapę interfejsu w pliku implementacji (.CPP) z BEGIN_INTERFACE_MAP i END_INTERFACE_MAP makr.

5hhehwba.collapse_all(pl-pl,VS.110).gifBEGIN_INTERFACE_PART i END_INTERFACE_PART — opisy makra

BEGIN_INTERFACE_PART( 
   localClass,
   iface 
);
END_INTERFACE_PART( 
   localClass 
)

Uwagi

5hhehwba.collapse_all(pl-pl,VS.110).gifParametry

  • localClass
    Nazwa klasy, która implementuje interfejs

  • face
    Nazwa interfejsu, który implementuje tej klasy

Uwagi

Dla każdego interfejsu, który wprowadzi klasy, musisz mieć BEGIN_INTERFACE_PART i END_INTERFACE_PART para.Te makra zdefiniować lokalnych klasy pochodzącej z interfejsu OLE, określające jak również osadzone zmienną tej klasy.AddRef, Wersji, i QueryInterface członków zgłaszane są automatycznie.Musi zawierać deklaracje dla innych Członkowskich funkcje interfejs realizowane (deklaracje te są umieszczane między BEGIN_INTERFACE_PART i END_INTERFACE_PART makr).

Iface argument jest interfejs OLE, który chcesz wdrożyć, takich jak IAdviseSink, lub IPersistStorage (lub interfejs niestandardowy).

LocalClass argument jest nazwą lokalnego klasy, która zostanie zdefiniowana."X" będzie automatycznie zostać dołączona do nazwy.Konwencja nazewnictwa jest używany w celu uniknięcia kolizji z globalnego klas o tej samej nazwie.Ponadto, Nazwa osadzonego elementu członkowskiego, taki sam, jak localClass nazwy, z wyjątkiem prefiks 'm_x'.

Na przykład:

BEGIN_INTERFACE_PART(MyAdviseSink, IAdviseSink)
   STDMETHOD_(void,OnDataChange)(LPFORMATETC, LPSTGMEDIUM);
   STDMETHOD_(void,OnViewChange)(DWORD, LONG);
   STDMETHOD_(void,OnRename)(LPMONIKER);
   STDMETHOD_(void,OnSave)();
   STDMETHOD_(void,OnClose)();
END_INTERFACE_PART(MyAdviseSink)

Definiuje klasy lokalnej o nazwie XMyAdviseSink, pochodzące z IAdviseSink i jest członkiem klasy, w którym jest on zadeklarowany jako o nazwie m_xMyAdviseSink.Note:

[!UWAGA]

Linie, począwszy od STDMETHOD_ zasadniczo są kopiowane z OLE2.H i nieco zmodyfikowany.Kopiowanie ich z OLE2.H można zmniejszyć błędów, które są trudne do rozwiązania.

5hhehwba.collapse_all(pl-pl,VS.110).gifBEGIN_INTERFACE_MAP i END_INTERFACE_MAP — opisy makra

BEGIN_INTERFACE_MAP( 
   theClass,
   baseClass 
)
END_INTERFACE_MAP

Uwagi

5hhehwba.collapse_all(pl-pl,VS.110).gifParametry

  • theClass
    Klasę, mapę interfejsu jest określane

  • baseClass
    Klasa, z której theClass pochodzi z.

Uwagi

BEGIN_INTERFACE_MAP i END_INTERFACE_MAP makra są używane w pliku implementacji faktycznie zdefiniowanie mapę interfejsu.Dla każdego interfejsu, który jest implementowany istnieje jeden lub więcej INTERFACE_PART wywołania makra.Dla każdego agregatu używa tej klasy jest jeden INTERFACE_AGGREGATE wywołania makra.

5hhehwba.collapse_all(pl-pl,VS.110).gifINTERFACE_PART — Opis makra

INTERFACE_PART( 
   theClass,
   iid, 
   localClass 
)

Uwagi

5hhehwba.collapse_all(pl-pl,VS.110).gifParametry

  • theClass
    Nazwa klasy, która zawiera mapę interfejsu.

  • iid
    IID to być mapowane na klasy osadzonego.

  • localClass
    Nazwa lokalnego klasy (mniej "X").

Uwagi

To makro jest używana między BEGIN_INTERFACE_MAP makro i END_INTERFACE_MAP będzie obsługę makr dla każdego interfejsu obiektu.Umożliwia mapowanie IID do członka klasy, oznaczone theClass i localClass."m_x", które zostaną dodane do localClass automatycznie.Należy zauważyć, że więcej niż jeden IID może być skojarzony z jednego członka.Jest to bardzo przydatne, wdrażają tylko interfejs "najbardziej pochodne" i chcą zapewniają również wszystkie interfejsy pośrednich.Dobrym przykładem jest IOleInPlaceFrameWindow interfejsu.Jego hierarchii wygląda następująco:

IUnknown
    IOleWindow
        IOleUIWindow
            IOleInPlaceFrameWindow

Jeśli obiekt implementuje IOleInPlaceFrameWindow, klient może QueryInterface na żadnym z tych interfejsów: IOleUIWindow, IOleWindow, lub IUnknown, oprócz interfejsu "najbardziej pochodnych" IOleInPlaceFrameWindow (jeden są faktycznie wykonawczych).Do obsługi tego można użyć więcej niż jeden INTERFACE_PART makro mapować każdy interfejs podstawowy do IOleInPlaceFrameWindow interfejsu:

w pliku definicji klasy:

BEGIN_INTERFACE_PART(CMyFrameWindow, IOleInPlaceFrameWindow)

Plik implementacji klasy:

BEGIN_INTERFACE_MAP(CMyWnd, CFrameWnd)
    INTERFACE_PART(CMyWnd, IID_IOleWindow, MyFrameWindow)
    INTERFACE_PART(CMyWnd, IID_IOleUIWindow, MyFrameWindow)
    INTERFACE_PART(CMyWnd, IID_IOleInPlaceFrameWindow, MyFrameWindow)
END_INTERFACE_MAP

Ramy dba o IUnknown, ponieważ wymagana jest zawsze.

5hhehwba.collapse_all(pl-pl,VS.110).gifINTERFACE_PART — Opis makra

INTERFACE_AGGREGATE( 
   theClass,
   theAggr 
)

Uwagi

5hhehwba.collapse_all(pl-pl,VS.110).gifParametry

  • theClass
    Nazwa klasy, która zawiera mapę interfejsu

  • theAggr
    Nazwa zmienna członka, który ma zostać zagregowana.

Uwagi

To makro umożliwia tell ramach klasy używa obiektu agregacji.Musi znajdować się między BEGIN_INTERFACE_PART i END_INTERFACE_PART makr.Obiekt agregacji jest oddzielny obiekt pochodzące z IUnknown.Za pomocą zagregowane i INTERFACE_AGGREGATE makra, można wprowadzić wszystkich interfejsów, które obsługuje agregacji są bezpośrednio obsługiwane przez obiekt.TheAggr argument jest po prostu nazwą zmienną, która jest pochodną klasy IUnknown (bezpośrednio lub pośrednio).Wszystkie INTERFACE_AGGREGATE należy wykonać makra INTERFACE_PART makra umieszczone na mapie interfejsu.

Zobacz też

Inne zasoby

Uwagi techniczne przez liczbę

Uwagi techniczne według kategorii