En el corazón de OLE 2 es el "OLE Component Object Model" o COM. COM define un estándar para objetos cooperantes cómo comunicarse mutuamente. Esto incluye los detalles de lo que un "objeto" parece, incluyendo cómo se envían los métodos en un objeto. COM también define una clase base, del que se derivan todas las clases de COM compatibles. Esta clase base es IUnknown. Aunque la interfaz IUnknown se conoce como una clase de C++, COM no es específico de ningún uno idioma — puede implementarse en C, PASCAL o cualquier otro idioma que puede apoyar la distribución binaria de un objeto COM.
OLE se refiere a todas las clases derivadas de IUnknown como "interfaces". Esta distinción es importante, desde una "interfaz" como IUnknown no lleva consigo ninguna implementación. Simplemente define el Protocolo por el cual comunicar objetos, no los detalles de lo que hacen las implementaciones. Esto es razonable para un sistema que permite la máxima flexibilidad. Es trabajo de MFC para implementar un comportamiento predeterminado para programas de C++ y MFC.
Para entender la aplicación de MFC de IUnknown primero debe entender lo que es esta interfaz. Una versión simplificada de IUnknown se define a continuación:
clase IUnknown
{
público:
nbsp; virtual HRESULT QueryInterface(REFIID iid, void** ppvObj) = 0;
virtual ULO&NG AddRef() = 0;
virtual ULONG Release() = 0;
}
&Notanbsp; Ciertos detalles Convención llamada necesarios tales como __stdcall quedan de esta ilustración.
Las funciones miembro AddRef y Release controlan la administración de memoria del objeto. COM utiliza un esquema de recuento de referencia para el seguimiento de objetos. Nunca se hace referencia a un objeto directamente como lo haría en C++. En su lugar, siempre referencia a objetos COM a través de un puntero. Para liberar el objeto cuando el propietario se realiza usando, miembro de la versión del objeto se llama (como en lugar de utilizar el operador delete, como se haría para un objeto de C++ tradicional). La referencia contando mecanismo permite múltiples referencias a un único objeto sea administrado. Una implementación de AddRef y Release mantiene un contador de referencia en el objeto, el objeto no se eliminará hasta que llega a su número de referencia cero.
AddRef y Release son bastante sencillos desde un punto de vista de la aplicación. Aquí es una implementación trivial:
ULO&NG CMyObj::AddRef() {nbsp; devolver ++ m_dwRef;
}
ULONG CMyObj::Release() {si (--m_dwRef == 0) {}
eliminar este;
devuelven 0;
}
Return m_dwRef;
}
La función de miembro de QueryInterface es un poco más interesante. Como se puede imaginar, no es muy interesante tener un objeto cuyas funciones miembro sólo son AddRef y Release : estaría bien indicar el objeto de hacer más cosas que proporciona IUnknown . Esto es donde QueryInterface es útil. Permite obtener una "interfaz" diferente en el mismo objeto. Estas interfaces se derivan generalmente de IUnknown y agregar funcionalidad adicional mediante la adición de nuevas funciones de miembro. Interfaces COM nunca tienen variables miembro declaradas en la interfaz, y todas las funciones miembro se declaran como puro virtual. Por ejemplo,
clase IPri&ntInterface: IUnknown pública
{
público:
nbsp; virtual void PrintObject() = 0;
}
Para obtener una IPrintInterface si sólo tienes un IUnknown, llame a IUnknown:: QueryInterface utilizando el IID de la IPrintInterface. Un IID es un número de 128 bits que identifica la interfaz. Hay un IID para cada interfaz que usted o OLE definen. Si pUnk es un puntero a un objeto IUnknown , podría ser el código para recuperar un IPrintInterface de ella
IPrintInterface * pPrint = NULL;
Si (pUnk-gt;QueryInterface(IID_IPrintInterface, (void**) & pPrint) == NOERROR)
{
pPrint - > PrintObject();
pPrint - > Release();
/ / puntero versión obtenida a través de QueryInterface
}
Parece bastante fácil, pero ¿cómo implementaría un objeto compatible con interfaz IUnknown tanto el IPrintInterface? En este caso es simple ya que el IPrintInterface se deriva directamente de IUnknown — mediante la implementación de IPrintInterface, automáticamente se admite IUnknown . Por ejemplo:
clase CPrintObj: CPrintInterface pública
{
nbsp; virtual de HRESULT de QueryInterface(REFIID iid, void** ppvObj);
virtual de ULO&NG de AddRef();
virtual ULONG Release();
virtual void PrintObject();
}
Las implementaciones de AddRef y Release sería exactamente lo mismo que las aplicadas anteriormente. CPrintObj::QueryInterface sería algo como esto
HRESULT CPrintObj::QueryInterface(REFIID iid, void FAR* FAR* ppvObj)
{
nbsp; Si (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
* ppvObj =;
AddRef();
Return &NOERROR;
}
Return ResultFromScode(E_NOINTERFACE);
}
Como puede ver, si se reconoce el identificador de interfaz (IID), se devuelve un puntero al objeto; de lo contrario se produce un error. También tenga en cuenta que un exitoso QueryInterface resulta en una implícita AddRef. Por supuesto, también tendría que implementar CEditObj::Print. Es simple porque el IPrintInterface se deriva directamente la interfaz IUnknown . Sin embargo, si desea apoyar dos interfaces diferentes, ambos derivados de IUnknown, considere lo siguiente
clase IEditI&nterface: IUnkown pública
{
público:
nbsp; virtual void EditObject() = 0;
}
Aunque hay un número de diferentes maneras de implementar una clase de soporte IEditInterface y IPrintInterface, incluyendo el uso de C++ herencia múltiple, esta nota se concentrará en el uso de las clases anidadas para implementar esta funcionalidad.
clase CEditPrintObj
{
público:
nbsp; CEditPrintObj();
HRESULT QueryInterface(REFIID iid, void**);
ULO&NG AddRef();
ULONG Release();
DWORD m_dwRef;
clase CPrintObj: IPrintInterface pública
{
público:
CEditPrintObj * m_pParent;
virtual de HRESULT de QueryInterface(REFIID iid, void** ppvObj);
virtual de ULONG de AddRef();
virtual ULONG Release();
} m_printObj;
clase CEditObj: IEditInterface pública
{
público:
CEditPrintObj * m_pParent;
virtual de ULONG de QueryInterface(REFIID iid, void** ppvObj);
virtual de ULONG de AddRef();
virtual ULONG Release();
} m_editObj;
}
La implementación completa se incluye a continuación:
CEditPrintObj::CEditPrintObj()
{
nbsp; m_editObj.m_pParent = this;
m_printObj.m_pParent = this;
}
ULONG CEditPrintObj::AddRef() {return ++ m_dwRef;
}
CEditPrintObj::Release()
{
Si (--m_dwRef == 0)
{
eliminar este;
devuelven 0;
}
Return m_dwRef;
}
HRESULT CEditPrintObj::QueryInterface(REFIID iid, void** ppvObj)
{
Si (iid == IID_IUnknown || iid == IID_IPrintInterface)
{
* ppvObj = & m_printObj;
AddRef();
Return NOERROR;
}
else if (iid == IID_IEditInterface)
{
* ppvObj = & m_editObj;
AddRef();
Return NOERROR;
}
Return ResultFromScode(E_NOINTERFACE);
}
ULONG CEditPrintObj::CEditObj::AddRef() {return m_pParent - > AddRef();
}
ULONG CEditPrintObj::CEditObj::Release() {return m_pParent - > Release();
}
HRESULT CEditPrintObj::CEditObj::QueryInterface (
REFIID iid, vacío ** 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, vacío ** ppvObj) {return m_pParent - > QueryInterface (iid, ppvObj);
}
Observe que la mayor parte de la aplicación de IUnknown se coloca en la clase de CEditPrintObj en lugar de duplicar el código en CEditPrintObj::CEditObj y CEditPrintObj::CPrintObj. Esto reduce la cantidad de código y evita errores. El punto clave aquí es que desde la interfaz IUnknown es posible llamar a QueryInterface para recuperar cualquier interfaz que podría apoyar el objeto, y de cada una de estas 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 estos objetos incrustados llamar a la implementación en el "objeto exterior", un puntero de espalda es utilizado (m_pParent). Se inicializa el puntero m_pParent durante el constructor CEditPrintObj. Luego sería aplicar CEditPrintObj::CPrintObj::PrintObject y CEditPrintObj::CEditObj::EditObject así. Se añadió un poco de código para agregar una característica: la capacidad para modificar el objeto. Afortunadamente, es bastante raro para las interfaces de tener sólo una función miembro único (aunque suceder) y en este caso, EditObject y PrintObject que suelen combinarse en una sola interfaz.
Eso es un montón de explicaciones y un montón de código para un escenario así de simple. Las clases MFC/OLE ofrecen una alternativa más sencilla. La implementación de MFC utiliza una técnica similar a la forma de mensajes de Windows están envueltos con mapas de mensajes. Este mecanismo se denomina Interfaz de mapas y se discute en la siguiente sección.
Mapas de interfaz MFC
MFC/OLE incluye una aplicación de "Mapas de interfaz" similar "de MFC mensaje mapas" y "envío" en la concepción y ejecución. Las características principales de los mapas de interfaz de MFC son los siguientes:
Además, mapas de interfaz admiten las siguientes características avanzadas:
Para obtener más información sobre totalización, consulte la referencia del programador de OLE.
Soporte de la interfaz mapa de MFC está arraigada en la clase de CCmdTarget. . CCmdTarget. "tiene una" referencia Conde, así como todas las funciones de miembro asociadas a la aplicación de IUnknown (el recuento de referencia por ejemplo está en CCmdTarget.). Para crear una clase que admita OLE COM, derivar una clase de CCmdTarget y utilizar varias macros, así como funciones de miembro de CCmdTarget para implementar las interfaces deseadas. Implementación de MFC utiliza las clases anidadas para definir cada implementación de interfaz al igual que el ejemplo anterior. Esto se hace más fácil con una implementación estándar de IUnknown, así como una serie de macros que eliminar algunos el código repetitivo.
Mapa básico de interfaz
Para implementar una clase utilizando la interfaz de MFC mapas siguen estos pasos:
El ejemplo de CPrintEditObj anterior podría implementarse como sigue:
clase CPrintEditObj: CCmdTarget pública.
{
público:
nbsp; / / datos de miembros y funciones miembro para CPrintEditObj ir aquí
/ / Mapas de interfaz
protegido:
DECLARE_I&NTERFACE_MAP()
BEGIN_INTERFACE_PART (EditObj, IEditInterface)
STDMETHOD_ (vacío, EditObject)();
END_INTERFACE_PART(EditObj)
BEGIN_INTERFACE_PART (PrintObj, IPrintInterface)
STDMETHOD_ (vacío, PrintObject)();
END_INTERFACE_PART(PrintObj)
}
La declaración anterior crea una clase que se deriva de CCmdTarget.. La macro DECLARE_INTERFACE_MAP indica el marco que esta clase tendrá un mapa de interfaz personalizada. Además, las macros BEGIN_INTERFACE_PART y END_INTERFACE_PART definen las clases anidadas, en este caso con los nombres CEditObj y CPrintObj (la x es utilizada sólo para diferenciar las clases anidadas de clases globales que comienzan con "C" y clases de interfaz que comienzan con "I"). Se crean dos miembros anidados de estas clases: m_CEditObj y m_CPrintObj, respectivamente. Las macros automáticamente declaran la AddRef, liberacióny QueryInterface funciones; por lo tanto sólo declarar las funciones específicas de esta interfaz: EditObject y PrintObject (la macro OLE STDMETHOD es tal utilizado por lo que se proporciona como apropiado para la plataforma de destino _stdcall y palabras clave virtual).
Para aplicar el mapa de interfaz para esta clase:
BEGI&N_INTERFACE_MAP (CPrintEditObj, CCmdTarget.)
nbsp; INTERFACE_PART (CPrintEditObj, IID_IPrintInterface, PrintObj)
INTERFACE_PART (CPrintEditObj, IID_IEditInterface, EditObj)
END_INTERFACE_MAP()
Esto conecta el IID de IID_IPrintInterface con m_CPrintObj y IID_IEditInterface con m_CEditObj respectivamente. La implementación de CCmdTarget de QueryInterface (CCmdTarget::ExternalQueryInterface) utiliza este mapa para devolver punteros m_CPrintObj y m_CEditObj cuando se solicita. 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.
A pesar de que la macro BEGIN_INTERFACE_PART declarado automáticamente la AddRef, liberación y funciones de QueryInterface para usted, aún necesita aplicarlos:
ULONG lejos exportación CEditPrintObj::XEditObj::AddRef()
{
nbsp; METHOD_PROLOGUE (CEditPrintObj, EditObj)
retorno pThis - > ExternalAddRef();
}
ULONG lejos exportación CEditPrintObj::XEditObj::Release()
{
METHOD_PROLOGUE (CEditPrintObj, EditObj)
retorno pThis - > ExternalRelease();
}
HRESULT ahora exportar () CEditPrintObj::XEditObj::QueryInterface
REFIID iid, void FAR * extremo * ppvObj)
{
METHOD_PROLOGUE (CEditPrintObj, EditObj)
Retorno (HRESULT) pThis - > ExternalQueryInterface (& iid, ppvObj);
}
anular ahora exportar CEditPrintObj::XEditObj::EditObject()
{
METHOD_PROLOGUE (CEditPrintObj, EditObj)
/ / código para "Modificar" el objeto, independientemente que significa...
}
La aplicación de CEditPrintObj::CPrintObj, sería similar a las definiciones anteriores para CEditPrintObj::CEditObj. Aunque sería posible crear una macro que podría utilizarse para generar automáticamente estas funciones (de hecho, anteriormente en el desarrollo de MFC/OLE este fue el caso), resulta 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 expande manualmente.
Mediante el uso de la aplicación del marco del mensaje de mapas que son un número de cosas que no eran necesarias para hacer:
Además, el marco utiliza mapas de mensajes internos. Esto permite derivar una clase de marco, dicen COleServerDoc, que ya soporta determinadas interfaces y proporciona sustituciones o adiciones a las interfaces proporcionadas por el marco. Esta opción está activada por el hecho de que el marco apoya plenamente heredando una interfaz de mapa de una clase base, que es la razón por qué BEGIN_INTERFACE_MAP toma como segundo parámetro el nombre de la clase base.
&Notanbsp; Generalmente, no es posible reutilizar la aplicación de las implementaciones integradas de MFC de las interfaces OLE por Heredar la especialización incrustada de la interfaz de la versión MFC. Esto no es posible porque el uso de la macro METHOD_PROLOGUE para obtener acceso a los que contengan CCmdTarget.-objeto derivado implica un fijo de desplazamiento del objeto incrustado desde el CCmdTarget.-objeto derivado. Esto significa, por ejemplo, que no se puede derivar un XMyAdviseSink incrustado desde la implementación de MFC en COleClientItem::XAdviseSink, porque XAdviseSink se basa en ser un desplazamiento específico desde la parte superior del objeto COleClientItem.
Sin embargo, puede delegar a la aplicación de MFC para todas las funciones que desea el comportamiento predeterminado de MFC. Esto se hace en la aplicación de MFC de IOleInPlaceFrame (XOleInPlaceFrame) en la clase COleFrameHook (delegados a m_xOleInPlaceUIWindow para muchas funciones). Este diseño fue elegido para reducir el tamaño de la ejecución de los objetos que implementan interfaces muchos; elimina la necesidad de un puntero de espalda (como el m_pParent de forma fue usado en la sección anterior).
Agregación y mapas de interfaz
Además de admitir objetos COM independientes, MFC también admite agregación. Agregación de sí mismo es un tema demasiado complejo para discutir aquí; Consulte la referencia del programador de OLE para obtener más información sobre la agregación. Esta nota describe simplemente el apoyo para la agregación incorporada en los mapas de marco e interfaz.
Hay dos formas de utilizar agregación: (1) utilizando un objeto COM que soporta agregación y (2) la implementación de un objeto que puede agregarse por otro. Estas capacidades se pueden hacer referencia a como "utilizando un objeto agregado" y "hacer que un objeto agregables". MFC admite ambos.
Utilizando un objeto agregado
Para utilizar un objeto agregado, tiene que haber alguna forma de atar el agregado en el mecanismo de QueryInterface. En otras palabras, el objeto agregado debe comportarse como si fuese una parte nativa de su objeto. Así que cómo funciona este empate en mecanismo de mapa de interfaz de MFC? Además de la macro INTERFACE_PART , donde un objeto anidado se asigna a un IID, también se puede declarar un objeto agregado como parte de su clase de CCmdTarget derivados. Para ello, se utiliza la macro INTERFACE_AGGREGATE . Esto le permite especificar una variable miembro (que debe ser un puntero a un IUnknown o clase derivada), que es integrarse en el mecanismo de mapa de interfaz. Si el puntero no es NULL cuando se llama a CCmdTarget::ExternalQueryInterface , el marco llamará automáticamente la función de miembro del objeto agregado QueryInterface , si así lo solicita el IID no es uno de los nativos s IIDapoyado por el propio objeto de CCmdTarget..
Para utilizar la macro INTERFACE_AGGREGATE, siga estos pasos:
Por ejemplo,
clase CAggrExample: CCmdTarget pública.
{
público:
nbsp; CAggrExample();
protegido:
LPUNKNOWN m_lpAggrInner;
virtual BOOL OnCreateAggregates();
DECLARE_INTERFACE_MAP()
/ / pueden utilizar macros de parte de interfaz "nativa" aquí
};
CAggrExample::CAggrExample()
{
m_lpAggrInner = NULL;
}
BOOL CAggrExample::OnCreateAggregates()
{
/ / alambre hasta agregado con correcto control desconocido
m_lpAggrInner = CoCreateInstance (CLSID_Example,
GetControllingUnknown(), CLSCTX_INPROC_SERVER,
IID_IUnknown, (LPVOID **) & m_lpAggrInner);
Si (m_lpAggrInner == NULL)
Return FALSE;
/ / crear opcionalmente, otros objetos agregados aquí
Devuelve TRUE;
}
BEGIN_INTERFACE_MAP (CAggrExample, CCmdTarget.)
/ / nativas entradas de "INTERFACE_PART" haga clic aquí
INTERFACE_AGGREGATE (CAggrExample, m_lpAggrInner)
END_INTERFACE_MAP()
El m_lpAggrInner es inicializar en el constructor a NULL. El marco no tendrá en cuenta una variable de miembro NULL en la implementación predeterminada de QueryInterface. OnCreateAggregates es un buen lugar para crear los objetos agregados. Tendrás que llamarlo explícitamente si va a crear el objeto fuera de la aplicación MFC de COleObjectFactory. El motivo para crear agregados en CCmdTarget::OnCreateAggregates , así como el uso de CCmdTarget::GetControllingUnknown se hará evidente cuando se discute la creación de objetos agregables.
Esta técnica le dará el objeto de todas las interfaces que admite el objeto agregado además sus interfaces nativas. Si sólo desea un subconjunto de las interfaces que soporta el agregado, puede reemplazar CCmdTarget::GetInterfaceHook. Esto le permite hookability de nivel muy bajo, similar a QueryInterface. Por lo general, desea que todas las interfaces que soporta el agregado.
Haciendo una implementación de objeto agregables
Para que un objeto ser agregables, debe delegar la ejecución de QueryInterface , AddRefy Releasea un "control desconocido". En otras palabras, para que sea parte del objeto, deben delegar QueryInterface , AddRefy Releasea un objeto distinto, también derivado de IUnknown. Este "control desconocido" es siempre al objeto cuando se crea, es decir, se proporciona a la aplicación de COleObjectFactory. Implementar esto lleva una pequeña cantidad de sobrecarga y en algunos casos no es deseable, por lo que MFC hace esto opcional. Para habilitar un objeto ser agregables, llame a CCmdTarget::EnableAggregation desde el constructor del objeto.
Si el objeto utiliza también los agregados, también debe estar seguro de pasar el correcto "control desconocido" a los objetos agregados. Normalmente este puntero IUnknown se pasa al objeto cuando se crea el agregado. Por ejemplo, el parámetro de pUnkOuter desconoce el "control" para objetos creados con CoCreateInstance. El puntero correcto "control a desconocido" se puede recuperar llamando a CCmdTarget::GetControllingUnknown. El valor devuelto por esta función, sin embargo, no es válido durante el constructor. Por esta razón, se sugiere que crear sus agregados sólo en una anulación de CCmdTarget::OnCreateAggregates, donde el valor devuelto por GetControllingUnknown es confiable, aunque creados a partir de la aplicación de COleObjectFactory.
También es importante que el objeto de manipular el recuento de referencias correcto al agregar o liberación de recuentos de referencias artificiales. Para asegurarse de que este es el caso, siempre llame a ExternalAddRef y ExternalRelease en lugar de InternalRelease y InternalAddRef. Es raro que se llame InternalRelease o InternalAddRef en una clase que admite agregación.
Material de referencia
Uso avanzado de OLE, como definición de sus propias interfaces o reemplazar la aplicación del marco de las interfaces OLE requiere el uso del mecanismo subyacente de mapa de interfaz.
Esta sección describe cada macro y las API que se utilizan para implementar estas características avanzadas.
CCmdTarget::EnableAggregation: Descripción de la función
void EnableAggregation();
&Notanbsp; Llamar a esta función en el constructor de la clase derivada si desea admiten OLE agregación de objetos de este tipo. Esto prepara una implementación de IUnknown especial que se requiere para los objetos agregables.
CCmdTarget::ExternalQueryInterface: Descripción de la función
DWORD ExternalQueryInterface (const void FAR * lpIID, LPVOID lejano * ppvObj);
lpIID
Un puntero lejos a un IID (el primer argumento a QueryInterface)
ppvObj
Un puntero a un IUnknown * (segundo argumento a QueryInterface)
&Notanbsp; Llamar a esta función en su implementación de IUnknown para cada interfaz de la clase implementa. Esta función proporciona la implementación estándar impulsados por datos de QueryInterface basado en mapa de la interfaz del objeto. Es necesario convertir el valor devuelto para un valor HRESULT. Si el objeto es agregado, esta función llamará "IUnknown de control" en lugar de utilizar el mapa de la interfaz local.
CCmdTarget::ExternalAddRef: Descripción de la función
DWORD ExternalAddRef();
&Notanbsp; Llamar a esta función en su implementación de IUnknown::AddRef para cada interfaz de la clase implementa. El valor devuelto es el nuevo recuento de referencias en el objeto de CCmdTarget.. Si el objeto es agregado, esta función llamará "IUnknown de control" en lugar de manipular el recuento de referencias locales.
CCmdTarget::ExternalRelease: Descripción de la función
DWORD ExternalRelease();
&Notanbsp; Llamar a esta función en su implementación de IUnknown::Release para cada interfaz de la clase implementa. El valor devuelto indica el nuevo recuento de referencias en el objeto. Si el objeto es agregado, esta función llamará "IUnknown de control" en lugar de manipular el recuento de referencias locales.
DECLARE_INTERFACE_MAP: Descripción de la Macro
DECLARE_INTERFACE_MAP
&Notanbsp; Utilice esta macro en cualquier clase derivada de CCmdTarget que va a tener un mapa de la interfaz. Utilizado en gran parte del mismo modo que DECLARE_MESSAGE_MAP. Esta invocación macro debe colocarse en la definición de clase, normalmente en un encabezado (.H) archivo. Una clase con DECLARE_INTERFACE_MAP debe definir el mapa de la interfaz en el archivo de implementación (.CPP) con las macros BEGIN_INTERFACE_MAP y END_INTERFACE_MAP.
BEGIN_INTERFACE_PART y END_INTERFACE_PART — descripciones de Macro
BEGIN_INTERFACE_PART (localClass, iface);
END_INTERFACE_PART (localClass)
localClass
El nombre de la clase que implementa la interfaz
iface
El nombre de la interfaz que implementa esta clase
&Notanbsp; Para cada interfaz que implementará su clase, necesita tener un par de BEGIN_INTERFACE_PART y END_INTERFACE_PART . Estas macros definen una clase local derivada de la interfaz OLE que definen como una variable de miembro incrustado de esa clase. Los miembros de QueryInterface , AddRefy Releasese declaran automáticamente. Debe incluir las declaraciones de las funciones de miembros que forman parte de la interfaz está implementada (esas declaraciones se colocan entre las macros BEGIN_INTERFACE_PART y END_INTERFACE_PART ).
El argumento iface es la interfaz OLE que desea implementar, como IAdviseSink, o IPersistStorage (o su propia interfaz personalizada).
El argumento localClass es el nombre de la clase local que será definida. Un ' X' automáticamente se antepone al nombre. Esta Convención de nomenclatura se utiliza para evitar colisiones con clases mundiales del mismo nombre. Además, el nombre del miembro incrustado, el mismo que el nombre de localClass , excepto que se pone por 'm_x'.
Por ejemplo:
BEGI&N_INTERFACE_PART (MyAdviseSink, IAdviseSink)
nbsp; STDMETHOD_(void,OnDataChange) (LPFORMATETC, LPSTGMEDIUM);
STDMETHOD_(void,OnViewChange) (DWORD, largo);
STDMETHOD_(void,OnRename)(LPMONIKER);
STDMETHOD_(void,OnSave)();
STDMETHOD_(void,OnClose)();
END_INTERFACE_PART(MyAdviseSink)
definiría una clase local llamada XMyAdviseSink derivada IAdviseSink, y un miembro de la clase en la que se declara llamado m_xMyAdviseSink.Note:
&Notanbsp; Esencialmente se copian las líneas a partir de STDMETHOD_ de OLE2.H y ligeramente modificado. Copiarlos de OLE2.H puede reducir los errores que son difíciles de resolver.
BEGIN_INTERFACE_MAP y END_INTERFACE_MAP — descripciones de Macro
BEGIN_INTERFACE_MAP (theClass, baseClass)
END_INTERFACE_MAP
theClass
La clase en la que el mapa de la interfaz es definirse
baseClass
La clase de la que deriva theClass.
Observaciones: Las macros BEGIN_INTERFACE_MAP y END_INTERFACE_MAP se utilizan en el archivo de implementación para definir realmente el mapa de la interfaz. Para cada interfaz que implementa hay uno o más invocaciones de macro INTERFACE_PART . Para cada agregado que utiliza la clase, hay una llamada de macro INTERFACE_AGGREGATE.
INTERFACE_PART: Descripción de la Macro
INTERFACE_PART (theClass, iid, localClass)
theClass
El nombre de la clase que contiene el mapa de la interfaz.
iid
El IID que debe asignarse a la clase incrustada.
localClass
El nombre de la clase local (menos la ' X')
&Notanbsp; Esta macro se utiliza entre la macro BEGIN_INTERFACE_MAP y la macro END_INTERFACE_MAP para cada interfaz que apoyará su objeto. Le permite asignar un IID a un miembro de la clase indicada por theClass y localClass. Automáticamente se agregará a la localClass 'm_x'. Tenga en cuenta que más de un IID puede estar asociado con un solo miembro. Esto es muy útil cuando se está aplicando sólo una interfaz "más derivados" y deseen proporcionar interfaces intermedias todos así. Un buen ejemplo de esto es la interfaz IOleInPlaceFrameWindow . Su jerarquía este aspecto:
IU&nknown
nbsp; IOleWindow
IOleUIWindow
IOleInPlaceFrameWindow
Si un objeto implementa IOleInPlaceFrameWindow, un cliente puede QueryInterface en cualquiera de estas interfaces: IOleUIWindow, IOleWindowo IUnknown, además de la interfaz "más derivada" IOleInPlaceFrameWindow (el uno realmente está implementando). Para manejar esto puede utilizar más de una macro INTERFACE_PART para cada interfaz base se asignan 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:
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
El marco se encarga de IUnknown ya que siempre es necesario.
INTERFACE_PART: Descripción de la Macro
INTERFACE_AGGREGATE (theClass, theAggr)
theClass
El nombre de la clase que contiene el mapa de la interfaz,
theAggr
El nombre de la variable miembro que deba agregarse.
&Notanbsp; Esta macro se utiliza para indicar el marco que la clase es utilizando un objeto agregado. Debe aparecer entre las macros BEGIN_INTERFACE_PART y END_INTERFACE_PART . Un objeto agregado es un objeto separado, derivado de IUnknown. Mediante un agregado y la macro INTERFACE_AGGREGATE , puede hacer que todas las interfaces que soporta agregado parece ser admitidos directamente por el objeto. El argumento theAggr es simplemente el nombre de una variable de miembro de la clase que se deriva de IUnknown (directa o indirectamente). Todas las macros INTERFACE_AGGREGATE deben seguir las macros INTERFACE_PART cuando se coloca en un mapa de interfaz.
&Notas técnicas por número |nbsp; Notas técnicas por categoría