您的位置:首页 > 移动开发 > Objective-C

MSN / QQ 中的CRichEditCtrl (一) —— 动画表情

2004-11-22 11:48 453 查看
首先对标题说明一下,在MSN中,聊天的窗口可能是一个自定义的类。大家用Spy ++可以看看。
对与自定义窗口,可以使用CreateWindow, SetWindowLong或者是SubclassWindow实现,不过这不
是我现在讨论的话题。

好, 先看看效果再说:



我实现的主要就是:(一)字体格式; (二)超链接;(三)背景图片;(四)动画表情

关于这个的实现。我们首先应该明了,我们必须实现一个OLE对象。而且这个对象能够播放GIF.
对于播放GIF,代码已经很多了。比较有名气的就是那个谁封装的Gif89a,还不错,我喜欢那个CPictureEx.
可以在vchelp找到。
有了这个就完了么?当然不是。你还有写一个OLE/COM对象。实现IOleObject等。
你是用ATL还是MFC呢?
呵呵,我什么也没有用。在这个目录下%program file%/tencent/qq/,你可以看到一个ImageOle.dll,她就是
你日夜思念的人!
好吧,让我们来看看他的真面目。怎么看?X Ray? 当然不是——OLE/COM Viewer.
Click on “All Objects”,

View TypeLib... 打开那个文件,你可以看到:
[
  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);
};

这个接口就是我们要的。你可以用ActiveX Control Test Container测试一下。还挺管用的。

那么怎么在我们的程序中使用呢?我也没有那么多的时间,先给出代码吧,有时间再说啊,见谅。

1	LPLOCKBYTES lpLockBytes = NULL;
2	SCODE sc;
3	HRESULT hr;
4	//print to RichEdit' s IClientSite
5	LPOLECLIENTSITE m_lpClientSite;
6	//A smart point to IAnimator
7	IGifAnimatorPtr	m_lpAnimator;
8	//ptr 2 storage
9	LPSTORAGE m_lpStorage;
10	//the object 2 b insert 2
11	LPOLEOBJECT	m_lpObject;
12
13	//Create lockbytes
14	sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
15	if (sc != S_OK)
16		AfxThrowOleException(sc);
17	ASSERT(lpLockBytes != NULL);
18
19	//use lockbytes to create storage
20	sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
21		STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &m_lpStorage);
22	if (sc != S_OK)
23	{
24		VERIFY(lpLockBytes->Release() == 0);
25		lpLockBytes = NULL;
26		AfxThrowOleException(sc);
27	}
28	ASSERT(m_lpStorage != NULL);
29
30	//get the ClientSite of the very RichEditCtrl
31	GetIRichEditOle()->GetClientSite(&m_lpClientSite);
32	ASSERT(m_lpClientSite != NULL);
33
34	try
35	{
36		//Initlize COM interface
37		hr = ::CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
38		if( FAILED(hr) )
39			_com_issue_error(hr);
40
41		//Get GifAnimator object
42		//here, I used a smart point, so I do not need to free it
43		hr = m_lpAnimator.CreateInstance(CLSID_GifAnimator);
44		if( FAILED(hr) )
45				_com_issue_error(hr);
46		//COM operation need BSTR, so get a BSTR
47		BSTR path = strPicPath.AllocSysString();
48
49		//Load the gif
50		hr = m_lpAnimator->LoadFromFile(path);
51		if( FAILED(hr) )
52			_com_issue_error(hr);
53
54		TRACE0( m_lpAnimator->GetFilePath() );
55
56		//get the IOleObject
57		hr = m_lpAnimator.QueryInterface(IID_IOleObject, (void**)&m_lpObject);
58		if( FAILED(hr) )
59			_com_issue_error(hr);
60
61		//Set it 2 b inserted
62		OleSetContainedObject(m_lpObject, TRUE);
63
64		//2 insert in 2 richedit, you need a struct of REOBJECT
65		REOBJECT reobject;
66		ZeroMemory(&reobject, sizeof(REOBJECT));
67
68		reobject.cbStruct = sizeof(REOBJECT);
69		CLSID clsid;
70		sc = m_lpObject->GetUserClassID(&clsid);
71		if (sc != S_OK)
72			AfxThrowOleException(sc);
73		//set clsid
74		reobject.clsid = clsid;
75		//can be selected
76		reobject.cp = REO_CP_SELECTION;
77		//content, but not static
78		reobject.dvaspect = DVASPECT_CONTENT;
79		//goes in the same line of text line
80		reobject.dwFlags = REO_BELOWBASELINE; //REO_RESIZABLE |
81		reobject.dwUser = 0;
82		//the very object
83		reobject.poleobj = m_lpObject;
84		//client site contain the object
85		reobject.polesite = m_lpClientSite;
86		//the storage
87		reobject.pstg = m_lpStorage;
88
89		SIZEL sizel;
90		sizel.cx = sizel.cy = 0;
91		reobject.sizel = sizel;
92		HWND hWndRT = this->m_hWnd;
93		//Sel all text
94//		::SendMessage(hWndRT, EM_SETSEL, 0, -1);
95//		DWORD dwStart, dwEnd;
96//		::SendMessage(hWndRT, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
97//		::SendMessage(hWndRT, EM_SETSEL, dwEnd+1, dwEnd+1);
98		//Insert after the line of text
99		GetIRichEditOle()->InsertObject(&reobject);
100		::SendMessage(hWndRT, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
101		VARIANT_BOOL ret;
102		//do frame changing
103		ret = m_lpAnimator->TriggerFrameChange();
104		//show it
105		m_lpObject->DoVerb(OLEIVERB_UIACTIVATE, NULL, m_lpClientSite, 0, m_hWnd, NULL);
106		m_lpObject->DoVerb(OLEIVERB_SHOW, NULL, m_lpClientSite, 0, m_hWnd, NULL);
107
108		//redraw the window to show animation
109		RedrawWindow();
110
111		if (m_lpClientSite)
112		{
113			m_lpClientSite->Release();
114			m_lpClientSite = NULL;
115		}
116		if (m_lpObject)
117		{
118			m_lpObject->Release();
119			m_lpObject = NULL;
120		}
121		if (m_lpStorage)
122		{
123			m_lpStorage->Release();
124			m_lpStorage = NULL;
125		}
126
127		SysFreeString(path);
128	}
129	catch( _com_error e )
130	{
131		AfxMessageBox(e.ErrorMessage());
132		::CoUninitialize();
133	}

呵呵,核心代码,就这么点,我还弄了好长时间。惭愧!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息