Puntos de conexión
En este artículo se explica cómo implementar puntos de conexión (anteriormente conocidos como puntos de conexión OLE) mediante las clases CCmdTarget
y CConnectionPoint
de MFC.
En el pasado, el Modelo de objetos componentes (COM) definió un mecanismo general (IUnknown::QueryInterface
*) que permitía a los objetos implementar y exponer la funcionalidad en interfaces, pero no se definió un mecanismo correspondiente que les permitiese exponer su capacidad para llamar a interfaces específicas. Es decir, COM definió cómo se controlaban los punteros entrantes a objetos (los punteros a las interfaces de ese objeto), pero no tenía un modelo explícito para las interfaces salientes (los punteros que el objeto contiene a otras interfaces de objetos). Actualmente, COM tiene un modelo denominado puntos de conexión que admite esta funcionalidad.
Una conexión tiene dos partes: el objeto que llama a la interfaz (denominado origen) y el objeto que implementa la interfaz (denominado receptor). Un punto de conexión es la interfaz expuesta por el origen. Al exponer un punto de conexión, un origen permite a los receptores establecer conexiones a sí mismos (el origen). Mediante el mecanismo de punto de conexión (la interfaz IConnectionPoint
), se pasa al objeto de origen un puntero a la interfaz receptora. Este puntero proporciona al origen acceso a la implementación del receptor de un conjunto de funciones miembro. Por ejemplo, para desencadenar un evento implementado por el receptor, el origen puede llamar al método adecuado de la implementación del receptor. En la ilustración siguiente se muestra el punto de conexión que se acaba de describir.
Un punto de conexión implementado
MFC implementa este modelo en las clases CConnectionPoint y CCmdTarget. Las clases derivadas de CConnectionPoint
implementan la interfaz IConnectionPoint
, que se usa para exponer puntos de conexión a otros objetos. Las clases derivadas de CCmdTarget
implementan la interfaz IConnectionPointContainer
, que puede enumerar todos los puntos de conexión disponibles de un objeto o buscar un punto de conexión específico.
Para cada punto de conexión implementado en la clase, debe declarar un elemento de conexión que implemente el punto de conexión. Si implementa uno o varios puntos de conexión, también debe declarar un único mapa de conexión en la clase. Un mapa de conexión es una tabla de los puntos de conexión que admite el control ActiveX.
En los ejemplos siguientes se muestra un mapa de conexión simple y un punto de conexión. En el primer ejemplo se declara el mapa de conexión y el punto; el segundo ejemplo implementa el mapa y el punto. Tenga en cuenta que CMyClass
debe ser una clase derivada de CCmdTarget
. En el primer ejemplo, el código se inserta en la declaración de clase, en la sección protected
:
class CMyClass : public CCmdTarget
{
protected:
// Connection point for ISample interface
BEGIN_CONNECTION_PART(CMyClass, SampleConnPt)
CONNECTION_IID(IID_ISampleSink)
END_CONNECTION_PART(SampleConnPt)
DECLARE_CONNECTION_MAP()
Las macros BEGIN_CONNECTION_PART y END_CONNECTION_PART declaran una clase insertada, XSampleConnPt
(derivada de CConnectionPoint
), que implementa este punto de conexión determinado. Si quiere invalidar cualquier función miembro CConnectionPoint
o agregar funciones miembro propias, declárelas entre estas dos macros. Por ejemplo, la macro CONNECTION_IID
invalida la función miembro CConnectionPoint::GetIID
cuando se coloca entre estas dos macros.
En el segundo ejemplo, el código se inserta en el archivo de implementación del control (archivo .cpp). Este código implementa el mapa de conexión, que incluye el punto de conexión, SampleConnPt
:
BEGIN_CONNECTION_MAP(CMyClass, CCmdTarget)
CONNECTION_PART(CMyClass, IID_ISampleSink, SampleConnPt)
END_CONNECTION_MAP()
Si la clase tiene más de un punto de conexión, inserte macros CONNECTION_PART adicionales entre las macros BEGIN_CONNECTION_MAP y END_CONNECTION_MAP.
Por último, agregue una llamada a EnableConnections
en el constructor de la clase. Por ejemplo:
CMyClass::CMyClass()
{
EnableConnections();
}
Una vez insertado este código, la clase derivada de CCmdTarget
expone un punto de conexión para la interfaz ISampleSink
. En la siguiente figura, se ilustra este ejemplo.
Un punto de conexión implementado con MFC
Normalmente, los puntos de conexión admiten la "multidifusión", es decir, la capacidad de difundir a varios receptores conectados a la misma interfaz. En el fragmento de ejemplo siguiente se muestra cómo realizar la multidifusión mediante la iteración en cada receptor de un punto de conexión:
void CMyClass::CallSinkFunc()
{
POSITION pos = m_xSampleConnPt.GetStartPosition();
ISampleSink* pSampleSink;
while (pos != NULL)
{
pSampleSink = (ISampleSink*)(m_xSampleConnPt.GetNextConnection(pos));
if (pSampleSink != NULL)
pSampleSink->SinkFunc();
}
}
En este ejemplo se recupera el conjunto actual de conexiones en el punto de conexión SampleConnPt
con una llamada a CConnectionPoint::GetConnections
. A continuación, itera por las conexiones y llama a ISampleSink::SinkFunc
en cada conexión activa.