Share via


TN038: implementación de MFC/OLE IUnknown

[!NOTA]

La nota técnica siguiente no se ha actualizado desde que primero incluida en la documentación en línea.Como resultado, algunos procedimientos y temas podrían estar obsoletas o incorrectos.Para obtener la información más reciente, se recomienda busca el tema de interés en el índice de la documentación en línea.

En el núcleo de OLE 2 es “modelo de objetos componentes OLE”, o COM.COM define un estándar para cómo los objetos cooperativos comunican a otro.Esto incluye los detalles de lo que parece un “objeto”, como los métodos se envían en un objeto.COM también define una clase base, que todas las clases compatibles COM son derivadas.Esta clase base es IUnknown.Aunque se conoce la interfaz de IUnknown como la clase en cuestión., COM no es específica de ningún idioma (se puede implementar en C, PASCAL, o cualquier otro lenguaje que admita el diseño binario del objeto COM.

OLE hace referencia a todas las clases derivadas de IUnknown como “interfaces”. Esta distinción es importante, ya que una “interfaz” como IUnknown no contiene con ella ninguna implementación.Define simplemente el protocolo mediante el cual los objetos comunicación, no los detalles de lo que haga esas implementaciones.Esto es razonable para un sistema que permita flexibilidad máxima.Es el trabajo MFC implementar un comportamiento predeterminado para los programas de MFC/C++.

Para entender la implementación de MFC de IUnknown primero debe entender lo que es esta interfaz.Una versión simplificada de IUnknown se define a continuación:

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

[!NOTA]

Permiten ciertos detalles necesarios de la convención de llamada, como __stdcall out para esta ilustración.

Las funciones miembro de AddRef y de Liberar controlan la administración de memoria del objeto.COM utiliza un esquema del recuento de referencias de conservar objetos.Un objeto nunca se hace referencia directamente como haría en C++.En su lugar, los objetos COM se hace referencia siempre a través de un puntero.Para liberar el objeto cuando el propietario se realiza con él, el miembro de Liberar de objeto (en comparación con el operador delete, tal como se hace para un objeto tradicional de C++).El mecanismo de recuento de referencias permite varias referencias a un objeto único administrar.Una implementación de AddRef y de Liberar mantiene un recuento de referencia en el objeto (el objeto no se elimina hasta que el recuento de referencias alcanza cero.

AddRef y Liberar son bastante directos de un punto de vista de la implementación.A continuación se muestra una implementación trivial:

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

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

La función miembro de QueryInterface es un poco más interesante.No es muy interesante tener un objeto cuyas únicas funciones miembro son AddRef y Liberar — sería de bienvenida indicar al objeto que haga más cosas que IUnknown proporciona.Aquí es donde es útil QueryInterface .Permite obtener otra “interfaz” en el mismo objeto.Estas interfaces son normalmente derivadas de IUnknown y agregan funcionalidad adicional agregando nuevas funciones miembro.Las interfaces COM nunca tienen variables miembro declaradas en la interfaz, y todas las funciones miembro se declaran como puro-virtuales.Por ejemplo,

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

Para obtener IPrintInterface si sólo tiene IUnknown, llamada IUnknown::QueryInterface mediante IID de IPrintInterface.IID es el número de 128 bits que identifica de forma única la interfaz.Hay IID para cada interfaz que se o OLE defina.Si el punky es un puntero a un objeto de IUnknown , el código para recuperar IPrintInterface de podría ser:

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

¿Eso es sencilla, pero cómo tendría que implementar un objeto que admite la interfaz de IPrintInterface y de IUnknown ?En este caso es simple porque el IPrintInterface es derivado directamente de IUnknown — implementando IPrintInterface, IUnknown automáticamente es compatible.Por ejemplo:

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

Las implementaciones de AddRef y de Liberar se exactamente igual que las implementadas anteriormente.CPrintObj::QueryInterface será parecido a:

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

Como puede ver, si se reconoce el identificador de interfaz (IID), un puntero vuelve a su objeto; si no se produce un error.Observe también que QueryInterface correcto da lugar a AddRefimplícitamente.Por supuesto, también tiene que implementar CEditObj::Print.Esto es fácil porque IPrintInterface era directamente derivado de la interfaz de IUnknown .Sin embargo si desea admitir dos interfaces diferentes, ambos derivado de IUnknown, vea lo siguiente:

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

Aunque hay varias maneras de implementar una clase que admite IEditInterface y IPrintInterface, incluidos mediante la herencia múltiple de C++, esta nota concentrará en el uso de clases anidadas de implementar esta funcionalidad.

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

La implementación completa se incluye a continuación:

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

Observe que la mayor parte de la implementación de IUnknown se pone en la clase de CEditPrintObj en lugar de duplicando el código en CEditPrintObj::CEditObj y CEditPrintObj::CPrintObj.Esto reduce la cantidad de código y evita los errores.El punto clave aquí es el de la interfaz IUnknown que es posible llamar a QueryInterface para recuperar cualquier interfaz el objeto podría admitir, y cada una de esas interfaces es posible hacer lo mismo.Esto significa que todas las funciones de QueryInterface disponibles de cada interfaz deben comportarse exactamente de la misma manera.Para que estos objetos incrustados pueden llamar a la implementación en “objeto externo”, se utiliza un espalda-puntero (m_pParent).El puntero m_pParent inicializa durante el constructor de CEditPrintObj.A continuación se implementaría CEditPrintObj::CPrintObj::PrintObject y CEditPrintObj::CEditObj::EditObject también.Un bit de se ha agregado código muy para agregar una característica — la capacidad de modificar el objeto.Afortunadamente, es bastante raro que las interfaces tienen una sola función miembro (aunque resulta) y en este caso, EditObject y PrintObject se combinados normalmente en una única interfaz.

Eso es mucha explicación y mucho código para un escenario tan simple.Las clases de MFC/OLE proporcionan una alternativa más sencilla.Implementación de MFC utiliza una técnica similar a la manera en que los mensajes de Windows se ajustan con los mapas de mensajes.Esta función se denomina Interface Maps y se describe en la sección siguiente.

Mapas de interfaz de MFC

MFC/OLE incluye una implementación de “interfaz asigna” similar mensajes MFC a “asigna” y “envío asigna” en concepto y la ejecución.Las características básicas de mapas de interfaz de MFC son los siguientes:

  • Una implementación estándar de IUnknown, compilada en CCmdTarget la clase.

  • Mantenimiento del recuento de referencias, modificado por AddRef y Liberar

  • Implementación controlada datos de QueryInterface

Además, los mapas de interfaz admiten las siguientes características avanzadas:

  • Compatibilidad para crear objetos COM aggregatable

  • Compatibilidad para utilizar objetos globales en la implementación de un objeto COM

  • La implementación es hookable y extensible

Para obtener más información sobre la agregación, vea referencia) del Programador.

Compatibilidad de asignación de la interfaz de MFC se raíces en la clase de CCmdTarget .CCmdTargettiene-uno” recuento de referencias junto con todas las funciones miembro asociado con la implementación de IUnknown (el recuento de referencias por ejemplo está en CCmdTarget).Para crear una clase que admita COM OLE, derive una clase de CCmdTarget y utiliza diferentes macros así como funciones miembro de CCmdTarget para implementar interfaces deseadas.Implementación de MFC utiliza clases anidadas para definir cada implementación de la interfaz como el ejemplo anterior.Esto se facilita con una implementación estándar de IUnknown así como de varias macros que eliminen algo de código repetitivo.

Para implementar una clase mediante los mapas de interfaz de MFC

  1. Derive una clase directa o indirectamente de CCmdTarget.

  2. Utilice la función de DECLARE_INTERFACE_MAP en la definición de clase derivada.

  3. Para cada interfaz que desee admitir, que use las macros de BEGIN_INTERFACE_PART y de END_INTERFACE_PART en la definición de clase.

  4. En el archivo de implementación, utilice las macros de BEGIN_INTERFACE_MAP y de END_INTERFACE_MAP para definir la asignación de la interfaz de clase.

  5. Para cada IID compatible, utilice la macro de INTERFACE_PART entre BEGIN_INTERFACE_MAP y macros de END_INTERFACE_MAP asignar ese identificador IID a una “parte específica” de la clase.

  6. Implemente cada una de las clases anidadas que representan las interfaces que admita.

  7. Utilice la macro de METHOD_PROLOGUE para tener acceso al elemento primario, CCmdTarget- objeto derivado.

  8. AddRef, Liberar, y QueryInterface pueden delegar a CCmdTarget la implementación de estas funciones (ExternalAddRef, ExternalRelease, y ExternalQueryInterface).

El ejemplo de CPrintEditObj anterior podría implementarse como sigue:

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 declaración anterior crea una clase derivada de CCmdTarget.La macro de DECLARE_INTERFACE_MAP indica al marco que esta clase tiene un mapa de interfaz personalizado.Además, las macros de BEGIN_INTERFACE_PART y de END_INTERFACE_PART definen clases anidadas, en este caso con los nombres CEditObj y CPrintObj (X se utiliza para distinguir sólo clases anidadas de las clases globales que empiezan por “C” y las clases de interfaz que comienzan con “i”).Crean dos miembros anidados de estas clases: m_CEditObj, y m_CPrintObj, respectivamente.Las macros automáticamente declaran AddRef, Liberar, y las funciones de QueryInterface ; por consiguiente solo declara las funciones concretas de esta interfaz: EditObject y PrintObject ( STDMETHOD macro OLE se utiliza como para proporcionar _stdcall y palabras clave virtuales según corresponda para la plataforma de destino).

Para implementar la interfaz asignada de esta clase:

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

Esto conecta el IID_IPrintInterface IID con el m_CPrintObj e IID_IEditInterface con el m_CEditObj respectivamente.La implementación de CCmdTarget de QueryInterface (CCmdTarget::ExternalQueryInterface) utiliza este mapa para devolver punteros al m_CPrintObj y el m_CEditObj cuando se solicite.No es necesario incluir una entrada para IID_IUnknown; el marco utilizará la primera interfaz en el mapa (en este caso, m_CPrintObj) cuando se solicita IID_IUnknown .

Aunque la macro de BEGIN_INTERFACE_PART automáticamente declarado AddRef, Liberar y las funciones de QueryInterface para usted, todavía deberá implementarlos:

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

La implementación de CEditPrintObj::CPrintObj, sería similar a las definiciones anteriores para CEditPrintObj::CEditObj.Aunque fuera posible crear una macro que se puede utilizar para generar automáticamente estas funciones (pero anterior en el desarrollo de MFC/OLE esto fuera el caso), se vuelve difícil establecer puntos de interrupción cuando una macro genera más de una línea de código.Por esta razón, este código se expanda manualmente.

Mediante la implementación de los mapas de mensajes, hay varias cosas que no estaban necesarias hacer:

  • Implementar QueryInterface

  • Implementar AddRef y release

  • Declare cualquiera de estos métodos integrados en ambas de sus interfaces

Además, el marco de trabajo usa mapas de mensajes internamente.Esto permite que derive de una clase de .NET framework, indica COleServerDoc, que admite algunas interfaces y ya proporciona reemplazos o adiciones a las interfaces proporcionadas por el marco.Esto está habilitada por el hecho de que el marco admite totalmente herencia de una interfaz asignada de una clase base )que es la razón por la que BEGIN_INTERFACE_MAP toma como su segundo parámetro el nombre de la clase base.

[!NOTA]

Normalmente no es posible reutilizar la implementación de las implementaciones integradas de MFC de las interfaces VIEJAS heredando la especialización incrustada de esa interfaz de la versión de MFC.Esto no es posible porque el uso de la macro de METHOD_PROLOGUE de obtener acceso a CCmdTargetque contiene - objeto derivado implica fixed offset de objetos incrustados de CCmdTarget- objeto derivado.Esto significa, por ejemplo, no puede derivar un XMyAdviseSink incrustado de implementación de MFC en COleClientItem::XAdviseSink, porque XAdviseSink depende de ser en un desplazamiento concreto desde la parte superior del objeto de COleClientItem .

[!NOTA]

Puede, sin embargo, delegar a MFC la implementación para todas las funciones que desea el comportamiento predeterminado de MFC.Esto se hace en la implementación de MFC de IOleInPlaceFrame (XOleInPlaceFrame) en la clase de COleFrameHook (delega en el m_xOleInPlaceUIWindow para muchas funciones).Este diseño se ha elegido para reducir el tamaño en tiempo de ejecución de los objetos que implementan las interfaces; elimina la necesidad de un espalda-puntero (como la manera m_pParent se utilizó en la sección anterior).

5hhehwba.collapse_all(es-es,VS.110).gifAsigna la agregación y de interfaz

Además de admitir objetos COM independientes, MFC también admite la agregación.La agregación en sí es un tema demasiado complejo a analizar aquí; consulte la referencia) del Programador para obtener más información sobre la agregación.Esta nota describirá simplemente la compatibilidad para la agregación compilada en mapas de marco de trabajo y de la interfaz.

Hay dos formas de utilizar la agregación: (1) mediante un objeto COM que admite la agregación y (2), implementando un objeto que se puede agregar a otro.Estas funciones se pueden hacer referencia como “utilizando un objeto global” y “crear un objeto aggregatable”.MFC admite ambos.

5hhehwba.collapse_all(es-es,VS.110).gifMediante un objeto global

Para utilizar un objeto global, se necesita alguna manera de asociar el agregado en el mecanismo de QueryInterface.Es decir el objeto global debe comportarse como si es una parte nativa del objeto.¿Tan cómo este lazo en la interfaz de MFC asigna el mecanismo?Además de la macro de INTERFACE_PART , donde un objeto anidado se asigna a un identificador IID, también puede declarar un objeto global como parte de la clase derivada de CCmdTarget .Para ello, la macro de INTERFACE_AGGREGATE se utiliza.Esto permite especificar una variable miembro (que debe ser un puntero a IUnknown o clase derivada), que debe ser integrada en el mecanismo de asignación de la interfaz.Si el puntero no es NULL cuando se llama a CCmdTarget::ExternalQueryInterface , el marco automáticamente llamará a la función miembro de QueryInterface del objeto global, si IID solicitado no es uno de s para IIDnativo admitida por el propio objeto de CCmdTarget .

Para utilizar la macro de INTERFACE_AGGREGATE

  1. Declare una variable miembro ( IUnknown*) que contiene un puntero al objeto global.

  2. Incluya una macro de INTERFACE_AGGREGATE en la asignación de interfaz, que hace referencia a la variable miembro por nombre.

  3. En algún momento (normalmente durante CCmdTarget::OnCreateAggregates), inicializa la variable miembro distinto de NULL.

Por ejemplo:

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 se inicializa en el constructor en NULL.El marco omitirá una variable miembro NULL en la implementación predeterminada de QueryInterface.OnCreateAggregates es un buen lugar para crear realmente los objetos globales.Tendrá que llamarlo explícitamente si está creando el objeto fuera de la implementación de MFC de COleObjectFactory.La razón para crear agregados en CCmdTarget::OnCreateAggregates así como el uso de CCmdTarget::GetControllingUnknown será manifiesto al crear objetos aggregatable se explica.

Esta técnica dará a su objeto todas las interfaces del objeto global admite más sus interfaces nativas.Si sólo un subconjunto de las interfaces del agregado admite, puede reemplazar CCmdTarget::GetInterfaceHook.No se permite el hookability muy de bajo nivel, similar a QueryInterface.Normalmente, desea todas las interfaces del agregado admite.

5hhehwba.collapse_all(es-es,VS.110).gifCrear una implementación Aggregatable de objeto

Para que un objeto poderse agregar, la implementación de AddRef, Liberar, y QueryInterface deben delegar a “controlar el desconocido”. Es decir que forma parte del objeto, debe delegar AddRef, Liberar, y QueryInterface a otro objeto, también derivado de IUnknown.Esto “que controla desconocido” se proporciona al objeto cuando se crea, es decir, se proporciona la implementación de COleObjectFactory.Implementar esto lleva una pequeña cantidad de sobrecarga, y no es en algunos casos deseable, por lo que MFC crea esto opcional.Para permitir que un objeto como aggregatable, se llama a CCmdTarget::EnableAggregation del constructor del objeto.

Si el objeto también utiliza los agregados, también debe estar seguro de pasar el correcto “supervisando el desconocido” a objetos globales.Este puntero de IUnknown se suele pasar el objeto cuando se crea el agregado.Por ejemplo, el parámetro de pUnkOuter es “controlar el desconocido” para los objetos creados con CoCreateInstance.El correcto “a” el puntero desconocido puede recuperar llamando a CCmdTarget::GetControllingUnknown.El valor devuelto de la función, sin embargo, no es válido durante el constructor.Por esta razón, se sugiere que crea los agregados sólo en un reemplazo de CCmdTarget::OnCreateAggregates, donde es confiable el valor devuelto de GetControllingUnknown , incluso si se creó con la implementación de COleObjectFactory .

También es importante que el objeto manipula el número correcto de la referencia al agregar o liberando recuentos artificiales de referencia.Para asegurarse es el caso, siempre llamada ExternalAddRef y ExternalRelease en lugar de InternalRelease y de InternalAddRef.Es raro que llamar a InternalRelease o InternalAddRef en una clase que admite la agregación.

5hhehwba.collapse_all(es-es,VS.110).gifMaterial de referencia

El uso avanzado OLE, como definición de sus propias interfaces o invalidar la implementación de las interfaces VIEJAS requiere el uso del mecanismo subyacente de mapas de interfaz.

Esta sección describe cada macro y las API que se utiliza para implementar estas características avanzadas.

5hhehwba.collapse_all(es-es,VS.110).gifCCmdTarget::EnableAggregation — descripción de la función

void EnableAggregation();

Comentarios

Llame a esta función en el constructor de clase derivada si desea admitir la agregación) para los objetos de este tipo.Esto prepara una implementación especial de IUnknown necesarios para los objetos aggregatable.

5hhehwba.collapse_all(es-es,VS.110).gifCCmdTarget::ExternalQueryInterface — descripción de la función

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

Comentarios

5hhehwba.collapse_all(es-es,VS.110).gifParámetros

  • lpIID
    Un puntero lejano a un identificador IID (el primer argumento QueryInterface)

  • ppvObj
    Un puntero a IUnknown* (segundo argumento QueryInterface)

Comentarios

Llame a esta función en su implementación de IUnknown para cada interfaz que la clase implementa.Esta función proporciona la implementación controlada por datos estándar QueryInterface basándose en la asignación de la interfaz del objeto.Es necesario convertir el valor devuelto a HRESULT.Si se agrega el objeto, esta función llamará “controlar IUnknown” en lugar de utilizar el mapa local de la interfaz.

5hhehwba.collapse_all(es-es,VS.110).gifCCmdTarget::ExternalAddRef — descripción de la función

DWORD ExternalAddRef();

Comentarios

Llame a esta función en su implementación de IUnknown::AddRef para cada interfaz que la clase implementa.El valor devuelto es el nuevo número de referencias del objeto de CCmdTarget.Si se agrega el objeto, esta función llamará “controlar IUnknown” en lugar de manipular el recuento local de referencia.

5hhehwba.collapse_all(es-es,VS.110).gifCCmdTarget::ExternalRelease — descripción de la función

DWORD ExternalRelease();

Comentarios

Llame a esta función en su implementación de IUnknown::Release para cada interfaz que la clase implementa.El valor devuelto indica el nuevo número de referencias del objeto.Si se agrega el objeto, esta función llamará “controlar IUnknown” en lugar de manipular el recuento local de referencia.

5hhehwba.collapse_all(es-es,VS.110).gifDECLARE INTERFACE MAP - descripción de macro

DECLARE_INTERFACE_MAP

Comentarios

Use esta macro en cualquier clase derivada de CCmdTarget que tiene un mapa de interfaz.Independientemente de la misma manera que DECLARE_MESSAGE_MAP.Esta llamada de macro se debe colocar en la definición de clase, normalmente con un encabezado (. h) archivo.Una clase con DECLARE_INTERFACE_MAP debe definir la interfaz asignada en el archivo de implementación (.CPP) con macros de BEGIN_INTERFACE_MAP y de END_INTERFACE_MAP .

5hhehwba.collapse_all(es-es,VS.110).gifBEGIN_INTERFACE_PART y END_INTERFACE_PART — descripciones de macro

BEGIN_INTERFACE_PART( 
   localClass,
   iface 
);
END_INTERFACE_PART( 
   localClass 
)

Comentarios

5hhehwba.collapse_all(es-es,VS.110).gifParámetros

  • localClass
    El nombre de la clase que implementa la interfaz

  • iface
    El nombre de interfaz que esta clase implementa

Comentarios

Para cada interfaz que la clase implemente, necesita tener un par de BEGIN_INTERFACE_PART y de END_INTERFACE_PART .Estas macros definen una clase local derivada de la interfaz OLE que se define junto con una variable miembro incrustada de esa clase.Declaran AddRef, Liberar, y los miembros de QueryInterface automáticamente.Debe incluir las declaraciones de las otras funciones miembro que forman parte de la interfaz que implementan (estas declaraciones se colocan entre macros de BEGIN_INTERFACE_PART y de END_INTERFACE_PART ).

El argumento de iface es la interfaz OLE que desee al implementar, como IAdviseSink, o IPersistStorage (o su propia interfaz personalizada).

El argumento de los localClass es el nombre de la clase local que se definirá.Una “x” automáticamente se anteponen al nombre.Utilizan esta convención de nomenclatura para evitar conflictos con las clases globales del mismo nombre.Además, el nombre del miembro incrustado, lo mismo que los localClass llama a menos que vaya precedido por “m_x”.

Por ejemplo:

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)

define una clase local denominada XMyAdviseSink derivado de IAdviseSink, y un miembro de la clase en la que se declara m_xMyAdviseSink.Note denominado:

[!NOTA]

Las líneas a partir de STDMETHOD_ esencialmente se copian de OLE2.H y modifican ligeramente.Copiarlas de OLE2.H pueden reducir los errores que son difíciles de resolver.

5hhehwba.collapse_all(es-es,VS.110).gifBEGIN_INTERFACE_MAP y END_INTERFACE_MAP — descripciones de macro

BEGIN_INTERFACE_MAP( 
   theClass,
   baseClass 
)
END_INTERFACE_MAP

Comentarios

5hhehwba.collapse_all(es-es,VS.110).gifParámetros

  • theClass
    La clase en la que la asignación de la interfaz es definir

  • baseClass
    La clase de la que theClass deriva.

Comentarios

Las macros de BEGIN_INTERFACE_MAP y de END_INTERFACE_MAP se utilizan en el archivo de implementación para definir realmente la asignación de la interfaz.Para cada interfaz implementada que hay una o más llamadas a la macro de INTERFACE_PART .Para cada agregado que la clase utilice, hay una llamada de macro de INTERFACE_AGGREGATE .

5hhehwba.collapse_all(es-es,VS.110).gifINTERFACE PART - descripción de macro

INTERFACE_PART( 
   theClass,
   iid, 
   localClass 
)

Comentarios

5hhehwba.collapse_all(es-es,VS.110).gifParámetros

  • theClass
    El nombre de la clase que contiene la asignación de la interfaz.

  • iid
    IID que debe para asignarla a la clase incrustada.

  • localClass
    El nombre de la clase local (menos “X ").

Comentarios

Esta macro se utiliza entre la macro de BEGIN_INTERFACE_MAP y la macro de END_INTERFACE_MAP para cada interfaz que el objeto admitirá.Permite asignar un identificador IID a un miembro de la clase indicada por theClass y los localClass.“M_x” se agregará a los localClass automáticamente.Observe que más de un IID puede estar asociado a un solo miembro.Esto es muy útil cuando se implementa sólo “la mayoría” de la interfaz y el deseo derivados para proporcionar todas las interfaces intermedias también.Un buen ejemplo de esto es la interfaz de IOleInPlaceFrameWindow .Su jerarquía tiene el siguiente aspecto:

IUnknown
    IOleWindow
        IOleUIWindow
            IOleInPlaceFrameWindow

Si un objeto implementa IOleInPlaceFrameWindow, un cliente puede QueryInterface en cualquiera de estas interfaces: IOleUIWindow, IOleWindow, o IUnknown, además de “la mayoría” de la interfaz derivada IOleInPlaceFrameWindow (el que implementa realmente).Para administrar esto puede utilizar más de una macro de INTERFACE_PART para asignar cada interfaz base a la interfaz de IOleInPlaceFrameWindow :

en el archivo de definición de clase:

BEGIN_INTERFACE_PART(CMyFrameWindow, IOleInPlaceFrameWindow)

en el archivo de implementación de la clase:

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

El marco se ocupa de IUnknown porque siempre se requiere.

5hhehwba.collapse_all(es-es,VS.110).gifINTERFACE PART - descripción de macro

INTERFACE_AGGREGATE( 
   theClass,
   theAggr 
)

Comentarios

5hhehwba.collapse_all(es-es,VS.110).gifParámetros

  • theClass
    El nombre de la clase que contiene el mapa de interfaz,

  • theAggr
    El nombre de la variable miembro que debería agregar.

Comentarios

Esta macro se utiliza para indicar al marco que la clase está utilizando un objeto global.Debe aparecer entre macros de BEGIN_INTERFACE_PART y de END_INTERFACE_PART .Un objeto global es un objeto independiente, derivado de IUnknown.Mediante un agregado y la macro de INTERFACE_AGGREGATE , puede crear todas las interfaces del global admite parece ser compatible directamente el objeto.El argumento de theAggr es simplemente el nombre de una variable miembro de la clase que se deriva de IUnknown (directa o indirectamente).Todas las macros de INTERFACE_AGGREGATE deben seguir las macros de INTERFACE_PART cuando se coloquen en un mapa de interfaz.

Vea también

Otros recursos

Notas técnicas por número

Notas técnicas por categoría