Connections and Events in an ATL-Based Control

[Previous] [Next]

The last item to look at within a control is how to set up the connection points so that the control can fire events back to the container. This section serves as an overview—Chapter 12 provides more detailed information about connection points.

When you set up an event set for your control, you start by defining the events in the control's IDL file. You then compile the project, which builds the type library. In this example, the control fires an event under two conditions: when the number of events exceeds a certain threshold, and upon each new interval.

The following code shows the message traffic control's event set described in IDL:

 #include <olectl.h> // ATLMsgTraffic.idl : IDL source for ATLMsgTraffic.dll // // This file will be processed by the MIDL tool to //  produce the type library (ATLMsgTraffic.tlb) and //  marshaling code. import "oaidl.idl"; import "ocidl.idl"; // Interface definitions and such  [     uuid(1AB5D84F-B593-11D1-8CAA-952EA6C89F6D),     version(1.0),     helpstring("ATLMsgTraffic 1.0 Type Library") ] library ATLMSGTRAFFICLib {     importlib("stdole32.tlb");     importlib("stdole2.tlb");     [         uuid(1C4BFAC4-B4A5-11D1-8CAA-FC1024D62D6E),         helpstring("Event interface for ATLMsgTraffic Control")     ]     dispinterface _DATLMsgTrafficEvents     {         properties:             // Event interface has no properties         methods:             [id(1)] void ExceededThreshold(long NumMessages,                  long CurrentThreshold);             [id(2)] void NewInterval(long NumMessages);     };     [         uuid(1AB5D85D-B593-11D1-8CAA-952EA6C89F6D),         helpstring("ATLMsgTrafficCtl Class")     ]     coclass ATLMsgTrafficCtl     {         [default] interface IATLMsgTrafficCtl;         [default, source] dispinterface _DATLMsgTrafficEvents;     }; }; 

Once the type library is compiled, you can ask ClassView to create a callback proxy for you by selecting the control's class from ClassView, right-clicking on the class, and selecting Implement Connection Point. Visual Studio displays a dialog box showing all the available event interfaces listed in the control's type library. You select the one(s) for which you want a callback proxy, and Visual Studio writes a proxy for you. The following code shows the ATL-based message traffic control's callback proxy:

 class CProxy_DATLMsgTrafficEvents :     public IConnectionPointImpl<T, &DIID_ _DATLMsgTrafficEvents,     CComDynamicUnkArray> { public: // methods: // _DATLMsgTrafficEvents : IDispatch public:     void Fire_ExceededThreshold(long NumMessages,         long CurrentThreshold)     {         VARIANTARG* pvars = new VARIANTARG[2];         for (int i = 0; i < 2; i++)             VariantInit(&pvars[i]);         T* pT = (T*)this;         pT->Lock();         IUnknown** pp = m_vec.begin();         while (pp < m_vec.end())         {             if(*pp != NULL)             {                 pvars[1].vt = VT_I4;                 pvars[1].lVal= NumMessages;                 pvars[0].vt = VT_I4;                 pvars[0].lVal= CurrentThreshold;                 DISPPARAMS disp = { pvars, NULL, 2, 0 };                 IDispatch* pDispatch =                     reinterpret_cast<IDispatch*>(*pp);                 pDispatch->Invoke(0x1, IID_NULL,                      LOCALE_USER_DEFAULT,                      DISPATCH_METHOD, &disp,                      NULL, NULL, NULL);             }             pp++;         }         pT->Unlock();             delete[] pvars;     }     void Fire_NewInterval(long NumMessages)     {         // Similar treatment for Fire_NewInterval     } }; 

The callback proxy generated by Visual Studio represents a set of C++-friendly functions that call back to the interface implemented by the client.

Whereas MFC's IConnectionPointContainer implementation is hardwired into COleControl and each connection point is handled by a connection map, ATL's implementation is handled using multiple inheritance. Your control class inherits from IConnectionPointContainerImpl and the proxy generated by ClassView. If you select Supports Connection Points when you start the project, the Object Wizard inserts IConnectionPointContainerImpl for you. If you forget to mark the check box, you can just type it in. The following code shows how a connection point mechanism is brought into a control:

 class ATL_NO_VTABLE CATLMsgTrafficCtl :  {      public IConnectionPointContainerImpl<CATLMsgTrafficCtl>,     public CProxy_DATLMsgTrafficEvents<CATLMsgTrafficCtl>      LRESULT OnTimer(UINT msg, WPARAM wParam,          LPARAM lParam,          BOOL& bHandled)     {          if(nMessagesToShow > m_threshold)         {             Fire_ExceededThreshold(nMessagesToShow, m_threshold);         }      } }; 

That does it for connection points and event sets on the control side. We'll revisit connections and events when we look at integrating controls with their environments in Chapter 13.

Inside Atl
Inside ATL (Programming Languages/C)
ISBN: 1572318589
EAN: 2147483647
Year: 1998
Pages: 127 © 2008-2017.
If you may any questions please contact us: