龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

CRichEditCtrl实现MSN/QQ动画表情[组图]

时间:2009-12-22 15:42来源:未知 作者:admin 点击:
分享到:
首先对标题说明一下,在MSN中,聊天的窗口可能是一个自定义的类。大家用Spy ++可以看看。对与自定义窗口,可以使用CreateWindow, SetWindowLong或者是SubclassWindow实现,不过这不是我现在讨
  首先对标题说明一下,在MSN中,聊天的窗口可能是一个自定义的类。大家用Spy ++可以看看。对与自定义窗口,可以使用CreateWindow, SetWindowLong或者是SubclassWindow实现,不过这不是我现在讨论的话题。   好, 先看看效果再说:
  

  
  关于这个的实现。我们首先应该明了,我们必须实现一个OLE对象。而且这个对象能够播放GIF.对于播放GIF,代码已经很多了。
  
  有了这个就完了么?当然不是。你还有写一个OLE/COM对象。实现IOleObject等。你是用ATL还是MFC呢?我什么也没有用。在这个目录下%program file% encentQQ,你可以看到一个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测试一下。还挺管用的。
  
  以下给出代码:
  首先我们导入ImageOle.dll
   #import "D:Program files encentqqImageOle.dll" named_guids  named_guids 表示让编译器为我把对应库的GUID和声明对应起来。我们就可以用CLSID_GifAnimator引用对应的接口了。不用那一长串的东西。然后它就会为我们生成两个文件。
  
更多内容请看MSN图像  MSN专题  QQ表情专题,或
  ImageOle.tlh
   1// Created by Microsoft (R) C/C++ Compiler Version 12.00.8168.0 (9de7951a).
  2//
  3// d:myprojectmsgerdebugImageOle.tlh
  4//
   <!-- frame contents -->
<!-- /frame contents --> 5// C++ source equivalent of Win32 type library D:Program files encentqqImageOle.dll
  6// compiler-generated file created 10/25/04 at 22:00:58 - DO NOT EDIT!
  7#pragma once
  8#pragma pack(push, 8)
  9#include
  10
  11namespace ImageOleLib {
  12
  13//
  14// Forward references and typedefs
  15//
  16
  17strUCt /* coclass */ GifAnimator;
  
   18struct __declspec(uuid("0c1cf2df-05a3-4fef-8cd4-f5cfc4355a16"))
  19/* dual interface */ IGifAnimator;
  20
  21//
  22// Smart pointer typedef declarations
  23//
  24
  25_COM_SMARTPTR_TYPEDEF(IGifAnimator, __uuidof(IGifAnimator));
  26
  27//
  28// Type library items
  29//
  30
  31struct __declspec(uuid("06ada938-0fb0-4bc0-b19b-0a38ab17f182"))
  32GifAnimator;
  33 // [ default ] interface IGifAnimator
  34
  35struct __declspec(uuid("0c1cf2df-05a3-4fef-8cd4-f5cfc4355a16"))
  36IGifAnimator : IDispatch
  37{
  38 //
  39 // Wrapper methods for error-handling
  40 //
  41
  42 HRESULT LoadFromFile (
  43 _bstr_t FileName );
  44 VARIANT_BOOL TriggerFrameChange ( );
  45 _bstr_t GetFilePath ( );
  46 HRESULT ShowText (
  47 _bstr_t Text );
  48
  49 //
  50 // Raw methods provided by interface
  51 //
  52
  53 virtual HRESULT __stdcall raw_LoadFromFile (
  54 BSTR FileName ) = 0;
  55 virtual HRESULT __stdcall raw_TriggerFrameChange (
  56 VARIANT_BOOL * pbChanged ) = 0;
  57 virtual HRESULT __stdcall raw_GetFilePath (
  58 BSTR * pFilePath ) = 0;
  59 virtual HRESULT __stdcall raw_ShowText (
  60 BSTR Text ) = 0;
  61};
  62
  63//
  64// Named GUID constants initializations
  65//
  66
  67extern "C" const GUID __declspec(selectany) LIBID_ImageOleLib =
  68 {0x710993a2,0x4f87,0x41d7,{0xb6,0xfe,0xf5,0xa2,0x03,0x68,0x46,0x5f}};
  69extern "C" const GUID __declspec(selectany) CLSID_GifAnimator =
  70 {0x06ada938,0x0fb0,0x4bc0,{0xb1,0x9b,0x0a,0x38,0xab,0x17,0xf1,0x82}};
  71extern "C" const GUID __declspec(selectany) IID_IGifAnimator =
  72 {0x0c1cf2df,0x05a3,0x4fef,{0x8c,0xd4,0xf5,0xcf,0xc4,0x35,0x5a,0x16}};
  73
  74//
  75// Wrapper method implementations
  76//
  77#include "d:myprojectmsgerdebugImageOle.tli"
  78
  79} // namespace ImageOleLib
  80#pragma pack(pop)
  
更多内容请看MSN图像  MSN专题  QQ表情专题,或
  ImageOle.tli
   1// Created by Microsoft (R) C/C++ Compiler Version 12.00.8168.0 (9de7951a).
  2//
  3// d:myprojectmsgerdebugImageOle.tli
  4//
   <!-- frame contents -->
<!-- /frame contents --> 5// Wrapper implementations for Win32 type library D:Program files encentqqImageOle.dll
  6// compiler-generated file created 10/25/04 at 22:00:58 - DO NOT EDIT!
  7#pragma once
  8
  9//
  10// interface IGifAnimator wrapper method implementations
  11//
  12
  13inline HRESULT IGifAnimator::LoadFromFile ( _bstr_t FileName ) {
  14 HRESULT _hr = raw_LoadFromFile(FileName);
  15 if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
  16 return _hr;
  17}
  18
  19inline VARIANT_BOOL IGifAnimator::TriggerFrameChange ( ) {
  
   20 VARIANT_BOOL _result;
  21 HRESULT _hr = raw_TriggerFrameChange(&_result);
  22 if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
  23 return _result;
  24}
  25
  26inline _bstr_t IGifAnimator::GetFilePath ( ) {
  27 BSTR _result;
  28 HRESULT _hr = raw_GetFilePath(&_result);
  29 if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
  30 return _bstr_t(_result, false);
  31}
  32
  33inline HRESULT IGifAnimator::ShowText ( _bstr_t Text ) {
  34 HRESULT _hr = raw_ShowText(Text);
  35 if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
  36 return _hr;
  37}
  有了这些,你使用接口和函数就很方便了。
  
  然后就这样:
     WINOLEAPI CoInitializeEx(LPVOID pvReserved, DWord dwCoInit)
  为什么要这样呢?因为我们使用这个函数。那有必要这样么?在MSDN是说要 #define _DCOM_ 就行了。可惜我没有成功。就只好这样了。
  
  接着就是实现代码了。现在看应该没有很大的问题。假如还是很难明白。那么我你得好好研究CRichEditCtrl和OLE了。听说Inside OLE和Inside COM很好。我没有弄到。就看了《COM+编程指南》和潘爱民的《COM原理和应用》,不错!还有一个好东西。就是 ActiveX Control Test Container 的源代码。
  
更多内容请看MSN图像  MSN专题  QQ表情专题,或
  最后该出场的就是实现代码了。
   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
   <!-- frame contents -->
<!-- /frame contents --> 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_EXCLUSIVESTGM_CREATESTGM_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 }
  
更多内容请看MSN图像  MSN专题  QQ表情专题,或
  
   附:Delphi版的实现
   unit Unit1;
  interface
  uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ActiveX, ComCtrls, RxRichEd, ImageOleLib_TLB;
   <!-- frame contents -->
<!-- /frame contents --> //RxRichEd单元是Rxlib下的RxRichEdit,一套增强功能的RichEdit
  //ImageOleLib_TLB是从qq的ImageOle.dll引入的类型库
  
  const
  IID_IOleObject: TGUID = (
  D1: $00000112; D2: $0000; D3: $0000; D4: ($C0, $00, $00, $00, $00, $00, $00,
  $46));
  EM_GETOLEINTERFACE= WM_USER + 60;
  
  type
  TForm1 = class(TForm)
  Button1: TButton;
  Editor: TRxRichEdit;
  procedure Button1Click(Sender: TObject);
  private
  { Private declarations }
  public
  { Public declarations }
  end;
  
  var
  Form1: TForm1;
  implementation
  {$R *.DFM}
  procedure TForm1.Button1Click(Sender: TObject);
  
  var
  FRTF: IRichEditOle;
  FLockBytes: ILockBytes;
  FStorage: ISTORAGE;
  FClientSite: IOLECLIENTSITE;
  m_lpObject: IOleObject;
  m_lpAnimator: TGifAnimator;
  i_GifAnimator: IGifAnimator;
  reobject: TReObject;
  clsid: TGuid;
  sizel: tagSize;
  dwStart, dwEnd: DWORD;
  Rect:TRect;
  
  begin
  try
  if CreateILockBytesOnHGlobal(0, True, FLockBytes) <> S_OK then
  begin
  showmessage('Error to create Global Heap');
  exit;
  end;
  //建立一个混合文档存取对象
  if StgCreateDocfileOnILockBytes(FLockBytes, STGM_SHARE_EXCLUSIVE or
  STGM_CREATE or STGM_READWRITE, 0, FStorage) <> S_OK then
  begin
  Showmessage('Error to create storage');
  exit;
  end;
  //取得RichEdit的接口
  Sendmessage(Editor.handle,EM_GETOLEINTERFACE,0,LongInt(@FRTF));
  
  if FRTF.GetClientSite(FClientSite)<>S_OK then
  begin
  ShowMessage('Error to get ClentSite');
  Exit;
  end;
  
  CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
  m_lpAnimator := TGifAnimator.Create(Self);
  i_GifAnimator := m_lpAnimator.ControlInterface;
  i_GifAnimator.LoadFromFile('c: i.gif');
  i_GifAnimator.QueryInterface(IID_IOleObject, m_lpObject);
  OleSetContainedObject(m_lpObject, True);
  FillChar(ReObject, SizeOf(ReObject), 0);
  ReObject.cbStruct := SizeOf(ReObject);
  m_lpObject.GetUserClassID(clsid);
  ReObject.clsid := clsid;
  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 := FClientSite;
  //the storage
  reobject.pstg := FStorage;
  sizel.cx := 0;
  sizel.cy := 0;
  reobject.sizel := sizel;
  //Sel all text
  
  
   SendMessage(Editor.Handle, EM_SETSEL, 0, -1);
  SendMessage(Editor.Handle, EM_GETSEL, dwStart, dwEnd);
  SendMessage(Editor.Handle, EM_SETSEL, dwEnd + 1, dwEnd + 1);
  //Insert after the line of text
  FRTF.InsertObject(reobject);
  SendMessage(Editor.Handle, EM_SCROLLCARET, 0, 0);
  //VARIANT_BOOL ret;
  //do frame changing
  m_lpAnimator.TriggerFrameChange();
  //show it
  m_lpObject.DoVerb(OLEIVERB_UIACTIVATE, Nil, FClientSite, 0, Editor.Handle,Rect);
  // m_lpObject.DoVerb(
  m_lpObject.DoVerb(OLEIVERB_SHOW, Nil, FClientSite, 0, Editor.Handle, Rect);
  //redraw the window to show animation
  redrawwindow(Handle, nil, 0, RDW_ERASE or RDW_INVALIDATE or RDW_FRAME or RDW_ERASENOW or RDW_ALLCHILDREN);
  finally
  FRTF:=nil;
  FClientSite := nil;
  FStorage :=nil;
  end;
  end;
  end
更多内容请看MSN图像  MSN专题  QQ表情专题,或
  
精彩图集

赞助商链接