Environment:
VC++ 6 SP5, Win2000 SP2
There are a
lot of articles
in ucancode or MSDN that discuss how to
insert a bitmap
file inside the RichEdit control.
Those articles
are not working when the image is in the
resource or within a handle (HBITMAP).
My
article
is based on the MSDN code "HOWTO:
Insert a Bitmap
Into an RTF Document Using the
RichEdit Control",
and the use of IDataObject Interface. When
you refer back to the MSDN
article,
you will find that it uses the OLE API (OleCreateFromFile),
which accepts the name of the file as a
string. There are many other ways to create
an OLE object (IOleObject). Those OLE APIs
are started with the prefix (OleCreate). The
one that I will use here is (OleCreateStaticFromData),
which allows us to build an Ole object that
contains only a representation without any
relative data. The data for sure might be an
HBITMAP
value that represents an image.
How do you
create an OleObject (IOleObject) using the
mentioned OLE API? In order for that
function to return an IOleObject pointer,
you should prepare many objects before
invoking it. This includes objects like
IDataObject, IStorage, and IOleClientSite.
Preparing the last two objects is the same
method shown in the MSDN
article.
But, what about IDataObject?
There are
two methods to get the data object of the
HBITMAP. One uses COleDataSource, the MFC
implementation for IDataObject interface.
The second method is to supply your own
implementation of IDataObject. The second
one, which I use in the code, is the
preferable method if you are not going to
use MFC in your application.
The first
method uses the following code:
STGMEDIUM stgm;
stgm.tymed = TYMED_GDI;
stgm.hBitmap = hBitmap;
stgm.pUnkForRelease = NULL;
COleDataSource *pDataSource = new COleDataSource;
pDataSource->CacheData(CF_BITMAP, &stgm);
LPDATAOBJECT lpDataObject =
(LPDATAOBJECT)pDataSource->GetInterface(&IID_IDataObject);
Using the
returned lpDataObject and the other objects
you can insert the Object in the RichEdit.
The second
method is to write your own IOleObject
Implementation as shown in the next code:
class CImageDataObject : IDataObject
{
public:
static void InsertBitmap(IRichEditOle* pRichEditOle,
HBITMAP hBitmap);
private:
ULONG m_ulRefCnt;
BOOL m_bRelease;
STGMEDIUM m_stgmed;
FORMATETC m_fromat;
public:
CImageDataObject() : m_ulRefCnt(0) {
m_bRelease = FALSE;
}
~CImageDataObject() {
if (m_bRelease)
::ReleaseStgMedium(&m_stgmed);
}
STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject)
{
if (iid == IID_IUnknown || iid == IID_IDataObject)
{
*ppvObject = this;
AddRef();
return S_OK;
}
else
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)(void)
{
m_ulRefCnt++;
return m_ulRefCnt;
}
STDMETHOD_(ULONG, Release)(void)
{
if (--m_ulRefCnt == 0)
{
delete this;
}
return m_ulRefCnt;
}
STDMETHOD(GetData)(FORMATETC *pformatetcIn,
STGMEDIUM *pmedium) {
HANDLE hDst;
hDst = ::OleDuplicateData(m_stgmed.hBitmap,
CF_BITMAP, NULL);
if (hDst == NULL)
{
return E_HANDLE;
}
pmedium->tymed = TYMED_GDI;
pmedium->hBitmap = (HBITMAP)hDst;
pmedium->pUnkForRelease = NULL;
return S_OK;
}
STDMETHOD(GetDataHere)(FORMATETC* pformatetc,
STGMEDIUM* pmedium ) {
return E_NOTIMPL;
}
STDMETHOD(QueryGetData)(FORMATETC* pformatetc ) {
return E_NOTIMPL;
}
STDMETHOD(GetCanonicalFormatEtc)(FORMATETC* pformatectIn ,
FORMATETC* pformatetcOut ) {
return E_NOTIMPL;
}
STDMETHOD(SetData)(FORMATETC* pformatetc ,
STGMEDIUM* pmedium ,
BOOL fRelease ) {
m_fromat = *pformatetc;
m_stgmed = *pmedium;
return S_OK;
}
STDMETHOD(EnumFormatEtc)(DWORD dwDirection ,
IEnumFORMATETC** ppenumFormatEtc ) {
return E_NOTIMPL;
}
STDMETHOD(DAdvise)(FORMATETC *pformatetc,
DWORD advf,
IAdviseSink *pAdvSink,
DWORD *pdwConnection) {
return E_NOTIMPL;
}
STDMETHOD(DUnadvise)(DWORD dwConnection) {
return E_NOTIMPL;
}
STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise) {
return E_NOTIMPL;
}
void SetBitmap(HBITMAP hBitmap);
IOleObject *GetOleObject(IOleClientSite *pOleClientSite,
IStorage *pStorage);
};
The
previous implementation for IDataObject is
specialized for holding
HBITMAP
handle.
To use the
previous implementation to
insert
any image
in the RichEdit,
use the static member function
CImageDataObject::InsertBitmap. This static
function accepts two parameters:
IRichEditOle* pRichEditOle : A pointer
to IRichEditOle interface for the
RichEdit control.
You can use the method GetRichEditOle() in
the MFC
CRichEditCtrl class to obtain
that pointer, or use the following code:
::SendMessage((HWND)m_ctlRichText.GetHwnd(),
EM_GETOLEINTERFACE,
0,
(LPARAM)&m_pRichEditOle);
HBITMAP
hBitmap : The bitmap handle of the
image. The class is responsible of freeing
or closing the handle. So, don't close it
your self.
For a bonus
you will learn how to use high-color images
in the toolbar by using CImageList. One of
the advantages of using CImageList is that
it automatically mucancode.nets out the background
color.
That's it,
and enjoy!
Downloads
Download demo
project - 55 Kb
Download source
- 3 Kb