首先对标题说明一下,在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测试一下。还挺管用的。
那么怎么在我们的程序中使用呢?我也没有那么多的时间,先给出代码吧,有时间再说啊,见谅。
1LPLOCKBYTES lpLockBytes = NULL;
2SCODE sc;
3HRESULT hr;
4//print to RichEdit' s IClientSite
5LPOLECLIENTSITE m_lpClientSite;
6//A smart point to IAnimator
7IGifAnimatorPtrm_lpAnimator;
8//ptr 2 storage
9LPSTORAGE m_lpStorage;
10//the object 2 b insert 2
11LPOLEOBJECTm_lpObject;
12
13//Create lockbytes
14sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
15if (sc != S_OK)
16AfxThrowOleException(sc);
17ASSERT(lpLockBytes != NULL);
18
19//use lockbytes to create storage
20sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
21STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &m_lpStorage);
22if (sc != S_OK)
23{
24VERIFY(lpLockBytes->Release() == 0);
25lpLockBytes = NULL;
26AfxThrowOleException(sc);
27}
28ASSERT(m_lpStorage != NULL);
29
30//get the ClientSite of the very RichEditCtrl
31GetIRichEditOle()->GetClientSite(&m_lpClientSite);
32ASSERT(m_lpClientSite != NULL);
33
34try
35{
36//Initlize COM interface
37hr = ::CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
38if( 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
43hr = m_lpAnimator.CreateInstance(CLSID_GifAnimator);
44if( FAILED(hr) )
45_com_issue_error(hr);
46//COM operation need BSTR, so get a BSTR
47BSTR path = strPicPath.AllocSysString();
48
49//Load the gif
50hr = m_lpAnimator->LoadFromFile(path);
51if( FAILED(hr) )
52_com_issue_error(hr);
53
54TRACE0( m_lpAnimator->GetFilePath() );
55
56//get the IOleObject
57hr = m_lpAnimator.QueryInterface(IID_IOleObject, (void**)&m_lpObject);
58if( FAILED(hr) )
59_com_issue_error(hr);
60
61//Set it 2 b inserted
62OleSetContainedObject(m_lpObject, TRUE);
63
64//2 insert in 2 richedit, you need a struct of REOBJECT
65REOBJECT reobject;
66ZeroMemory(&reobject, sizeof(REOBJECT));
67
68reobject.cbStruct = sizeof(REOBJECT);
69CLSID clsid;
70sc = m_lpObject->GetUserClassID(&clsid);
71if (sc != S_OK)
72AfxThrowOleException(sc);
73//set clsid
74reobject.clsid = clsid;
75//can be selected
76reobject.cp = REO_CP_SELECTION;
77//content, but not static
78reobject.dvaspect = DVASPECT_CONTENT;
79//goes in the same line of text line
80reobject.dwFlags = REO_BELOWBASELINE; //REO_RESIZABLE |
81reobject.dwUser = 0;
82//the very object
83reobject.poleobj = m_lpObject;
84//client site contain the object
85reobject.polesite = m_lpClientSite;
86//the storage
87reobject.pstg = m_lpStorage;
88
89SIZEL sizel;
90sizel.cx = sizel.cy = 0;
91reobject.sizel = sizel;
92HWND 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
99GetIRichEditOle()->InsertObject(&reobject);
100::SendMessage(hWndRT, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
101VARIANT_BOOL ret;
102//do frame changing
103ret = m_lpAnimator->TriggerFrameChange();
104//show it
105m_lpObject->DoVerb(OLEIVERB_UIACTIVATE, NULL, m_lpClientSite, 0, m_hWnd, NULL);
106m_lpObject->DoVerb(OLEIVERB_SHOW, NULL, m_lpClientSite, 0, m_hWnd, NULL);
107
108//redraw the window to show animation
109RedrawWindow();
110
111if (m_lpClientSite)
112{
113m_lpClientSite->Release();
114m_lpClientSite = NULL;
115}
116if (m_lpObject)
117{
118m_lpObject->Release();
119m_lpObject = NULL;
120}
121if (m_lpStorage)
122{
123m_lpStorage->Release();
124m_lpStorage = NULL;
125}
126
127SysFreeString(path);
128}
129catch( _com_error e )
130{
131AfxMessageBox(e.ErrorMessage());
132::CoUninitialize();
133}
呵呵,核心代码,就这么点,我还弄了好长时间。惭愧!