青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

S.l.e!ep.¢%

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

EDIT SHOW GIF

Posted on 2010-07-21 15:23 S.l.e!ep.¢% 閱讀(1380) 評論(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.

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲小说欧美另类社区| 最新中文字幕亚洲| 亚洲一品av免费观看| 欧美国产三区| 日韩亚洲欧美成人| 亚洲破处大片| 欧美午夜免费| 欧美怡红院视频| 欧美一区二区三区在线播放| 国产一区二区三区高清播放| 久久精品国产亚洲一区二区| 久久九九全国免费精品观看| 亚洲国产日韩在线一区模特| 亚洲精品乱码久久久久久日本蜜臀 | 国产精品99免费看 | 一区二区不卡在线视频 午夜欧美不卡在| 欧美激情网站在线观看| 一区二区三区日韩精品| 亚洲一区二区精品在线| 国产亚洲成av人在线观看导航| 久久女同互慰一区二区三区| 免费久久精品视频| 亚洲午夜精品一区二区| 欧美一级片在线播放| 亚洲国产精品嫩草影院| 日韩一区二区福利| 国产亚洲精品久久久| 欧美丰满少妇xxxbbb| 欧美精品亚洲| 久久噜噜亚洲综合| 欧美日本不卡高清| 久久亚洲精选| 国产精品白丝av嫩草影院| 久久久久久亚洲精品杨幂换脸| 欧美大片在线看| 久久av老司机精品网站导航| 欧美成人激情视频免费观看| 欧美一区二区三区免费视| 欧美jizzhd精品欧美巨大免费| 午夜精品一区二区在线观看 | 最新国产精品拍自在线播放| 国产精品日日摸夜夜摸av| 蜜臀久久99精品久久久久久9| 欧美天堂亚洲电影院在线观看| 久久久精品国产一区二区三区| 欧美日本成人| 欧美成年人视频网站| 国产精品狠色婷| 亚洲第一色在线| 国产日韩在线一区| 一本色道久久综合亚洲精品婷婷 | 免费高清在线一区| 欧美影院在线| 欧美日韩天天操| 欧美激情精品久久久久久久变态| 国产精品永久免费视频| 亚洲人成绝费网站色www| 精品电影在线观看| 午夜精品在线观看| 亚洲综合日韩| 国产精品国产三级国产专播品爱网| 欧美大尺度在线| 韩国av一区二区三区四区| 亚洲永久在线观看| 一区二区av| 欧美理论大片| 日韩亚洲在线观看| 99精品欧美| 欧美~级网站不卡| 亚洲成色www8888| 136国产福利精品导航网址| 欧美伊人久久久久久午夜久久久久| 午夜久久资源| 国产午夜亚洲精品不卡| 亚洲欧美日韩精品久久久久| 午夜精品一区二区三区在线视 | 欧美www视频在线观看| 蜜桃久久精品乱码一区二区| 经典三级久久| 久久一区亚洲| 亚洲丰满在线| 99热免费精品| 欧美日韩午夜在线| 99精品欧美一区| 亚洲欧美成人在线| 国产日韩欧美一区二区三区四区| 亚洲综合国产激情另类一区| 欧美在线三区| 亚洲国产精品一区二区第一页| 美日韩免费视频| 亚洲精品国产精品乱码不99| 亚洲私人影院在线观看| 国产精品美女999| 欧美一区二区三区在线观看| 免费亚洲电影| 正在播放欧美一区| 国产亚洲一区在线| 欧美成人视屏| 亚洲视频一区在线| 久久婷婷av| 99这里只有精品| 国产欧美精品| 免费毛片一区二区三区久久久| 亚洲精品五月天| 久久精品在线免费观看| 最新国产乱人伦偷精品免费网站 | 久久这里有精品视频| 亚洲狼人综合| 久久国产精品99国产| 亚洲人成欧美中文字幕| 国产精品久久久久久户外露出| 久久国产精品久久国产精品| 最新热久久免费视频| 久久精品国产一区二区三区免费看 | 欧美一区亚洲二区| 亚洲肉体裸体xxxx137| 午夜在线精品| 亚洲国产一区二区在线| 国产精品网站一区| 欧美精品在线免费观看| 亚洲欧美一区二区三区极速播放| 亚洲国产精品一区制服丝袜| 欧美一级成年大片在线观看| 亚洲区在线播放| 在线不卡欧美| 国产亚洲高清视频| 欧美精品尤物在线| 久久躁日日躁aaaaxxxx| 午夜精品久久久| 中文一区字幕| 亚洲理伦在线| 欧美激情小视频| 免费成人高清视频| 久久久无码精品亚洲日韩按摩| 亚洲欧美日韩一区| 中文在线不卡视频| 一本久道久久久| 亚洲日本成人网| 亚洲国产精品高清久久久| 激情久久久久久久| 国产一区二区三区久久悠悠色av | 国产一二精品视频| 国产精品一区二区三区四区五区| 欧美日本三区| 欧美不卡在线| 欧美激情精品久久久久| 免费日韩av| 美女主播视频一区| 蜜桃精品一区二区三区| 欧美r片在线| 欧美成人精品在线视频| 欧美国产另类| 欧美日韩在线一区二区| 欧美日韩视频在线第一区| 欧美日韩在线一区二区三区| 国产精品爱久久久久久久| 国产精品黄色| 国产欧美在线观看| 欲香欲色天天天综合和网| 亚洲福利视频专区| 亚洲日本aⅴ片在线观看香蕉| 亚洲裸体俱乐部裸体舞表演av| 亚洲国产精品久久人人爱蜜臀| 亚洲人成欧美中文字幕| 在线亚洲观看| 欧美一区二区视频97| 久久婷婷国产综合国色天香| 女女同性精品视频| 亚洲九九精品| 亚洲女ⅴideoshd黑人| 久久国产主播精品| 欧美高清在线精品一区| 欧美日韩国产小视频在线观看| 国产精品国产三级国产普通话蜜臀| 国产女人水真多18毛片18精品视频| 国产视频精品xxxx| 亚洲丶国产丶欧美一区二区三区| 亚洲欧洲在线看| 亚洲一区二区免费看| 久久国产视频网| 亚洲国产影院| 亚洲综合不卡| 蜜桃av噜噜一区| 国产精品亚洲а∨天堂免在线| 1769国内精品视频在线播放| 亚洲视频免费在线| 久久久久久久久久看片| 亚洲精品视频中文字幕| 午夜在线视频观看日韩17c| 另类天堂视频在线观看| 国产精品久久久久久久久久免费 | 国产精品视频xxx| 在线看无码的免费网站| 亚洲一区999| 欧美二区在线看| 久久成人18免费网站| 欧美日韩中文字幕精品| 亚洲第一精品福利| 久久精品国产清高在天天线 | 久久婷婷一区|