Eric Hartwell's InfoDabble

 
Welcome to Eric Hartwell's InfoDabble
About | Site Map
Home Tech Notes Apollo 17: Blue Marble Apollo 17 Flight Journal   Calendars About me  
 Exoware .....  

Tech Note 

Using the CodeGuru HTML View Automation Classes

Eric Hartwell - December 1999

Microsoft's CHtmlView class provides the functionality of the WebBrowser control within the context of MFC's document/view architecture. The WebBrowser control is a window in which the user can browse sites on the World Wide Web, as well as folders in the local file system and on a network. This effectively makes the application a web browser. 

The functionality of CHtmlView is designed for applications that access the Web (and/or HTML documents). For HTML-based applications, however, we need a tighter integration between the view class and the actual application. For example,

  • Set HTML text directly from a string, rather than a URL
  • Access the HTML DOM directly from the application's CDocument class
  • Capture arbitrary events within the browser
  • Interact with scripting code running on the browser

V. Rama Krishna (mailto:ramakrsna@hotmail.com) has published an excellent series of articles about automating the HTML view on the CodeGuru web site (see references). This article explains how his code is extended and implemented for MyApp Studio.

CHTMLPage Classes

Rama explains the architecture of his CHTMLPage classes (excerpts):

A traditional MFC multiple form-based application has a class derived from some base class like CFormView, for each dialog resource (or form). In that derived class the controls are mapped to variables through DDX_ functions. The events are mapped through Message Map macros. I wished to have a similar architecture for working with DHTML pages. 

Class HierArchyTherefore, the class CHTMLPage serves as a base class from which you derive any other class to represent a particular page. For example, to convert a form-based application to DHTML, all you have to do is to derive a class from CHTMLPage and add your specialized processing for the events occurring in the page. You can also map HTML events to a variable of the class CHTMLElement or you can derive your own class from CHTMLElement for special elements.

CHTMLEventSink, derived from IDisptach, serves to sink events from any HTML element through connection points. The class CHTMLEventTarget is the class where ultimately the event is handled. When you advise a connection you advise pass the target as an object of CHTMLEventSink which has a member m_pTraget where it is supposed to pass the event to. CHTMLPage and CHTMLEvent have both been derived from CHTMLEventTarget. This gives me the flexibility to develop certain elements that have respond to events in a particular way. 

The CHTMLElementCollection collection is just a wrapper class for IHTMLElementCollection . CHTMLPage is also derived from CHTMLElementCollection, since the CHTMLElementCollection part of CHTMLPage mainatins the 'all' collection. CHTMLPage also serves to wrap around the interfaces IHTMLDocument2, which represents the HTML document, and IHTMLWindow2, which represents the "window" scripting object.

 - Programming Dynamic HTML through VC++

Once the CHtmlView has been initialized, you can get a dispatch pointer to the document and connect it to the CHTMLPage-derived class. There's a catch - the document object isn't valid until after the browser has finished navigating to the first page. So, before you can do anything, you have to navigate to a page. The browser fires a NavigateComplete event when the initial document is loaded, so this is done in the OnNavigateComplete or OnDocumentComplete methods:

CDerivedHTMLPage* pPage = new CDerivedHTMLPage();
LPDISPATCH pDisp1 = GetHtmlDocument();
pPage->SetDocument(pDisp1);
pDisp1->Release();

The CHTMLPage code gets the document interface, initializes the element classes, creates and attaches an event sink, and builds the customized event and variable maps. CHTMLPage auto deletes itself, all connections, and all associated classes, when the unload event is fired by the window object.

 

CHtmlView2 Class

CHtmlView2 was originally developed for displaying HTML screens in BenWin32. Basically, this class adds the NavigateText method, which lets you specify the screen as an HTML characters string instead of a URL (see Exoware Tech Note: Setting HTML View Text Directly From a String).

void CHtmlView2::NavigateText(const char *pszHtmlText)

If the browser has already navigated to a page, the HTML is loaded directly. However, if it hasn't, the method caches the text, navigates to the internal page "about:blank" to initialize the document object, then loads the HTML.

 

CMyAppHtmlView Class

CMyAppHtmlView was developed for displaying HTML screens in BenWin32. It builds on the CHtmlView2 foundation to add event sourcing and sinking (see Q181845), printing (see Q156732), and the ability to execute a script within the browser (see Exoware Tech Note: Issuing Commands to the HTML View).

Printing support is simply a matter of sending a print command to the browser control. (It's actually more complicated in BenWin32, since the user may choose to print a screen that isn't currently displayed).

void CMyAppHtmlView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
    // Let the HTML control print the current screen
    ExecWB(pInfo->m_bPreview ? OLECMDID_PRINTPREVIEW : OLECMDID_PRINT,
           OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
}

 

Implementation

  1. Create a document/view pair, where the view class is derived from CHtmlView or CHtmlView2, and the document class is derived from CMyAppStudioDoc.
  2. Add printing support to the view class:
    void CnewView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
    {
        // Let the HTML control print the current screen
        ExecWB(pInfo->m_bPreview ? OLECMDID_PRINTPREVIEW : OLECMDID_PRINT,
               OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
    }
  3. Add support for the clipboard [Edit - Cut, Copy, Paste, Select All] to the document/view's menu and the actual view class (see How to add clipboard use to CHtmlView):
    void CnewView::OnEditCut()       { ExecWB(OLECMDID_CUT,       OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL); }
    void CnewView::OnEditCopy()      { ExecWB(OLECMDID_COPY,      OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL); }
    void CnewView::OnEditPaste()     { ExecWB(OLECMDID_PASTE,     OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL); }
    void CnewView::OnEditSelectall() { ExecWB(OLECMDID_SELECTALL, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL); }
  4. Edit the document class declaration so it derives from CHTMLPage as well as CMyAppStudioDoc:
    class CnewDoc : public CMyAppStudioDoc, public CHTMLPage
    It is important to clear the HTML autodelete flag so the document isn't deleted by the HTML routines:
    CnewDoc::CnewDoc()
    {
        CHTMLPage::m_bAutoDelete = FALSE;
        . . . . 
  5. Override the view's OnInitialUpdate method to load an empty document (blank screen):
    void CnewView::OnInitialUpdate()
    {
        CHtmlView::OnInitialUpdate();
        Navigate2("about:blank");         // Initialize system to a blank screen
    }
  6. Override the view's OnDocumentComplete method to attach the document class to the browser:
    void CnewView::OnDocumentComplete(LPCTSTR lpszURL) 
    {
        LPDISPATCH pDisp = GetHtmlDocument();            // Get the HTML COM interface
        ((CnewDoc *)GetDocument())->SetDocument(pDisp);  // Set document does the rest for us
        pDisp->Release();                                // Finished with this copy of COM interface
        CHtmlView::OnDocumentComplete(lpszURL);          // Default processing
    }
  7. You now have full control of the HTML DOM directly through the document class. The CHTMLPage code calls the OnInitPage function as soon as the DOM is ready. This is first called after the blank screen has been loaded; you can set the HTML text or directly manipulate the DOM at this point. Note that the navigate, open, write, reload, and other methods trigger the onbeforeunload event, which causes it to delete the attached event sink.
     
  8. The document class can also implement the MapVars and MapEvents functions to map HTML elements and events as desired.
     

References:

Resources:

MSDN, Microsoft Knowledge Base, Site Builder Workshop, Platform SDK, etc.


Revisions:

  1. December, 1999 - Description for MyApp implementation.
Creative Commons License

Unless otherwise noted, this work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License

 

Site Map | About Me