Visual C++ 6.0 supports DHTML through both MFC and ATL. Both MFC and ATL give you complete access to the DHTML object model. Unfortunately, access to the object model from languages like C++ is done through OLE Automation (IDispatch) and in many cases isn't as cut-and-dried as some of the scripts we looked at earlier.
The DHTML object model is exposed to C++ developers through a set of COM objects with the prefix IHTML (IHTMLDocument, IHTMLWindow, IHTMLElement, IHTMLBodyElement, and so on). In C++, once you obtain the document interface, you can use any of the IHTMLDocument2 interface methods to obtain or to modify the document's properties.
You can access the all collection by calling the IHTMLDocument2::get_all method. This method returns an IHTMLElementCollection collection interface that contains all the elements in the document. You can then iterate through the collection using the IHTMLElementCollection::item method (similar to the parentheses in the script above). The IHTMLElementCollection::item method supplies you with an IDispatch pointer that you can call QueryInterface on, requesting the IID_IHTMLElement interface. This call to QueryInterface will give you an IHTMLElement interface pointer that you can use to get or set information for the HTML element.
Most elements also provide a specific interface for working with that particular element type. These element-specific interface names take the format of IHTMLXXXXElement, where XXXX is the name of the element (IHTMLBodyElement, for example). You must call QueryInterface on the IHTMLElement object to request the element-specific interface you need. This might sound confusing (because it can be!). But don't worrythe MFC and ATL sections in this chapter contain plenty of samples that demonstrate how it all ties together. You'll be writing DHTML code in no time.
MFC's support for DHTML starts with a new CView derivative, CHtmlView. CHtmlView allows you to embed an HTML view inside frame windows or splitter windows, where with some DHTML work it can act as a dynamic form. Example EX37A demonstrates how to use the new CHtmlView class in a vanilla MDI application.
Follow these steps to create the EX37A example:
Navigate2(_T("http://www.microsoft.com/visualc/"),NULL,NULL);
You can edit this line to have the application load a local page or a URL other than the Visual C++ page.
Figure 37-3. The EX37A example.
Now let's create a sample that really shows how to use DHTML with MFC. EX37B creates a CHtmlView object and a CListView object separated by a splitter. The example then uses DHTML to enumerate the HTML elements in the CHtmlView object and displays the results in the CListView object. The end result will be a DHTML explorer that you can use to view the DHTML object model of any HTML file.
Here are the steps to create EX37B:
virtual void DoDHTMLExplore(void);
Now add the implementation for DoHTMLExplore to MainFrm.cpp.
void CMainFrame::DoDHTMLExplore(void) { CLeftView *pListView = (CLeftView *)m_wndSplitter.GetPane(0,0); CEx37bView * pDHTMLView = (CEx37bView *)m_wndSplitter.GetPane(0,1); //Clear the listview pListView->GetListCtrl().DeleteAllItems(); IDispatch* pDisp = pDHTMLView->GetHtmlDocument(); if (pDisp != NULL ) { IHTMLDocument2* pHTMLDocument2; HRESULT hr; hr = pDisp->QueryInterface( IID_IHTMLDocument2, (void**)&pHTMLDocument2 ); if (hr == S_OK) { IHTMLElementCollection* pColl = NULL; hr = pHTMLDocument2->get_all( &pColl ); if (hr == S_OK && pColl != NULL) { LONG celem; hr = pColl->get_length( &celem ); if ( hr == S_OK ) { for ( int i=0; i< celem; i++ ) { VARIANT varIndex; varIndex.vt = VT_UINT; varIndex.lVal = i; VARIANT var2; VariantInit( &var2 ); IDispatch* pDisp; hr = pColl->item( varIndex, var2, &pDisp ); if ( hr == S_OK ) { IHTMLElement* pElem; hr = pDisp->QueryInterface( IID_IHTMLElement, (void **)&pElem); if ( hr == S_OK ) { BSTR bstr; hr = pElem->get_tagName(&bstr); CString strTag = bstr; IHTMLImgElement* pImgElem; //Is it an image element? hr = pDisp->QueryInterface( IID_IHTMLImgElement, (void **)&pImgElem ); if ( hr == S_OK ) { pImgElem->get_href(&bstr); strTag += " - "; strTag += bstr; pImgElem->Release(); } else { IHTMLAnchorElement* pAnchElem; //Is it an anchor? hr = pDisp->QueryInterface( IID_IHTMLAnchorElement, (void **)&pAnchElem ); if ( hr == S_OK ) { pAnchElem->get_href(&bstr); strTag += " - "; strTag += bstr; pAnchElem->Release(); } }//end of else pListView->GetListCtrl().InsertItem( pListView->GetListCtrl() .GetItemCount(), strTag); pElem->Release(); } pDisp->Release(); } } } pColl->Release(); } pHTMLDocument2->Release(); } pDisp->Release(); } }
Here are the steps that this function takes to "explore" the HTML document using DHTMLs:
#include <mshtml.h>
void CEx37bApp::OnAppAbout() { CMainFrame * pFrame = (CMainFrame*)AfxGetMainWnd(); pFrame->DoDHTMLExplore(); }
cs.style |= LVS_LIST;
Figure 37-4 shows the EX37B example in action.
Figure 37-4. The EX37B example in action.
Now that you've seen how to use DHTML and MFC, let's look at how ATL implements DHMTL support.
ATL's support for DHTML comes in the form of an HTML object that can be embedded in any ATL ActiveX control. EX37C creates an ATL control that illustrates DHTML support.
To create the example, follow these steps:
If you look at the IDHTMLUI object, you will see this stock implementation of the OnClick handler:
STDMETHOD(OnClick)(IDispatch* pdispBody, VARIANT varColor) { CComQIPtr<IHTMLBodyElement> spBody(pdispBody); if (spBody != NULL) spBody->put_bgColor(varColor); return S_OK; }The default OnClick handler uses QueryInterface on the IDispatch pointer to get the IHTMLBodyElement object. The handler then calls the put_bgColor method to change the background color.
Figure 37-5. EX37C ActiveX control.
We hope this introduction to DHTML has you thinking of some ways to use this exciting new technology in your Visual C++ applications. The possibilities are endless: completely dynamic applications, applications that update from the Internet, client/server ActiveX controls, and many more.
If you would like to learn more about DHTML, we suggest the following resources: