Вставляем HBITMAP (Bitmap) в
элемент управления RichEdit
Автор: Hani Atassi.
Требования: VC6 SP5, Win2000 SP2
Существует множество примеров, объясняющих как
вставить файл bitmap в RichEdit. Но недостаток этих
примеров в том, что они непригодны в случае, если
изображение находится в виде ресурса либо в виде
дескриптора (HBITMAP).
Статья основывается на примере MSDN "HOWTO: Insert a
Bitmap Into an RTF Document Using the RichEdit Control", и использует
интерфейс IDataObject. В статье MSDN используется OLE API
(OleCreateFromFile), которая использует имя файла в виде
строки. Так же существует множество способов
создания объекта OLE (IOleObject). Все эти OLE API
начинаются с префикса OleCreate. Одну из них я
использовал в данном примере (OleCreateStaticFromData),
которая позволяет нам создавать объект Ole,
который в свою очередь содержит только
представление без каких либо ссылок на данные.
Естевственно, что данные могут быть в виде
значения HBITMAP, которое может быть представлением
картинки.
Думаю не стоит объяснять - как создать OleObject
(IOleObject). Этот процесс хорошо описан в MSDN. Однако,
один составляющих OLE объектов требует некоторого
пояснения. В данном случае наша HBITMAP будет
храниться в IDataObject.
Существует два метода получения нашего HBITMAP из
объекта. Первый использует COleDataSource, который
включён в интерфейс IDataObject. Второй метод - это
добавить свою собственную обработку данного
процесса в IDataObject. Второй метод хорош тем, что нет
необходимости использовать MFC в приложении.
Первый метод использует следующий код:
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);
Используя возвращаемое lpDataObject а так же другие
объекты, Вы можете добавить объект в RichEdit.
Далее показан второй метод:
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);
};
Приведённая реализация IDataObject специально
расчитана на хранение дескриптора HBITMAP.
Чтобы вставить картинку в RichEdit, достаточно
вызвать функцию CImageDataObject::InsertBitmap. Функция имеет
два параметра:
IRichEditOle* pRichEditOle : Указатель на интерфейс
IRichEditOle для элемента управления RichEdit. Вы можете
использовать метод GetRichEditOle() в MFC классе CRichEditCtrl
для получения этого указателя или следующий код:
::SendMessage((HWND)m_ctlRichText.GetHwnd(),
EM_GETOLEINTERFACE,
0,
(LPARAM)&m_pRichEditOle);
HBITMAP hBitmap : дескриптор изображения. Класс
отвечает за закрытие и освобождение ресурсов,
занимаемы дескриптором, поэтому не закрывайте
его самостоятельно.
Downloads
Download demo project - 55 Kb
Download source - 3 Kb
|