//需要用枚举的办法来获得指定OLE的显示位置,不知道有没有其它更好的办法。 BOOL CImageOle::GetOleRect( LPRECT lpRect ) { IRichEditOle *pRichEditOle=NULL; LRESULT lRes=m_pRichedit->DuiSendMessage(EM_GETOLEINTERFACE,0,(LPARAM)&pRichEditOle); if(!pRichEditOle) return FALSE; BOOL bRet=FALSE; int nObjCount = pRichEditOle->GetObjectCount(); int i = 0; for (i = 0;i < nObjCount;i++) { REOBJECT reo; ZeroMemory(&reo, sizeof(REOBJECT)); reo.cbStruct = sizeof(REOBJECT); HRESULT hr = pRichEditOle->GetObject(i, &reo, REO_GETOBJ_POLEOBJ); if (hr != S_OK) continue; reo.poleobj->Release(); if (reo.poleobj == (IOleObject *)this) { ITextDocument *pTextDocument = NULL; ITextRange *pTextRange = NULL; pRichEditOle->QueryInterface(IID_ITextDocument, (void **)&pTextDocument); if (!pTextDocument) break; long nLeft = 0; long nBottom = 0; pTextDocument->Range(reo.cp, reo.cp, &pTextRange); if (reo.dwFlags & REO_BELOWBASELINE) hr = pTextRange->GetPoint(TA_BOTTOM|TA_LEFT, &nLeft, &nBottom); else hr = pTextRange->GetPoint(TA_BASELINE|TA_LEFT, &nLeft, &nBottom); pTextDocument->Release(); pTextRange->Release(); CRect rcRichedit; GetWindowRect(m_pRichedit->GetContainer()->GetHostHwnd(),&rcRichedit); CSize szOle=m_pSkin->GetSkinSize(); lpRect->left = nLeft - rcRichedit.left; lpRect->bottom = nBottom - rcRichedit.top; lpRect->right = lpRect->left + szOle.cx ; lpRect->top = lpRect->bottom - szOle.cy; bRet=TRUE; break; } } pRichEditOle->Release(); return bRet; }
static bool bbCodeImageFunc(IFormattedTextDraw *ftd, CHARRANGE range, TCHAR *txt, DWORD cookie) { ITextServices *ts = ftd->getTextService(); ITextDocument *td = ftd->getTextDocument(); long cnt; LRESULT lResult; /* TEXTRANGE trg; trg.chrg = range; trg.lpstrText = new TCHAR[trg.chrg.cpMax - trg.chrg.cpMin + 1]; ts->TxSendMessage(EM_GETTEXTRANGE, 0, (LPARAM)&trg, &lResult); MessageBox(0, txt, trg.lpstrText, MB_OK); */ ts->TxSendMessage(EM_SETSEL, range.cpMin, range.cpMax, &lResult); IRichEditOle* RichEditOle; ts->TxSendMessage(EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle, &lResult); td->Freeze(&cnt); // HDC emfdc = CreateEnhMetaFile(NULL, NULL, NULL, _T("icon")); // DrawIconEx(emfdc, 0, 0, (HICON)_ttol(txt), 16, 16, 0, NULL, DI_NORMAL); // InsertBitmap(RichEditOle, CloseEnhMetaFile(emfdc)); #ifdef _WIN64 bool res = InsertBitmap(RichEditOle, CacheIconToEmf((HICON)_tstoi64(txt))); #else bool res = InsertBitmap(RichEditOle, CacheIconToEmf((HICON)_ttoi(txt))); #endif td->Unfreeze(&cnt); RichEditOle->Release(); return res; }
static bool bbCodeImageFunc(IFormattedTextDraw *ftd, CHARRANGE range, TCHAR *txt, DWORD) { ITextServices *ts = ftd->getTextService(); ITextDocument *td = ftd->getTextDocument(); long cnt; LRESULT lResult; ts->TxSendMessage(EM_SETSEL, range.cpMin, range.cpMax, &lResult); IRichEditOle* RichEditOle; ts->TxSendMessage(EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle, &lResult); td->Freeze(&cnt); #ifdef _WIN64 bool res = InsertBitmap(RichEditOle, CacheIconToEmf((HICON)_tstoi64(txt))); #else bool res = InsertBitmap(RichEditOle, CacheIconToEmf((HICON)_ttoi(txt))); #endif td->Unfreeze(&cnt); RichEditOle->Release(); return res; }
BOOL RichEditPara::GetLineRect(int nLineNo, CRect& rcLine) { rcLine.SetRectEmpty(); int ncpStart; int nLength; m_pObjectHost->SendMessage(EM_LINEINDEX, nLineNo, 0, (LRESULT*)&ncpStart); m_pObjectHost->SendMessage(EM_LINELENGTH, ncpStart, 0, (LRESULT*)&nLength); SComPtr<ITextRange> spRangeLine; ITextDocument * pdoc = m_pObjectHost->GetTextDoc(); pdoc->Range(ncpStart, ncpStart + nLength, &spRangeLine); if (!spRangeLine) { return FALSE; } CHARRANGE chr = {ncpStart, ncpStart + nLength}; // http://technet.microsoft.com/zh-cn/hh768766(v=vs.90) 新类型定义 #define _tomClientCoord 256 // 默认获取到的是屏幕坐标, Use client coordinates instead of screen coordinates. #define _tomAllowOffClient 512 // Allow points outside of the client area. long lTypeTopLeft = _tomAllowOffClient|_tomClientCoord|tomStart|TA_TOP|TA_LEFT; long lTypeRightBottom = _tomAllowOffClient|_tomClientCoord|tomEnd|TA_BOTTOM|TA_RIGHT; POINT ptEnd, ptStart; spRangeLine->GetPoint(lTypeTopLeft, &ptStart.x, &ptStart.y); spRangeLine->GetPoint(lTypeRightBottom, &ptEnd.x, &ptEnd.y); rcLine.SetRect(ptStart, ptEnd); if (rcLine.Width() == 0) { rcLine.right += 1; } return TRUE; }
bool tomEditCallback::PrepareClipboardData() { m_text_packer.Clear() ; m_html_packer.Clear() ; bool res = false ; // 获得当前选择图文 IRichEditOle * edit_ole = m_edit->GetIRichEditOle() ; if (edit_ole != NULL) { ITextDocument * doc = NULL ;//IID_ITextDocument //__uuidof(ITextDocument) GUID guid = __uuidof(ITextDocument) ; if (S_OK == edit_ole->QueryInterface(__uuidof(ITextDocument), (void**)&doc) && doc != NULL) // 不知道多判断一个!= NULL是不是脱裤子放屁 { ITextSelection * sel = NULL ; if (S_OK == doc->GetSelection(&sel) && sel != NULL) { //BSTR * sel_text ; long sel_start = 0 ; sel->GetStart(&sel_start) ; BSTR sel_text ; if (S_OK == sel->GetText(&sel_text)) // 用完后要负责释放sel_text { // 遍历 long i ; std::wstring text_temp ; for (i = 0 ; sel_text[i] != 0 ; ++ i) { if (sel_text[i] == WCH_EMBEDDING) { if (!text_temp.empty()) { m_text_packer.Append(Clipboard::Ele_Text, text_temp) ; m_html_packer.Append(Clipboard::Ele_Text, text_temp) ; text_temp.clear() ; } // 获得对象 REOBJECT ro ; ro.cbStruct = sizeof(ro) ; ro.cp = sel_start + i ; if (S_OK == edit_ole->GetObject(REO_IOB_USE_CP, &ro, REO_GETOBJ_POLEOBJ)) { IClipboardDataObject * cdo = NULL ; if (S_OK == ro.poleobj->QueryInterface(IID_IClipboardDataObject, (void**)&cdo)) { std::wstring text_data ; if (cdo->QueryTextStreamClipboardData(Clipboard::Text, text_data)) { m_text_packer.Append(Clipboard::Ele_Image, text_data) ; } std::wstring html_data ; if (cdo->QueryTextStreamClipboardData(Clipboard::Html, html_data)) { m_html_packer.Append(Clipboard::Ele_Image, html_data) ; } cdo->Release() ; } ro.poleobj->Release() ; } } else { text_temp.append(1, (wchar_t)(sel_text[i])) ; } } if (!text_temp.empty()) { m_text_packer.Append(Clipboard::Ele_Text, text_temp) ; m_html_packer.Append(Clipboard::Ele_Text, text_temp) ; text_temp.clear() ; } SysFreeString(sel_text) ; res = true ; } sel->Release() ; } doc->Release() ; } } return res ; }
static void SetPosition(HWND hwnd) { IRichEditOle* RichEditOle; if (SendMessage(hwnd, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) return; ITextDocument* TextDocument; if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) { RichEditOle->Release(); return; } // retrieve text range ITextRange* TextRange; if (TextDocument->Range(0, 0, &TextRange) != S_OK) { TextDocument->Release(); RichEditOle->Release(); return; } TextDocument->Release(); int objectCount = RichEditOle->GetObjectCount(); for (int i = objectCount - 1; i >= 0; i--) { REOBJECT reObj = {0}; reObj.cbStruct = sizeof(REOBJECT); HRESULT hr = RichEditOle->GetObject(i, &reObj, REO_GETOBJ_POLEOBJ); if (FAILED(hr)) continue; ISmileyBase *igsc = NULL; if (reObj.clsid == CLSID_NULL) reObj.poleobj->QueryInterface(IID_ISmileyAddSmiley, (void**) &igsc); reObj.poleobj->Release(); if (igsc == NULL) continue; TextRange->SetRange(reObj.cp, reObj.cp); BOOL res; POINT pt; RECT rect; hr = TextRange->GetPoint(tomStart | TA_BOTTOM | TA_LEFT, &pt.x, &pt.y); if (hr == S_OK) { res = ScreenToClient(hwnd, &pt); rect.bottom = pt.y; rect.left = pt.x; } else rect.bottom = -1; hr = TextRange->GetPoint(tomStart | TA_TOP | TA_LEFT, &pt.x, &pt.y); if (hr == S_OK) { res = ScreenToClient(hwnd, &pt); rect.top = pt.y; rect.left = pt.x; } else rect.top = -1; igsc->SetPosition(hwnd, &rect); igsc->Release(); } TextRange->Release(); RichEditOle->Release(); }
void RichEditPara::UpdatePosition() { RichEditObj::UpdatePosition(); if (m_bDisableLayout) { // 如果不需要布局,直接返回 return; } CComPtr<ITextPara> ppara; CComPtr<ITextRange> prange; ITextDocument* pdoc = m_pObjectHost->GetTextDoc(); CHARRANGE chr = m_chrContent; if (m_bBreakAtTheEnd) { chr.cpMax += 1; } pdoc->Range(chr.cpMin, chr.cpMax, &prange); prange->GetPara(&ppara); if (!m_bInited) { m_bInited = TRUE; ppara->SetSpaceBefore(px2pt(m_rcMargin.top)); ppara->SetSpaceAfter(px2pt(m_rcMargin.bottom)); } CRect rcAdjust = m_pObjectHost->GetAdjustedRect(); CRect rcClient = m_pObjectHost->GetHostRect(); int nLeftIndents = m_alignType==ALIGN_RIGHT? m_rcMargin.right : m_rcMargin.left; int nRightIndents = m_alignType==ALIGN_RIGHT? m_rcMargin.left: m_rcMargin.right; nRightIndents += rcClient.Width() - rcAdjust.Width();// 计算真实的右边距 // 尽量不要使用模拟计算,能提高速度 if (!m_bSimulateAlign || m_alignType == ALIGN_LEFT) { m_bWrapped = IsWrapped(); if (m_bNeedUpdateLayout) { int nAlign = tomAlignLeft; if (m_alignType == ALIGN_RIGHT) nAlign = tomAlignRight; else if (m_alignType == ALIGN_CENTER) nAlign = tomAlignCenter; ppara->SetAlignment(nAlign); ppara->SetIndents(0, px2pt(nLeftIndents), px2pt(nRightIndents)); m_bNeedUpdateLayout = FALSE; } return; } /* 模拟计算右对齐 * 注意:SetIndents和CalcParagraphRect很耗时,所以尽量不使用模拟计算靠右 * * 1.先按最靠边的左右缩进设置 * 2.按照cp计算段落的rect * 3.用richedit.width() - para.widht()计算左缩进,模拟右对齐 * 4.根据计算出的左/缩进重新设置 */ // step 1 ppara->SetIndents(0, px2pt(nLeftIndents), px2pt(nRightIndents)); if ((m_bWrapped = IsWrapped())) return; // step 2 CalcParagraphRect(); // step 3 if (m_alignType == ALIGN_RIGHT) { nLeftIndents = rcClient.Width() - m_rcObj.Width() - nRightIndents - 1; // 这里不减1,段落就换行了 } else { int mid = (rcClient.Width() - m_rcObj.Width() - nRightIndents -nLeftIndents) / 2 - 1; nLeftIndents = m_rcMargin.left + mid; nRightIndents = m_rcMargin.right + mid; } // step 4 ppara->SetIndents(0, px2pt(nLeftIndents), px2pt(nRightIndents)); m_bNeedUpdateLayout = FALSE; m_bDirty = TRUE; }
//------------------------------------------------------------------------------------------- // This public member function opens file with the given name in the Developer Studio // and highlights the siven line. It also gives focus to the Developer Studio. //------------------------------------------------------------------------------------------- bool CCommands::MakeSelection(CString& file, int line, int col, int len) { ITextDocument* iDocument; IDocuments* iDocuments; ITextSelection* iSelection; // First, check if the given file exists. (Developer Studio will hang for a while // trying to open non-existing file). if(_access(file,04)==-1) return false; // Get document collection from the application object. if(m_pApplication->get_Documents((IDispatch **)&iDocuments)!=S_OK) return false; if(iDocuments==NULL) return false; // Open new document and add it to the documents collection (if not exists). VARIANT varType; varType.vt = VT_BSTR; varType.bstrVal=CString("Auto").AllocSysString(); VARIANT varReadonly; varReadonly.vt = VT_BOOL; varReadonly.boolVal = FALSE; if(iDocuments->Open(file.AllocSysString(),varType,varReadonly,(IDispatch **)&iDocument)!=S_OK) { iDocuments->Release(); return false; } // We do not need documents collection any more iDocuments->Release(); if(iDocument==NULL) return false; // Get text selection from the current document if(iDocument->get_Selection((IDispatch **)&iSelection)!=S_OK) return false; // We do not need document object any more. iDocument->Release(); if(iSelection==NULL) return false; // Move to the first position in the given line VARIANT selAct; selAct.vt = VT_INT; selAct.intVal = dsMove; iSelection->MoveTo(line,1,selAct); VARIANT repCount; repCount.vt = VT_INT; repCount.intVal = col-1; iSelection->CharRight(selAct, repCount); // Move to the end of this line in "Shift key pressed" mode. selAct.intVal = dsExtend; repCount.intVal = len; iSelection->CharRight(selAct, repCount); // We do not need text selection object any more iSelection->Release(); // Pop-up MSDEV application. m_pApplication->put_Active(VARIANT_TRUE); return true; }
//------------------------------------------------------------------------------ // This function fills file name, line number and ending column number // for the selected token as well as a token itself. //------------------------------------------------------------------------------ bool CCommands::getSelection(CComBSTR& file, CComBSTR& token, long& offset, long& line, long& column) { ITextDocument* iDocument; ITextSelection* iSelection; // Getting the currently opened document object. if(m_pApplication->get_ActiveDocument((IDispatch **)&iDocument)!=S_OK) return false; if(iDocument==NULL) return false; // Reading the file name BSTR bstrName; iDocument->get_FullName(&bstrName); file=bstrName; // Getting text selection object from the active document if(iDocument->get_Selection((IDispatch **)&iSelection)!=S_OK) return false; // We do not need active document object any more. iDocument->Release(); if(iSelection==NULL) return false; // Reading currently selected token BSTR bstrToken; if(iSelection->get_Text(&bstrToken)!=S_OK) return false; token = bstrToken; long size = token.Length(); if(iSelection->get_TopLine(&line)!=S_OK) return false; if(iSelection->get_CurrentColumn(&column)!=S_OK) return false; VARIANT selMove; selMove.vt = VT_INT; selMove.intVal = dsMove; VARIANT selExtend; selExtend.vt = VT_INT; selExtend.intVal = dsExtend; VARIANT repCount; repCount.vt = VT_INT; repCount.intVal = 1; // To determine which end of the selection the cursor is at, // we extend the selection one character left from the cursor // and see whether the selection has gotten longer or shorter. bool cursor_at_right_end = true; if (column <= 1) { cursor_at_right_end = false; } else { long newsize; iSelection->CharLeft(selExtend, repCount); if(iSelection->get_Text(&bstrToken)==S_OK) { CComBSTR newToken = bstrToken; newsize = newToken.Length(); if (newsize > size) { // If extending left increases the size, the // cursor must be at the left end. cursor_at_right_end = false; } } iSelection->CharRight(selExtend, repCount); } // Calculating column in file characters, not in screen // position (detecting tabs) long lineOffset = 0; long tempColumn = column; while (tempColumn > 1) { iSelection->CharLeft(selMove, repCount); iSelection->get_CurrentColumn(&tempColumn); lineOffset++; } // Restoring selection after calculation: // First, go to the end without the cursor if (cursor_at_right_end) { iSelection->MoveTo(line, column-size, selMove); } else // Cursor at left end of selection { iSelection->MoveTo(line, column+size, selMove); } // Now make the selection iSelection->MoveTo(line, column, selExtend); iSelection->Release(); column = lineOffset; if(size!=0) column--; offset = -1; // can not determine the offset return true; }