TN038: implementazione di MFC/OLE IUnknown

[!NOTA]

La seguente nota tecnica non è stata aggiornata dalla prima volta che viene inclusa nella documentazione online.Di conseguenza, alcune procedure e argomenti potrebbero non essere aggiornati o errati.Per le informazioni più recenti, è consigliabile cercare l'argomento di interesseindice della documentazione online.

Al centro OLE 2 è “Component Object Model OLE„, o COM.COM definisce uno standard per come gli oggetti di cooperazione comunicano tra loro.Ciò include i dettagli di l “oggetto„ l'aspetto, tra cui come i metodi vengono inviati su un oggetto.COM definisce anche una classe base, da cui tutte le classi compatibili COM sono derivate.Questa classe base è IUnknown.Benché l'interfaccia di IUnknown faccia riferimento a come la classe C++, COM non è specifica di un unico linguaggio (può essere distribuita in C#, PASCAL, o qualsiasi altro linguaggio che può supportare il layout binario di un oggetto COM.

OLE fa riferimento a tutte le classi derivate da IUnknown come “interfacce.„ Questa distinzione è importante, poiché “interfaccia„ come IUnknown non porta con implementazione.Definisce semplicemente il protocollo da cui gli oggetti comunicano, non le specifiche di cui tali implementazioni in.Ciò è ragionevole per un sistema che consente la massima flessibilità.È il processo di MFC implementare un comportamento predefinito per i programmi di MFC/C++.

Per comprendere l'implementazione di MFC di IUnknown è innanzitutto necessario comprendere cosa questa interfaccia è.Una versione semplificata di IUnknown è definita di seguito:

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

[!NOTA]

I dettagli necessari sicuri della convenzione di chiamata, come __stdcall vengono lasciati out per questa illustrazione.

Le funzioni membro di Release e di AddRef controllano la gestione della memoria dell'oggetto.COM utilizza un sistema di conteggio dei riferimenti tenere traccia degli oggetti.Un oggetto non viene fatto riferimento mai direttamente come in C++.Viceversa, gli oggetti COM viene fatto riferimento sempre tramite un puntatore.Per rilasciare l'oggetto se il proprietario viene eseguito mediante, il membro di Release dell'oggetto viene chiamato (anziché tramite operator delete, come verrebbe eseguito per un oggetto tradizionale (C++).Il meccanismo di conteggio dei riferimenti sono consentiti i più riferimenti a un singolo oggetto da gestire.Un'implementazione di AddRef e di Release gestisce un conteggio dei riferimenti all'oggetto e non eliminare l'oggetto fino alle relative intervalli zero di conteggio dei riferimenti.

AddRef e Release sono piuttosto semplici da un punto di vista di implementazione.Di seguito è un'implementazione semplice:

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

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

La funzione membro di QueryInterface è un poco più di interesse.Non è particolarmente interessante avere un oggetto di cui le sole funzioni membro vengono AddRef e Release sarebbe piacevole impostare l'oggetto di eseguire più operazioni che IUnknown fornisce.Questo è il punto in cui QueryInterface è utile.Consente di ottenere “interfaccia„ diversa nello stesso oggetto.Queste interfacce vengono solitamente derivate da IUnknown e aggiungere la funzionalità aggiuntiva aggiungendo nuove funzioni membro.Le interfacce COM non includono mai variabili membri dichiarati nell'interfaccia e tutte le funzioni membro e sono dichiarate come puro-virtuali.Di seguito è riportato un esempio:

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

Per ottenere IPrintInterface se si dispone solo IUnknown, chiamata IUnknown::QueryInterface utilizzando IID di IPrintInterface.IID è di 128 bit che identifica in modo univoco l'interfaccia.È IID per ogni interfaccia di l o OLE definisce.Se il punk è un puntatore a un oggetto di IUnknown , il codice per recuperare IPrintInterface da potrebbe essere:

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

Tale evidenti abbastanza facile, ma come verrebbero implementare un oggetto che supporta sia l'interfaccia di IUnknown di IPrintInterface?In questo caso è semplice poiché il IPrintInterface deriva direttamente da IUnknown — distribuzione IPrintInterface, IUnknown viene automaticamente supportato.Di seguito è riportato un esempio:

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

Le implementazioni di AddRef e di Release sono esattamente a quelle implementate su.CPrintObj::QueryInterface è simile alla seguente:

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

Come si può notare, se identificatore di interfaccia (IID) viene riconosciuto, un puntatore viene restituito all'oggetto; altrimenti si verifica un errore.Si noti inoltre che il QueryInterface comporta AddRefimplicito.Naturalmente, sarà necessario implementare CEditObj::Print.Ciò è semplice perché IPrintInterface direttamente è stato derivato dall'interfaccia di IUnknown .Tuttavia se si desidera supportare due diverse interfacce, entrambi derivati da IUnknown, si consideri quanto segue:

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

Anche se vi sono vari modi di implementare una classe sia IEditInterface di supporto che IPrintInterface, anche mediante ereditarietà multipla C++, questa nota si concentra sull'utilizzo delle classi annidate implementare questa funzionalità.

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;
};

L'intera implementazione è inclusa nell'esempio seguente:

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); 
}

Si noti che la maggior parte dell'implementazione di IUnknown viene posizionata nella classe di CEditPrintObj anziché la duplicazione il codice in CEditPrintObj::CEditObj e in CEditPrintObj::CPrintObj.In questo modo si riduce la quantità di codice ed evita i bug.Il punto chiave di seguito è quello dall'interfaccia di IUnknown è possibile chiamare QueryInterface per recuperare un'interfaccia l'oggetto potrebbe supportare e da ognuna di queste interfacce è possibile eseguire la stessa operazione.Ciò significa che tutte le funzioni di QueryInterface disponibili a ogni interfaccia devono comportarsi esattamente la stessa modalità.In modo che tali oggetti incorporati per chiamare l'implementazione “nell'oggetto esterno„, un retro-puntatore viene utilizzato (m_pParent).Il puntatore m_pParent viene inizializzato nel costruttore di CEditPrintObj.Successivamente occorre implementare CEditPrintObj::CPrintObj::PrintObject e CEditPrintObj::CEditObj::EditObject anche.Sufficiente un frammento di codice è stato aggiunto per aggiungere una funzionalità alla possibilità di modificare l'oggetto.Fortunatamente, per le interfacce sono molto raro disporre di una sola funzione membro (anche se si verifichi) e in questo caso, EditObject e PrintObject in genere sono stati combinati in una singola interfaccia.

Ciò è molta spiegazioni e molto codice per tale scenario semplice.Le classi di MFC/OLE forniscono un'alternativa più semplice.Implementazione MFC viene utilizzata una tecnica simile alla modalità di visualizzazione dei messaggi viene eseguito il wrapping con le mappe dei messaggi.Questa funzionalità è denominata mapping dell'interfaccia e viene discusso nella sezione successiva.

Mapping dell'interfaccia MFC

MFC/OLE include un'implementazione “interfaccia esegue il mapping„ simile a MFC “di mappe messaggi„ e “mappe di invio„ nel concetto ed eseguito.Le funzionalità principali della mappa dell'interfaccia di MFC sono le seguenti:

  • Un'implementazione standard di IUnknown, compilata in CCmdTarget la classe.

  • Manutenzione del conteggio dei riferimenti, modificato da AddRef e da Release

  • Implementazione determinata dati di QueryInterface

Inoltre, i mapping dell'interfaccia supportano le seguenti funzionalità avanzate:

  • Supporto per la creazione di oggetti COM aggregabili

  • Supporto per utilizzare gli oggetti di aggregazione nell'implementazione di un oggetto COM

  • L'implementazione è hookable ed estensibile

Per ulteriori informazioni su aggregazione, vedere la documentazione di riferimento del programmatore OLE.

Il supporto del mapping dell'interfaccia di MFC è con radice nella classe di CCmdTarget .CCmdTargetha-un„ il conteggio dei riferimenti nonché tutte le funzioni membro associate all'implementazione di IUnknown (il conteggio dei riferimenti ad esempio è in CCmdTarget).Per creare una classe che supporta OLE COM, derivare una classe da CCmdTarget e utilizzare le varie macro nonché funzioni membro di CCmdTarget per implementare interfacce desiderato.L'implementazione di MFC utilizza le classi annidate per definire ogni implementazione dell'interfaccia molto simile all'esempio precedente.Ciò viene resa più semplice con un'implementazione standard di IUnknown nonché di varie macro che eliminano parte del codice ripetitivo.

Per implementare una classe utilizzando le mappe dell'interfaccia di MFC

  1. Derivare direttamente o indirettamente da una classe da CCmdTarget.

  2. Utilizzare la funzione di DECLARE_INTERFACE_MAP nella definizione della classe derivata.

  3. Per ogni interfaccia che si desidera supportare, utilizzare la macro di END_INTERFACE_PART e di BEGIN_INTERFACE_PART nella definizione della classe.

  4. Nel file di implementazione, utilizzare le macro di END_INTERFACE_MAP e di BEGIN_INTERFACE_MAP per definire il mapping dell'interfaccia della classe.

  5. Per ogni IID supportato, utilizzare la macro di INTERFACE_PART tra BEGIN_INTERFACE_MAP e le macro di END_INTERFACE_MAP per eseguire il mapping dell'IID “parte„ specifica della classe.

  6. Implementare ciascuna delle classi annidate che rappresentano le interfacce supportate.

  7. Utilizzare la macro di METHOD_PROLOGUE per accedere al padre, CCmdTargetoggetto derivato da.

  8. AddRef, Releasee QueryInterface possono delegare CCmdTarget l'implementazione di queste funzioni (ExternalAddRef, ExternalReleasee ExternalQueryInterface).

Nell'esempio di CPrintEditObj potrebbe essere implementato come segue:

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)
};

La dichiarazione precedente crea una classe derivata da CCmdTarget.La macro di DECLARE_INTERFACE_MAP indica al framework che questa classe disporrà di un mapping dell'interfaccia personalizzata.Inoltre, le macro di END_INTERFACE_PART e di BEGIN_INTERFACE_PART definiscono le classi annidate, in questo caso con i nomi CEditObj e CPrintObj (X viene utilizzato per distinguere solo le classi annidate dalle classi globali che iniziano con “C„ le interfacce e le classi che iniziano con “i„).Due membri annidati di queste classi vengono creati: m_CEditObj e m_CPrintObj, rispettivamente.Le macro vengono automaticamente dichiarano AddRef, Releasee le funzioni di QueryInterface ; quindi si dichiara solo funzioni specifiche di questa interfaccia: EditObject e PrintObject (OLE macro STDMETHOD viene utilizzato tali in modo da fornire _stdcall le parole chiave e virtuali a seconda della piattaforma di destinazione).

Per implementare il mapping dell'interfaccia della classe:

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

Si connette lo IID_IPrintInterface IID con m_CPrintObj e IID_IEditInterface con m_CEditObj rispettivamente.L'implementazione di CCmdTarget di QueryInterface (CCmdTarget::ExternalQueryInterface) utilizza questo mapping per restituire i puntatori a m_CPrintObj e a m_CEditObj quando richiesto.Non è necessario includere una voce per IID_IUnknown; il framework utilizzerà la prima interfaccia nel mapping (in questo caso, m_CPrintObj) quando IID_IUnknown è obbligatorio.

Anche se la macro di BEGIN_INTERFACE_PART automaticamente dichiarata AddRef, Release e le funzioni di QueryInterface di, è comunque necessario implementarli:

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...
}

L'implementazione per CEditPrintObj::CPrintObj, sarebbe simile alle definizioni di precedenza per CEditPrintObj::CEditObj.Sebbene sia possibile creare una macro che potrebbe essere utilizzata per generare automaticamente queste funzioni (ma in precedenza nello sviluppo di MFC/OLE questo è il caso), diventa difficile impostare i punti di interruzione quando una macro genera più righe di codice.Per questo motivo, questo codice viene espanso manualmente.

Tramite l'implementazione del framework delle mappe dei messaggi, esistono numerose operazioni che non erano necessarie da fare:

  • Utilizzo QueryInterface

  • Utilizzo AddRef e versione

  • Dichiarare uno di questi metodi incorporati in entrambe le interfacce

Inoltre, il framework utilizza le mappe dei messaggi internamente.Ciò consente di deriviate da una classe del framework, indica COleServerDoc, che supporta già determinate interfacce e fornisce le sostituzioni o le aggiunte alle interfacce fornite dal framework.Ciò è consentito dal fatto che il framework completo che ereditano una mappa dell'interfaccia da una classe base (che è il motivo per cui BEGIN_INTERFACE_MAP accetta come secondo parametro il nome della classe base.

[!NOTA]

Genere non è possibile riutilizzare l'implementazione delle implementazioni incorporate di MFC delle interfacce OLE ereditando la specializzazione incorporata dell'interfaccia dalla versione di MFC.Ciò non è possibile in quanto l'utilizzo della macro di METHOD_PROLOGUE ottenere l'accesso a CCmdTargetcontenitore oggetto derivato da implica fixed offset dell'oggetto incorporato da CCmdTargetoggetto derivato da.Ciò significa, ad esempio, non è possibile derivare un XMyAdviseSink incorporato dall'implementazione di MFC in COleClientItem::XAdviseSink, poiché XAdviseSink si basa su essere un offset specifico dalla parte superiore dell'oggetto di COleClientItem .

[!NOTA]

È possibile, tuttavia, delegare l'implementazione di MFC per tutte le funzioni che il comportamento predefinito di MFC.Questa operazione viene eseguita nell'implementazione di IOleInPlaceFrame (XOleInPlaceFrame) nella classe di COleFrameHook (delega m_xOleInPlaceUIWindow per molte funzioni.Questa progettazione è stata scelta per ridurre la dimensione runtime di oggetti che implementano molte interfacce, elimina la necessità di un retro-puntatore (ad esempio la modalità m_pParent è stato utilizzato nella sezione precedente).

5hhehwba.collapse_all(it-it,VS.110).gifMapping dell'interfaccia e di aggregazione

Oltre a supportare gli oggetti COM autonomi, MFC supporta inoltre aggregato.L'aggregazione stessa è un argomento troppo complesso da discutere di seguito; fare riferimento a programmer's reference OLE per ulteriori informazioni su aggregazione.Questa nota descriverà semplicemente il supporto di aggregazione compilata nei mapping dell'interfaccia e del framework.

Esistono due modi per utilizzare l'aggregazione: (1) utilizzando un oggetto COM che aggregazione di supporta e (2) implementando un oggetto che può essere aggregatoe da un altro.Queste funzionalità possono sono stato denominato “utilizzo di un oggetto di aggregazione„ e “di rendere un oggetto cui aggregatable„.MFC supporta entrambi.

5hhehwba.collapse_all(it-it,VS.110).gifUtilizzo di un oggetto di aggregazione

Per utilizzare un oggetto di aggregazione, deve essere un modo per bloccare l'aggregato nel meccanismo di QueryInterface.Ovvero l'oggetto di aggregazione deve comportarsi come se fosse una parte nativa dell'oggetto.Così come il collegamento in MFC collega il meccanismo di mapping?Oltre alla macro di INTERFACE_PART , in cui un oggetto annidato viene eseguito il mapping a un IID, è anche possibile dichiarare un oggetto di aggregazione come parte della classe derivata di CCmdTarget .A tale scopo, la macro di INTERFACE_AGGREGATE viene utilizzata.Ciò consente di specificare una variabile membro (che deve essere un puntatore a IUnknown o classe derivata), che deve essere integrato nel meccanismo di mapping dell'interfaccia.Se il puntatore non è NULL quando CCmdTarget::ExternalQueryInterface viene chiamato, il framework chiamerà automaticamente la funzione membro di aggregazione di QueryInterface dell'oggetto, se IID richiesto non è uno di IIDnativo o supportato dall'oggetto stesso di CCmdTarget .

Per utilizzare la macro di INTERFACE_AGGREGATE

  1. Dichiarare una variabile membro ( IUnknown*) che conterrà un puntatore a un oggetto di aggregazione.

  2. Includere una macro di INTERFACE_AGGREGATE nel mapping dell'interfaccia, che fa riferimento alla variabile membro per nome.

  3. A un certo punto (in genere durante il CCmdTarget::OnCreateAggregates), inizializzare la variabile membro con nomi diversi da NULL.

Di seguito è riportato un esempio:

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 inizializzato nel costruttore SU NULL.Il framework ignorerà una variabile membro NULL nell'implementazione predefinita di QueryInterface.OnCreateAggregates è l'oggetto ideale in realtà per creare gli oggetti di aggregazione.Sarà necessario chiamarlo in modo esplicito se si crea l'oggetto esterno dell'implementazione di COleObjectFactory.Il motivo per creare aggregati in CCmdTarget::OnCreateAggregates nonché l'utilizzo di CCmdTarget::GetControllingUnknown diventerà evidente quando vengono creati gli oggetti aggregabili viene illustrato.

Questa tecnica consenta all'oggetto tutte le interfacce che supporta di aggregazione oggetto e le relative interfacce native.Se si desidera solo un sottoinsieme delle interfacce che supportano l'aggregazione, è possibile eseguire l'override di CCmdTarget::GetInterfaceHook.Ciò consente il hookability molto basso livello, simile a QueryInterface.In genere, si desidera che tutte le interfacce supportate da aggregazione.

5hhehwba.collapse_all(it-it,VS.110).gifRendere un'implementazione dell'oggetto cui aggregatable

Perché un oggetto siano cui aggregatable, l'implementazione di AddRef, Releasee QueryInterface devono delegare uno “sconosciuto di controllo.„ Ovvero che fa parte dell'oggetto, deve delegati AddRef, Releasee QueryInterface un oggetto diverso, anche derivato da IUnknown.Ciò “sconosciuto di controllo„ è fornita all'oggetto quando viene creata, ovvero, viene fornito all'implementazione di COleObjectFactory.Implementare questo porta una piccola quantità di sovraccarico e in alcuni casi non è appropriato, in modo da MFC semplifica questa facoltativo.Per consentire a un oggetto per essere cui aggregatable, chiamate CCmdTarget::EnableAggregation dal costruttore dell'oggetto.

Se l'oggetto utilizza anche le aggregazioni, è inoltre necessario assicurarsi di passare “sconosciuto di controllo corretto agli oggetti di aggregazione.In genere questo puntatore di IUnknown viene passato all'oggetto quando l'aggregazione viene creata.Ad esempio, il parametro del pUnkOuter è “sconosciuto di controllo„ per gli oggetti creati con CoCreateInstance.Il puntatore “sconosciuto„ di controllo corretto può essere recuperato chiamando CCmdTarget::GetControllingUnknown.Il valore restituito dalla funzione, tuttavia, non è valido durante il costruttore.Per questo motivo, è consigliato di creare le aggregazioni solo nell'override di CCmdTarget::OnCreateAggregates, dove il valore restituito da GetControllingUnknown è considerata affidabile, anche se creati dall'implementazione di COleObjectFactory .

È inoltre importante che l'oggetto modifica il conteggio dei riferimenti corretto quando si aggiunge o si i conteggi dei riferimenti artificiali.Per fornire questo caso, sempre la chiamata ExternalAddRef e ExternalRelease anziché InternalRelease e di InternalAddRef.È raro da chiamare InternalRelease o InternalAddRef su una classe l'aggregazione di supportare.

5hhehwba.collapse_all(it-it,VS.110).gifMateriale di riferimento

L'utilizzo avanzato OLE, come la definizione delle proprie interfacce o eseguire l'override dell'implementazione del framework delle interfacce OLE richiede l'utilizzo del meccanismo sottostante del mapping dell'interfaccia.

In questa sezione viene descritto ogni macro e API utilizzata per distribuire queste funzionalità avanzate.

5hhehwba.collapse_all(it-it,VS.110).gifCCmdTarget::EnableAggregation — descrizione di funzione

void EnableAggregation();

Note

Chiamare questa funzione in un costruttore di classe derivata se si desidera supportare l'aggregazione OLE per gli oggetti di questo tipo.Ciò rende un'implementazione speciale di IUnknown che è obbligatoria per gli oggetti aggregabili.

5hhehwba.collapse_all(it-it,VS.110).gifCCmdTarget::ExternalQueryInterface — descrizione di funzione

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

Note

5hhehwba.collapse_all(it-it,VS.110).gifParametri

  • lpIID
    Un puntatore lontano a un IID (il primo argomento a QueryInterface)

  • ppvObj
    Un puntatore a una IUnknown* (secondo argomento di QueryInterface)

Note

Chiamare questa funzione nell'implementazione di IUnknown per ogni interfaccia dati implementa la classe.Questa funzione fornisce l'implementazione basata sui dati standard di QueryInterface in base al mapping dell'interfaccia dell'oggetto.È necessario eseguire il cast del valore restituito a un HRESULT.Se l'oggetto verranno aggregati, questa funzione chiamerà “di IUnknown di controllo„ anziché utilizzare il mapping locale dell'interfaccia.

5hhehwba.collapse_all(it-it,VS.110).gifCCmdTarget::ExternalAddRef — descrizione di funzione

DWORD ExternalAddRef();

Note

Chiamare questa funzione nell'implementazione di IUnknown::AddRef per ogni interfaccia dati implementa la classe.Il valore restituito è il nuovo conteggio dei riferimenti all'oggetto di CCmdTarget.Se l'oggetto verranno aggregati, questa funzione chiamerà “di IUnknown di controllo„ anziché modificare il conteggio dei riferimenti locale.

5hhehwba.collapse_all(it-it,VS.110).gifCCmdTarget::ExternalRelease — descrizione di funzione

DWORD ExternalRelease();

Note

Chiamare questa funzione nell'implementazione di IUnknown::Release per ogni interfaccia dati implementa la classe.Il valore restituito indica il nuovo conteggio dei riferimenti all'oggetto.Se l'oggetto verranno aggregati, questa funzione chiamerà “di IUnknown di controllo„ anziché modificare il conteggio dei riferimenti locale.

5hhehwba.collapse_all(it-it,VS.110).gifDECLARE INTERFACE MAP - macro descrizione

DECLARE_INTERFACE_MAP

Note

Utilizzare questa macro in qualsiasi classe derivata da CCmdTarget che disporrà di un mapping dell'interfaccia.Utilizzato in modo molto simile a DECLARE_MESSAGE_MAP.Questa chiamata di macro deve essere inserita nella definizione della classe, in genere in un'intestazione (. h) file.La classe con DECLARE_INTERFACE_MAP necessario definire il mapping dell'interfaccia nel file di implementazione (.CPP) con le macro di END_INTERFACE_MAP e di BEGIN_INTERFACE_MAP .

5hhehwba.collapse_all(it-it,VS.110).gifBEGIN_INTERFACE_PART e END_INTERFACE_PART — macro descrizioni

BEGIN_INTERFACE_PART( 
   localClass,
   iface 
);
END_INTERFACE_PART( 
   localClass 
)

Note

5hhehwba.collapse_all(it-it,VS.110).gifParametri

  • localClass
    Il nome della classe che implementa l'interfaccia

  • iface
    Il nome dell'interfaccia che questa classe implementa

Note

Per ogni interfaccia della classe implementerà, è necessario disporre di una coppia di END_INTERFACE_PART e di BEGIN_INTERFACE_PART .Queste macro consentono di definire una classe locale derivata da OLE che definite e una variabile membro incorporato di tale classe.AddRef, Releasee i membri di QueryInterface vengono dichiarati automaticamente.È necessario includere dichiarazioni per le altre funzioni membro che fa parte dell'interfaccia che viene distribuita (tali dichiarazioni inserite tra le macro di END_INTERFACE_PART e di BEGIN_INTERFACE_PART ).

L'argomento del iface è l'interfaccia OLE che si desidera distribuire, come IAdviseSink, o IPersistStorage (o la propria interfaccia).

L'argomento di localClass è il nome della classe locale che verrà definita.Una “X„ verrà automaticamente anteposta al nome.Questa convenzione di denominazione utilizzata per evitare conflitti con le classi globali con lo stesso nome.Inoltre, il nome del membro incorporato, lo stesso modo in cui i localClass denominino a meno che non sia preceduto da “m_x„.

Di seguito è riportato un esempio:

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)

definirebbe una classe locale chiamata XMyAdviseSink derivato da IAdviseSink e un membro della classe in cui viene dichiarato ha chiamato m_xMyAdviseSink.Note:

[!NOTA]

Le linee a partire da STDMETHOD_ essenzialmente vengono copiate da OLE2.H e vengono modificate leggermente.La copia da OLE2.H possibile ridurre gli errori che sono difficili da risolvere.

5hhehwba.collapse_all(it-it,VS.110).gifBEGIN_INTERFACE_MAP e END_INTERFACE_MAP — macro descrizioni

BEGIN_INTERFACE_MAP( 
   theClass,
   baseClass 
)
END_INTERFACE_MAP

Note

5hhehwba.collapse_all(it-it,VS.110).gifParametri

  • theClass
    La classe in cui il mapping dell'interfaccia è di essere definito

  • baseClass
    La classe che theClass deriva da.

Note

Le macro di END_INTERFACE_MAP e di BEGIN_INTERFACE_MAP sono utilizzate nel file di implementazione effettiva per definire il mapping dell'interfaccia.Per ogni interfaccia implementato sono presenti uno o più chiamate di macro di INTERFACE_PART .Per ogni aggregazione che la classe utilizza, esiste una chiamata di macro di INTERFACE_AGGREGATE .

5hhehwba.collapse_all(it-it,VS.110).gifINTERFACE PART - macro descrizione

INTERFACE_PART( 
   theClass,
   iid, 
   localClass 
)

Note

5hhehwba.collapse_all(it-it,VS.110).gifParametri

  • theClass
    Il nome della classe che contiene la mappa dell'interfaccia.

  • iid
    IID che deve essere eseguito il mapping alla classe incorporata.

  • localClass
    Il nome della classe locale (meno “X ").

Note

Questa macro viene utilizzata tra la macro di BEGIN_INTERFACE_MAP e la macro di END_INTERFACE_MAP per ogni interfaccia che l'oggetto supporta.Consente di eseguire il mapping di un IID a un membro della classe identificata da theClass e da localClass.“Il m_x„ verrà aggiunto a localClass automaticamente.Si noti che più di un IID può essere associato a un singolo membro.Questa funzionalità è molto utile quando si implementa solo un'interfaccia “la più derivata„ e il desidera specificare qualsiasi elemento intermedio collega anche.Un esempio efficace è l'interfaccia di IOleInPlaceFrameWindow .Gli aspetti della gerarchia è simile al seguente:

IUnknown
    IOleWindow
        IOleUIWindow
            IOleInPlaceFrameWindow

Se un oggetto implementi IOleInPlaceFrameWindow, un client può QueryInterface su una qualsiasi di queste interfacce: IOleUIWindow, IOleWindow, o IUnknown, oltre all'interfaccia “più derivata„ IOleInPlaceFrameWindow (in realtà si sta distribuendo).Per gestire questo problema è possibile utilizzare più di una macro di INTERFACE_PART per eseguire il mapping di ogni interfaccia base all'interfaccia di IOleInPlaceFrameWindow :

nel file di definizione della classe:

BEGIN_INTERFACE_PART(CMyFrameWindow, IOleInPlaceFrameWindow)

nel file di implementazione della classe:

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

Il framework consente infatti di IUnknown perché è sempre necessario.

5hhehwba.collapse_all(it-it,VS.110).gifINTERFACE PART - macro descrizione

INTERFACE_AGGREGATE( 
   theClass,
   theAggr 
)

Note

5hhehwba.collapse_all(it-it,VS.110).gifParametri

  • theClass
    Il nome della classe che contiene la mappa dell'interfaccia,

  • theAggr
    Il nome della variabile membro che deve essere aggregatoe.

Note

Questa macro viene utilizzata per indicare al framework che la classe utilizza un oggetto di aggregazione.Deve trovarsi tra le macro di END_INTERFACE_PART e di BEGIN_INTERFACE_PART .Un oggetto di aggregazione è un oggetto separato, derivato da IUnknown.Utilizzando un aggregato e la macro di INTERFACE_AGGREGATE , è possibile fare in modo che tutte le interfacce che supporta di aggregazione sembrano essere direttamente supportati dall'oggetto.L'argomento del theAggr è semplicemente il nome di una variabile membro della classe derivata da IUnknown direttamente o indirettamente).Tutte le macro di INTERFACE_AGGREGATE devono seguire le macro di INTERFACE_PART una volta posizionati in una mappa dell'interfaccia.

Vedere anche

Altre risorse

Note tecniche del numero

Note tecniche per categoria