| Tenouk C & C++ | MFC Home | Using ActiveX Controls 1 | Using ActiveX Controls 3 | Download | Site Index |


 

 

 

 

 

Module 18a:

Using ActiveX Controls 2

 

 

 

 

 

 

This is a continuation from the previous module... Program examples compiled using Visual C++ 6.0 (MFC 6.0) compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this Tutorial are listed below:

  1. The MYMFC24 Example: An ActiveX Control Dialog Container

  2. For Win32 Programmers

  3. ActiveX Controls in HTML Files

  4. Creating ActiveX Controls at Runtime

 

The MYMFC24 Project Example: An ActiveX Control Dialog Container

 

Now it's time to build an application that uses a Calendar control in a dialog. Here are the steps to create the MYMFC24 example:

 

Run AppWizard to produce \mfcproject\mymfc24. Accept all of the default settings but two: select Single Document and deselect Printing And Print Preview. In the AppWizard Step 3 dialog, make sure the ActiveX Controls option is selected, as shown below.

 

AppWizard step 3 of 6, enabling ActiveX control option.

 

Figure 7: AppWizard step 3 of 6, enabling ActiveX control option.

 

 

MYMFC24 ActiveX control project summary.

 

Figure 8: MYMFC24 ActiveX control project summary.

 

Verify that the Calendar control is registered. If the control does not appear in the Visual C++ Gallery's Registered ActiveX Controls page, copy the files MSCal.ocx, MSCal.hlp, and MSCal.cnt to your system directory and register the control by running the REGCOMP program.

 

Install the Calendar control in the MYMFC24 project. Choose Add To Project from Visual C++'s Project menu, and then choose Components And Controls. Choose Registered ActiveX Controls, and then choose Calendar Control 8.0.

 

Installing the Calendar control in the MYMFC24 project.

 

Figure 9: Installing the Calendar control in the MYMFC24 project.

 

ClassWizard generates two classes in the MYMFC24 directory, as shown here or through the ClassView.

 

Two classes, CCalendar and COleFont generated in the MYMFC24 directory.

 

Figure 10: Two classes, CCalendar and COleFont generated in the MYMFC24 directory.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The generated classes viewed in ClassView.

 

Figure 11: The generated classes viewed in ClassView.

 

Edit the Calendar control class to handle help messages. Add Calendar.cpp to the following message map code:

 

BEGIN_MESSAGE_MAP(CCalendar, CWnd)

    ON_WM_HELPINFO()

END_MESSAGE_MAP()

 

 

MFC Visual C++ code segment

 

Listing 1.

 

In the same file, add the OnHelpInfo() function:

 

BOOL CCalendar::OnHelpInfo(HELPINFO* pHelpInfo)

{

    // Edit the following string for your system

    ::WinHelp(GetSafeHwnd(), "c:\\winnt\\system32\\mscal.hlp", HELP_FINDER, 0);

    return FALSE;

}

 

 

MFC Visual C++ code segment

 

Listing 2.

 

In Calendar.h, add the function prototype and declare the message map:

 

protected:

    afx_msg BOOL OnHelpInfo(HELPINFO* pHelpInfo);

    DECLARE_MESSAGE_MAP()

 

 

MFC Visual C++ code segment

 

Listing 3.

 

The OnHelpInfo() function is called if the user presses the F1 key when the Calendar control has the input focus. We have to add the message map code by hand because ClassWizard doesn't modify generated ActiveX classes.

 

The ON_WM_HELPINFO macro maps the WM_HELP message, which is new to Microsoft Windows 95 and Microsoft Windows NT 4.0. You can use ON_WM_HELPINFO in any view or dialog class and then code the handler to activate any help system. Module 15 describes the MFC context-sensitive help system, some of which predates the WM_HELP message.

 

Use the dialog editor to create a new dialog resource. Choose Resource from Visual C++'s Insert menu, and then choose Dialog.

 

Inserting a new dialog to MYMFC24 project.

 

Figure 12: Inserting a new dialog to MYMFC24 project.

 

The dialog editor assigns the ID IDD_DIALOG1 to the new dialog. Next change the ID to IDD_ACTIVEXDIALOG, change the dialog caption to ActiveX Dialog, and set the dialog's Context Help property on the More Styles page.

 

Modifying dialog properties.

 

Figure 13: Modifying dialog properties.

 

Accept the default OK and Cancel buttons with the IDs IDOK and IDCANCEL, and then add the other controls as shown in Figure 4. Drag the Calendar control from the control palette. Assign control IDs as shown in the following table.

 

Control

ID

Calendar control

IDC_CALENDAR1

Select Date button

IDC_SELECTDATE

Edit control

IDC_DAY

Edit control

IDC_MONTH

Edit control

IDC_YEAR

Next Week button

IDC_NEXTWEEK

 

Table 2.

 

Adding ActiveX Calendar and other controls to the dialog.

 

Figure 14: Adding ActiveX Calendar and other controls to the dialog.

 

Make the Select Date button the default button. Then set an appropriate tab order.

 

Modifying button properties.

 

Figure 15: Modifying button properties.

 

Use ClassWizard to create the CActiveXDialog class. If you run ClassWizard directly from the dialog editor window, it will know that you want to create a CDialog-derived class based on the IDD_ACTIVEXDIALOG template. Simply accept the default options, and name the class CActiveXDialog.

 

Creating a new class dialog prompt.

 

Figure 16: Creating a new class dialog prompt.

 

New class CActiveXDialog information.

 

Figure 17: New class CActiveXDialog information.

 

 

Click on the ClassWizard Message Maps tab, and then add the message handler functions shown in the table below. To add a message handler function, click on an object ID, click on a message, and click the Add Function button. If the Add Member Function dialog box appears, type the function name and click the OK button.

 

Object ID

Message

Member Function

CActiveXDialog

WM_INITDIALOG

OnInitDialog() (virtual function)

IDC_CALENDAR1

NewMonth (event)

OnNewMonthCalendar1()

IDC_SELECTDATE

BN_CLICKED

OnSelectDate()

IDC_NEXTWEEK

BN_CLICKED

OnNextWeek()

IDOK

BN_CLICKED

OnOK() (virtual function)

 

Table 3

 

Adding message handler functions of the objects.

 

Figure 18: Adding message handler functions of the objects.

 

Use ClassWizard to add data members to the CActiveXDialog class. Click on the Member Variables tab, and then add the data members as shown in the illustration below.

 

You might think that the ClassWizard ActiveX Events tab is for mapping ActiveX control events in a container. That's not true: it's for ActiveX control developers who are defining events for a control.

 

Adding member variables for the controls.

 

Figure 19: Adding member variables for the controls.

 

Edit the CActiveXDialog class. Add the m_varValue and m_BackColor data members and then edit the code for the five handler functions OnInitDialog(), OnNewMonthCalendar1(), OnSelectDate(), OnNextWeek(), and OnOK(). Listing 4 shows all the code for the dialog class, with new code added.

 

ACTIVEXDIALOG.H

//{{AFX_INCLUDES()

#include "calendar.h"

//}}AFX_INCLUDES

#if !defined(AFX_ACTIVEXDIALOG_H__1917789D_6F24_11D0_8FD9_00C04FC2A0C2__INCLUDED_)

#define AFX_ACTIVEXDIALOG_H__1917789D_6F24_11D0_8FD9_00C04FC2A0C2__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

// ActiveXDialog.h : header file

//

 

//////////////////////////////////////////////////////////////////////

// CActiveXDialog dialog

class CActiveXDialog : public CDialog

 

{

// Construction

public:

    CActiveXDialog(CWnd* pParent = NULL);   // standard constructor

 

// Dialog Data

    //{{AFX_DATA(CActiveXDialog)

    enum { IDD = IDD_ACTIVEXDIALOG };

    CCalendar    m_calendar;

    short    m_sDay;

    short    m_sMonth;

    short    m_sYear;

    //}}AFX_DATA

    COleVariant m_varValue;

    unsigned long m_BackColor;

 

// Overrides

    // ClassWizard generated virtual function overrides

    //{{AFX_VIRTUAL(CActiveXDialog)

    protected:

    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV

                                                     //  support

    //}}AFX_VIRTUAL

 

// Implementation

protected:

    // Generated message map functions

    //{{AFX_MSG(CActiveXDialog)

    virtual BOOL OnInitDialog();

    afx_msg void OnNewMonthCalendar1();

    afx_msg void OnSelectDate();

    afx_msg void OnNextWeek();

    virtual void OnOK();

    DECLARE_EVENTSINK_MAP()

    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()

};

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional

//  declarations immediately before the previous line.

 

#endif // !defined(AFX_ACTIVEXDIALOG_H__1917789D_6F24_11D0_8FD9_00C04FC2A0C2__INCLUDED_)

 

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ACTIVEXDIALOG.CPP

// ActiveXDialog.cpp : implementation file

//

 

#include "stdafx.h"

#include "mymfc24.h"

#include "ActiveXDialog.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[ ] = __FILE__;

#endif

 

//////////////////////////////////////////////////////////////////////

// CActiveXDialog dialog

 

CActiveXDialog::CActiveXDialog(CWnd* pParent /*=NULL*/) : CDialog(CActiveXDialog::IDD, pParent)

{

    //{{AFX_DATA_INIT(CActiveXDialog)

    m_sDay = 0;

    m_sMonth = 0;

    m_sYear = 0;

    //}}AFX_DATA_INIT

    m_BackColor = 0x8000000F;

}

 

void CActiveXDialog::DoDataExchange(CDataExchange* pDX)

{

    CDialog::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CActiveXDialog)

    DDX_Control(pDX, IDC_CALENDAR1, m_calendar);

    DDX_Text(pDX, IDC_DAY, m_sDay);

    DDX_Text(pDX, IDC_MONTH, m_sMonth);

    DDX_Text(pDX, IDC_YEAR, m_sYear);

    //}}AFX_DATA_MAP

    DDX_OCColor(pDX, IDC_CALENDAR1, DISPID_BACKCOLOR, m_BackColor);

}

 

BEGIN_MESSAGE_MAP(CActiveXDialog, CDialog)

    //{{AFX_MSG_MAP(CActiveXDialog)

    ON_BN_CLICKED(IDC_SELECTDATE, OnSelectDate)

    ON_BN_CLICKED(IDC_NEXTWEEK, OnNextWeek)

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

//////////////////////////////////////////////////////////////////////

// CActiveXDialog message handlers

 

BEGIN_EVENTSINK_MAP(CActiveXDialog, CDialog)

    //{{AFX_EVENTSINK_MAP(CActiveXDialog)

    ON_EVENT(CActiveXDialog, IDC_CALENDAR1, 3 /* NewMonth */, OnNewMonthCalendar1, VTS_NONE)

    //}}AFX_EVENTSINK_MAP

END_EVENTSINK_MAP()

 

BOOL CActiveXDialog::OnInitDialog()

{

    CDialog::OnInitDialog();

    m_calendar.SetValue(m_varValue); // no DDX for VARIANTs

    return TRUE;  // return TRUE unless you set the focus to a control

                            // EXCEPTION: OCX Property Pages should return FALSE

}

 

void CActiveXDialog::OnNewMonthCalendar1()

{

    AfxMessageBox("EVENT:  CActiveXDialog::OnNewMonthCalendar1");

}

 

void CActiveXDialog::OnSelectDate()

{

    CDataExchange dx(this, TRUE);

    DDX_Text(&dx, IDC_DAY, m_sDay);

    DDX_Text(&dx, IDC_MONTH, m_sMonth);

    DDX_Text(&dx, IDC_YEAR, m_sYear);

    m_calendar.SetDay(m_sDay);

    m_calendar.SetMonth(m_sMonth);

    m_calendar.SetYear(m_sYear);

}

 

void CActiveXDialog::OnNextWeek()

{

    m_calendar.NextWeek();

}

 

void CActiveXDialog::OnOK()

{

    CDialog::OnOK();

    m_varValue = m_calendar.GetValue(); // no DDX for VARIANTs

}

 

 

Listing 4: Code for the CActiveXDialog class.

 

The OnSelectDate() function is called when the user clicks the Select Date button. The function gets the day, month, and year values from the three edit controls and transfers them to the control's properties. ClassWizard can't add DDX code for the BackColor property, so you must add it by hand. In addition, there's no DDX code for VARIANT types, so you must add code to the OnInitDialog() and OnOK() functions to set and retrieve the date with the control's Value property.

Connect the dialog to the view. Use ClassWizard to map the WM_LBUTTONDOWN message, and then edit the handler function as follows:

 

Mapping the WM_LBUTTONDOWN message.

 

Figure 20: Mapping the WM_LBUTTONDOWN message.

 

void CMymfc24View::OnLButtonDown(UINT nFlags, CPoint point)

{

    CActiveXDialog dlg;

    dlg.m_BackColor = RGB(255, 251, 240); // light yellow

    COleDateTime today = COleDateTime::GetCurrentTime();

    dlg.m_varValue = COleDateTime(today.GetYear(), today.GetMonth(), today.GetDay(), 0, 0, 0);

    if (dlg.DoModal() == IDOK) {

        COleDateTime date(dlg.m_varValue);

        AfxMessageBox(date.Format("%B %d, %Y"));

    }

}

 

MFC Visual C++ code segment

 

Listing 5.

 

The code sets the background color to light yellow and the date to today's date, displays the modal dialog, and reports the date returned by the Calendar control. You'll need to include ActiveXDialog.h in mymfc24View.cpp.

 

MFC Visual C++ code segment

 

Listing 6.

 

Edit the virtual OnDraw() function in the file mymfc24View.cpp. To prompt the user to press the left mouse button, replace the code in the view class OnDraw() function with this single line:

 

pDC->TextOut(0, 0, "Press the left mouse button here.");

 

 

MFC Visual C++ code segment

 

Listing 7.

 

Build and test the MYMFC24 application. Open the dialog, enter a date in the three edit controls, and then click the Select Date button. Click the Next Week button. Try moving the selected date directly to a new month, and observe the message box that is triggered by the NewMonth event. Watch for the final date in another message box when you click OK. Press the F1 key for help on the Calendar control.

 

MYMFC24 program output, showing the ActiveX control – a calendar.

 

Figure 21: MYMFC24 program output, showing the ActiveX control – a calendar.

 

For Win32 Programmers

 

If you use a text editor to look inside the mymfc24.rc file, you might be quite mystified. Here's the entry for the Calendar control in the ActiveX Dialog template:

 

CONTROL     "",IDC_CALENDAR1,

            "{8E27C92B-1264-101C-8A2F-040224009C02}",

            WS_TABSTOP,7,7,217,113

 

There's a 32-digit number sequence where the window class name should be. What's going on? Actually, the resource template isn't the one that Windows sees. The CDialog::DoModal function "preprocesses" the resource template before passing it on to the dialog box procedure within Windows. It strips out all the ActiveX controls and creates the dialog window without them. Then it loads the controls (based on their 32-digit identification numbers, called CLSIDs) and activates them in place, causing them to create their own windows in the correct places. The initial values for the properties you set in the dialog editor are stored in binary form inside the project's custom DLGINIT resource.

When the modal dialog runs, the MFC code coordinates the messages sent to the dialog window both by the ordinary controls and by the ActiveX controls. This allows the user to tab between all the controls in the dialog, even though the ActiveX controls are not part of the actual dialog template.

When you call the member functions for the control object, you might think you're calling functions for a child window. The control window is quite far removed, but MFC steps in to make it seem as if you're communicating with a real child window. In ActiveX terminology, the container owns a site, which is not a window. You call functions for the site, and ActiveX and MFC make the connection to the underlying window in the ActiveX control.

 

The container window is an object of a class derived from CWnd. The control site is also an object of a class derived from CWnd, the ActiveX control wrapper class. That means that the CWnd class has built-in support for both containers and sites.

What you're seeing here is MFC ActiveX control support grafted onto regular Windows. Maybe some future Windows version will have more direct support for ActiveX Controls. As a matter of fact, ActiveX versions of the Windows common controls already exist.

 

ActiveX Controls in HTML Files

 

You've seen the ActiveX Calendar control in an MFC modal dialog. You can use the same control in a Web page. The following HTML code will work (assuming the person reading the page has the Calendar control installed and registered on his or her machine):

 

<OBJECT

    CLASSID="clsid:8E27C92B-1264-101C-8A2F-040224009C02"

    WIDTH=300 HEIGHT=200 BORDER=1 HSPACE=5 ID=calendar>

<PARAM NAME="Day" VALUE=7>

<PARAM NAME="Month" VALUE=11>

<PARAM NAME="Year" VALUE=1998>

</OBJECT>

 

The CLASSID attribute (the same number that was in the MYMFC24 dialog resource) identifies the Calendar control in the Registry. A browser can download an ActiveX control.

 

Creating ActiveX Controls at Runtime

 

You've seen how to use the dialog editor to insert ActiveX controls at design time. If you need to create an ActiveX control at runtime without a resource template entry, here are the programming steps:

 

  1. Insert the component into your project. ClassWizard will create the files for a wrapper class.

  2. Add an embedded ActiveX control wrapper class data member to your dialog class or other C++ window class. An embedded C++ object is then constructed and destroyed along with the window object.

  3. Choose Resource Symbols from Visual C++'s View menu. Add an ID constant for the new control.

  4. If the parent window is a dialog, use ClassWizard to map the dialog's WM_INITDIALOG message, thus overriding CDialog::OnInitDialog. For other windows, use ClassWizard to map the WM_CREATE message. The new function should call the embedded control class's Create member function. This call indirectly displays the new control in the dialog. The control will be properly destroyed when the parent window is destroyed.

  5. In the parent window class, manually add the necessary event message handlers and prototypes for your new control. Don't forget to add the event sink map macros.

 

ClassWizard doesn't help you with event sink maps when you add a dynamic ActiveX control to a project. Consider inserting the target control in a dialog in another temporary project. After you're finished mapping events, simply copy the event sink map code to the parent window class in your main project.

 

 

Continue on next module...part 3.

 

 

 

 

 

 

Further reading and digging:

  1. MSDN MFC 7.0 class library online documentation.

  2. MSDN MFC 9.0 class library online documentation - latest version.

  3. MSDN Library

  4. Windows data type.

  5. Win32 programming Tutorial.

  6. The best of C/C++, MFC, Windows and other related books.

  7. Unicode and Multibyte character set: Story and program examples.

 

 

 


 

| Tenouk C & C++ | MFC Home | Using ActiveX Controls 1 | Using ActiveX Controls 3 | Download | Site Index |