利用RichEdit制作表情控件是,首先需要向RichEdit中插入图片(Bitmap)或GIF动画,然后需要从RichEdit中获取Bitmap/GIF的信息,以便向远端传送。
本人对RichEdit了解很有限。下面是本人根据网上找到的资料,以通过看MSDN整理出来的实现在RichEdit中插入Bitmap与/GIF的方法,在这里共享给大家。RichEdit方面的高手不要取笑。
1.在RichEdit中插入Bitmap/GIF的方法
下面的代码是从网上找来的,我稍微作了一点修改(代码中红色部分是我改过的)。
ImageDataObect.h
====================================================
#ifndef IMAGE_DATA_OBJECT__H
#define IMAGE_DATA_OBJECT__H
#include <Richedit.h>
#include <objidl.h.>
#include <Richole.h>
class CImageDataObject : IDataObject
{
public:
// This static fumction accepts those parameters:
// IRichEditOle* : a pointer to IRochEditOle interface for the RichEdit Control
// HBITMAP : the bitmap handle.
//DWORD dwUser - 位图相关的信
// After calling the function, it inserts the image in the current
// position of the RichEdit
//
static void InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap,DWORD dwUser);
static void InsertGif(IRichEditOle *pRichEditOle,const char *gif_file,DWORD dwUser);
private:
ULONG m_ulRefCnt;
BOOL m_bRelease;
// The data being bassed to the richedit
//
STGMEDIUM m_stgmed;
FORMATETC m_fromat;
public:
CImageDataObject() : m_ulRefCnt(0)
{
m_bRelease = FALSE;
}
~CImageDataObject()
{
if (m_bRelease)
::ReleaseStgMedium(&m_stgmed);
}
// Methods of the IUnknown interface
//
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;
}
// Methods of the IDataObject Interface
//
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;
}
// Some Other helper functions
//
void SetBitmap(HBITMAP hBitmap);
IOleObject *GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage);
};
#endif // IMAGE_DATA_OBJECT__H
===========================
ImageDataObject.cpp
#include "stdafx.h" //我很不喜欢这个头文件,这个程序只能在windows下运行,就留着吧
#include "ImageDataObject.h"
#import "ImageOle.dll" raw_interfaces_only, raw_native_types, no_namespace, named_guids, auto_search
static CLSID const gif_clsid = { 0x6ADA938, 0xFB0, 0x4BC0, { 0xB1, 0x9B, 0xA, 0x38, 0xAB, 0x17, 0xF1, 0x82 } };
void CImageDataObject::InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap,DWORD dwUser)
{
SCODE sc;
// Get the image data object
//
CImageDataObject *pods = new CImageDataObject;
LPDATAOBJECT lpDataObject;
pods->QueryInterface(IID_IDataObject, (void **)&lpDataObject);
pods->SetBitmap(hBitmap);
// Get the RichEdit container site
//
IOleClientSite *pOleClientSite;
pRichEditOle->GetClientSite(&pOleClientSite);
// Initialize a Storage Object
//
IStorage *pStorage;
LPLOCKBYTES lpLockBytes = NULL;
sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &pStorage);
// The final ole object which will be inserted in the richedit control
//
IOleObject *pOleObject;
pOleObject = pods->GetOleObject(pOleClientSite, pStorage);
// all items are "contained" -- this makes our reference to this object
// weak -- which is needed for links to embedding silent update.
OleSetContainedObject(pOleObject, TRUE);
// Now Add the object to the RichEdit
//
REOBJECT reobject;
ZeroMemory(&reobject, sizeof(REOBJECT));
reobject.cbStruct = sizeof(REOBJECT);
CLSID clsid;
sc = pOleObject->GetUserClassID(&clsid);
reobject.clsid = clsid;
reobject.cp = REO_CP_SELECTION;
reobject.dvaspect = DVASPECT_CONTENT;
reobject.poleobj = pOleObject;
reobject.polesite = pOleClientSite;
reobject.pstg = pStorage;
reobject.dwUser = dwUser;
// Insert the bitmap at the current location in the richedit control
//
pRichEditOle->InsertObject(&reobject);
// Release all unnecessary interfaces
//
pOleObject->Release();
pOleClientSite->Release();
pStorage->Release();
lpDataObject->Release();
}
void CImageDataObject::InsertGif(IRichEditOle *lpRichEditOle,const char *gif_file,DWORD dwUser)
{
LPOLEOBJECT lpObject=NULL;
LPSTORAGE lpStorage=NULL;
LPOLECLIENTSITE lpClientSite=NULL;
LPLOCKBYTES lpLockBytes = NULL;
HRESULT hr=S_OK;
CLSID clsid=CLSID_NULL;
do{
hr= ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
if (hr != S_OK || lpLockBytes==NULL)
break;
hr= ::StgCreateDocfileOnILockBytes(lpLockBytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &lpStorage);
if (hr!= S_OK||lpStorage==NULL)
break;
hr=lpRichEditOle->GetClientSite(&lpClientSite);
if (hr!= S_OK||lpClientSite==NULL)
break;
try
{
HRESULT hr;
IGifAnimator *pGif = NULL;
hr = CoCreateInstance(gif_clsid,NULL,CLSCTX_INPROC_SERVER , IID_IGifAnimator,(void **)&pGif);
if(FAILED(hr) || pGif == NULL)
break ;
_bstr_t bstrPath(gif_file);
pGif->LoadFromFile(bstrPath);
if(FAILED(hr))
{
pGif->Release();
break ;
}
hr = pGif->QueryInterface(IID_IOleObject, (void**)&lpObject);
if( FAILED(hr)||lpObject==NULL)
{
pGif->Release();
break ;
}
hr=OleSetContainedObject(lpObject, TRUE);
if( FAILED(hr) )
{
pGif->Release();
break ;
}
hr=lpObject->GetUserClassID(&clsid);
if( FAILED(hr) )
{
pGif->Release();
break ;
}
REOBJECT reobject;
ZeroMemory(&reobject, sizeof(REOBJECT));
reobject.cbStruct = sizeof(REOBJECT);
reobject.clsid = clsid;
reobject.cp = REO_CP_SELECTION;
reobject.dvaspect = DVASPECT_CONTENT;
reobject.dwFlags = REO_BELOWBASELINE;
reobject.dwUser = dwUser;
reobject.poleobj = lpObject;
reobject.polesite = lpClientSite;
reobject.pstg = lpStorage;
SIZEL sizel={0,0};
reobject.sizel = sizel;
hr=lpRichEditOle->InsertObject(&reobject);
}
catch( _com_error &e )
{
}
}while(FALSE);
if(lpLockBytes) lpObject->Release();
if(lpLockBytes) lpLockBytes->Release();
if(lpClientSite) lpClientSite->Release();
if(lpRichEditOle) lpRichEditOle->Release();
}
//
// Construction/Destruction
//
void CImageDataObject::SetBitmap(HBITMAP hBitmap)
{
STGMEDIUM stgm;
stgm.tymed = TYMED_GDI; // Storage medium = HBITMAP handle
stgm.hBitmap = hBitmap;
stgm.pUnkForRelease = NULL; // Use ReleaseStgMedium
FORMATETC fm;
fm.cfFormat = CF_BITMAP; // Clipboard format = CF_BITMAP
fm.ptd = NULL; // Target Device = Screen
fm.dwAspect = DVASPECT_CONTENT; // Level of detail = Full content
fm.lindex = -1; // Index = Not applicaple
fm.tymed = TYMED_GDI; // Storage medium = HBITMAP handle
this->SetData(&fm, &stgm, TRUE);
}
IOleObject *CImageDataObject::GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage)
{
SCODE sc;
IOleObject *pOleObject;
sc = ::OleCreateStaticFromData(this, IID_IOleObject, OLERENDER_FORMAT,
&m_fromat, pOleClientSite, pStorage, (void **)&pOleObject);
return pOleObject;
}
/
OK,下面是想RichEdit中插入bitmap的范例
CImageDataObject::InsertBitmap(m_sendRichEdit.GetOleInterface(),bmp.m_hBitmap,dwBitmapInfo);
上面是m_sendRichEdit是一个RichEdit控件(这段代码是从一个WTL项目中提取出来的)。
注意:上面的dwBitmapInfo就是应用程序设置的与插入RichEdit中的Bitmap相关的信息。
2. 从EditRich中提取位图信息
下面是范例代码,其中原来就不多说了,看代码吧。
//获取RichEdit中有几个bitmap,这里假设RichEdit中有位图文件
int c = m_sendRichEdit.GetOleInterface()->GetObjectCount();
for(int i = 0 ; i < c ; i++) //遍历位图
{
REOBJECT object; //位图信息存在这里
memset(&object,0,sizeof(REOBJECT));
object.cbStruct = sizeof(REOBJECT);
m_sendRichEdit.GetOleInterface()->GetObject(i,&object,REO_GETOBJ_ALL_INTERFACES);
int pos = object.cp ; //位图的位置信息
DWORD dwUSer =object.dwUSer ; //位图的信息,之前应用程序设置的,应有程序当然知道什么意思了
}
/
OVER