给大家提供一个可以显示图片(包括GIF动画)的ATL控件,以及在RichEdit中如何使用此控件插入图片。其实自己没做什么,主要是参考了Oleg Bykov的文档,只是把他的代码加进ATL工程中封装成了一个ATL控件,原文地址在:http://www.codeproject.com/KB/graphics/pictureex.aspx
最直接的办法是您下载已经编译好的文件,您下载MaiYuanOleImg.zip然后解压缩,运行解压缩后目录下Reg.bat就可以直接使用此控件了。点击下载
如果您需要对此控件作修改,可以下载此控件的源代码。点击下载
源代码的一点说明,MYOleImage.h和MYOleImage.cpp中的CMYOleImage类用来显示图像和GIF动画。对这个类,绝大部分的代码是从Oleg Bykov的CPictureExWnd这个类Copy而来。
修改的地方主要在OnDraw(ATL_DRAWINFO& di)这个成员函数中。GIF的动画是采用开线程的方式,我想,如果您需要显示几百上千的GIF动画,那会把您的电脑跑得很慢。
自己添加了一个函数Load(BSTR),调用此函数将设置控件要显示的图像。
其他还有小的修改,请参照源代码
然后介绍在RichEdit中使用此控件插入图片(包括GIF动画), 采用在RichEdit中插入COM对象的方式插入此控件,这里只需要知道此控件对象的CLSID为:CLSID_MYOleImage,以及接口的IID为:IID_IMaiYuanOleImage。调用控件的成员函数Load就可以把图片加载到控件中显示。然后就能显示在RichEdit中了。
TCHAR Filter[]=_T("JGP文件(*.jpg)|*.jpg;*.jpeg|GIF文件(*.gif)|*.gif|BMP文件(*.bmp)|*.bmp|所有文件(*.*)|*.*||");
CFileDialog dlgOpen(TRUE,0,0,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,(LPCTSTR)Filter,NULL);
if(dlgOpen.DoModal()==IDOK)
{
IRichEditOle* lpRichEditOle = m_RichEdit.GetIRichEditOle(); //m_RichEdit为您的RichEdit对象
IStorage* lpStorage = NULL;//存储接口
IOleObject* lpOleObject = NULL;//OLE对象
LPLOCKBYTES lpLockBytes = NULL;//LOCKBYTE
IOleClientSite* lpOleClientSite = NULL;
CComPtr<IMaiYuanOleImage> IPic;
CLSID clsid;
REOBJECT reobject;
HRESULT hr;
if(lpRichEditOle == NULL)
return;
//创建IMaiYuanOleImage对象并获取接口
hr = ::CoCreateInstance(CLSID_MYOleImage,NULL,CLSCTX_INPROC,IID_IMaiYuanOleImage,(LPVOID*)&IPic);
if( IPic == NULL )
{
return;
}
BOOL bRet = TRUE;
try{
hr = IPic->QueryInterface(IID_IOleObject, (void**)&lpOleObject);//获得数据对象接口
if( hr != S_OK )
AfxThrowOleException(hr);
hr = lpOleObject->GetUserClassID(&clsid);
if ( hr != S_OK)
AfxThrowOleException(hr);
hr = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);//创建LOCKBYTE对象
if (hr != S_OK)
AfxThrowOleException(hr);
ASSERT(lpLockBytes != NULL);
hr = ::StgCreateDocfileOnILockBytes(lpLockBytes,//创建复合文档
STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &lpStorage);
if (hr != S_OK)
{
VERIFY(lpLockBytes->Release() == 0);
lpLockBytes = NULL;
AfxThrowOleException(hr);
}
lpRichEditOle->GetClientSite(&lpOleClientSite);
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.poleobj = lpOleObject;
reobject.polesite = lpOleClientSite;
reobject.pstg = lpStorage;
lpOleObject->SetClientSite(lpOleClientSite);//
hr = lpRichEditOle->InsertObject( &reobject );
if (hr != S_OK)
AfxThrowOleException(hr);
OleSetContainedObject(lpOleObject,TRUE);
IPic->Load(_bstr_t(dlgOpen.GetPathName())); //装载要显示的图像
}
catch( COleException* e )
{
TRACE(_T("OleException code:%d"),e->m_sc);
e->Delete();
bRet = FALSE;
}
// release the interface
//if( IPic != NULL ) IPic->Release();
if( lpOleObject != NULL ) lpOleObject->Release();
if( lpOleClientSite != NULL ) lpOleClientSite->Release();
if( lpStorage != NULL ) lpStorage->Release();
lpRichEditOle->Release();
}
这里是使用测试的例子,点击下载
原来我打算在自己的IM软件中使用RichEdit作为输入框,所以写了这个控件,但是后来决定不使用RichEdit了,就没有再继续完善了。
因为这里显示图片用的是IPicture接口,所以.png图片是无法显示的。
如果需要显示更多的图片,推荐修改此控件的源代码,使用GDI+来显示图片。
如果我以后有时间,我用GDI+来重新实现