To solve a similar problem for a previous website, after looking at and
dismissing many other options, I ended up using the following technique:
- Found and customized a custom Visual Basic ActiveX control (not .NET)
that subclasses the RichEdit control and exposes the tom interface (text
object model, similar to the the MS Word object model). I called this
ActiveX control RichEditTom.
- Inserted the RichEditTom control into an Access form, along with
buttons to make text bold, italic, etc.
- Used the tom interface to handle user interface events, eg clicking on
the add bulleted list button, undo/redo, etc.
- Saved the rich text in XML form into a plain text field.
The main reason I went to all this trouble was that I needed a way to
insert hyperlinks into the text. The MS Rich Text control was no good
for my purposes as you cannot create a link that has a url that is
different from the visible link text. Indeed most third party controls I
came across suffered from this problem.
Even though the RichEdit control too has this drawback, the tom objects
allowed me to handle hyperlinks as I needed by manually formatting text
to make it look like a link (underlining it in blue) and adding the url
as hidden text just before the link text. But as you can imagine, this
led to some very messy code, for example having to take to care when a
user added text just before the link.
This time around, I am desperately hoping that using the WebBrowser
control, MSHTML and VBA could provide a much more elegant solution.
However, in my early experiments I am encountering some potentially
show-stopping problems that I hope you can help me to solve.
Note that my Access form contains a WebBrowser control which loads a
simple template HTML document. Then I get a reference to the
corresponding HTMLDocument object and use it to set the contentEditable
property of the body tag to true.
So far so good. I can enter text, copy/paste, undo/redo, enter
hyperlinks (all using the standard keyboard shortcuts), even use Access
buttons to trigger the HTMLDocument.execCommand to make simple
formatting changes, eg make text bold. Below though are the issues that
could render all this useless:
- At the moment the Return key has no effect, ie I cannot enter new
paragraphs. I have tried using the Access form's KeyPreview property to
intercept key presses to manually insert paragraphs -
HTMLDocument.execCommand("InsertParagraph", True). But any text on the
new line appears outside of the corresponding <p> tags (eg "<p></p>new
line text").
- When pasting from a Word document etc, a lot of unwanted messy HTML is
added. I need to be able to modify the clipboard content before it is
processed by HTMLDocument. How do I do this? I already have code to read
data from the clipboard, just need to know how to capture the paste key
combination before the document.
- I need to be able to open a custom link entry form when a user wants
to enter/edit a hyperlink (to be able to link to other objects in the
database etc).
Basically, from what I can tell, I really need to able to add Edit
Designers (and use other MSHMTL interfaces) that appear only to be
accessible using C++ - need to invoke IHTMLDocument.QueryInterface etc.
Looking back at the code for RichEditTom, I am guessing though I could
gain access to these interfaces using a similar technique to the one below:
---------------------------------------------------------
' Prepare the IID for the tom ITextDocument interface
' 8CC497C0-A1DF-11ce-8098-00AA0047BE5D
With IID_ITextDocument
.Data1 = &H8CC497C0
.Data2 = &HA1DF
.Data3 = &H11CE
.Data4(0) = &H80
.Data4(1) = &H98
.Data4(2) = &H0
.Data4(3) = &HAA
.Data4(4) = &H0
.Data4(5) = &H47
.Data4(6) = &HBE
.Data4(7) = &H5D
End With
' Ask the RichEdit control to provide its OLE Interface
SendMessage m_hWnd, EM_GETOLEINTERFACE, 0, iUnk
' Now query for ITextDocument support
hr = iUnk.QueryInterface(IID_ITextDocument, oTom)
' If we got it...
If COMSucceeded(hr) Then
' ... then AddRef (COM rules)
Set iUnkTom = oTom
iUnkTom.AddRef
Set iUnkTom = Nothing
' Store a reference to it
Set m_oTomDoc = oTom
Else
Set m_oTomDoc = Nothing
Err.Raise efretErrTomUnavailable, "FOTRichEditTOM.TomDoc", _
"Failed to get ITextDocument interface."
End If
' We release the AddRef that was added by RichEdit
iUnk.Release
' But we don't want VB to try and release it again
CopyMemory iUnk, 0&, 4
' Make sure the tom Saved flag matches this control's modified flag
SyncTomDoc
' Return a reference to the object
Set TomDoc = m_oTomDoc
---------------------------------------------------------
However I am nervous of coding this from scratch and cannot find, for
example, details of IHTMLDocument messages or the
MSHTML.IServiceProvider GUID.
Do you have any ideas or am I attempting the impossible, or even missing
a much simpler solution to the original problem?
Cheers
Fran