Sample Image - HtmlEdit.gif

Introduction

Today applications often need a rich user interface. One of them is ability to compose or edit HTML documents in a easy, effective and reliable way. This article and source code attached gives you a nice control to perform this task. And now the best part: this control works fine with Microsoft VC++ 6.0!

Background

I'm author of Tray Helper application. For a long time I wanted to add a feature to send a colorful HTML mail. After some research I found that Microsoft did a nice thing implementing IHTMLDocument2 interface (and a few others related to it) - but working with raw COM interfaces is not very easy, effective or programmer-friendly. I think someone from Microsoft also realized that and in MFC 7.0 there is a very nice wrapper for COM: CHtmlEditCtrlBase class. After examining code of this class I decided to port to to MFC 4.0 and VC++ 6.0.

Using the code

The CHtmlEditCtrl2 class I want to introduce there is not only ported from CHtmlEditCtrlBase - I did some other improvements and changes to the orginal code - so it not only compiles under VC++ 6.0 but also has some new features and is even easier to use in existing projects.
The main change was that CHtmlEditCtrl2 class derives from CWebBrowser2. It means that if your projects already uses a standard web browser control to display a HTML documents - adding editing capabilities would be trivial (read bellow for a full instruction).

Adding HTML editor to your projects:

Step 1: Adding an ordinary web browser control to your project.
If you already use a web browser controls in your project - skip this paragraph and start reading from "Step 2".

Let's assume that you want add a HTML edit control to your dialog based application. First you need to add a web browser control that will contain your HTML documents.

Step 2: Adding a edit capabilities to web browser.

It's VERY easy. Just follow those few steps:

 

Highlight of the most important methods of the control (most likely you will need to use them):

void Navigate(LPCTSTR URL, VARIANT* Flags, VARIANT* TargetFrameName, VARIANT* PostData, VARIANT* Headers)

Use this function to load a HTML document. Pass as URL a string with a path to file to open. It could be remote site or local file.
Rest of parameters could be null. 

Examples:
Navigate("http://www.codeproject.com/", NULL, NULL, NULL, NULL);
Navigate("C:\\my_file.html", NULL, NULL, NULL, NULL);

 

BOOL SetDesignMode(BOOL bMode);

Enables or disables edit mode. In versions of Internet Explorer prior to 6.0 document must be loaded in a first place to enter a design mode.

 

HRESULT GetDocumentHTML(CString& szHTML, BOOL a_bClearDirtyFlag = FALSE);

Gets a content of HTML document.

 

HRESULT SetDocumentHTML(LPCTSTR szHTML);

Sets a new content of HTML document. Please note that you can't call this function on empty control. You need to load a document first (for example by calling Navigate method).

 

Complete list of public member functions of CHtmlEditCtrl2 class:

 
BOOL SetDesignMode(BOOL bMode);
HRESULT ExecCommand(const GUID *pGuid, long cmdID, long cmdExecOpt, VARIANT* pInVar=NULL, VARIANT* pOutVar=NULL);
HRESULT ExecCommand(long cmdID, long cmdExecOpt, VARIANT* pInVar=NULL, VARIANT* pOutVar=NULL);
long QueryStatus(long cmdID);
HRESULT GetEvent(IHTMLEventObj **ppEventObj);
HRESULT GetEventSrcElement(IHTMLElement **ppSrcElement);
HRESULT GetDocument(IHTMLDocument2** ppDoc);
HRESULT NewDocument();
HRESULT GetDocumentHTML(CString& szHTML, BOOL a_bClearDirtyFlag = FALSE);
HRESULT SetDocumentHTML(LPCTSTR szHTML);
HRESULT GetIsDirty();
HRESULT GetDocumentTitle(CString& szTitle);
HRESULT GetBlockFormatNames(CStringArray &sa);
HRESULT SetForeColor(LPCTSTR szColor);
HRESULT SetForeColor(int nColor);
HRESULT GetForeColor(int &nColor);
HRESULT GetBackColor(int& nColor);
HRESULT SetBackColor(LPCTSTR szColor);
HRESULT SetBackColor(int nColor);

HRESULT SetDefaultComposeSettings(LPCSTR szFontName=NULL,
                  unsigned short nFontSize=3,
                  COLORREF crFontColor=0xFF000000,
                  COLORREF crFontBgColor=0xFF000000,
                  bool bBold = false,
                  bool bItalic = false,
                  bool bUnderline = false);

HRESULT GetBlockFormat(CString& strFormat);
HRESULT SetBlockFormat(LPCTSTR szFormat);
HRESULT GetFontFace(CString& strFace);
HRESULT SetFontFace(LPCTSTR szFace);
HRESULT IE50Paste(LPCTSTR szData);
HRESULT GetBookMark(CString& strAnchor);
HRESULT SetBookMark(LPCTSTR szAnchorName);
HRESULT SetOverwriteMode(bool bMode);
HRESULT Is1DElement(bool& bValue);
HRESULT Is2DElement(bool& bValue);
HRESULT GetFontSize(short& nSize);
HRESULT SetFontSize(unsigned short size);
HRESULT GetFrameZone(short& nZone);
HRESULT SetCSSEditingLevel(short nLevel);
HRESULT HyperLink(LPCTSTR szUrl = NULL);
HRESULT Image(LPCTSTR szUrl = NULL);
HRESULT OrderList(LPCTSTR szId = NULL);
HRESULT UnorderList(LPCTSTR szId = NULL);

HRESULT AddToGlyphTable(LPCTSTR szTag,
            LPCTSTR szImgUrl,
            unsigned short nTagType,
            unsigned short nAlignment,
            unsigned short nPosInfo,
            unsigned short nDirection,
            unsigned int nImgWidth,
            unsigned int nImgHeight);

HRESULT EmptyGlyphTable();
HRESULT Button(LPCTSTR szId = NULL);
HRESULT CheckBox(LPCTSTR szId = NULL);
HRESULT DropDownBox(LPCTSTR szId = NULL);
HRESULT HorizontalLine(LPCTSTR szId = NULL);
HRESULT Iframe(LPCTSTR szId = NULL);
HRESULT InsFieldSet(LPCTSTR szId = NULL);
HRESULT InsInputButton(LPCTSTR szId = NULL);
HRESULT InsInputHidden(LPCTSTR szId = NULL);
HRESULT InsInputImage(LPCTSTR szId = NULL);
HRESULT InsInputPassword(LPCTSTR szId = NULL);
HRESULT InsInputReset(LPCTSTR szId = NULL);
HRESULT InsInputSubmit(LPCTSTR szId = NULL);
HRESULT InsInputUpload(LPCTSTR szId = NULL);
HRESULT ListBox(LPCTSTR szId = NULL);
HRESULT Marquee(LPCTSTR szId = NULL);
HRESULT Paragraph(LPCTSTR szId = NULL);
HRESULT RadioButton(LPCTSTR szId = NULL);
HRESULT SaveAs(LPCTSTR szPath = NULL);
HRESULT TextArea(LPCTSTR szId = NULL);
HRESULT TextBox(LPCTSTR szId = NULL);
HRESULT GetAbsolutePosition(bool &bCurValue);
HRESULT SetAbsolutePosition(bool bNewValue);
HRESULT Set2DPosition(bool bNewValue);
HRESULT SetAtomicSelection(bool bNewValue);
HRESULT SetAutoURLDetectMode(bool bNewValue);
HRESULT SetDisableEditFocusUI(bool bNewValue);
HRESULT SetIE5PasteMode(bool bNewValue);
HRESULT SetLiveResize(bool bNewValue);
HRESULT SetMultiSelect(bool bNewValue);
HRESULT SetOverrideCursor(bool bNewValue);
HRESULT SetRespectVisInDesign(bool bNewValue);
HRESULT GetShowAlignedSiteTags(bool &bCurValue);
HRESULT SetShowAlignedSiteTags(bool bNewValue);
HRESULT GetShowAllTags(bool &bCurValue);
HRESULT SetShowAllTags(bool bNewValue);
HRESULT GetShowAreaTags(bool &bCurValue);
HRESULT SetShowAreaTags(bool bNewValue);
HRESULT GetShowCommentTags(bool &bCurValue);
HRESULT SetShowCommentTags(bool bNewValue);
HRESULT GetShowMiscTags(bool &bCurValue);
HRESULT SetShowMiscTags(bool bNewValue);
HRESULT GetShowScriptTags(bool &bCurValue);
HRESULT SetShowScriptTags(bool bNewValue);
HRESULT GetShowStyleTags(bool &bCurValue);
HRESULT SetShowStyleTags(bool bNewValue);
HRESULT GetShowUnknownTags(bool &bCurValue);
HRESULT SetShowUnknownTags(bool bNewValue);
HRESULT GetShowBRTags(bool &bCurValue);
HRESULT SetShowBRTags(bool bNewValue);
HRESULT PrintDocument();
HRESULT PrintDocument(LPCTSTR szPrintTemplate);
HRESULT PrintDocument(bool bShowPrintDialog);
HRESULT PrintPreview();
HRESULT PrintPreview(LPCTSTR szPrintTemplate);
HRESULT Bold();
HRESULT Copy();
HRESULT Cut();
HRESULT Delete();
HRESULT Indent();
HRESULT Italic();
HRESULT JustifyCenter();
HRESULT JustifyLeft();
HRESULT JustifyRight();
HRESULT Outdent();
HRESULT Paste();
HRESULT RemoveFormat();
HRESULT SelectAll();
HRESULT Underline();
HRESULT Unlink();
HRESULT ClearSelection();
HRESULT Font();
HRESULT RefreshDocument();
HRESULT UnBookmark();

//IZ: Added by Irek Zielinski: //////////////////////////////////////////////////////
BOOL IsBold();
BOOL IsUnderline();
BOOL IsStrikeOut();
BOOL IsItalic();
BOOL CanPaste();
    
HRESULT LineBreakNormal();
BOOL    IsDesignMode();
HRESULT StrikeOut();
HRESULT GetURLsOfAllImages(CStringArray& a_arrImages);
HRESULT ReplaceImageURL(const CString& a_sUrlToReplace, const CString& a_sUrlToReplaceWith);
HRESULT GetDocumentBody(CString& a_sBody, BOOL a_bTextInsteadHTML);
HRESULT Undo();
HRESULT Redo();
HRESULT Find();
HRESULT SubScriptSelectedText();
HRESULT SuperScriptSelectedText();
HRESULT SetDocumentCharset(const CString& a_sCharsetEncoding);
HRESULT GetDocumentCharset(CString& a_sCharsetEncoding);
HRESULT ShowSource();
HRESULT ShowIEOptionsDialog();

HRESULT GetBodyBackgroundImage(CString& a_sImage);
HRESULT SetBodyBackgroundImage(const CString& a_sImage);
HRESULT GetBodyProperties(CString& a_sTag);
HRESULT GetBodyBackgroundColor(CString& a_sColor);
HRESULT GetBodyTextColor(CString& a_sColor);
HRESULT GetBodyBackgroundCSSText(CString& a_sStyleText);
HRESULT PasteHTMLAtCurrentSelection(const CString& a_sHTMLText, BOOL a_bSetCursorAtBeginingOfInsertedText);

The meaning and usage of near all of those functions is very easy to guess / understand. Most of those functions are a simple wrappers over COM calls - so in case of any problems - check the what COM function is being called and read about it in MSDN.
The ultimate MSDN resource is a description of CHtmlEditCtrlBase class. Since my class is in 80% only a port of CHtmlEditCtrlBase I recommend to read this page first (in case of any questions).

Here are some tips that could save you some time:
1) Call SetDesignerMode(TRUE) function when document is loaded into control. Doing it just after calling Navigate(url...) could be too early (function will fail if on machine there is installed Internet Explorer prior to 6.0 version).

2) If you create an empty HTML document and start editing it - you quickly realize that pressing an enter key inserts a paragraph not a line break.
This default behavior is pretty irritating and could be solved in two ways: first you could press SHIFT + ENTER instead, or load into HTML control such HTML document:

<HTML>
<BODY>
<DIV>&nbsp;</DIV>
</BODY>
</HTML>


At this point of article I would like to wish you a good look creating a killer applications ;-D
Sorry for my English - it's not my native language.

Points of Interest

MSDN pages about CHtmlEditCtrlBase class.
MSDN pages about IHTMLDocument2 interface.
MSDN Programming and Reusing the Browser Overviews and Tutorials