如何在RichEditCtrl中插入ActiveX控件

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

前两天在CSDN上看到一篇文章介绍如何在RichEditCtrl控件中添加一个动态的Gif,比较有意思。去年用老版的QQ时倒是模仿写了一下,当时只解决插入bmp和词法解析,后来就没有继续下去。

    CSDN上的文章,采用的是腾讯QQ带的组件库ImageOle.dll提供的GifAnimator类提供的ActiveX对象来实现这个功能。该对象暴露一个IGifAnimator接口,具体的定义如下:

interface IGifAnimator : IDispatch {

    HRESULT LoadFromFile([in] BSTR FileName);

    HRESULT TriggerFrameChange([out, retval] VARIANT_BOOL* pbChanged);

    HRESULT GetFilePath([out, retval] BSTR* pFilePath);

    HRESULT ShowText([in] BSTR Text);

};

CSDN中给出了一个例子,采用Import方式倒入com类,并且给出了如何插入到RichEdit中。不过,我不太喜欢这种方式,自己建了一个。

下面是通过从类型库创建类的方式创建的一个类,比较简洁。

#include <initguid.h>

DEFINE_GUID(CLSID_GIFAnimator,

0x06ADA938,0x0FB0,0x4BC0,0xB1,0x9B,0x0A,0x38,0xAB,0x17,0xF1,0x82);

DEFINE_GUID(IID_IGIFAnimator,

0x0C1CF2DF,0x05A3,0x4FEF,0x8C,0xD4,0xF5,0xCF,0xC4,0x35,0x5A,0x16);

 

class CGifAnimator : public COleDispatchDriver

{

public:

    CGifAnimator(){} // 调用 COleDispatchDriver 默认构造函数

    CGifAnimator(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}

    CGifAnimator(const CGifAnimator& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}

    // 操作

public:

    // IGifAnimator 方法

public:

    void LoadFromFile(LPCTSTR FileName){

        static BYTE parms[] = VTS_BSTR ;

        InvokeHelper(0x1, DISPATCH_METHOD, VT_EMPTY, NULL, parms, FileName);

    }

    BOOL TriggerFrameChange(){

        BOOL result;

        InvokeHelper(0x2, DISPATCH_METHOD, VT_BOOL, (void*)&result, NULL);

        return result;

    }

    CString GetFilePath(){

        CString result;

        InvokeHelper(0x3, DISPATCH_METHOD, VT_BSTR, (void*)&result, NULL);

        return result;

    }

    void ShowText(LPCTSTR Text){

        static BYTE parms[] = VTS_BSTR ;

        InvokeHelper(0x4, DISPATCH_METHOD, VT_EMPTY, NULL, parms, Text);

    }

};

    通过编码,对上面的四个函数进行了简单的测试,每个函数的功能如下:

1  void LoadFromFile(LPCTSTR FileName)

装载要显示的文件到控件,文件为图像类型,不局限于GIF格式。失败时抛出异常。

2     BOOL TriggerFrameChange()

发出消息,动态的GIF动起来。在对话框中有问题,可以通过向父窗口发送WM_PAINT消息来激活。

3     CString GetFilePath()

返回装入的文件的名称。

4     void ShowText(LPCTSTR Text)

没有测出其作用,只是调用以后,动态的GIF不动了。

    下面给出的代码,将该控件插入到RichEdit控件。

BOOL CImageRichEditCtrl::InsertGifAnimator(LPCTSTR lpszGifName)

{

    CGifAnimator    animator;

    IStorage*       lpStorage       = NULL;

    IOleObject*     lpOleObject     = NULL;

    LPLOCKBYTES     lpLockBytes     = NULL;

    IOleClientSite* lpOleClientSite = NULL;

    IRichEditOle*   lpRichEditOle   = NULL;

    CLSID           clsid;

    REOBJECT        reobject;

 

    lpRichEditOle   = GetIRichEditOle();

    if( lpRichEditOle == NULL ) return FALSE;

 

    BOOL bRet = animator.CreateDispatch(CLSID_GIFAnimator);

    if( bRet == FALSE ){

        lpRichEditOle->Release();

        return FALSE;

    }

 

    try{

        animator.LoadFromFile(lpszGifName);     //Load失败时,抛出异常

        HRESULT hr = animator.m_lpDispatch->QueryInterface(&lpOleObject);

        if( hr != S_OK )

            AfxThrowOleException(hr);

        hr = lpOleObject->GetUserClassID(&clsid);

        if ( hr != S_OK)

            AfxThrowOleException(hr);

       

        hr = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);

        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;

 

        hr = lpRichEditOle->InsertObject( &reobject );

        if (hr != S_OK)

            AfxThrowOleException(hr);

        OleSetContainedObject(lpOleObject,TRUE);

 

//      bRet = animator.TriggerFrameChange();  

//      作用是更新显示,让ActiveX控件动起来,不过在对话框中的控件无效。

 

//如果本函数在OnInitDialog中调用,本消息不能被处理,可能不会动态显示

        SendMessage(WM_PAINT,0,0); 

    }

 

    catch( COleException* e )

    {

        TRACE(_T("CImageRichEditCtrl::InsertGifAnimator() OleException

                code:%d"),e->m_sc);

        e->Delete();

        bRet = FALSE;

    }

 

    // release the interface

    lpRichEditOle->Release();

    if( lpOleObject     != NULL )   lpOleObject->Release();

    if( lpOleClientSite != NULL )       lpOleClientSite->Release();

    if( lpStorage       != NULL )           lpStorage->Release();

 

    return bRet;

}

这样,通过调用InsertGifAnimator就可以将一个图像文件插入到RichEdit控件中,并且如果是动态的GIF则可以动起来,对于聊天来说,效果比较好。

    那么这个控件是如何实现的呢?通过的分析,实现控件需要的技术要点如下:

1  必须是ActiveX控件,这可以用ATL模板来生成,Easy

2  用于可以插入很多控件实例,为了尽可能的少占用系统资源,必须为WndLess控件。

3  为了动态显示GIFTIFF文件,必须采用时钟,(线程占用资源太大)。

4  为了显示所有的图像文件,这里采用Gdiplus来简化图像的操作。

5  为了支持Undo操作,必须在处理Undo后的动态显示。

    而上述操作中,相对较难的是时钟处理和Undo恢复操作。

    经过几天的努力,我也写了一个支持在RichEdit控件中显示动画的控件DynamicGif,下面是测试结果(在插入了6128×128的动态GIF文件后),和QQ带的ImageOle.dll相比较。

 

CPU

内存(KB)

句柄数

线程数

GDI

未插入控件时

0

6104

94

2

59

DynamicGif

28

8332

118

3

69

QQ

44

8372

118

3

70

测试结果:资源占用比较

   

 

 

RichEdit嵌入自开发OLE控件技术要点(ATL) richedit插入gif实例下载: OLE封装库 RICHEDIT_DEMO 1、创建ATL复合文档控件。可通过wizard创建。 下面是创建OLE控件的最小头文件 // CSimpleOleObject class ATL_NO_VTABLE CSimpleOleObject : public CComObjectRootEx, public IDispatchImpl, 阅读详情

相关推荐

在RichEdit控件插入OLE对象(ActiveX控件)

  有时候,我们需要在一个容器中插入各种不同的对象,比如,QQ聊天对话框里可以插入各种静态和动态的图片,甚至还可以插入flash文件,这些都是通过OLE技术来实现的。OLE技术是基于COM的,而COM又是非常复杂的东西,想要学习COM得花很多的时间,《COM技术内幕》,《COM原理和应用》,《INSIDE OLE 2》都是非常好的学习COM和OLE的书,但要把这些书啃完,弄懂,几个月甚至半年都过去

水妖的专栏 7796

也谈向Richedit插入动态Gif的实现

http://www.deadc0de.com/archives/insert-gif-to-richedit.html#more-14 最近在做IM软件,需要实现向Richedit插入表情,表情是动态的GIF图像。由于以前没有做过关于richedit的开发,百度了下,需要使用OLE技术。也就是说,插入的图片都是一个OLE对象。而RICHEDIT则是一个OLE容器,相关链接如下。

Richard的专栏 6480

VC/MFC高级控件(列表控件ActiveX控件等)开发实例

给出了关于VC/MFC高级控件编程的各种编程实例(21个实例),包含了所能遇到的大部分高级控件的编程资料,比如列表控件 ActiveX控件开发 日期和动画控件 IP地址控件 等等一些列控件的编程方法,很值得下载,(本资源所有实例均是本人从买的范例大全上拷贝出来的,能正常运行使用)

自带的richedit控件显示图片文字(仿QQ聊天内容文字图片)

unit RichEx; interface { 使用: RichEx.InsertBitmap(RichEdit1.Handle, ExtractFilePath(ParamStr(0)) + ‘e.bmp’); RichEx.InsertBitmap(RichEdit1.Handle, Image1.Picture.Bitmap); RichEx.InsertGif(RichEdit1.Handle, ExtractFilePath(ParamStr(0)) + ‘c.gif’); } uses Win

yygyyygy1233的博客 671

为什么在RichEdit控件插入ActiveX控件,该ActiveX控件不能响应事件?

<br />为什么在RichEdit控件插入ActiveX控件,该ActiveX控件不能响应事件?

QCSteven的专栏 419

[in][out][retval]

[in][out][retval]用于COM自动化组件,主要是用于生成包装类用的 [in]类型表明参数是一个输入参数,所以这个参数不会向外界返回结果 [out]类型表明参数是个输出参数,所以这个参数会向外界返回结果,参数类型只能是指针类型 [outretval]类型表明参数是个输出参数, retval 必须与 out 联用,并且在参数类表中只有最后一个参数可以被指定为 [out,re

一品梅的博客 4437

Richedit使用大全

[转]Richedit使用大全一.常见问题a.可以编译,不能执行的AfxInitRichEdit();b.升级默认的Riched版本(默认的有一些bug),如可在InitInstance中添加LoadLibrary("RICHED20.DLL") 最后注意 FreeLibrary 如果是CRichEditView基类的可用BOOL CXXXXXXView::

denglei265的专栏 3935

win32sdk学习-Richedit组件使用

Richedit组件使用 Richedit组件可以使用CreateWindow来创建,也可以使用对话框模板资源,在创建对话框的同时,自动创建richedit。 在使用richedit组件之前,需要先使用LoadLibrary("RichEd20.dll"),因为richedit是作为一个单独的dll保存的,如果不事先调用这个函数,会出现组件不显示的情况。Richedit有多个版本,RICHED

sujudz的专栏 8622

向MFC的RichTextCtrl中插入GIF问题总结,~

http://www.4ucode.com/Study/Topic/1371594 Using Windowless RichEdit Controls http://www.codeproject.com/KB/edit/RichDrawText.aspx OLE Drag and Drop http://www.catch22.net/book/expor...

作一个独立连续的思考者 1107

使用MFC开发ActiveX控件(二)

 实现属性表  属性表是ActiveX控件所特有的一种技术,可以在包容器程序处于设计阶段时为其提供一个可视化的人机交 互界面,并可以通过其对控件的自定义属性和库存属性进行设置。在用向导生成程序框架的同时即已经生成了一个空的用于管理自定义属性的属性页。在代码上通过 控件类实现文件中的属性页ID表对其进行维护: BEGIN_PROPPAGE

perddy的专栏 1705

vc++快速使用richedit控件

vc++快速使用richedit控件 1)初始化//必须加,否则无法显示窗口 CXXXApp::CXXXApp()  //找到应用类 { // TODO: add construction code here, // Place all significant initialization in InitInstance    AfxInitRichEdit();  //此句必须加

penjie0418的专栏 3864

点击CRichEdit ctrl 后如何获得当前点击位置

点击CRichEdit ctrl 后的消息消息映射 是 OnCaptureChanged 消息, 在这个消息里能够处理 // TODO: 在此处添加消息处理程序代码 long nStart, nEnd; this->GetSel(nStart, nEnd); int a= 1; 就能够获得当前点击位置

carl2380的专栏 663

CRichEditVCtrl(一)生成右键菜单

基于对话框的程序,怎样自定义自己的右键菜单呢? 我们知道对于(Edit box)控件来说,它默认的有自己的右键菜单,而对于我们自己定义的(Rich Edit)控件控件来说,却没有右键功能。CRichEditVCtrl的主要功能用于实现设置字体、设置字体颜色、设置字号等都提供了完善的支持。这些内容后面再做总结。今天我们主要来谈谈,用CRichEditVCtrl来实现右键功能的添加。 一:首先新添

longzhiten98的专栏 1930
下一篇: win32 shell编程记录 之-
kql01
博客等级 码龄24年 17粉丝 13原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值