Advertising

Using ActiveX Controls with MFC

Contents

Introduction

You may use ActiveX controls in Visual C++ just as you would any other control such as a Button or an Edit box. You may have created these controls yourself or they may have been written by someone else. You do not need the source code.

Creating a Wrapper for the ActiveX Control.

Open the Project in which you intend to use an ActiveX control.

Project | Add To Project | Components and Controls. You will be taken to the Gallery where you may choose from Registered ActiveX Controls. Choose the Control from the list and click Insert. You will be asked to choose the Control from a list (usually one) and to confirm the names of the wrapper files which will be created. I advise suffixing the class name and file names with 'wrapper' to avoid confusion with the actual C++ files which define the control.

A new 'wrapper' class will be added to your Project. This class inherits from CWnd and is otherwise quite simple.

You may use this class as if it were any other windows control such as a button or an edit box. A new 'OCX' button will be added to the Controls palette for use on Dialogs or you may use the Create method of the wrapper class to create the ActiveX controls dynamically. (See Creating ActiveX controls with MFC for an example of this).

Of course if you are developing a system of interacting ActiveX controls you will find yourself having to re-create this wrapper class whenever you change the specification of the ActiveX control. Do so by removing the files from the file view (highlight and press delete), and by deleting the actual files in your project folder. You needn't worry about doing this as long as you have put the word wrapper in the name of the wrapper classes. Then use the Gallery to add the wrapper again.

Responding to ActiveX Events.

The Classwizard Message Maps tab helps you to easily add handlers for the events fired by ActiveX controls if you have placed one of those controls on a dialog resource. However, most useful ActiveX controls will create and position their child controls dynamically so ClassWizard will not be able to detect them. We must therefore resort to entering the macros ourselves. Remember that if you're not sure what the macro should look like for your particular control, you can put an ActiveX control on a dialog and create a Message Map for its events. Just be careful to remove the entries after you have used them to see the form they should take.

Firstly, create an IDR resource symbol for your control. Use View | View Resource Symbols. You should use this resource symbol when creating the control wrapper.

e.g.

m_SubSectionWrapper.Create( _T("SUB"), WS_CHILD | WS_VISIBLE, tempRect, this, IDR_SUBSECTION);

MFC controls capture ActiveX Events by using an 'Events Sink' which is basically just an extension of the regular message map. You must declare the Events Sink map inside the regular message map declarations in the declaration (.h) file. e.g.

// Message maps
//{{AFX_MSG(CSubSectionCtrl)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
DECLARE_EVENTSINK_MAP()
//}}AFX_MSG
DECLARE_MESSAGE_MAP()

Add the Event Sinks Map near the start of the definition (.cpp) file, before the regular BEGIN_MESSAGE_MAP section, as follows:

BEGIN_EVENTSINK_MAP(CSubContainerCtrl, COleControl)
     //{{AFX_EVENTSINK_MAP(CSubContainerCtrl)
     ON_EVENT(CSubContainerCtrl, IDR_SUBSECTION, 1 /* ResizeControls */, OnResizeColumns, VTS_NONE)
     //}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

The BEGIN_EVENTSINK_MAP macro takes the container's Class name, then the base class name as parameters. The container's class name is used again in the AFX_EVENTSINK_MAP macro and the ON_EVENT macro.

The ON_EVENT macro needs the ID number of the ActiveX Event, which you can get from the ODL file, the OLE/COM Object viewer, or by creating an example handler using the classwizard as mentioned above. The final parameter is a space-separated list of parameter types for the event. Again, if you are not sure which types to use here, you could create an example using a dialog and the classwizard.

Next, declare the handler in the declaration (.h) file.

	//{{AFX_MSG(CSubSectionCtrl)
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnResizeColumns();
	DECLARE_EVENTSINK_MAP()
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()

Then just write the definition for your handler. e.g.

void CSubContainerCtrl::OnResizeColumns() 
{
    ...
} 

Serializing.

If you are using the MFC Document/View architecture with Compound Document support then the controls which you add will be persisted automatically.

The issue of serializing ActiveX controls which are used by other ActiveX controls is generally avoided in the documentation because it is not straightforward. In theory it can be done by using the PX_Blob macro, a temporary file archive, and a call to one of the control's COM methods. However I have yet to see a working example of this, though it is obvious that Microsoft have managed it in their own applications.

Alternatively, you may extract the properties of the ActiveX control (assuming they are directly available as COM properties) and serialize those values.

Copyright © Murray Cumming. Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.

Murray's Web Pages