Click here to Skip to main content
15,867,686 members
Articles / Desktop Programming / MFC
Article

Using MSHTML Editing in VC6 Doc/View Applications

Rate me:
Please Sign up or sign in to vote.
4.82/5 (21 votes)
25 Apr 2004CPOL6 min read 128.4K   4.5K   69   21
How to enable MSHTML editing in a view in VC6

Sample Image - htmleditvc6.jpg

Introduction

I've recently published a couple of articles on CodeProject covering customisation of the MSHTML editor. Those articles are VC7 and MFC7 specific. Naturally there have been some posts asking how one can do the same things using VC6. This article will show you how you can use the MSHTML editor in a VC6 MFC document/view application.

Background

The version of MFC that ships with VC6 includes support for displaying HTML documents in a view. You derive your view class from the CHtmlView class, override a few virtual methods and voila, there's an embedded HTML display in your app.

MFC7, as shipped with VC7, extends this to include a CHtmlEditView class. See this [^] article for a quick overview of the class.

Scope of this article

I didn't set out to completely rewrite the CHtmlEditView class. Instead, I'll show you how to put the MSHTML control into edit mode and show how to implement the various commands it supports. You'll have to do most of the work yourself.

Structural differences between this implemenation and the MFC one

MFC adds HTML editing capability to CHtmlView by bolting on a class called CHtmlEditCtrlBase which actually implements the low level details. They did it that way so they could reuse the code in the CHtmlEditCtrl class (also new to MFC7). Being a lazy sod I chose to add the edit support into a direct derivative of CHtmlView called (so as not to conflict with MFC's naming) CHtmlEditorView.

Putting MSHTML into edit mode

is trivial. All you do is get an IHTMLDocument2 interface for the document being displayed and call the put_designMode(() function passing a case sensitive BSTR specifying edit mode as either On or Off. You can only do this once a document has been loaded into MSHTML and each time you navigate to a new document you need to repeat the process. I do it in the OnNavigateComplete2() event handler. In code it looks like this.
C++
void CHTMLEditorView::OnNavigateComplete2(LPCTSTR strURL) 
{
    BSTR bs = SysAllocString(L"On");

    CHtmlView::OnNavigateComplete2(strURL);

    //  Get a pointer to our document
    m_pHTMLDoc = (IHTMLDocument2 *) GetHtmlDocument();
    
    if (m_pHTMLDoc != (IHTMLDocument2 *) NULL)
        m_pHTMLDoc->put_designMode(bs);

    SysFreeString(bs);
}
which will always force the document into edit mode. Once that's done you can click around on the document to your hearts content changing things, moving them around and generally messing up the page.

What about formatting the content?

That's the next step. The IHTMLDocument2 interface has an execCommand() method that lets you execute commands on the current selection in the MSHTML editor. For the purpose of this article I've only implemented the Bold command, which looks like this.
C++
void CHTMLEditorView::Bold(BOOL bState)
{
    BSTR         bCmd = SysAllocString(L"Bold");
    VARIANT_BOOL vb;
    VARIANT      vValue;

    vValue.vt = VT_BOOL;
    vValue.boolVal = bState;

    if (m_pHTMLDoc != (IHTMLDocument2 *) NULL)
        m_pHTMLDoc->execCommand(bCmd, VARIANT_FALSE, vValue, &vb);

    SysFreeString(bCmd);
}
we set up a BSTR containing our command verb and a VARIANT containing the desired state. Then we call IHTMLDocument2::execCommand to actually execute the command. The second parameter in the call indicates that we don't want any user interface shown. In the case of the Bold command there isn't a user interface required but some other commands may support one. That second parameter gives us the chance to suppress the user interface if we wish. The fourth parameter is a pointer to a VARIANT_BOOL which recieves a value indicating the success of the operation.

All of the MSHTML commands follow this pattern however it should be clear that the variant type you assign to the variant depends on the datatype which in turn depends on the command. Setting the font face requires a string, setting the text colour requires a specially formatted string and so forth.

Querying the current state of a selection

is done using the IHTMLDocument2::QueryCommandState() or IHTMLDocument2::QueryCommandValue() methods. In each case you pass the name of the command you're querying (for example, is the selection bolded?) and a location to return the value. The demo project has a button on the toolbar to let you toggle Bold on selected text. Naturally it's expected that if the selection is already bold the button will be depressed indicating that fact. So whenever we change the selection we need to query the Bold state. The code to do this looks like
C++
BOOL CHTMLEditorView::Bold()
{
    BSTR         bCmd = SysAllocString(L"Bold");
    VARIANT_BOOL vb = FALSE;

    if (m_pHTMLDoc != (IHTMLDocument2 *) NULL)
        m_pHTMLDoc->queryCommandState(bCmd, &vb);

    SysFreeString(bCmd);
    return vb;
}
which queries the document for the Bold state. This is returned in the VARIANT_BOOL which we simply return to the caller. The IHTMLDocument2::queryCommandState() method works only for BOOL properties. If we wanted to query the font name we'd do it like this
C++
CString CHTMLEditorView::FontName()
{
    BSTR    bCmd = SysAllocString(L"FontName");
    VARIANT vb;
    CString csValue;

    if (m_pHTMLDoc != (IHTMLDocument2 *) NULL)
        m_pHTMLDoc->queryCommandValue(bCmd, &vb);

    SysFreeString(bCmd);
    
    if (vb.vt == VT_BSTR)
        csValue = CW2CT(vb.bstrVal);

    return csValue;
}
which receives the return value in a VARANT. Then it checks that the return value is indeed a string; if so it converts it from the BSTR returned in the VARIANT to a CString and returns the CString. If the return value isn't a string the conversion attempt doesn't take place and the empty CString is returned instead. Naturally the caller needs to allow for the case where an empty CString is returned, which might happen if one were to execute a font name query on an image, which leads to the next topic.

Determing if a command can be executed

This is done by calling the IHTMLDocument2::queryCommandEnabled() method. This takes the command name and a pointer to a VARIANT_BOOL which receives the return value. If the command is valid for the current selection you get back TRUE, otherwise you get back FALSE. The code that determines if the Bold command is valid for the current selection looks like this.
C++
BOOL CHTMLEditorView::CanBold()
{
    BSTR         bCmd = SysAllocString(L"Bold");
    VARIANT_BOOL vb = FALSE;

    if (m_pHTMLDoc != (IHTMLDocument2 *) NULL)
        m_pHTMLDoc->queryCommandEnabled(bCmd, &vb);

    SysFreeString(bCmd);
    return vb;
}
which is almost identical to querying the current value.

Putting it all together

So now we have the code in place to set Bold on the current selection, determine if the current selection is Bold or not and determine if the current selection can be Bolded. We'd use that code in our toolbar Bold button command handler and UI state update handler like this.
C++
void CHTMLEditorView::OnBold() 
{
    Bold(Bold() ? 1 : 0);
}

void CHTMLEditorView::OnUpdateBold(CCmdUI* pCmdUI) 
{
    pCmdUI->SetCheck(Bold() ? 1 : 0);
    pCmdUI->Enable(CanBold());
}
which is trivial in the extreme.

What commands are available?

I refer you to the IHTMLDocument2::execCommand() documentation available online at MSDN for the exhaustive list. I'm not providing a URL because MSDN sometimes change things around on their site and invalidate links.

Wich versions of Microsoft Internet Explorer will this work with?

According to the MSDN documentation the IHTMLDocument2 interface was added in version 4.0 of Microsoft Internet Explorer. It's probably safe to assume that almost every Windows machine you install your code on will have at least that version. You may run across the occasional command that requires a later version of Internet Explorer - if so the MSDN documentation will list version requirements.

Using the code

The source file download contains a copy of the CHtmlEditorView header and implementation files. As aforesaid I've only implemented the Bold command - it's up to you to add handlers for any other commands you're interested in. The class does include an override of OnNavigateComplete2() which puts the document into edit mode.

You derive your own class from this, or use the class directly if you wish.

History

26 April 2004 - Initial version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
I've been programming for 35 years - started in machine language on the National Semiconductor SC/MP chip, moved via the 8080 to the Z80 - graduated through HP Rocky Mountain Basic and HPL - then to C and C++ and now C#.

I used (30 or so years ago when I worked for Hewlett Packard) to repair HP Oscilloscopes and Spectrum Analysers - for a while there I was the one repairing DC to daylight SpecAns in the Asia Pacific area.

Afterward I was the fourth team member added to the Australia Post EPOS project at Unisys Australia. We grew to become an A$400 million project. I wrote a few device drivers for the project under Microsoft OS/2 v 1.3 - did hardware qualification and was part of the rollout team dealing directly with the customer.

Born and bred in Melbourne Australia, now living in Scottsdale Arizona USA, became a US Citizen on September 29th, 2006.

I work for a medical insurance broker, learning how to create ASP.NET websites in VB.Net and C#. It's all good.

Oh, I'm also a Kentucky Colonel. http://www.kycolonels.org

Comments and Discussions

 
GeneralGetFont() function as coded does not work. Pin
Erik Larson26-Aug-04 9:20
Erik Larson26-Aug-04 9:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.