📄 tomdoc.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 tomdoc.cpp - Implement the ITextDocument interface on CTxtEdit |
*
* This module contains the implementation of the TOM ITextDocument
* class as well as the global TOM type-info routines
*
* History: <nl>
* sep-95 MurrayS: stubs and auto-doc created <nl>
* nov-95 MurrayS: upgrade to top-level TOM interface
* dec-95 MurrayS: implemented file I/O methods
*
* @future
* 1. Begin/EndEditCollection
* 2. Freeze/Unfreeze
*
*/
#include "_common.h"
#include "_range.h"
#include "_edit.h"
#include "_disp.h"
#include "_rtfconv.h"
ASSERTDATA
// TOM Type Info HRESULT and pointers
HRESULT g_hrGetTypeInfo = NOERROR;
ITypeInfo * g_pTypeInfoDoc;
ITypeInfo * g_pTypeInfoSel;
ITypeInfo * g_pTypeInfoFont;
ITypeInfo * g_pTypeInfoPara;
ITypeLib * g_pTypeLib;
EXTERN_C const GUID LIBID_TOM =
{ 0x8CC497C9, 0xA1DF, 0x11ce, { 0x80, 0x98, 0x0, 0xaa, 0x0, 0x47, 0xBE, 0x5D } };
//------------------------ Global TOM Type Info Methods -----------------------------
/*
* GetTypeInfoPtrs()
*
* @func
* Ensure that global TOM ITypeInfo ptrs are valid (else g_pTypeInfoDoc
* is NULL). Return NOERROR immediately if g_pTypeInfoDoc is not NULL,
* i.e., type info ptrs are already valid.
*
* @rdesc
* HRESULT = (success) ? NOERROR
* : (HRESULT from LoadTypeLib or GetTypeInfoOfGuid)
*
* @comm
* This routine should be called by any routine that uses the global
* type info ptrs, e.g., IDispatch::GetTypeInfo(), GetIDsOfNames, and
* Invoke. That way if noone is using the type library info, it doesn't
* have to be loaded.
*
*/
HRESULT GetTypeInfoPtrs()
{
HRESULT hr;
CLock lock; // Only one thread at a time...
if(g_pTypeInfoDoc) // Type info ptrs already valid
return NOERROR;
if(g_hrGetTypeInfo != NOERROR) // Tried to get before and failed
return g_hrGetTypeInfo;
if (pLoadRegTypeLib(LIBID_TOM, 1, 0, LANG_NEUTRAL, &g_pTypeLib) != NOERROR)
{
hr = pLoadTypeLib(OLESTR("RICHED20.DLL"), &g_pTypeLib);
if(hr != NOERROR)
goto err;
}
// Get ITypeInfo pointers with g_pTypeInfoDoc last
hr = g_pTypeLib->GetTypeInfoOfGuid(IID_ITextSelection, &g_pTypeInfoSel);
if(hr == NOERROR)
{
g_pTypeLib->GetTypeInfoOfGuid(IID_ITextFont, &g_pTypeInfoFont);
g_pTypeLib->GetTypeInfoOfGuid(IID_ITextPara, &g_pTypeInfoPara);
g_pTypeLib->GetTypeInfoOfGuid(IID_ITextDocument, &g_pTypeInfoDoc);
if(g_pTypeInfoFont && g_pTypeInfoPara && g_pTypeInfoDoc)
return NOERROR; // Got 'em all
}
hr = E_FAIL;
err:
Assert("Error getting type info pointers");
g_pTypeInfoDoc = NULL; // Type info ptrs not valid
g_hrGetTypeInfo = hr; // Save HRESULT in case called
return hr; // again
}
/*
* ReleaseTypeInfoPtrs()
*
* @func
* Release TOM type info ptrs in case they have been defined.
* Called when RichEdit dll is being unloaded.
*/
void ReleaseTypeInfoPtrs()
{
if(g_pTypeInfoDoc)
{
g_pTypeInfoDoc->Release();
g_pTypeInfoSel->Release();
g_pTypeInfoFont->Release();
g_pTypeInfoPara->Release();
}
if(g_pTypeLib)
g_pTypeLib->Release();
}
/*
* GetTypeInfo(iTypeInfo, &pTypeInfo, ppTypeInfo)
*
* @func
* IDispatch helper function to check parameter validity and set
* *ppTypeInfo = pTypeInfo if OK
*
* @rdesc
* HRESULT
*/
HRESULT GetTypeInfo(
UINT iTypeInfo, //@parm Index of type info to return
ITypeInfo *&pTypeInfo, //@parm Address of desired type info ptr
ITypeInfo **ppTypeInfo) //@parm Out parm to receive type info
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetTypeInfo");
if(!ppTypeInfo)
return E_INVALIDARG;
*ppTypeInfo = NULL;
if(iTypeInfo > 1)
return DISP_E_BADINDEX;
HRESULT hr = GetTypeInfoPtrs(); // Ensure TypeInfo ptrs are OK
if(hr == NOERROR)
{
*ppTypeInfo = pTypeInfo; // Have to use reference in
pTypeInfo->AddRef(); // case defined in this call
}
return hr;
}
/*
* MyRead(dwCookie, pbBuffer, cb, pcb)
*
* @func
* Callback function for converting a file into an editstream for
* input.
*
* @rdesc
* (DWORD)HRESULT
*/
DWORD CALLBACK MyRead(DWORD dwCookie, BYTE *pbBuffer, long cb, long *pcb)
{
if(!dwCookie) // No handle defined
return (DWORD)E_FAIL;
Assert(pcb);
*pcb = 0;
if(!ReadFile((HANDLE)dwCookie, (void *)pbBuffer, (DWORD)cb,
(DWORD *)pcb, NULL))
return HRESULT_FROM_WIN32(GetLastError());
return (DWORD)NOERROR;
}
/*
* MyWrite(dwCookie, pbBuffer, cb, pcb)
*
* @func
* Callback function for converting a file into an editstream for
* output.
*
* @rdesc
* (DWORD)HRESULT
*/
DWORD CALLBACK MyWrite(DWORD dwCookie, BYTE *pbBuffer, long cb, long *pcb)
{
if(!dwCookie) // No handle defined
return (DWORD)E_FAIL;
Assert(pcb);
*pcb = 0;
if(!WriteFile((HANDLE)dwCookie, (void *)pbBuffer, (DWORD)cb,
(DWORD *)pcb, NULL))
return HRESULT_FROM_WIN32(GetLastError());
return (DWORD)(*pcb ? NOERROR : E_FAIL);
}
//-----------------CTxtEdit IUnknown methods: see textserv.cpp -----------------------------
//------------------------ CTxtEdit IDispatch methods -------------------------
/*
* CTxtEdit::GetTypeInfoCount(pcTypeInfo)
*
* @mfunc
* Get the number of TYPEINFO elements (1)
*
* @rdesc
* HRESULT = (pcTypeInfo) ? NOERROR : E_INVALIDARG;
*/
STDMETHODIMP CTxtEdit::GetTypeInfoCount(
UINT *pcTypeInfo) //@parm Out parm to receive count
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetTypeInfoCount");
if(!pcTypeInfo)
return E_INVALIDARG;
*pcTypeInfo = 1;
return NOERROR;
}
/*
* CTxtEdit::GetTypeInfo(iTypeInfo, lcid, ppTypeInfo)
*
* @mfunc
* Return ptr to type information object for ITextDocument interface
*
* @rdesc
* HRESULT
*/
STDMETHODIMP CTxtEdit::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, "CTxtEdit::GetTypeInfo");
return ::GetTypeInfo(iTypeInfo, g_pTypeInfoDoc, ppTypeInfo);
}
/*
* CTxtEdit::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid)
*
* @mfunc
* Get DISPIDs for all TOM methods and properties
*
* @rdesc
* HRESULT
*
* @devnote
* This routine tries to find DISPIDs using the type information for
* ITextDocument. If that fails, it asks the selection to find the
* DISPIDs.
*/
STDMETHODIMP CTxtEdit::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, "CTxtEdit::GetIDsOfNames");
HRESULT hr = GetTypeInfoPtrs(); // Ensure TypeInfo ptrs are OK
if(hr != NOERROR)
return hr;
hr = g_pTypeInfoDoc->GetIDsOfNames(rgszNames, cNames, rgdispid);
if(hr == NOERROR) // Succeeded in finding an
return NOERROR; // ITextDocument method
IDispatch *pSel = (IDispatch *)GetSel(); // See if the selection knows
// the desired method
if(!pSel)
return hr; // No selection
return pSel->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
}
/*
* CTxtEdit::Invoke(dispidMember, riid, lcid, wFlags, pdispparams,
* pvarResult, pexcepinfo, puArgError)
* @mfunc
* Invoke members for all TOM DISPIDs, i.e., for ITextDocument,
* ITextSelection, ITextRange, ITextFont, and ITextPara. TOM DISPIDs
* for all but ITextDocument are delegated to the selection object.
*
* @rdesc
* HRESULT
*
* @devnote
* This routine trys to invoke ITextDocument members if the DISPID is
* in the range 0 thru 0xff. It trys to invoke ITextSelection members if
* the DISPID is in the range 0x100 thru 0x4ff (this includes
* ITextSelection, ITextRange, ITextFont, and ITextPara). It returns
* E_MEMBERNOTFOUND for DISPIDs outside these ranges.
*/
STDMETHODIMP CTxtEdit::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, "CTxtEdit::Invoke");
HRESULT hr = GetTypeInfoPtrs(); // Ensure TypeInfo ptrs are OK
if(hr != NOERROR)
return hr;
if((DWORD)dispidMember < 0x100) // ITextDocment method
return g_pTypeInfoDoc->Invoke((IDispatch *)this, dispidMember, wFlags,
pdispparams, pvarResult, pexcepinfo, puArgError);
IDispatch *pSel = (IDispatch *)GetSel(); // See if the selection has
// the desired method
if(pSel && (DWORD)dispidMember <= 0x4ff)
return pSel->Invoke(dispidMember, riid, lcid, wFlags,
pdispparams, pvarResult, pexcepinfo, puArgError);
return DISP_E_MEMBERNOTFOUND;
}
//--------------------- ITextDocument Methods/Properties -----------------------
/*
* ITextDocument::BeginEditCollection()
*
* @mfunc
* Method that turns on undo grouping
*
* @rdesc
* HRESULT = (undo enabled) ? NOERROR : S_FALSE
*/
STDMETHODIMP CTxtEdit::BeginEditCollection ()
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::BeginEditCollection");
return E_NOTIMPL;
}
/*
* ITextDocument::EndEditCollection()
*
* @mfunc
* Method that turns off undo grouping
*
* @rdesc
* HRESULT = NOERROR
*/
STDMETHODIMP CTxtEdit::EndEditCollection ()
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::EndEditCollection");
return E_NOTIMPL;
}
/*
* ITextDocument::Freeze(long *pValue)
*
* @mfunc
* Method to increment the freeze count. If this count is nonzero,
* screen updating is disabled. This allows a sequence of editing
* operations to be performed without the performance loss and
* flicker of screen updating. See Unfreeze() to decrement the
* freeze count.
*
* @rdesc
* HRESULT = (screen updating disabled) ? NOERROR : S_FALSE
*
* @devnote
* The ifdef'd code works in principle (need to add _cFreeze to
* _edit.h), but we don't enable it pending dealing with APIs like
* EM_LINEFROMCHAR that don't yet know how to react to a frozen display.
*/
STDMETHODIMP CTxtEdit::Freeze (
long *pCount) //@parm Out parm to receive updated freeze count
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::Freeze");
#ifdef FUTURE
if(_pdp)
{
_pdp->Freeze();
if(_pdp->IsFrozen())
_cFreeze++;
else
_cFreeze = 0;
}
if(pCount)
*pCount = _cFreeze;
return _cFreeze ? NOERROR : S_FALSE;
#endif
return E_NOTIMPL;
}
/*
* ITextDocument::GetDefaultTabStop (pValue)
*
* @mfunc
* Property get method that gets the default tab stop to be
* used whenever the explicit tabs don't extend far enough.
*
* @rdesc
* HRESULT = (!pValue) ? E_INVALIDARG : NOERROR
*/
STDMETHODIMP CTxtEdit::GetDefaultTabStop (
float * pValue) //@parm Out parm to receive default tab stop
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetDefaultTabStop");
if(!pValue)
return E_INVALIDARG;
const LONG lTab = GetDefaultTab();
*pValue = TWIPS_TO_FPPTS(lTab);
return NOERROR;
}
/*
* CTxtEdit::GetName (pName)
*
* @mfunc
* Retrieve ITextDocument filename
*
* @rdesc
* HRESULT = (!<p pName>) ? E_INVALIDARG :
* (no name) ? S_FALSE :
* (if not enough RAM) ? E_OUTOFMEMORY : NOERROR
*/
STDMETHODIMP CTxtEdit::GetName (
BSTR * pName) //@parm Out parm to receive filename
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetName");
if(!pName)
return E_INVALIDARG;
*pName = NULL;
if(!_pDocInfo || !_pDocInfo->pName)
return S_FALSE;
*pName = pSysAllocString(_pDocInfo->pName);
return *pName ? NOERROR : E_OUTOFMEMORY;
}
/*
* ITextDocument::GetSaved (pValue)
*
* @mfunc
* Property get method that gets whether this instance has been
* saved, i.e., no changes since last save
*
* @rdesc
* HRESULT = (!pValue) ? E_INVALIDARG : NOERROR
*
* @comm
* Next time to aid C/C++ clients, we ought to make pValue optional
* and return S_FALSE if doc isn't saved, i.e., like our other
* boolean properties (see, e.g., ITextRange::IsEqual())
*/
STDMETHODIMP CTxtEdit::GetSaved (
long * pValue) //@parm Out parm to receive Saved property
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetSaved");
if(!pValue)
return E_INVALIDARG;
*pValue = _fSaved ? tomTrue : tomFalse;
return NOERROR;
}
/*
* ITextDocument::GetSelection (ITextSelection **ppSel)
*
* @mfunc
* Property get method that gets the active selection.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -