// IrcEdit.cpp : 实现文件 // #include "stdafx.h" #include #include #include #include "IRC_UI.h" #include "IrcEdit.h" #include "Util.h" // CIrcEdit #ifdef _DEBUG #import "../GifAnimatePlayer/GifAnimatePlayer.tlb" named_guids #else #import "../GifAnimatePlayer/GifAnimatePlayer.tlb" named_guids #endif using namespace GifAnimatePlayerLib; HRESULT CIrcEditCallback::DeleteObject(LPOLEOBJECT lpoleobj) { return S_OK; } ULONG CIrcEditCallback::AddRef() { return ++m_dwRef; } HRESULT CIrcEditCallback::ContextSensitiveHelp(BOOL fEnterMode) { return S_OK; } HRESULT CIrcEditCallback::GetClipboardData(CHARRANGE *lpchrg, DWORD reco, LPDATAOBJECT *lplpdataobj) { return S_OK; } HRESULT CIrcEditCallback::GetContextMenu(WORD seltype, LPOLEOBJECT lpoleobj, CHARRANGE *lpchrg, HMENU *lphmenu) { return S_OK; } HRESULT CIrcEditCallback::GetDragDropEffect(BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect) { return S_OK; } HRESULT CIrcEditCallback::GetInPlaceContext(LPOLEINPLACEFRAME *lplpFrame, LPOLEINPLACEUIWINDOW *lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo) { return S_OK; } HRESULT CIrcEditCallback::GetNewStorage(LPSTORAGE *lplpstg) { return S_OK; } HRESULT CIrcEditCallback::QueryAcceptData(LPDATAOBJECT lpdataobj, CLIPFORMAT *lpcfFormat, DWORD reco, BOOL fReally, HGLOBAL hMetaPict) { return S_OK; } HRESULT CIrcEditCallback::QueryInsertObject(LPCLSID lpclsid, LPSTORAGE lpstg, LONG cp) { return S_OK; } HRESULT CIrcEditCallback::QueryInterface(REFIID iid, void ** ppvObject) { HRESULT hr = S_OK; *ppvObject = NULL; if (iid == IID_IUnknown || iid == IID_IRichEditOleCallback) { *ppvObject = this; AddRef(); hr = NOERROR; } else { hr = E_NOINTERFACE; } return hr; } ULONG CIrcEditCallback::Release() { if (--m_dwRef == 0) { delete this; return 0; } return m_dwRef; } HRESULT CIrcEditCallback::ShowContainerUI(BOOL fShow) { return S_OK; } IMPLEMENT_DYNAMIC(CIrcEdit, CRichEditCtrl) CIrcEdit::CIrcEdit() { m_WorldFilter = NULL; EnableAutomation(); m_pCallback = new CIrcEditCallback; } CIrcEdit::~CIrcEdit() { } void CIrcEdit::OnFinalRelease() { // 释放了对自动化对象的最后一个引用后,将调用 // OnFinalRelease。基类将自动 // 删除该对象。在调用该基类之前,请添加您的 // 对象所需的附加清除代码。 CRichEditCtrl::OnFinalRelease(); } BEGIN_MESSAGE_MAP(CIrcEdit, CRichEditCtrl) //ON_NOTIFY_REFLECT(EN_MSGFILTER, &CIrcEdit::OnEnMsgfilter) ON_NOTIFY_REFLECT(EN_LINK, &CIrcEdit::OnEnLink) ON_NOTIFY_REFLECT(EN_MSGFILTER, &CIrcEdit::OnEnMsgfilter) ON_CONTROL_REFLECT(EN_CHANGE, &CIrcEdit::OnEnChange) ON_CONTROL_REFLECT(EN_VSCROLL, &CIrcEdit::OnEnVscroll) END_MESSAGE_MAP() BEGIN_DISPATCH_MAP(CIrcEdit, CRichEditCtrl) END_DISPATCH_MAP() // 注意: 我们添加 IID_IIrcEdit 支持 // 以支持来自 VBA 的类型安全绑定。此 IID 必须同附加到 .IDL 文件中的 // 调度接口的 GUID 匹配。 // {5E4D0B51-8F88-4DE5-AB8C-D3A2C97B4ACB} static const IID IID_IIrcEdit = { 0x5E4D0B51, 0x8F88, 0x4DE5, { 0xAB, 0x8C, 0xD3, 0xA2, 0xC9, 0x7B, 0x4A, 0xCB } }; BEGIN_INTERFACE_MAP(CIrcEdit, CRichEditCtrl) INTERFACE_PART(CIrcEdit, IID_IIrcEdit, Dispatch) END_INTERFACE_MAP() // CIrcEdit 消息处理程序 void CIrcEdit::InsertBmpToEdit(HBITMAP hBitmap, int nIndex, int nCharIndex) { STGMEDIUM stgm; stgm.tymed = TYMED_GDI; // Storage medium = HBITMAP handle stgm.hBitmap = hBitmap; stgm.pUnkForRelease = NULL; // Use ReleaseStgMedium FORMATETC fm; fm.cfFormat = CF_BITMAP; // Clipboard format = CF_BITMAP fm.ptd = NULL; // Target Device = Screen fm.dwAspect = DVASPECT_CONTENT; // Level of detail = Full content fm.lindex = -1; // Index = Not applicaple fm.tymed = TYMED_GDI; ////创建输入数据源 IStorage *pStorage; ///分配内存 LPLOCKBYTES lpLockBytes = NULL; SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes); if (sc != S_OK) AfxThrowOleException(sc); ASSERT(lpLockBytes != NULL); //创建storage sc = ::StgCreateDocfileOnILockBytes(lpLockBytes, STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &pStorage); if (sc != S_OK) { VERIFY(lpLockBytes->Release() == 0); lpLockBytes = NULL; AfxThrowOleException(sc); } ASSERT(pStorage != NULL); //创建数据对象 COleDataSource *pDataSource = new COleDataSource; pDataSource->CacheData(CF_BITMAP, &stgm); LPDATAOBJECT lpDataObject = (LPDATAOBJECT)pDataSource->GetInterface(&IID_IDataObject); ///获取RichEdit的OLEClientSite LPOLECLIENTSITE lpClientSite; LPRICHEDITOLE lpRichEditOle; lpRichEditOle = GetIRichEditOle(); lpRichEditOle->GetClientSite( &lpClientSite ); ///创建OLE对象 IOleObject *pOleObject; sc = OleCreateStaticFromData(lpDataObject,IID_IOleObject,OLERENDER_FORMAT, &fm,lpClientSite,pStorage,(void **)&pOleObject); if(sc!=S_OK) AfxThrowOleException(sc); OleSetContainedObject(pOleObject, TRUE); ///插入OLE对象 REOBJECT reobject; ZeroMemory(&reobject, sizeof(REOBJECT)); reobject.cbStruct = sizeof(REOBJECT); reobject.dwUser = nIndex; CLSID clsid; sc = pOleObject->GetUserClassID(&clsid); if (sc != S_OK) AfxThrowOleException(sc); reobject.clsid = clsid; reobject.cp = nCharIndex; reobject.dvaspect = DVASPECT_CONTENT; reobject.poleobj = pOleObject; reobject.polesite = lpClientSite; reobject.pstg = pStorage; HRESULT hr = lpRichEditOle->InsertObject( &reobject ); lpRichEditOle->Release(); pOleObject->Release(); pStorage->Release(); lpClientSite->Release(); } void CIrcEdit::CheckMaxLine() { if (m_DispMsg.size() == MAX_DISP_LINE) { int nDiff = m_DispMsg[0].nEndIndex - m_DispMsg[0].nStartIndex + 1; int nBegin = LineIndex(m_DispMsg[0].nStartIndex); int nEnd = 0; for (int nIndex = m_DispMsg[0].nStartIndex; nIndex <= m_DispMsg[0].nEndIndex; nIndex++) { int nLineIndex = LineIndex(m_DispMsg[0].nEndIndex); nEnd = nEnd + LineLength(nIndex) + 1; } SetSel(nBegin, nEnd); ReplaceSel(_T("")); SetSel(0, -1); SetSel(-1, -1); m_DispMsg.erase(m_DispMsg.begin()); for (int nIndex = 0; nIndex < (int)m_DispMsg.size(); nIndex++) { m_DispMsg[nIndex].nStartIndex -= nDiff; m_DispMsg[nIndex].nEndIndex -= nDiff; } for (map::iterator Ite = m_LinkInfo.begin(); Ite != m_LinkInfo.end(); ) { LINKINFO linkinfo = Ite->second; m_LinkInfo.erase(Ite++); if (linkinfo.nStartIndex >= nEnd) { linkinfo.nStartIndex = linkinfo.nStartIndex - (nEnd - nBegin); linkinfo.nEndIndex = linkinfo.nEndIndex - (nEnd - nBegin); } m_LinkInfo[linkinfo.nStartIndex] = linkinfo; } } } void CIrcEdit::GetLinks(wstring& wstrChat, int nStartIndex, map& NewLinkInfo) { //解析附加数据串 size_t nExtrDataPos = wstrChat.rfind(L"[ExtraData"); if (nExtrDataPos == wstrChat.npos) { AfxMessageBox(CW2A(wstrChat.c_str())); return; } wstring wstrExtraData = wstrChat.substr(nExtrDataPos + wcslen(L"[ExtraData"), -1); wstrExtraData = wstrExtraData.substr(0, wstrExtraData.size() - 1); wchar_t wcSplitChar = L' '; size_t nSplitPos = wstrExtraData.rfind(wcSplitChar); while (nSplitPos != wstring::npos) { wstring wstrLink = wstrExtraData.substr(nSplitPos + 1, -1); wstrLink += L';'; size_t nElePos = wstrLink.find(L';'); vector vectEle; while (nElePos != wstring::npos) { wstring wstrEle = wstrLink.substr(0, nElePos); vectEle.push_back(_wtoi(wstrEle.c_str())); wstrLink = wstrLink.substr(nElePos + 1, -1); nElePos = wstrLink.find(L';'); } if (vectEle[2] < 3) { LINKINFO LinkInfo; LinkInfo.nStartIndex = vectEle[0] + nStartIndex; LinkInfo.nEndIndex = vectEle[1] + nStartIndex; LinkInfo.nType = vectEle[2]; LinkInfo.nID = vectEle[3]; LinkInfo.LevelUp = vectEle[4]; LinkInfo.AddLevel = vectEle[5]; LinkInfo.MassLevel = vectEle[6]; LinkInfo.Wear = vectEle[7]; //剩下来的字段待确定 NewLinkInfo[LinkInfo.nStartIndex] = LinkInfo; } wstrExtraData = wstrExtraData.substr(0, nSplitPos); nSplitPos = wstrExtraData.rfind(wcSplitChar); } } void CIrcEdit::SetChatStyle(int nChannelType, bool bMe, int nStartIndex, int nEndIndex) { CHARFORMAT2 cf2; ZeroMemory(&cf2, sizeof(CHARFORMAT2)); cf2.cbSize = sizeof(CHARFORMAT2); COLORREF ChatClr; switch(nChannelType) { //世界 case CT_WORLD_IRC_CHAT: case CT_WORLD_CHAT: { ChatClr = RGB(255, 153, 0); } break; case CT_UNION_IRC_CHAT: case CT_UNION_CHAT: { ChatClr = RGB(0, 255, 0); } break; //私聊 case CT_PRIVATE_CHAT: case CT_PRIVATE_IRC_CHAT: { if (bMe) { ChatClr = RGB(255, 0, 0); } else { ChatClr = RGB(255, 102, 255); } } break; default: { ChatClr = RGB(0, 0, 0); } break; } cf2.dwMask |= CFM_COLOR; cf2.crTextColor = ChatClr; cf2.dwMask |= CFM_SIZE; cf2.yHeight = 200; cf2.dwMask |= CFM_FACE; strcpy(cf2.szFaceName, "宋体"); SetSel(nStartIndex, nEndIndex); SetSelectionCharFormat(cf2); } void CIrcEdit::SetLinkFmt(int nStartIndex, int nEndIndex) { SetSel(nStartIndex, nEndIndex); //道具、技能等链接显示 CHARFORMAT2 cf2; ZeroMemory(&cf2, sizeof(CHARFORMAT2)); cf2.cbSize = sizeof(CHARFORMAT2); cf2.dwMask |= CFM_LINK; cf2.dwEffects |= CFM_LINK; SetSelectionCharFormat(cf2); SetSel(-1, -1); } void CIrcEdit::AddChat(int nChannelType, CHATMSG *pChatMsg, bool bMe, bool bShowRole, CBitmap* UserPhoto) { bool bReachBottom = IsReachBottom(); int nTextLen = GetCharCount(); if (nTextLen != 0) { AppendMsg(_T("\r\n")); nTextLen = GetCharCount(); } CheckMaxLine(); CString strPrex; CString strRoleName(pChatMsg->szRoleName); if (UserPhoto != NULL) { strPrex = _T("="); } if (nChannelType != CT_PRIVATE_CHAT && nChannelType != CT_PRIVATE_IRC_CHAT) { strPrex = strPrex + _T(":"); } if (nChannelType == CT_PRIVATE_CHAT || nChannelType == CT_PRIVATE_IRC_CHAT) { CString strCurTime = CUtil::GetCurTime(); strPrex = _T(" ") + strCurTime + _T("\n"); } CString strChat(pChatMsg->szChat); CString strMsg; strRoleName = strRoleName + strPrex; wchar_t wszMsg[MAX_CHAT_SIZE]; int nUnicodeSize = (strRoleName.GetLength() + 1) * sizeof(wchar_t); MultiByteToWideChar(CP_ACP, 0, strRoleName, strRoleName.GetLength() + 1, wszMsg, nUnicodeSize); wstring wstrRoleName(wszMsg); nUnicodeSize = (strChat.GetLength() + 1) * sizeof(wchar_t); MultiByteToWideChar(CP_ACP, 0, strChat, strChat.GetLength() + 1, wszMsg, nUnicodeSize); wstring wstrChat(wszMsg); if (!bShowRole) { wstrRoleName = L""; strRoleName = _T(""); } //获得新消息要写入的字符位置 int nLineCharIndex = LineIndex(); map NewLinkInfo; GetLinks(wstrChat, nLineCharIndex + (int)wstrRoleName.size(), NewLinkInfo); int nExtraDataPos = strChat.ReverseFind(_T('[')); strChat = strChat.Left(nExtraDataPos); strMsg = strRoleName + strChat; SetSel(-1, -1); ReplaceSel(strMsg); SetChatStyle(nChannelType, bMe, nLineCharIndex); if (nChannelType != CT_PRIVATE_CHAT && nChannelType != CT_PRIVATE_IRC_CHAT && bShowRole) { //角色名链接 SetLinkFmt(nLineCharIndex, nLineCharIndex + (int)wstrRoleName.size() - (int)strPrex.GetLength()); } //增加IRC图标 if (UserPhoto != NULL) { int nIrcFlagPos = (int)wstrRoleName.rfind(L"="); SetSel(nLineCharIndex + nIrcFlagPos, nLineCharIndex + nIrcFlagPos + 1); ReplaceSel(_T("")); InsertBmpToEdit(*UserPhoto, -1); } //表情消息显示 int nFacePos = (int)wstrChat.find(L"&"); int nFaceNum = 0; while (nFacePos != -1) { bool bFace = false; //判断=下一个字符是否是数字,如果是,则表示是表情,选择该索引对应的表情图片 if (nFacePos + 3 < (int)wstrChat.size() && (iswdigit(wstrChat[nFacePos + 1]) && iswdigit(wstrChat[nFacePos + 2]) && iswdigit(wstrChat[nFacePos + 3]))) { wstring strTmp(wstrChat.substr(nFacePos + 1, 3)); int nFaceIndex = _wtoi(strTmp.c_str()); int nFaceCharIndex = nLineCharIndex + nFacePos + (int)wstrRoleName.size() - nFaceNum * 3; CWnd* pParentWnd = GetOwner(); CGif* pFace = reinterpret_cast(pParentWnd->SendMessage(WM_GETFACE, (WPARAM)this, (LPARAM)nFaceIndex)); if (pFace != NULL && nFaceNum < MAX_ICON_MSG) { nFaceNum++; SetSel(nFaceCharIndex, nFaceCharIndex + 4); ReplaceSel(_T("")); InsertFaceToEdit(pFace, nFaceIndex); for (map::iterator Ite = NewLinkInfo.begin(); Ite != NewLinkInfo.end(); Ite++) { if (Ite->second.nStartIndex > nFaceCharIndex) { Ite->second.nStartIndex -= 3; Ite->second.nEndIndex -= 3; } } bFace = true; } } if (bFace) { nFacePos = (int)wstrChat.find(L"&", nFacePos + 4); } else { nFacePos = (int)wstrChat.find(L"&", nFacePos + 1); } } //道具链接消息显示 for (map::iterator Ite = NewLinkInfo.begin(); Ite != NewLinkInfo.end(); Ite++) { int nCharStartIndex = Ite->second.nStartIndex; int nCharEndIndex = Ite->second.nEndIndex; //SetLinkFmt(rchEdit, nCharStartIndex, nCharEndIndex); m_LinkInfo[nCharStartIndex] = Ite->second; } MsgInfo msginfo; msginfo.nStartIndex = LineFromChar(nLineCharIndex); msginfo.nEndIndex = GetLineCount() - 1; m_DispMsg.push_back(msginfo); if (bReachBottom) { SendMessage(WM_VSCROLL, SB_BOTTOM, 0); } } bool CIrcEdit::IsReachBottom() { int nMax = GetScrollLimit(SB_VERT); int nCur = GetScrollPos(SB_VERT); bool bReachBottom = nMax == 0 ? true : (nCur == nMax || nCur == (nMax - 1)); if (!bReachBottom) { CRect Rect; GetRect(&Rect); CPoint pnt; pnt.x = Rect.left; pnt.y = Rect.bottom; int nCharIndex = CharFromPos(pnt); int nLineIndex = LineFromChar(nCharIndex); bReachBottom = nLineIndex == GetLineCount() - 1; } return bReachBottom; } void CIrcEdit::OnEnLink(NMHDR *pNMHDR, LRESULT *pResult) { ENLINK *pEnLink = reinterpret_cast(pNMHDR); if (pEnLink->msg == WM_LBUTTONDOWN) { CPoint pntLastCharPos = GetCharPos(GetCharCount() - 1); CClientDC dc(this); TEXTMETRIC tm; dc.GetTextMetrics(&tm); int nHeight = tm.tmHeight + tm.tmExternalLeading; if (m_msgClickPos.x > pntLastCharPos.x || m_msgClickPos.y > pntLastCharPos.y + nHeight) { *pResult = 0; return; } CWnd* pParentWnd = GetOwner(); pParentWnd->SendMessage(WM_NEWPRICHAT, (WPARAM)this, (LPARAM)&(pEnLink->chrg)); } *pResult = 0; } void CIrcEdit::OnEnMsgfilter(NMHDR *pNMHDR, LRESULT *pResult) { MSGFILTER *pMsgFilter = reinterpret_cast(pNMHDR); if (pMsgFilter->msg == WM_LBUTTONDOWN) { m_msgClickPos.x = GET_X_LPARAM(pMsgFilter->lParam); m_msgClickPos.y = GET_Y_LPARAM(pMsgFilter->lParam); CPoint pntLastCharPos = GetCharPos(GetCharCount() - 1); CClientDC dc(this); TEXTMETRIC tm; dc.GetTextMetrics(&tm); int nHeight = tm.tmHeight + tm.tmExternalLeading; if (m_msgClickPos.x > pntLastCharPos.x || m_msgClickPos.y > pntLastCharPos.y + nHeight) { *pResult = 0; return; } int nCharIndex = CharFromPos(m_msgClickPos); for (map::iterator Ite = m_LinkInfo.begin(); Ite != m_LinkInfo.end(); Ite++) { if (Ite->second.nStartIndex < nCharIndex && Ite->second.nEndIndex > nCharIndex) { CWnd* pParentWnd = GetOwner(); pParentWnd->SendMessage(WM_DOLINK, 0, (LPARAM)&(Ite->second)); break; } } } else if (pMsgFilter->msg == WM_KEYDOWN) { CWnd* pOwnerWnd = GetOwner(); if (pMsgFilter->wParam == VK_RETURN) { UINT nOption = GetOptions(); if (!(nOption & ECO_READONLY)) { CString strMsg = GetMsg(); if (strMsg.Trim() != _T("")) { pOwnerWnd->SendMessage(WM_SENDMSG, (WPARAM)this, (LPARAM)&strMsg); } } } else if (pMsgFilter->wParam == 'C' && GetKeyState(VK_CONTROL) < 0) { CString strSelData(CUtil::GetSel(*this)); CUtil::CopyToClipBoard(strSelData, *pOwnerWnd); *pResult = 1; return; } else if (pMsgFilter->wParam == 'V' && GetKeyState(VK_CONTROL) < 0) { UINT nOption = GetOptions(); if (!(nOption & ECO_READONLY)) { CUtil::PasteFromClipBoard(*this, *pOwnerWnd); *pResult = 1; return; } } } *pResult = 0; } CString CIrcEdit::GetMsg() { //获得文本内容 CString strMsg; GetWindowText(strMsg); USES_CONVERSION; LPWSTR lpwstrMsg = A2W(strMsg); wstring wstrMsg(lpwstrMsg); wstring wstrNewMsg; //获得表情的位置 LPRICHEDITOLE lpRichEditOle = GetIRichEditOle(); int nPos = 0; for (int nIndex = 0; nIndex < lpRichEditOle->GetObjectCount(); nIndex++) { REOBJECT reObject; ZeroMemory(&reObject, sizeof(reObject)); reObject.cbStruct = sizeof(REOBJECT); lpRichEditOle->GetObject(nIndex, &reObject, REO_GETOBJ_ALL_INTERFACES); //因为当插入表情后,在文本内容中会插入一个空格表示,所以不用判断图片的字符位置大于文本内容的情况 CString strFace; strFace.Format(_T("%s%03d"), _T("&"), reObject.dwUser); wstring wstrFace(A2W(strFace)); wstrNewMsg += wstrMsg.substr(nPos, reObject.cp - nPos); wstrNewMsg += wstrFace; nPos = reObject.cp + 1; } lpRichEditOle->Release(); if (nPos != wstrMsg.size()) { wstrNewMsg += wstrMsg.substr(nPos); } //过滤关键字 if (m_WorldFilter) { m_WorldFilter->FilterStr(wstrNewMsg, L"**"); } CString strChat(CW2A(wstrNewMsg.c_str())); if (strChat.Trim() != _T("")) { //根据用户所选的频道,调用相关的接口发送消息,为测试用,先向世界频道发送消息 strChat += _T("[ExtraData]"); } return strChat; } void CIrcEdit::OnEnChange() { UINT nOption = GetOptions(); if (!(nOption & ECO_READONLY)) { //获得文本内容 CString strMsg; GetWindowText(strMsg); USES_CONVERSION; LPWSTR lpwstrMsg = A2W(strMsg); wstring wstrMsg(lpwstrMsg); LPRICHEDITOLE lpRichEditOle = GetIRichEditOle(); int nFacePos = (int)wstrMsg.find(L"&"); int nFaceNum = 0; while (nFacePos != -1) { bool bFace = false; if (nFacePos + 3 < (int)wstrMsg.size() && (iswdigit(wstrMsg[nFacePos + 1]) && iswdigit(wstrMsg[nFacePos + 2]) && iswdigit(wstrMsg[nFacePos + 3]))) { wstring strTmp(wstrMsg.substr(nFacePos + 1, 3)); int nFaceIndex = _wtoi(strTmp.c_str()); CWnd* pParentWnd = GetOwner(); CGif* pFace = reinterpret_cast(pParentWnd->SendMessage(WM_GETFACE, (WPARAM)this, (LPARAM)nFaceIndex)); if (pFace != NULL) { //检查表情个数 if (lpRichEditOle->GetObjectCount() == MAX_ICON_MSG) { REOBJECT reObject; ZeroMemory(&reObject, sizeof(reObject)); reObject.cbStruct = sizeof(REOBJECT); lpRichEditOle->GetObject(lpRichEditOle->GetObjectCount() - 1, &reObject, REO_GETOBJ_ALL_INTERFACES); if (reObject.cp > nFacePos) { SetSel(reObject.cp, reObject.cp + 1); CString strFace; strFace.Format(_T("%s%03d"), _T("&"), reObject.dwUser); ReplaceSel(strFace); nFacePos -= nFaceNum; SetSel(nFacePos, nFacePos + 2); ReplaceSel(_T("")); InsertFaceToEdit(pFace, nFaceIndex); bFace = true; nFaceNum++; } } else { nFacePos -= nFaceNum * 3; SetSel(nFacePos, nFacePos + 4); ReplaceSel(_T("")); InsertFaceToEdit(pFace, nFaceIndex); bFace = true; nFaceNum++; } } } if (bFace) { nFacePos = (int)wstrMsg.find(L"&", nFacePos + 4); } else { nFacePos = (int)wstrMsg.find(L"&", nFacePos + 1); } } long nObjCount = lpRichEditOle->GetObjectCount(); long nLeftLimit = MAX_TEXT_MSG - nObjCount; if (nLeftLimit > 0) { LimitText(nLeftLimit); } lpRichEditOle->Release(); } } void CIrcEdit::FlushMsg() { m_LinkInfo.clear(); m_DispMsg.clear(); SetWindowText(_T("")); } void CIrcEdit::OnEnVscroll() { this->Invalidate(); } void CIrcEdit::LoadFilterWord(CWordFilter* pWorldFilter) { m_WorldFilter = pWorldFilter; } void CIrcEdit::InsertFaceToEdit(CGif* pGif, int nIndex, int nCharIndex /* = -1 */) { LPLOCKBYTES lpLockBytes = NULL; SCODE sc; HRESULT hr; LPOLECLIENTSITE lpClientSite; IGifAnimatorPtr ptrGif; LPSTORAGE lpStorage; LPOLEOBJECT lpOleObject; LPRICHEDITOLE lpRichEditOle; sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes); if (sc != S_OK) { return; } sc = ::StgCreateDocfileOnILockBytes(lpLockBytes, STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE, 0, &lpStorage); if (sc != S_OK) { lpLockBytes = NULL; return; } lpRichEditOle = GetIRichEditOle(); lpRichEditOle->GetClientSite(&lpClientSite); hr = ptrGif.CreateInstance(CLSID_GifAnimator); ASSERT(SUCCEEDED(hr)); pGif->SaveToFile(".//Tmp.gif"); Image img(L".//Tmp.gif"); ptrGif->LoadFromFile(".//Tmp.gif"); hr = ptrGif.QueryInterface(IID_IOleObject, &lpOleObject); ASSERT(SUCCEEDED(hr)); OleSetContainedObject(lpOleObject, TRUE); lpOleObject->SetClientSite(lpClientSite); REOBJECT reobj; ZeroMemory(&reobj, sizeof(REOBJECT)); reobj.cbStruct = sizeof(REOBJECT); CLSID clsid; sc = lpOleObject->GetUserClassID(&clsid); reobj.clsid = clsid; reobj.cp = nCharIndex; reobj.dvaspect = DVASPECT_CONTENT; reobj.dwFlags = REO_BELOWBASELINE; reobj.dwUser = nIndex; reobj.poleobj = lpOleObject; reobj.polesite = lpClientSite; reobj.pstg = lpStorage; lpRichEditOle->InsertObject(&reobj); ptrGif->Play(); lpClientSite->Release(); lpStorage->Release(); lpOleObject->Release(); lpRichEditOle->Release(); } void CIrcEdit::PreSubclassWindow() { CRichEditCtrl::PreSubclassWindow(); SetUndoLimit(0); SetOLECallback(m_pCallback); } int CIrcEdit::GetCharCount() { int nTextLen = 0; int nIndex = 0; int nLen = 0; for (nIndex = 0; nIndex < GetLineCount() && GetTextLength() > 0; nIndex++ ) { nLen = LineLength(LineIndex(nIndex)); nTextLen += nLen; } //还需要加上换行符 CString strText; GetWindowText(strText); int nPos = strText.Find(_T("\r\n")); while (nPos != -1) { nTextLen++; nPos = strText.Find(_T("\r\n"), nPos + 1); } return nTextLen; } void CIrcEdit::AppendMsg(LPCTSTR lpMsg) { SetSel(0, -1); SetSel(-1, -1); ReplaceSel(lpMsg); } void CIrcEdit::ClearMsg() { SetSel(0, -1); ReplaceSel(_T("")); }