The current MFC and ATL represent two frameworks for different types of windows-based development. MFC represents a simple, consistent way to create stand-alone Windows applications; ATL provides a framework for implementing boilerplate code necessary to create COM clients and servers. Both of these frameworks converge on their use for developing ActiveX. We'll look at how these two frameworks work for creating ActiveX controls-highlighting their pros and cons, and going through the process of creating a control-so you can decide when to use a framework and when to use another.
If you want to write activex® controls in C + +, there are two popular frameworks, one is Microsoft®foundation Classes (MFC) and the other is ATL. I'll explain in depth the support that these two frameworks provide for developing ActiveX controls to help you better decide which models are best suited to your development environment and requirements.
Full form of ActiveX controls
ActiveX controls are based on Component Object Model COM, which makes ActiveX controls possible. The basic principle of COM is that an object's interface and its implementation can and should be treated separately. As long as COM objects and its client code agree on the details of the interface, how to achieve it is not a problem. The ActiveX control demonstrates a large number of interfaces that the ActiveX Control Package container understands. Because client-side code and controls recognize the external performance of these interfaces, you can write an ActiveX control and simply put it into the containment device. The package container will drive the controls through well-defined interfaces, and the controls will respond appropriately in their own way. At a higher level, an ActiveX control is a COM object that implements several of the main ActiveX technologies, including the usual introduction of COM interfaces, OLE embedding protocols, connection points, and property pages. At a lower programming level, the ActiveX control is simply a COM class that implements certain types of interfaces. When some client-side code succeeds in querying one of these interfaces, it knows how to use an ActiveX control.
An ActiveX control exposes an interface that is divided into 3 main classes. First, ActiveX controls are embeddable objects; that is, they implement most OLE documents, In-place activation, and embedding protocols. The ActiveX control implements the following interface:
IOleObject, IPersistStorage, IDataObject, IOleInPlaceActiveObject, IOleInPlaceObject, IViewObject2 and Irunnableobject ( This one is rarely used). The second ActiveX control typically supports property pages so that the client can modify the properties of the control. Finally, ActiveX controls typically use COM's connection point technology to achieve an Out-of-office interface that customers can discover.
To help you compare the ATL and MFC frameworks, let's look at the same controls that are written in each frame. This control monitors the message flow that is passed on the thread that created it. The message flow control is a good example because it demonstrates all the main aspects of an ActiveX control, including the Feed interface, Out-of-office interface, attributes, permanence, and property pages. Let's start by studying the standard COM support provided by these two frameworks.
Basic COM support for MFC
Microsoft's establishment of MFC makes it much easier to develop windows® applications than to use the SDK. With Mfc,microsoft, COM support for the stored framework is added. This means that MFC developers must maintain the integrity of the framework when adding more and more functions. Also, the Visual c++® compiler does not support templates at that time, so they have to use other means other than templates to incorporate COM functionality into their classes. Microsoft has solved this problem by adding some virtual functions to the CCmdTarget class and some macros, making it possible to implement COM interfaces in MFC.
COM support within MFC begins with CCmdTarget, the CCmdTarget class implements the IUnknown interface, and includes a member variable (M_DWREF) for reference counting and 6 functions for implementing IUnknown:: InternalAddRef, InternalRelease, InternalQueryInterface, Externaladdref, Externalrelease, and ExternalQueryInterface. QueryInterface's two versions--addref and release support COM aggregation. InternalAddRef, InternalRelease and InternalQueryInterface Complete reference counting and QueryInterface operations, while Externaladdref, Externalrelease, and The ExternalQueryInterface agent controls the aggregated object (if this object participates in aggregation).
MFC implements COM interfaces using nested class-composite policies. In MFC, classes that want to implement COM interfaces are derived from CCmdTarget. Each class implemented by the CCmdTarget derived from the interface gets its own nested class. MFC uses macros Begin_interface_part and End_interface_part to produce nested classes.
Finally, MFC implements the table-driven QueryInterface. MFC's interface mapping works the same as its message map: MFC's message map links a Windows message to a function in a C + + class; MFC's interface Mappings associate the GUID of an interface with the address of a specific vptr that represents this interface. Each CCmdTarget-based class implements COM interfaces through more macros: Declare_interface_map, Begin_interface_map, Interface_part, and End_interface_ Map to add an interface map.
To understand what these macros look like in practice, look at Figure 1, which illustrates the MFC classes that implement ActiveX controls and COleControl. When you read the code carefully, note that COleControl has a signature for each interface sandwiched between a pair of Begin_interface_part and End_interface_part macros, and that there are 22 entries in the COleControl Interface mapping table.
In addition to implementing the IUnknown interface, MFC includes a standard implementation of IClassFactory. Once again, MFC provides this support through a number of macros. MFC has two macros to provide class objects: DECLARE_OLECREATE_EX and IMPLEMENT_OLECREATE_EX. Use these macros in a CCmdTarget class to add a static member of a COleObjectFactory type to the class. If you look at the definition of coleobjectfactory in AFXDISP.H, you will see that a nested class of MFC in COleObjectFactory defines a nested class for implementation IClassFactory2. The MFC version of IClassFactory::CreateInstance uses the dynamic creation mechanism of MFC (DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE macros to open this feature) to instantiate a COM class. So buying MFC's COM support also means buying its dynamic creation mechanism.
The last few basic COM support in ActiveX controls provided by MFC is support for IDispatch. Implementing a distribution interface with Visual C + + and MFC is almost negligible. In MFC to implement a distribution interface, only need to use the ClassWizard on it. The automatic creation board in ClassWizard has one button for adding properties and another for adding methods. In MFC, IDispatch support comes from the CCmdTarget class. The actual implementation of MFC for IDispatch in a class called Coledispatchimpl, Coledispatchimpl derives from IDispatch and implements all 4 IDispatch functions: GetTypeInfoCount, GetTypeInfo, GetIDsOfNames, and Invoke. Classes derived from CCmdTarget add IDispatch vptr to their interface mappings by calling Enableautomation. When a customer invokes IDispatch QueryInterface on an MFC-based ActiveX control, CCmdTarget surrenders vptr on the Coledispatchimpl.
Every time you use ClassWizard to add an automatic property or method to a class, you also add an entry in the distribution mapping table for that class. A Distribution mapping table is a simple table that links Dispids (the symbols used to call distribution members) and their names for people to read, as well as some C + + code that actually completes the work. The Coledispatchimpl call and the GetIDsOfNames function work by looking for distribution members in the distribution map table of the class and distributing the corresponding functions of the DISPID. MFC provides very good support for some of the advanced technologies of COM, such as OLE documents, OLE drag-and-drop, and automatic operations, however, if you want to change the framework-for example, if you want to program the distribution interface to a dual interface-you have to do something big. ATL, on the other hand, is more of a COM center.