• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運(yùn)轉(zhuǎn),開心的工作
            簡單、開放、平等的公司文化;尊重個(gè)性、自由與個(gè)人價(jià)值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            EDIT SHOW GIF

            Posted on 2010-07-21 15:23 S.l.e!ep.¢% 閱讀(1360) 評論(0)  編輯 收藏 引用 所屬分類: VC

            Introduction

            Most of us know that in MSN Messenger, while chatting, we can insert animated emoticons in the chat window. That's very cool. In China, there is another famous messenger called QQ (the former OICQ) that can display GIFs as emoticons. After I read some code about RichEdit and COM, and after many tests on QQ and MSN Messenger, I got the code and put it on my blog on CSDN . :)

            Background

            First, how does MSN Messenger show animated emoticons? In MSN Messenger, it uses PNG files as emoticons, every PNG image shows a list of frames for a whole animation. In QQ, it uses GIFs as emoticons, so the user can customize the emoticons by changing the image, in fact, in QQ, we can send any image to a friend, and it can set to be an emoticon. If we just need to display static emoticons, you can refer to Insert any HBITMAP (Bitmap) in your RichEdit Control .

            Can CRichEditCtrl display a dynamic GIF? Of course not. But CRichEditCtrl can display a COM object, then what can a COM object do? Nearly anything. So we insert a COM object into the CRichEditCtrl instance, then what we can see will be the COM object. Is this what we want to see? No. What we want to see is animated emoticons! So we display the GIF in the COM object. Then what we can see will be the emoticons.

            Using the code

            First we need a COM object to display a GIF and for it to be inserted in the richedit. This COM object can be developed using ATL. If you do not know how to display a GIF, you can get the Gif89a source code or CPictureEx source code. If you do not care about the size of your application, GDI+ can be your choice. If you want to ask me which of the above I used to display GIF, my answer may be "none". Because I used a DLL in QQ, this DLL is a COM object, named ImageOle.dll. It is inserted and can show GIFs (in this module, it use GDI+ to show GIFs).

            Follow these steps to get your own emoticons RichEdit:

            First, open your OLE/COM Viewer in Microsoft Visual Studio 6.0 Tools. Use View TypeLib... to open ImageOle.dll (you' d better register it with regsvr32.exe), then you can get the text below:

            [
              uuid(0C1CF2DF-05A3-4FEF-8CD4-F5CFC4355A16),
              helpstring("IGifAnimator Interface"),
              dual,
              nonextensible
            ]
            dispinterface IGifAnimator {
                properties:
                methods:
                    [id(0x00000001), helpstring("method LoadFromFile")]
                    void LoadFromFile([in] BSTR FileName);
                    [id(0x00000002), helpstring("method TriggerFrameChange")]
                    VARIANT_BOOL TriggerFrameChange();
                    [id(0x00000003), helpstring("method GetFilePath")]
                    BSTR GetFilePath();
                    [id(0x00000004), helpstring("method ShowText")]
                    void ShowText([in] BSTR Text);
            };

            This object implements an interface called IGifAnimator, we can use it to display GIFs. To see the effect, you can run ActiveX Control Test Container to test it. First invoke LoadFromFile, then TriggerFrameChange.

            				//use this line to import the dll and genetate tlh and tli file.
            				#import "D:\\Program files\\tencent\\qq\\ImageOle.dll" named_guids
            		

            ImageOle.tlh

            				// Created by Microsoft (R) C/C++ Compiler Version 12.00.8168.0 (9de7951a).
            				//
            				// d:\myproject\msger\debug\ImageOle.tlh
            				//
            				// C++ source equivalent of Win32 type library
            				// D:\\Program files\\tencent\\qq\\ImageOle.dll
            				// compiler-generated file created 10/25/04 at 22:00:58 - DO NOT EDIT!
            				#pragma once
            				#pragma pack(push, 8)
            				#include <comdef.h>
            				namespace ImageOleLib {
            
            //// Forward references and typedefs//struct/* coclass */ GifAnimator;
            struct __declspec(uuid("0c1cf2df-05a3-4fef-8cd4-f5cfc4355a16"))
            /* dual interface */ IGifAnimator;
            
            //// Smart pointer typedef declarations//
            
            _COM_SMARTPTR_TYPEDEF(IGifAnimator, __uuidof(IGifAnimator));
            
            //// Type library items//struct __declspec(uuid("06ada938-0fb0-4bc0-b19b-0a38ab17f182"))
            GifAnimator;
                // [ default ] interface IGifAnimatorstruct __declspec(uuid("0c1cf2df-05a3-4fef-8cd4-f5cfc4355a16"))
            IGifAnimator : IDispatch
            {
                //// Wrapper methods for error-handling//
            
                HRESULT LoadFromFile (
                    _bstr_t FileName );
                VARIANT_BOOL TriggerFrameChange ( );
                _bstr_t GetFilePath ( );
                HRESULT ShowText (
                    _bstr_t Text );
            
                //// Raw methods provided by interface//virtual HRESULT __stdcall raw_LoadFromFile (
                    BSTR FileName ) = 0;
                virtual HRESULT __stdcall raw_TriggerFrameChange (
                    VARIANT_BOOL * pbChanged ) = 0;
                virtual HRESULT __stdcall raw_GetFilePath (
                    BSTR * pFilePath ) = 0;
                virtual HRESULT __stdcall raw_ShowText (
                    BSTR Text ) = 0;
            };
            
            //// Named GUID constants initializations//extern"C"const GUID __declspec(selectany) LIBID_ImageOleLib =
                {0x710993a2,0x4f87,0x41d7,{0xb6,0xfe,0xf5,0xa2,0x03,0x68,0x46,0x5f}};
            extern"C"const GUID __declspec(selectany) CLSID_GifAnimator =
                {0x06ada938,0x0fb0,0x4bc0,{0xb1,0x9b,0x0a,0x38,0xab,0x17,0xf1,0x82}};
            extern"C"const GUID __declspec(selectany) IID_IGifAnimator =
                {0x0c1cf2df,0x05a3,0x4fef,{0x8c,0xd4,0xf5,0xcf,0xc4,0x35,0x5a,0x16}};
            
            //// Wrapper method implementations//#include "d:\myproject\msger\debug\ImageOle.tli"
            
            } // namespace ImageOleLib#pragma pack(pop)

            ImageOle.tli

            				// Created by Microsoft (R) C/C++ Compiler Version 12.00.8168.0 (79a657ba).
            				//
            				// ImageOle.tli
            				//
            				// Wrapper implementations for Win32 type library
            				// D:\\Program Files\\Tencent\\qq\\ImageOle.dll
            				// compiler-generated file created 10/11/04 at 18:24:40 - DO NOT EDIT!
            				#pragma once
            				//
            				// interface IGifAnimator wrapper method implementations
            				//
            				inline HRESULT IGifAnimator::LoadFromFile ( _bstr_t FileName ) {
                HRESULT _hr = raw_LoadFromFile(FileName);
                if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
                return _hr;
            }
            
            inline VARIANT_BOOL IGifAnimator::TriggerFrameChange ( ) {
                VARIANT_BOOL _result;
                HRESULT _hr = raw_TriggerFrameChange(&_result);
                if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
                return _result;
            }
            
            inline _bstr_t IGifAnimator::GetFilePath ( ) {
                BSTR _result;
                HRESULT _hr = raw_GetFilePath(&_result);
                if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
                return _bstr_t(_result, false);
            }
            
            inline HRESULT IGifAnimator::ShowText ( _bstr_t Text ) {
                HRESULT _hr = raw_ShowText(Text);
                if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
                return _hr;
            }

            How can we use it? Here is the code:

                LPLOCKBYTES lpLockBytes = NULL;
                SCODE sc;
                HRESULT hr;
                //print to RichEdit' s IClientSite
                LPOLECLIENTSITE m_lpClientSite;
                //A smart point to IAnimator
                IGifAnimatorPtr    m_lpAnimator;
                //ptr 2 storage    
                LPSTORAGE m_lpStorage;
                //the object 2 b insert 2
                LPOLEOBJECT    m_lpObject;
            
                //Create lockbytes
                sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
                if (sc != S_OK)
                    AfxThrowOleException(sc);
                ASSERT(lpLockBytes != NULL);
                
                //use lockbytes to create storage
                sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
                    STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &m_lpStorage);
                if (sc != S_OK)
                {
                    VERIFY(lpLockBytes->Release() == 0);
                    lpLockBytes = NULL;
                    AfxThrowOleException(sc);
                }
                ASSERT(m_lpStorage != NULL);
                
                //get the ClientSite of the very RichEditCtrl
                GetIRichEditOle()->GetClientSite(&m_lpClientSite);
                ASSERT(m_lpClientSite != NULL);
            
                try
                {
                    //Initlize COM interface
                    hr = ::CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
                    if( FAILED(hr) )
                        _com_issue_error(hr);
                    
                    //Get GifAnimator object//here, I used a smart point, so I do not need to free it
                    hr = m_lpAnimator.CreateInstance(CLSID_GifAnimator);    
                    if( FAILED(hr) )
                            _com_issue_error(hr);
                    //COM operation need BSTR, so get a BSTR
                    BSTR path = strPicPath.AllocSysString();
            
                    //Load the gif
                    hr = m_lpAnimator->LoadFromFile(path);
                    if( FAILED(hr) )
                        _com_issue_error(hr);
                        
                    TRACE0( m_lpAnimator->GetFilePath() );
                    
                    //get the IOleObject
                    hr = m_lpAnimator.QueryInterface(IID_IOleObject, (void**)&m_lpObject);
                    if( FAILED(hr) )
                        _com_issue_error(hr);
                    
                    //Set it 2 b inserted
                    OleSetContainedObject(m_lpObject, TRUE);
                    
                    //2 insert in 2 richedit, you need a struct of REOBJECT
                    REOBJECT reobject;
                    ZeroMemory(&reobject, sizeof(REOBJECT));
            
                    reobject.cbStruct = sizeof(REOBJECT);    
                    CLSID clsid;
                    sc = m_lpObject->GetUserClassID(&clsid);
                    if (sc != S_OK)
                        AfxThrowOleException(sc);
                    //set clsid
                    reobject.clsid = clsid;
                    //can be selected
                    reobject.cp = REO_CP_SELECTION;
                    //content, but not static
                    reobject.dvaspect = DVASPECT_CONTENT;
                    //goes in the same line of text line
                    reobject.dwFlags = REO_BELOWBASELINE; //REO_RESIZABLE |
                    reobject.dwUser = 0;
                    //the very object
                    reobject.poleobj = m_lpObject;
                    //client site contain the object
                    reobject.polesite = m_lpClientSite;
                    //the storage 
                    reobject.pstg = m_lpStorage;
                    
                    SIZEL sizel;
                    sizel.cx = sizel.cy = 0;
                    reobject.sizel = sizel;
                    HWND hWndRT = this->m_hWnd;
                    
                    //Sel all text//        ::SendMessage(hWndRT, EM_SETSEL, 0, -1);//        DWORD dwStart, dwEnd;//        ::SendMessage(hWndRT, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);//        ::SendMessage(hWndRT, EM_SETSEL, dwEnd+1, dwEnd+1);//Insert after the line of text
                    GetIRichEditOle()->InsertObject(&reobject);
                    ::SendMessage(hWndRT, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
                    VARIANT_BOOL ret;
                    //do frame changing
                    ret = m_lpAnimator->TriggerFrameChange();
                    //show it
                    m_lpObject->DoVerb(OLEIVERB_UIACTIVATE, NULL, m_lpClientSite, 0, 
                                                                         m_hWnd, NULL);
                    m_lpObject->DoVerb(OLEIVERB_SHOW, NULL, m_lpClientSite, 0, m_hWnd, 
                                                                                   NULL);
                    
                    //redraw the window to show animation
                    RedrawWindow();
            
                    if (m_lpClientSite)
                    {
                        m_lpClientSite->Release();
                        m_lpClientSite = NULL;
                    }
                    if (m_lpObject)
                    {
                        m_lpObject->Release();
                        m_lpObject = NULL;
                    }
                    if (m_lpStorage)
                    {
                        m_lpStorage->Release();
                        m_lpStorage = NULL;
                    }
                    
                    SysFreeString(path);
                }
                catch( _com_error e )
                {
                    AfxMessageBox(e.ErrorMessage());
                    ::CoUninitialize();    
                }

            After that, your CEditCtrl can show animated GIFs.

            欧美粉嫩小泬久久久久久久 | 久久青青草原国产精品免费| 国产精久久一区二区三区| 97久久超碰国产精品2021| 国产精品对白刺激久久久| 日本精品久久久中文字幕| 久久久青草久久久青草| 久久国产成人午夜AV影院| 一本久久精品一区二区| 麻豆一区二区99久久久久| 国产午夜久久影院| 日韩欧美亚洲国产精品字幕久久久| 久久亚洲国产精品五月天婷| 久久中文字幕人妻熟av女| 伊人久久大香线蕉av一区| 久久久精品免费国产四虎| 久久受www免费人成_看片中文| 久久午夜伦鲁片免费无码| 大美女久久久久久j久久| 久久精品久久久久观看99水蜜桃| 久久精品午夜一区二区福利| 亚洲综合精品香蕉久久网97 | 精品久久久噜噜噜久久久 | 久久久久久精品免费看SSS| 国内精品人妻无码久久久影院| 国内精品久久久久久麻豆| 99久久精品免费看国产一区二区三区 | 久久午夜福利电影| 久久伊人精品青青草原高清| 久久久久久久波多野结衣高潮| 国产精品va久久久久久久| 一本色道久久88精品综合 | 久久精品一本到99热免费| 久久成人精品| 精品国产青草久久久久福利| 久久久久久久久久久久中文字幕| 性高湖久久久久久久久AAAAA | 中文国产成人精品久久不卡 | 久久天堂AV综合合色蜜桃网| 四虎久久影院| 开心久久婷婷综合中文字幕|