| Tenouk C++ & C | MFC Home | Using ActiveX Controls 2 | IE 4 Common Controls 1 | Download | Site Index |


 

 

 

 

 

Module 18b:

Using ActiveX Controls 3

 

 

 

 

 

 

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 MYMFC24B Example: The Web Browser ActiveX Control

  2. Picture Properties

  3. Bindable Properties: Change Notifications

  4. Other ActiveX Controls

 

The MYMFC24B Project Example: The Web Browser ActiveX Control

 

Microsoft Internet Explorer 4.x has become a leading Web browser. I was surprised to find out that most of its functionality is contained in one big ActiveX control, Shdocvw.dll. When you run Internet Explorer, you launch a small shell program that loads this Web Browser control in its main window. You can find complete documentation for the Web Browser control's properties, methods, and events in the Internet SDK, downloadable from MSDN (.NET, VS ver 8 or here). This documentation is in HTML form, of course. Because of this modular architecture, you can write your own custom browser program with very little effort. MYMFC24B creates a two-window browser that displays a search engine page side-by-side with the target page, as shown here.

 

 

Web browser ActiveX control in action.

 

Figure 22: Web browser ActiveX control in action.

 

 

This view window contains two Web Browser controls that are sized to occupy the entire client area. When the user clicks an item in the search (right-hand) control, the program intercepts the command and routes it to the target (left-hand) control.

Here are the steps for building the example:

 

Make sure the Web Browser control is registered. You undoubtedly have Microsoft Internet Explorer 4.x installed, since Visual C++ 6.0 requires it, so the Web Browser control should be registered. You can download Internet Explorer from microsoft.com if necessary.

Run AppWizard to produce \mfcproject\mymfc24B. Accept all the default settings but two: except select Single Document and deselect Printing And Print Preview. Make sure the ActiveX Controls option is checked as in MYMFC24.

 

MYMFC24B SDI and ActiveX control project summary.

 

Figure 23: MYMFC24B SDI and ActiveX control project summary.

 

Install the Web Browser control in the MYMFC24B project. Choose Add To Project from Visual C++'s Project menu, and choose Components And Controls from the submenu. Select Registered ActiveX Controls, and then choose Microsoft Web Browser. Visual C++ will generate the wrapper class CWebBrowser2 and add the files to your project.

 

Installing the Web Browser control in the MYMFC24B project.

 

Figure 24: Installing the Web Browser control in the MYMFC24B project.

 

Generated class, CWebBrowser2 and their files that will be added to the project.

 

Figure 25: Generated class, CWebBrowser2 and their files that will be added to the project.

 

Add two CWebBrowser2 data members to the CMymfc24BView class. Click on the ClassView tab in the Workspace window, and then right-click the CMymfc24BView class. Choose Add Member Variable, and fill in the dialog as shown here.

 

Adding data members/member variables with CWebBrowser2 type.

 

Figure 26: Adding data members/member variables with CWebBrowser2 type.

 

Repeat for m_target. ClassWizard adds an #include statement for the webbrowser2.h file.

 

MFC Visual C++ code segment

 

Listing 8.

 

Add the child window ID constants for the two controls. Select Resource Symbols from Visual C++'s View menu, and then add the symbols ID_BROWSER_SEARCH and ID_BROWSER_TARGET.

 

Adding child window ID constants for the previous two controls (browsers).

 

Figure 27: Adding child window ID constants for the previous two controls (browsers).

 

Add a static character array data member for the Yahoo URL. Add the following static data member to the class declaration in mymfc24BView.h:

 

private:

    static const char s_engineYahoo[ ];

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

MFC Visual C++ code segment

 

Listing 9.

 

Then add the following definition in mymfc24BView.cpp, outside any function:

 

const char CMymfc24BView::s_engineYahoo[ ] = "http://www.yahoo.com/";

 

 

MFC Visual C++ code segment

 

Listing 10.

 

Use ClassWizard to map the view's WM_CREATE and WM_SIZE messages. Edit the handler code in mymfc24BView.cpp as follows:

 

Using ClassWizard to map the view's WM_CREATE and WM_SIZE messages.

 

Figure 28: Using ClassWizard to map the view's WM_CREATE and WM_SIZE messages.

 

int CMymfc24BView::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

    if (CView::OnCreate(lpCreateStruct) == -1)

        return -1;

 

    DWORD dwStyle = WS_VISIBLE | WS_CHILD;

    if (m_search.Create(NULL, dwStyle, CRect(0, 0, 100, 100), this, ID_BROWSER_SEARCH) == 0) {

        AfxMessageBox("Unable to create search control!\n");

        return -1;

    }

    m_search.Navigate(s_engineYahoo, NULL, NULL, NULL, NULL);

 

    if (m_target.Create(NULL, dwStyle, CRect(0, 0, 100, 100), this, ID_BROWSER_TARGET) == 0) {

        AfxMessageBox("Unable to create target control!\n");

        return -1;

    }

    m_target.GoHome(); // as defined in Internet Explorer 4 options

 

    return 0;

}

 

MFC Visual C++ code segment

 

Listing 11.

 

 

void CMymfc24BView::OnSize(UINT nType, int cx, int cy)

{

    CView::OnSize(nType, cx, cy);

 

    CRect rectClient;

    GetClientRect(rectClient);

    CRect rectBrowse(rectClient);

    rectBrowse.right = rectClient.right / 2;

    CRect rectSearch(rectClient);

    rectSearch.left = rectClient.right / 2;

 

    m_target.SetWidth(rectBrowse.right - rectBrowse.left);

    m_target.SetHeight(rectBrowse.bottom - rectBrowse.top);

    m_target.UpdateWindow();

 

    m_search.SetLeft(rectSearch.left);

    m_search.SetWidth(rectSearch.right - rectSearch.left);

    m_search.SetHeight(rectSearch.bottom - rectSearch.top);

    m_search.UpdateWindow();

}

 

MFC Visual C++ code segment

 

Listing 12.

 

The OnCreate() function creates two browser windows inside the view window. The right-hand browser displays the top-level Yahoo page, and the left-hand browser displays the "home" page as defined through the Internet icon in the Control Panel. The OnSize() function, called whenever the view window changes size, ensures that the browser windows completely cover the view window. The CWebBrowser2 member functions SetWidth() and SetHeight() set the browser's Width and Height properties.

 

Add the event sink macros in the CMymfc24BView files. ClassWizard can't map events from a dynamic ActiveX control, so you must do it manually. Add the following lines inside the class declaration in the file mymfc24BView.h:

 

protected:

    afx_msg void OnBeforeNavigateExplorer1(LPCTSTR URL, long Flags, LPCTSTR TargetFrameName, VARIANT FAR* PostData, LPCTSTR Headers, BOOL FAR* Cancel);

    afx_msg void OnTitleChangeExplorer2(LPCTSTR Text);

    DECLARE_EVENTSINK_MAP()

 

MFC Visual C++ code segment

 

Listing 13.

 

Then add the following code in mymfc24BView.cpp:

 

BEGIN_EVENTSINK_MAP(CMymfc24BView, CView)

    ON_EVENT(CMymfc24BView, ID_BROWSER_SEARCH, 100, OnBeforeNavigateExplorer1, VTS_BSTR VTS_I4 VTS_BSTR VTS_PVARIANT VTS_BSTR VTS_PBOOL)

    ON_EVENT(CMymfc24BView, ID_BROWSER_TARGET, 113,  OnTitleChangeExplorer2, VTS_BSTR)

END_EVENTSINK_MAP()

 

MFC Visual C++ code segment

 

Listing 14.

 

Add two event handler functions. Add the following member functions in mymfc24BView.cpp:

 

void CMymfc24BView::OnBeforeNavigateExplorer1(LPCTSTR URL, long Flags, LPCTSTR TargetFrameName,

    VARIANT FAR* PostData, LPCTSTR Headers, BOOL FAR* Cancel)

{

    TRACE("CMymfc24BView::OnBeforeNavigateExplorer1 -- URL = %s\n", URL);

 

    if (!strnicmp(URL, s_engineYahoo, strlen(s_engineYahoo))) {

        return;

    }

    m_target.Navigate(URL, NULL, NULL, PostData, NULL);

    *Cancel = TRUE;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MFC Visual C++ code segment

 

Listing 15.

 

void CMymfc24BView::OnTitleChangeExplorer2(LPCTSTR Text)

{

    // Careful!  Event could fire before we're ready.

    CWnd* pWnd = AfxGetApp()->m_pMainWnd;

    if (pWnd != NULL) {

        if (::IsWindow(pWnd->m_hWnd)) {

            pWnd->SetWindowText(Text);

        }

    }

}

 

MFC Visual C++ code segment

 

Listing 16.

 

The OnBeforeNavigateExplorer1() handler is called when the user clicks on a link in the search page. The function compares the clicked URL (in the URL string parameter) with the search engine URL. If they match, the navigation proceeds in the search window; otherwise, the navigation is cancelled and the Navigate method is called for the target window. The OnTitleChangeExplorer2() handler updates the MYMFC24B window title to match the title on the target page.

 

Build and test the MYMFC24B application. Search for something on the Yahoo page, and then watch the information appear in the target page.

 

Note: This program may not work as specified or both windows may function as a separate browser for newer version of IE.

 

MYMFC24B program output.

 

Figure 29: MYMFC24B program output.

 

Picture Properties

 

Some ActiveX controls support picture properties, which can accommodate bitmaps, metafiles, and icons. If an ActiveX control has at least one picture property, ClassWizard generates a CPicture class in your project during the control's installation. You don't need to use this CPicture class, but you must use the MFC class CPictureHolder. To access the CPictureHolder class declaration and code, you need the following line in StdAfx.h:

 

#include <afxctl.h>

 

Suppose you have an ActiveX control with a picture property named Picture. Here's how you set the Picture property to a bitmap in your program's resources:

 

CPictureHolder  pict;

pict.CreateFromBitmap(IDB_MYBITMAP); // from project's resources

m_control.SetPicture(pict.GetPictureDispatch());

 

If you include the AfxCtl.h file, you can't statically link your program with the MFC library. If you need a stand-alone program that supports picture properties, you'll have to borrow code from the CPictureHolder class, located in the \Program Files\Microsoft Visual Studio\VC98\mfc\src\ctlpict.cpp file.

 

Bindable Properties: Change Notifications

 

If an ActiveX control has a property designated as bindable, the control will send an OnChanged() notification to its container when the value of the property changes inside the control. In addition, the control can send an OnRequestEdit() notification for a property whose value is about to change but has not yet changed. If the container returns FALSE from its OnRequestEdit() handler, the control should not change the property value.

MFC fully supports property change notifications in ActiveX control containers, but as of Visual C++ version 6.0, no ClassWizard support was available. That means you must manually add entries to your container class's event sink map. Suppose you have an ActiveX control with a bindable property named Note with a dispatch ID of 4. You add an ON_PROPNOTIFY macro to the EVENTSINK macros in this way:

 

BEGIN_EVENTSINK_MAP(CAboutDlg, CDialog)

    //{{AFX_EVENTSINK_MAP(CAboutDlg)

    // ClassWizard places other event notification macros here

    //}}AFX_EVENTSINK_MAP

    ON_PROPNOTIFY(CAboutDlg, IDC_MYCTRL1, 4, OnNoteRequestEdit, OnNoteChanged)

END_EVENTSINK_MAP()

 

You must then code the OnNoteRequestEdit() and OnNoteChanged() functions with return types and parameter types exactly as shown here:

 

BOOL CMyDlg::OnNoteRequestEdit(BOOL* pb)

{

    TRACE("CMyDlg::OnNoteRequestEdit\n");

    *pb = TRUE; // TRUE means change request granted

    return TRUE;

}

 

BOOL CMyDlg::OnNoteChanged()

{

    TRACE("CMyDlg::OnNoteChanged\n");

    return TRUE;

}

 

You'll also need corresponding prototypes in the class header, as shown here:

 

afx_msg BOOL OnNoteRequestEdit(BOOL* pb);

afx_msg BOOL OnNoteChanged();

 

Other ActiveX Controls

 

You'll probably notice that your disk fills up with ActiveX controls, especially if you accept controls from Web sites. Most of these controls are difficult to use unless you have the documentation on hand, but you can have fun experimenting. Try the Marquee.ocx control that is distributed with Visual C++ 6.0. It works fine in both MFC programs and HTML files. The trick is to set the szURL property to the name of another HTML file that contains the text to display in the scrolling marquee window. Many ActiveX controls were designed for use by Visual Basic programmers. The SysInfo.ocx control that comes with Visual C++, for example, lets you retrieve system parameters as property values. This isn't of much use to a C++ programmer, however, because you can make the equivalent Win32 calls anytime. Unlike the many objects provided by MFC, ActiveX controls are binary objects that are not extensible. For example, you cannot add a property or event to an ActiveX control. Nor can you use many C++ object-oriented techniques like polymorphism with ActiveX controls. Another downside of ActiveX controls is they are not compatible with many advanced MFC concepts such as the document/view architecture, which we will cover later.

 

 

 

 

 

 

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 2 | IE 4 Common Controls 1 | Download | Site Index |