TN038: MFC/OLE IUnknown wykonania

Sercem OLE 2 jest "OLE Component Object Model" lub COM. COM zdefiniowano standard dla obiektów jak współpracujący komunikować się ze sobą. Obejmuje to szczegóły "obiekt" wygląda jak, włączając, jak metody są wysyłane na obiekt. W modelu COM zdefiniowano także klasy bazowej, od których uzyskiwane są wszystkie zgodne klas COM. Ta klasa podstawowa jest IUnknown. Mimo że interfejs IUnknown jest określany jako klasa C++, COM nie jest specyficzny dla jednego języka — może być implementowana w C, PASCAL lub w jakimkolwiek innym języku, który może obsługiwać binarnych układ obiektu COM.

OLE odnosi się do wszystkich klas pochodzi od elementu IUnknown jako "interfejsów." Ważne rozróżnienie, to jest od "interfejsu", takich jak IUnknown przenosi implementacja nie. Definiuje on po prostu przez które obiekty komunikować, nie specyfika czego tych implementacji protokołu. Jest to uzasadnione na system, umożliwiający maksymalną elastyczność. To zadanie MFC firmy implementują domyślne zachowanie dla programów MFC/C++.

Zrozumienie MFC firmy o realizacji IUnknown musi najpierw zrozumieć, co to jest interfejs. Uproszczoną wersją IUnknown jest określone poniżej:

 klasa IUnknown
{
publiczne:
 nbsp;  wirtualny QueryInterface(REFIID iid, void** ppvObj) HRESULT = 0;
    wirtualny ULO&NG AddRef() obiektu = 0;
    wirtualny ULONG Release() = 0;
}

Uwaganbsp;  &Niektóre niezbędne wywołującego Konwencji szczegóły, takie jak __stdcall pozostają na tej ilustracji.

Funkcje składowe AddRef i uwalniania kontroli zarządzania pamięcią obiektu. COM używa schematu liczenia odwołania do śledzenia obiektów. Nigdy nie odwołuje się obiekt bezpośrednio, podobnie jak w języku C++. Zamiast tego obiektów COM są zawsze odwoływać za pomocą wskaźnika. Aby zwolnić obiektu, gdy właściciel jest wykonywane za pomocą je, obiektu Zwolnij Państwa jest nazywane (w przeciwieństwie do przy użyciu operatora delete, jak spowodowałoby dla tradycyjnych obiektu C++). Zliczanie mechanizm odwołań pozwala na wiele odwołań do jednego obiektu do zarządzanych. Implementacja AddRef i zwolnienia przechowuje licznika odwołań do obiektu — obiekt nie zostanie usunięty, dopóki jego licznika odwołań osiągnie zero.

AddRef i wydania są stosunkowo proste, z punktu widzenia realizacji. Tutaj jest trywialny wykonania:

ULO&NG CMyObj::AddRef() {nbsp;  Zwraca ++ m_dwRef; 
}

ULONG CMyObj::Release() {Jeżeli (--m_dwRef == 0) {}
        usunąć; 
        zwrócona wartość 0;
    }
    Zwraca m_dwRef;
}

Funkcja QueryInterface Państwa jest nieco bardziej interesujące. Jak można sobie wyobrazić, nie jest bardzo ciekawe jest obiekt, którego tylko funkcje składowe są AddRef i Release — byłoby miło stwierdzić obiektu do robienia rzeczy więcej niż IUnknown . Jest to, gdzie QueryInterface jest przydatne. Pozwala uzyskać inny "interfejs" dla tego samego obiektu. Te interfejsy są zazwyczaj pochodzi od elementu 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,

klasa IPri&ntInterface: publiczne IUnknown
{
publiczne:
 nbsp;  wirtualny PrintObject() void = 0;
}

Aby uzyskać IPrintInterface, jeśli masz tylko IUnknown, wywołanie IUnknown::QueryInterface przy użyciu IID IPrintInterface. Identyfikator IID jest liczbą 128-bitowego, który unikatowo identyfikuje interfejs. Istnieje IID dla każdego interfejsu, który użytkownik lub OLE. Jeśli pUnk jest wskaźnik do obiektu IUnknown , kod do pobierania IPrintInterface z niego może być

IPrintInterface * pPrint = NULL;
Jeżeli (pUnk BT;QueryInterface(IID_IPrintInterface, (void**) & pPrint) == NOERROR)
{
    pPrint - > PrintObject();
    pPrint - > Release();   
        / / wskaźnik wydania uzyskanych za pośrednictwem metody QueryInterface
}

Wydaje się stosunkowo proste, ale jak byłoby zaimplementowaniem obiekt, który obsługuje interfejs zarówno IPrintInterface, jak i IUnknown ? W tym przypadku to proste ponieważ IPrintInterface pochodzi bezpośrednio od elementu IUnknown — poprzez wdrożenie IPrintInterface, IUnknown jest automatycznie obsługiwane. Na przykład:

 klasa CPrintObj: CPrintInterface publicznych
{
 nbsp;  wirtualny HRESULT QueryInterface(REFIID iid, void** ppvObj);
    wirtualny ULO&NG AddRef() obiektu;
    wirtualny ULONG Release();
    wirtualny PrintObject() void;
}

Implementacje AddRef i zwolnienia byłoby dokładnie takie same, jak te, które są realizowane powyżej. CPrintObj::QueryInterface będzie wyglądać mniej więcej tak

HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
{
 nbsp;  Jeżeli (iid == IID_IUnknown || iid == IID_IPrintInterface)
    {
        * ppvObj =;
        AddRef() obiektu;
        Zwraca &NOERROR;
    }
    Zwraca ResultFromScode(E_NOINTERFACE);
}

Jak można zauważyć, jeśli identyfikator interfejsu (IID) jest rozpoznawana, wskaźnik zwracany jest obiekt; w przeciwnym razie wystąpi błąd. Należy również zauważyć, że skuteczne metody QueryInterface skutkuje domniemanych AddRef. Oczywiście również będzie mieć wykonania CEditObj::Print. To proste, ponieważ IPrintInterface pochodzi bezpośrednio w interfejsie IUnknown . Jednakże jeśli chciał obsługuje dwa różne interfejsy, zarówno pochodzące od elementu IUnknown, rozważ następujące

klasa IEditI&nterface: IUnkown publicznych
{
publiczne:
 nbsp;  wirtualny EditObject() void = 0;
}

Chociaż istnieje wiele różnych sposobów aby zaimplementować klasę wspieranie zarówno IEditInterface, jak i IPrintInterface, łącznie z pomocą C++ wielokrotne dziedziczenie, niniejsza Uwaga skoncentruje się na użycie klas zagnieżdżonych do wykonania tej funkcji.

klasa CEditPrintObj
{
publiczne:
 nbsp;  CEditPrintObj();

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

Klasa CPrintObj: IPrintInterface publicznych
    {
    publiczne:
        CEditPrintObj * m_pParent;
        wirtualny HRESULT QueryInterface(REFIID iid, void** ppvObj);
        wirtualny ULONG AddRef() obiektu;
        wirtualny ULONG Release();
    } m_printObj;

Klasa CEditObj: IEditInterface publicznych
    {
    publiczne:
        CEditPrintObj * m_pParent;
        wirtualny ULONG QueryInterface(REFIID iid, void** ppvObj);
        wirtualny ULONG AddRef() obiektu;
        wirtualny ULONG Release();
    } m_editObj;
}

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

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

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

CEditPrintObj::Release()
{
    Jeżeli (--m_dwRef == 0)
    {
        usunąć;
        zwrócona wartość 0;
    }
    Zwraca m_dwRef;
}

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

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

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

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

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

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

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

Należy zauważyć, że większość realizacji IUnknown jest umieszczany w klasę CEditPrintObj , a nie powielanie kod w CEditPrintObj::CEditObj i CEditPrintObj::CPrintObj. To zmniejsza ilość kodu i pozwala uniknąć błędów. Kluczowym punktem tutaj jest, że z interfejsu IUnknown jest możliwość wywołania metody QueryInterface pobrać interfejsu, którą obiekt może obsługiwać, i z każdego z tych interfejsów jest możliwe zrobić to samo. Oznacza to, że wszystkie metody QueryInterface funkcje dostępne w każdym interfejsie musi zachowywać się dokładnie w ten sam sposób. Aby te obiekty osadzone wywołać wykonania w "obiekt zewnętrzny" wskaźnik wstecz jest używany (m_pParent). Wskaźnik m_pParent jest inicjowany podczas konstruktora CEditPrintObj. Następnie zaimplementowaniem byłyby, CEditPrintObj::CPrintObj::PrintObject i CEditPrintObj::CEditObj::EditObject jak również. Dość bitowy kod został dodany do dodać jedną funkcji — możliwość edycji obiektu. Na szczęście, jest dość rzadko dla interfejsów mają tylko funkcję pojedynczego członka (chociaż się zdarzyć) i w tym przypadku, EditObject i PrintObject będzie zazwyczaj być połączone do jednego interfejsu.

Jest wiele wyjaśnienie i dużo kodu dla takiego scenariusza proste. Klas MFC/OLE zapewniają alternatywa prostszych. Wdrożenie MFC wykorzystuje technikę podobny do sposobu, w jaki system Windows wiadomości są pakowane z mapami wiadomości. Ten instrument nazywa się Interfejs map i została omówiona w następnej sekcji.

MFC interfejs map

MFC/OLE zawiera implementacja "Interfejs map" podobne "Maps wiadomości" i "Maps wysyłki" MFC firmy w koncepcji i wykonanie. Oto podstawowe funkcje MFC firmy interfejs map:

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

Więcej informacji na temat agregacji na ten temat można znaleźć w OLE Programmer's Reference.

MFC firmy interfejsu mapę wsparcia jest zakorzenione w klasie CCmdTarget . CCmdTarget "został w" odwołać się hrabia, jak również wszystkie funkcje składowe, związanych z realizacją IUnknown (licznika odwołań na przykład znajduje się w CCmdTarget). Aby utworzyć klasy, która obsługuje OLE COM, pochodną klasy CCmdTarget i za pomocą różnych makra jak również funkcje składowe 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. To jest łatwiejsze przy użyciu standardowej implementacji IUnknown, jak również wiele makr, które wyeliminować niektóre powtarzających się kodu.

Interfejs mapę podstawy

Aby zaimplementować klasę przy użyciu interfejsu MFC firmy mapy wykonaj następujące kroki:

  1. Czerpią klasy bezpośrednio lub pośrednio z CCmdTarget.

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

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

  4. W pliku implementacji używać makr BEGIN_INTERFACE_MAP i END_INTERFACE_MAP do zdefiniowania klasy interfejsu mapę.

  5. Dla każdego identyfikatora IID obsługiwane użyć makra INTERFACE_PART między BEGIN_INTERFACE_MAP i END_INTERFACE_MAP makra do mapowania tego IID do konkretnych "części" klasy.

  6. Wdrożenie każdej z klas zagnieżdżonych, które stanowią interfejsy, które obsługujesz.

  7. Dostęp do obiektu nadrzędnego, CCmdTargetza pomocą makra METHOD_PROLOGUE -pochodnych obiektu.

  8. AddRef, wydaniei metody QueryInterface można delegować do wykonania CCmdTarget te funkcje (ExternalAddRef, ExternalReleasei ExternalQueryInterface).

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

klasa CPrintEditObj: CCmdTarget publicznych
{
publiczne:
 nbsp;  / / danych i funkcje składowe dla CPrintEditObj go tutaj

/ / Interfejs map
chronione:
    DECLARE_I&NTERFACE_MAP()

BEGIN_INTERFACE_PART (EditObj, IEditInterface)
        STDMETHOD_ (nieważny, EditObject)();
    END_INTERFACE_PART(EditObj)

BEGIN_INTERFACE_PART (PrintObj, IPrintInterface)
        STDMETHOD_ (nieważny, PrintObject)();
    END_INTERFACE_PART(PrintObj)
}

Powyższej deklaracji tworzy klasę pochodną CCmdTarget. Makra DECLARE_INTERFACE_MAP mówi ramy, że ta klasa mapy niestandardowego interfejsu. Ponadto makra BEGIN_INTERFACE_PART i END_INTERFACE_PART definiowanie klas zagnieżdżonych, w tym przypadku o nazwach CEditObj i CPrintObj (X jest używana tylko do rozróżniania klas zagnieżdżonych z globalnego klas, które zaczynają się "C" i klas interfejsu, które zaczynają się "I"). Tworzone są dwa zagnieżdżone członków tych klas: m_CEditObj i m_CPrintObj, odpowiednio. Makra deklarowane automatycznie AddRef, wydaniei funkcji QueryInterface ; w związku z tym 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 odpowiednie dla platformy docelowej).

Aby zaimplementować mapę interfejsu dla tej klasy:

BEGI&N_INTERFACE_MAP (CPrintEditObj, CCmdTarget)
 nbsp;  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 życie QueryInterface (CCmdTarget::ExternalQueryInterface) używa tej mapy w celu zwrócenia wskaźniki do m_CPrintObj i m_CEditObj na żądanie. Nie jest konieczne dołączyć wpis do IID_IUnknown; ramach użyje pierwszego interfejsu na mapie (w tym przypadku m_CPrintObj) Jeżeli wnioskuje się o IID_IUnknown.

Nawet jeśli makro BEGIN_INTERFACE_PART automatycznie zadeklarowane AddRef, wydanie i funkcji QueryInterface dla Ciebie, nadal konieczne do ich wykonania:

ULONG DALEKO eksportu CEditPrintObj::XEditObj::AddRef()
{
 nbsp;  METHOD_PROLOGUE (CEditPrintObj, EditObj)
    Zwraca pThis - > ExternalAddRef();
}

ULONG DALEKO eksportu CEditPrintObj::XEditObj::Release()
{
    METHOD_PROLOGUE (CEditPrintObj, EditObj)
    Zwraca pThis - > ExternalRelease();
}

HRESULT DALEKO wywozu CEditPrintObj::XEditObj::QueryInterface (
    REFIID iid, nieważne FAR * FAR * ppvObj)
{
    METHOD_PROLOGUE (CEditPrintObj, EditObj)
    Zwraca (HRESULT) pThis - > ExternalQueryInterface (& iid, ppvObj);
}

Unieważnij DALEKO eksportu CEditPrintObj::XEditObj::EditObject()
{
    METHOD_PROLOGUE (CEditPrintObj, EditObj)
    / / kod "Edit" obiektu, niezależnie od środków...
}

Wykonania na CEditPrintObj::CPrintObj, byłoby podobne do powyższych definicji dla CEditPrintObj::CEditObj. Chociaż byłoby możliwe utworzenie makra, która może być używana do automatycznego generowania tych funkcji (w rzeczywistości wcześniej w rozwoju MFC/OLE to było w przypadku), trudno jest ustawić punkty przerwania, gdy makro generuje więcej niż jednej linii kodu. Z tego powodu ten kod jest rozwinięty ręcznie.

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

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

Uwaganbsp;  Ogólnie nie jest możliwe ponowne wykonanie MFC firmy wbudowanych implementacji interfejsów OLE przez dziedziczenie osadzone specjalizacji interfejsu z wersji MFC. &Nie jest to możliwe ponieważ użycie makra METHOD_PROLOGUE w celu uzyskania dostępu do zawierające CCmdTarget-pochodną obiektu pociąga za sobą stałe przesunięcie obiektu osadzonego z CCmdTarget-pochodnych obiektu. Oznacza to na przykład nie wynikają osadzone XMyAdviseSink z MFC firmy wykonania w COleClientItem::XAdviseSink, ponieważ XAdviseSink opiera się na na określone przesunięcie od górnej krawędzi obiektu COleClientItem.

Jednakże można przekazać realizację MFC dla wszystkich funkcji ma MFC firmy domyślne zachowanie. Robi się to w wykonaniu MFC IOleInPlaceFrame (XOleInPlaceFrame) w klasie COleFrameHook (przekazuje do m_xOleInPlaceUIWindow dla wielu funkcji). Ten projekt został wybrany do zmniejszenia rozmiaru runtime obiektów, które implementuje wiele interfejsów; eliminuje potrzebę oparcia wskaźnik (takie jak m_pParent sposób został użyty w poprzedniej sekcji).

Agregacja i interfejs map

Oprócz obsługi autonomicznych obiektów COM, MFC obsługuje również agregacji. Agregacja, sam jest zbyt skomplikowane tematu do omówienia tutaj; odnoszą się do OLE Programmer's Reference więcej informacji na temat agregacji. Uwaga ta po prostu będzie opisywać wsparcie dla agregacji wbudowane mapy ramy i interfejsem.

Istnieją dwa sposoby użycia agregacji: (1) za pomocą obiektu COM, który obsługuje agregacji i (2) wdrażanie obiektu, który może być agregowane przez inną. Funkcje te można dalej jako "przy użyciu obiektu agregacji" i "nadaniem obiektowi kumulowalnych". MFC obsługuje zarówno.

Za pomocą obiektu agregacji

Aby użyć obiektu agregacji, tam musi być w jakiś sposób powiązać kruszywa do mechanizmu QueryInterface. Innymi słowy agregacji obiekt musi zachowywać się, jakby była macierzysta część obiektu. W jaki sposób wiązania do interfejsu MFC firmy mapa mechanizm? Oprócz makra INTERFACE_PART , gdy obiekt zagnieżdżony jest mapowany do IID, można również zadeklarować obiektu agregacji, jako część klasy CCmdTarget pochodnych. Aby to zrobić, makro INTERFACE_AGGREGATE jest używany. Pozwala na określenie Państwa zmienną (który musi być wskaźnik IUnknown lub klasy), które ma zostać włączone do mechanizmu mapę interfejsu. Jeśli wskaźnik myszy nie jest równa NULL, gdy wywoływany jest CCmdTarget::ExternalQueryInterface , ramy automatycznie będzie wywoływać funkcji składowej QueryInterface obiektu agregacji, IID żądanie nie jest jednym z macierzystym s IIDobsługiwane przez samego obiektu CCmdTarget.

Aby użyć makra INTERFACE_AGGREGATE, wykonaj następujące kroki:

  1. Zadeklarować zmienną ( IUnknown *) będzie zawierać wskaźnik łącznej obiekt.

  2. Dołączyć makro INTERFACE_AGGREGATE mapy interfejsu, który odwołuje się do zmiennej Członkowskie według nazwy.

  3. W pewnym momencie (zwykle w trakcie CCmdTarget::OnCreateAggregates) zainicjuj zmienną na coś innego niż NULL.

Na przykład,

klasa CAggrExample: CCmdTarget publicznych
{
publiczne:
 nbsp;  CAggrExample();

chronione:
    LPUNKNOWN m_lpAggrInner;
    wirtualny BOOL OnCreateAggregates();

DECLARE_INTERFACE_MAP()
    / / "macierzystego" interfejsu część makra mogą być używane tutaj
};

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

BOOL CAggrExample::OnCreateAggregates()
{
    / / drutu się łącznie z poprawną kontrolowania nieznany
    m_lpAggrInner = funkcji CoCreateInstance (CLSID_Example,
        GetControllingUnknown(), CLSCTX_INPROC_SERVER,
        IID_IUnknown, elementem LPVOID ** & m_lpAggrInner);
    Jeżeli (m_lpAggrInner == NULL)
        return FALSE;
    / / Opcjonalnie, tworzenie obiektów agregacji tutaj
    Zwraca wartość PRAWDA;
}

BEGIN_INTERFACE_MAP (CAggrExample, CCmdTarget)
    / / macierzysty wpisy "INTERFACE_PART" Przejdź tutaj
    INTERFACE_AGGREGATE (CAggrExample, m_lpAggrInner)
END_INTERFACE_MAP()

m_lpAggrInnerJest inicjowana w konstruktorze null. Ramach zignoruje NULL zmienną w Domyślna implementacja metody QueryInterface. OnCreateAggregates jest dobrym miejscem do faktycznie tworzyć obiekty agregacji. Będziesz musiał wywołuj go jawnie, jeśli tworzysz obiekt poza wykonania MFC COleObjectFactory. Przyczyny utworzenia kruszywa w CCmdTarget::OnCreateAggregates , a także użycie CCmdTarget::GetControllingUnknown będzie oczywisty podczas tworzenia obiektów kumulowalnych opisanej.

Ta technika nada obiekt, wszystkie interfejsy, które agregacji obiekt obsługuje oraz jego macierzystych interfejsów. Jeśli chcesz tylko podzbiór interfejsów, które obsługuje agregacji, można zastąpić CCmdTarget::GetInterfaceHook. Dzięki temu można bardzo niski poziom hookability, podobna do metody QueryInterface. Zwykle ma wszystkie interfejsy, które obsługuje agregacji.

Dzięki implementacji obiektu kumulowalnych

Dla obiektu ma być kumulowane realizację AddRef, uwolnieniai metody QueryInterface musi przekazać "kontrolowania nieznane." Innymi słowy dla niego część obiektu, to musi przekazać AddRef, wydaniei metody QueryInterface innego obiektu, również pochodzi od elementu IUnknown. Ta "Nieznany kontroli" jest pod warunkiem, że do obiektu podczas jego tworzenia, oznacza to, że jest on podawany do wykonania COleObjectFactory. Wykonawczych tym prowadzi niewielką ilość narzutów, a w niektórych przypadkach nie jest pożądane, w tak MFC czyni to opcjonalne. Aby uaktywnić obiekt być kumulowane, wywołania CCmdTarget::EnableAggregation z konstruktora obiektu.

Jeśli obiekt używa również agregatów, również należy pamiętać, aby przekazać prawidłowe "kontrolowania nieznany" do agregacji obiektów. Zazwyczaj ten wskaźnik IUnknown jest przekazywana do obiektu, gdy tworzony jest suma. Na przykład parametr pUnkOuter jest "Nieznany kontroli" dla obiektów utworzonych za pomocą funkcji CoCreateInstance. Poprawne wskaźnik "kontrolowanie nieznany" mogą być pobierane przez wywołanie CCmdTarget::GetControllingUnknown. Wartość zwracany z tej funkcji, jednak nie jest prawidłowe podczas konstruktora. Z tego powodu jest sugerowany, tworzenie sieci agregatów tylko w nadpisanie CCmdTarget::OnCreateAggregates, gdzie wartość zwracany z GetControllingUnknown są wiarygodne, nawet jeśli utworzony z realizacji COleObjectFactory.

Jest również ważne, że obiekt manipuluje licznika odwołań poprawne przy dodawaniu lub zwalniania zliczanie odwołań sztuczne. Aby upewnić się, że taka sytuacja ma miejsce, wywoływanie zawsze ExternalAddRef i ExternalRelease zamiast InternalRelease i InternalAddRef. Rzadko do wywołania InternalRelease lub InternalAddRef na klasy, która obsługuje agregacji.

Materiał odniesienia

Zaawansowane użycie OLE, takich jak definiowanie własnych interfejsy lub przesłanianie ramy realizacji interfejsy OLE wymaga wykorzystania podległej mechanizmu mapę interfejsu.

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

CCmdTarget::EnableAggregation — Funkcja opis

nieważne EnableAggregation();

Uwaga   Wywołanie funkcji w konstruktorze klasy pochodnej, jeśli chcesz obsługuje agregacji OLE dla obiektów tego typu. Przygotowuje specjalne wykonania IUnknown, wymagany dla obiektów kumulowalnych.

CCmdTarget::ExternalQueryInterface — Funkcja opis

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

lpIID

Daleko wskaźnik IID (pierwszy argument funkcji QueryInterface)

ppvObj

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

Uwaga   Wywołanie funkcji w danej implementacji IUnknown dla każdego interfejsu klasy implementuje. Ta funkcja zapewnia standardowej implementacji opartej na danych QueryInterface oparte na mapie interfejsu użytkownika obiektu. Jest konieczne do oddania zwracanej wartości HRESULT. Jeśli obiekt jest zagregowane, ta funkcja będzie wywoływać "IUnknown kontroli" zamiast za pomocą mapy interfejsu lokalnego.

CCmdTarget::ExternalAddRef — Funkcja opis

DWORD ExternalAddRef();

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

CCmdTarget::ExternalRelease — Funkcja opis

DWORD ExternalRelease();

Uwaga   Wywołanie funkcji w danej implementacji IUnknown::Release dla każdego interfejsu klasy implementuje. Wartość zwracany 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.

DECLARE_INTERFACE_MAP — Opis makra

DECLARE_INTERFACE_MAP

Uwaganbsp;  Użyj tego makra w dowolnej klasy pochodzące z CCmdTarget , który będzie miał mapą interfejsu. Używane w bardzo w ten sam sposób, jak DECLARE_MESSAGE_MAP. Tego wywołania makra powinny być umieszczane w definicji klasy, zazwyczaj w nagłówku (.H) plik. Klasy DECLARE_I&NTERFACE_MAP , musisz zdefiniować mapę interfejsu w pliku implementacji (.CPP) z makra BEGIN_INTERFACE_MAP i END_INTERFACE_MAP.

BEGIN_INTERFACE_PART i END_INTERFACE_PART — makra opisy

BEGIN_INTERFACE_PART (localClass, iface);

END_INTERFACE_PART (localClass)

localClass

Nazwę klasy, która implementuje interfejs

face

Nazwa interfejsu, który implementuje tej klasy

Uwaganbsp;  Dla każdego interfejsu, który wprowadzi w klasie trzeba mieć parę BEGI&N_INTERFACE_PART i END_INTERFACE_PART . Te makra zdefiniowanie klasy lokalne pochodzące z interfejsu OLE, który definiujesz jak również osadzone zmienną tej klasy. Członkowie AddRef, wydaniei metody QueryInterface są zgłaszane automatycznie. Musi zawierać deklaracje dla innych funkcji Państwa, które są częścią interfejsu realizowane (deklaracje te są umieszczane między makra BEGIN_INTERFACE_PART i END_INTERFACE_PART ).

Argument Face to interfejs OLE, który chcesz wdrożyć, takich jak IAdviseSink, lub IPersistStorage (lub własnego niestandardowego interfejsu).

LocalClass argument jest nazwą klasy lokalnych, które zostaną określone. ' X' będzie automatycznie zostać dołączona do nazwy. Konwencja nazewnictwa jest używana w celu uniknięcia kolizji z globalnego klas o tej samej nazwie. Ponadto nazwa członka osadzone, taka sama jak nazwa localClass z wyjątkiem jest poprzedzane "m_x".

Na przykład:

BEGI&N_INTERFACE_PART (MyAdviseSink, IAdviseSink)
 nbsp; STDMETHOD_(void,OnDataChange) (LPFORMATETC, LPSTGMEDIUM);
   STDMETHOD_(void,OnViewChange) (DWORD, długie);
   STDMETHOD_(void,OnRename)(LPMONIKER);
   STDMETHOD_(void,OnSave)();
   STDMETHOD_(void,OnClose)();
END_INTERFACE_PART(MyAdviseSink)

definiuje się lokalne klasy o nazwie XMyAdviseSink z IAdviseSink i członek klasy, w której jest on zadeklarowany nazywany m_xMyAdviseSink.Note:

Uwaga   Linie rozpoczynające się STDMETHOD_ zasadniczo są kopiowane z OLE2.H i nieco zmodyfikowany. Kopiując je ze OLE2.H można zmniejszyć liczbę błędów, które są trudne do rozpoznania.

BEGIN_INTERFACE_MAP i END_INTERFACE_MAP — makra opisy

BEGIN_INTERFACE_MAP (theClass, baseClass)

END_INTERFACE_MAP

theClass

Klasy, w którym mapy interfejs ma zostać określone

baseClass

Klasy, z której theClass pochodzi z.

Uwagi: Makra BEGIN_INTERFACE_MAP i END_INTERFACE_MAP są używane w pliku implementacji faktycznie zdefiniowanie mapę interfejsu. Dla każdego interfejsu, który jest zaimplementowana istnieje jeden lub więcej wywołania makra INTERFACE_PART . Dla każdej funkcji agregującej, którą korzysta z klasy jest jedno wywołanie makra INTERFACE_AGGREGATE.

INTERFACE_PART — Opis makra

INTERFACE_PART (theClass, iid, localClass)

theClass

Nazwę klasy, która zawiera mapę interfejsu.

identyfikator iid

Identyfikator IID , która ma być mapowana do klasy osadzonego.

localClass

Nazwa klasy lokalne (mniej 'X')

Uwaganbsp;  To makro jest używana między makra BEGI&N_INTERFACE_MAP i makra END_INTERFACE_MAP dla każdego interfejsu, który obiekt będzie wspierać. Umożliwia on mapować IID do członka klasy wskazanej przez theClass i localClass. 'm_x' zostaną automatycznie dodane do localClass . Należy zauważyć, że więcej niż jeden identyfikator IID mogą być związane z jednego członka. Jest to bardzo użyteczne, gdy są wykonawczych tylko "najbardziej pochodne" interfejs i chcesz podać wszystkie interfejsy pośrednich jak również. Dobrym przykładem jest interfejs IOleInPlaceFrameWindow . Jak to wygląda swojej hierarchii:

IU&nknown
 nbsp;  IOleWindow
        IOleUIWindow
            IOleInPlaceFrameWindow

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

w pliku definicji klasy:

BEGIN_INTERFACE_PART (CMyFrameWindow, IOleInPlaceFrameWindow)

w pliku implementacji klasy:

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

Ramach dba o IUnknown, ponieważ zawsze wymaga się.

INTERFACE_PART — Opis makra

INTERFACE_AGGREGATE (theClass, theAggr)

theClass

Nazwę klasy, która zawiera mapę interfejsu,

theAggr

Nazwa Państwa zmienną, która ma zostać zagregowana.

Uwaganbsp;  To makro jest używany stwierdzić ramy, że klasa jest przy użyciu obiektu agregacji. Musi znajdować się między BEGI&N_INTERFACE_PART i END_INTERFACE_PART makr. Obiekt agregacji jest oddzielnym obiektem, pochodzi od elementu IUnknown. Za pomocą zbiorczych i makra INTERFACE_AGGREGATE , można wprowadzić wszystkie interfejsy, które obsługuje agregacji wydaje się być bezpośrednio obsługiwane przez obiekt. TheAggr argument jest po prostu nazwą zmienną z klasy, która pochodzi od elementu IUnknown (bezpośrednio lub pośrednio). Wszystkie makra INTERFACE_AGGREGATE należy wykonać makra INTERFACE_PART po umieszczeniu na mapie interfejsu.

Uwagi techniczne przez liczbę |nbsp; Uwagi techniczne według kategorii

Index