The Ex29b Example: DHTML and MFC
Now let's create a sample that really shows how to use DHTML with MFC. Ex29b creates a CHtmlView object and a CListView object separated by a splitter. It then uses DHTML to enumerate the HTML elements in the CHtmlView object and displays the results in the CListView object. The end result is a DHTML explorer that you can use to view the DHTML object model of any HTML file.Here are the steps to create Ex29b:
Run the MFC Application Wizard and create the Ex29b project. Accept all the defaults but three: Select Single Document and Windows Explorer on the Application Type page, and select CHtmlView as the base class on the Generated Classes page.
Change the CLeftView to a CListView derivative. By default, the MFC Application Wizard makes the CLeftView of the splitter window a CTreeView derivative. Open the LeftView.h file, and do a global search for CTreeView and replace it with CListView. Open LeftView.cpp , and do the same find and replace.
Edit the URL to be loaded. In the CEx29bView::OnInitialUpdate function, change the URL to http://msdn.microsoft.com.
Add a DoDHTMLExplore function to CMainFrame. First add the following declaration to the MainFrm.h file:virtual void DoDHTMLExplore(void);
Then add the implementation for DoHTMLExplore to MainFrm.cpp :void CMainFrame::DoDHTMLExplore(void)
{
CLeftView *pListView =
(CLeftView *)m_wndSplitter.GetPane(0,0);
CEx29bView * pDHTMLView =
(CEx29bView *)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();
}
}
To "explore" the HTML document using DHTML, the DoHTMLExplore function first gets pointers to the CListView and CHtmlView views in the splitter window. Then it makes a call to GetHtmlDocument to get an IDispatch pointer to the DHTML document object. Next, it gets the IHTMLDocument2 interface, retrieves the all collection, and iterates through it. In each iteration, DoHTMLExplore checks the element type. If the element is an image or an anchor, DoHTMLExplore retrieves additional information such as the link for the image. The all collection loop then places the textual description of the HTML element in the CListView object.
Be sure that Mainfrm.cpp includes mshtml.h. Add the following line to the top of Mainfrm.cpp so the DoHTMLExplore code will compile:#include <mshtml.h>
Add a call to DoHTMLExplore. For this example, we'll change the CEx29bApp::OnAppAbout function to call the DoDHTMLExplore function in the Ex29b.cpp file. Replace the existing code with the following boldface code:void CEx29bApp::OnAppAbout()
{
CMainFrame * pFrame = (CMainFrame*)AfxGetMainWnd();
pFrame->DoDHTMLExplore();
}
Customize the list view. In the CLeftView::PreCreateWindow function ( LeftView.cpp ), add this line:cs.style |= LVS_LIST;
Compile and run the application. Press the ? toolbar item or choose Help/About to invoke the explore function.Figure 29-4 shows the Ex29b example in action.
Figure 29-4: The Ex29b example in action.
Now that you've seen how to use DHTML and MFC, let's look at how ATL implements DHMTL support.