📄 tomrange.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*
* @doc TOM
*
* @module TOMRANGE.CPP - Implement the CTxtRange Class |
*
* This module contains the implementation of the TOM ITextRange
* interface on the CTxtRange object
*
* History: <nl>
* 5/24/95 - Alex Gounares: stubs created <nl>
* 8/95 - MurrayS: main implementation <nl>
* 11/95 - MurrayS: upgrade to TOM spec of 12/10/95 <nl>
* 5/96 - MurrayS: added zombie protection
*
* @comm
* All ITextRange methods return HRESULTs. If the method can move a
* range cp, the HRESULT is NOERROR if movement occurs and S_FALSE if
* no movement occurs. These methods usually take a <p pDelta> argument
* that returns the count of characters or Units actually moved. If this
* parameter is NULL, E_INVALIDARG is returned. Other return values
* include E_NOTIMPL, e.g., for Unit values not implemented,
* E_OUTOFMEMORY, e.g., when allocations fail, and CO_E_RELEASED, when
* the CTxtEdit (_ped) to which the range is attached has been deleted.
*
* For more complete documentation, please see tom.doc
*
* @devnote
* All ptr parameters must be validated before use and all entry points
* need to check whether this range is a zombie. These checks are
* done in one of three places: 1) immediately on entry to a function,
* 2) immediately on entry to a helper function (e.g., private Mover()
* for the move methods), or 3) before storing the out value.
* Alternative 3) is used for optional return values, such as pDelta
* and pB.
*
* To achieve a simple, efficient inheritance model, CTxtSelection
* inherits ITextSelection through CTxtRange. Otherwise we'd have a
* diamond inheritance, since ITextSelection itself inherits from
* ITextRange. Diamond inheritance creates two copies of the multiply
* inherited class unless that class is inherited virtually. Virtual
* inheritance uses run-time base-offset tables and is slower and
* bigger. To avoid such a mess, we include the extra ITextSelection
* methods in CTxtRange, with the intention that they'll never be called
* and therefore they return E_NOTIMPL. This is overridden for
* ITextSelection objects
*
* @future
* 1) Finder match ^p, etc.
* 2) Fast GetEffects() method. Would speed up the myriad IsProtected()
* calls and be useful for getting other effects as well.
* 3) Fast copies/pastes of RichEdit binary format. This can be done by
* creating a method to copy a range to a new CTxtStory and a method
* to insert a CTxtStory.
* 4) Delayed rendering
*
*/
#include "_common.h"
#include "_select.h"
#include "_edit.h"
#include "_line.h"
#include "_frunptr.h"
#include "_tomfmt.h"
#include "_disp.h"
#include "_objmgr.h"
#include "_callmgr.h"
ASSERTDATA
#define DEBUG_CLASSNAME CTxtRange
#include "_invar.h"
HRESULT QueryInterface (REFIID riid, REFIID riid1, IUnknown *punk,
void **ppv, BOOL fZombie);
BOOL SameVtables(IUnknown *punk1, IUnknown *punk2);
//----------------- CTxtRange (ITextRange) PUBLIC methods ----------------------------------
//----------------------- CTxtRange IUnknown Methods -------------------------------------
/*
* CTxtRange::QueryInterface (riid, ppv)
*
* @mfunc
* IUnknown method
*
* @rdesc
* HRESULT = (!ppv) ? E_INVALIDARG :
* (interface found) ? NOERROR : E_NOINTERFACE
*/
STDMETHODIMP CTxtRange::QueryInterface (
REFIID riid, // @parm Reference to requested interface ID
void ** ppv) // @parm Out parm to receive interface ptr
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::QueryInterface");
REFIID riid1 = _fSel && IsEqualIID(riid, IID_ITextSelection)
? IID_ITextSelection : IID_ITextRange;
#ifndef PEGASUS
return ::QueryInterface(riid, riid1, this, ppv, IsZombie());
#else
return 0;
#endif
}
/*
* CTxtRange::AddRef()
*
* @mfunc
* IUnknown method
*
* @rdesc
* ULONG - incremented reference count
*/
STDMETHODIMP_(ULONG) CTxtRange::AddRef()
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::AddRef");
return ++_cRefs;
}
/*
* CTxtRange::Release()
*
* @mfunc
* IUnknown method
*
* @rdesc
* ULONG - decremented reference count
*/
STDMETHODIMP_(ULONG) CTxtRange::Release()
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::Release");
_cRefs--;
if(!_cRefs)
{
delete this;
return 0;
}
Assert(_cRefs > 0);
return _cRefs;
}
//------------------------ CTxtRange IDispatch Methods -------------------------------------
/*
* CTxtRange::GetTypeInfoCount(pcTypeInfo)
*
* @mfunc
* Get the number of TYPEINFO elements (1)
*
* @rdesc
* HRESULT
*/
STDMETHODIMP CTxtRange::GetTypeInfoCount (
UINT * pcTypeInfo) //@parm Out parm to receive type-info count
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::GetTypeInfoCount");
if(!pcTypeInfo)
return E_INVALIDARG;
*pcTypeInfo = 1;
return NOERROR;
}
/*
* CTxtRange::GetTypeInfo(iTypeInfo, lcid, ppTypeInfo)
*
* @mfunc
* Return ptr to type information object for ITextSelection interface
*
* @rdesc
* HRESULT
*/
STDMETHODIMP CTxtRange::GetTypeInfo (
UINT iTypeInfo, //@parm Index of type info to return
LCID lcid, //@parm Local ID of type info
ITypeInfo **ppTypeInfo) //@parm Out parm to receive type info
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::GetTypeInfo");
return ::GetTypeInfo(iTypeInfo, g_pTypeInfoSel, ppTypeInfo);
}
/*
* CTxtRange::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid)
*
* @mfunc
* Get DISPIDs for methods in the ITextSelection, ITextRange, ITextFont,
* and ITextPara interfaces
*
* @rdesc
* HRESULT
*
* @devnote
* If the ITextFont and ITextPara ever offer more methods than exposed
* in their type libraries, the code should delegate to the corresponding
* GetIDsOfNames. The current code only gets DISPIDs for the methods in
* type libraries, thereby not having to instantiate the objects.
*/
STDMETHODIMP CTxtRange::GetIDsOfNames (
REFIID riid, //@parm Interface ID to interpret names for
OLECHAR ** rgszNames, //@parm Array of names to be mapped
UINT cNames, //@parm Count of names to be mapped
LCID lcid, //@parm Local ID to use for interpretation
DISPID * rgdispid) //@parm Out parm to receive name mappings
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::GetIDsOfNames");
HRESULT hr = GetTypeInfoPtrs(); // Ensure TypeInfo ptrs are OK
if(hr != NOERROR)
return hr;
if(g_pTypeInfoSel->GetIDsOfNames(rgszNames, cNames, rgdispid) == NOERROR)
return NOERROR;
if(g_pTypeInfoFont->GetIDsOfNames(rgszNames, cNames, rgdispid) == NOERROR)
return NOERROR;
return g_pTypeInfoPara->GetIDsOfNames(rgszNames, cNames, rgdispid);
}
/*
* CTxtRange::Invoke(dispidMember, riid, lcid, wFlags, pdispparams,
* pvarResult, pexcepinfo, puArgError)
* @mfunc
* Invoke methods for the ITextRange and ITextSelection objects, as
* well as for ITextFont and ITextPara interfaces on those objects.
*
* @rdesc
* HRESULT
*/
STDMETHODIMP CTxtRange::Invoke (
DISPID dispidMember, //@parm Identifies member function
REFIID riid, //@parm Pointer to interface ID
LCID lcid, //@parm Locale ID for interpretation
USHORT wFlags, //@parm Flags describing context of call
DISPPARAMS *pdispparams, //@parm Ptr to method arguments
VARIANT * pvarResult, //@parm Out parm for result (if not NULL)
EXCEPINFO * pexcepinfo, //@parm Out parm for exception info
UINT * puArgError) //@parm Out parm for error
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::Invoke");
HRESULT hr = GetTypeInfoPtrs(); // Ensure TypeInfo ptrs are OK
if(hr != NOERROR)
return hr;
if(IsZombie())
return CO_E_RELEASED;
IDispatch * pDispatch;
ITypeInfo * pTypeInfo;
if((DWORD)dispidMember <= 0x2ff) // Include default (0), selection,
{ // and range DISPIDs
pTypeInfo = g_pTypeInfoSel;
pDispatch = this;
AddRef(); // Compensate for Release() below
}
else if((DWORD)dispidMember <= 0x3ff) // 0x300 to 0x3ff: DISPIDs
{ // reserved for ITextFont
pTypeInfo = g_pTypeInfoFont;
hr = GetFont((ITextFont**)&pDispatch);
}
else if((DWORD)dispidMember <= 0x4ff) // 0x400 to 0x4ff: DISPIDs
{ // reserved for ITextPara
pTypeInfo = g_pTypeInfoPara;
hr = GetPara((ITextPara **)&pDispatch);
}
else // dispidMember is negative or
return DISP_E_MEMBERNOTFOUND; // > 0x4ff, i.e., not TOM
if(hr != NOERROR) // Couldn't instantiate ITextFont
return hr; // or ITextPara
hr = pTypeInfo->Invoke(pDispatch, dispidMember, wFlags,
pdispparams, pvarResult, pexcepinfo, puArgError);
#ifndef PEGASUS
pDispatch->Release();
#endif
return hr;
}
//----------------------- ITextRange Methods/Properties ------------------------
/*
* CTxtRange::CanEdit (pB)
*
* @mfunc
* Set *<p pB> = tomTrue iff this range can be edited and
* pB isn't NULL
*
* @rdesc
* HRESULT = (can edit) ? NOERROR : S_FALSE
*/
STDMETHODIMP CTxtRange::CanEdit (
long * pB) //@parm Out parm to receive boolean value
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::CanEdit");
if(IsZombie())
return CO_E_RELEASED;
CCallMgr callmgr(GetPed());
return IsTrue(!WriteAccessDenied(), pB);
}
/*
* CTxtRange::CanPaste (pVar, long Format, pB)
*
* @mfunc
* Set *<p pB> = tomTrue iff the data object <p pVar>->punkVal can be
* pasted into this range and pB isn't NULL. If <p pVar> is NULL,
* use the clipboard instead.
*
* @rdesc
* HRESULT = (can paste) ? NOERROR : S_FALSE
*/
STDMETHODIMP CTxtRange::CanPaste (
VARIANT * pVar, //@parm Data object to paste
long Format, //@parm Desired clipboard format
long * pB) //@parm Out parm to receive boolean value
{
#ifndef PEGASUS
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::CanPaste");
if(IsZombie())
return CO_E_RELEASED;
CCallMgr callmgr(GetPed());
HRESULT hr;
IDataObject * pdo = NULL; // Default clipboard
if(pVar && pVar->vt == VT_UNKNOWN)
pVar->punkVal->QueryInterface(IID_IDataObject, (void **)&pdo);
hr = IsTrue(!WriteAccessDenied() &&
(GetPed()->GetDTE()->CanPaste(pdo, (CLIPFORMAT)Format,
RECO_PASTE)), pB);
if( pdo )
{
pdo->Release();
}
return hr;
#else
return 0;
#endif
}
/*
* ITextRange::ChangeCase (long Type)
*
* @mfunc
* Change the case of letters in this range according to Type:
*
* tomSentenceCase = 0: capitalize first letter of each sentence
* tomLowerCase = 1: change all letters to lower case
* tomUpperCase = 2: change all letters to upper case
* tomTitleCase = 3: capitalize the first letter of each word
* tomToggleCase = 4: toggle the case of each letter
*
* @rdesc
* HRESULT = (WriteAccessDenied) ? E_ACCESSDENIED :
* (if change) ? NOERROR : S_FALSE
*/
STDMETHODIMP CTxtRange::ChangeCase (
long Type) //@parm Type of case change. Default value: tomLower
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::ChangeCase");
if(IsZombie())
return CO_E_RELEASED;
CCallMgr callmgr(GetPed());
if( WriteAccessDenied())
return E_ACCESSDENIED;
CGenUndoBuilder undobldr(GetPed(), UB_AUTOCOMMIT );
LONG cpMin, cpMax;
LONG cch = GetRange(cpMin, cpMax);
CRchTxtPtr rtp(*this);
undobldr.StopGroupTyping();
rtp.SetCp(cpMin);
return (rtp.ChangeCase(cch, Type, &undobldr)) ? NOERROR : S_FALSE;
}
/*
* CTxtRange::Collapse (bStart)
*
* @mfunc
* Collapse this range into a degenerate point either at the
* the start (<p bStart> is nonzero or the end (<p bStart> = 0)
*
* @rdesc
* HRESULT = (if change) ? NOERROR : S_FALSE
*/
STDMETHODIMP CTxtRange::Collapse (
long bStart) //@parm Flag specifying end to collapse at
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::Collapse");
if(IsZombie())
return CO_E_RELEASED;
CCallMgr callmgr(GetPed());
if(!_cch) // Already collapsed
return S_FALSE; // Signal that no change occurred
Collapser(bStart);
Update(TRUE); // Update selection
return NOERROR; // Signal that change occurred
}
/*
* CTxtRange::Copy (pVar)
*
* @mfunc
* Copy the plain and/or rich text to a data object and return the
* object ptr in <p pVar>. If <p pVar> is null, copy to the clipboard.
*
* @rdesc
* HRESULT = (if success) ? NOERROR : E_OUTOFMEMORY
*/
STDMETHODIMP CTxtRange::Copy (
VARIANT * pVar) //@parm Out parm for data object
{
#ifndef PEGASUS
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::Copy");
if(IsZombie())
return CO_E_RELEASED;
CLightDTEngine * pldte = &GetPed()->_ldte;
if(pVar && pVar->vt == (VT_UNKNOWN | VT_BYREF))
{
return pldte->RangeToDataObject(this, SF_TEXT | SF_RTF,
(IDataObject **)pVar->ppunkVal);
}
return pldte->CopyRangeToClipboard(this);
#else
return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -