2263 lines
53 KiB
C++
2263 lines
53 KiB
C++
|
/*
|
||
|
* @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. Implement Begin/EndEditCollection
|
||
|
*
|
||
|
* Copyright (c) 1995-2000, Microsoft Corporation. All rights reserved.
|
||
|
*/
|
||
|
|
||
|
#include "_common.h"
|
||
|
#include "_range.h"
|
||
|
#include "_edit.h"
|
||
|
#include "_disp.h"
|
||
|
#include "_rtfconv.h"
|
||
|
#include "_select.h"
|
||
|
#include "_font.h"
|
||
|
#include "_tomfmt.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;
|
||
|
|
||
|
BYTE szUTF8BOM[] = {0xEF, 0xBB, 0xBF}; // UTF-8 for 0xFEFF
|
||
|
|
||
|
//------------------------ 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...
|
||
|
WCHAR szModulePath[MAX_PATH];
|
||
|
|
||
|
|
||
|
|
||
|
if(g_pTypeInfoDoc) // Type info ptrs already valid
|
||
|
return NOERROR;
|
||
|
|
||
|
if(g_hrGetTypeInfo != NOERROR) // Tried to get before and failed
|
||
|
return g_hrGetTypeInfo;
|
||
|
|
||
|
// Obtain the path to this module's executable file
|
||
|
if (W32->GetModuleFileName(hinstRE, szModulePath, MAX_PATH))
|
||
|
{
|
||
|
// Provide the full-path name so LoadTypeLib will not register
|
||
|
// the type library
|
||
|
hr = LoadTypeLib(szModulePath, &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(hfile, pbBuffer, cb, pcb)
|
||
|
*
|
||
|
* @func
|
||
|
* Callback function for converting a file into an editstream for
|
||
|
* input.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* (DWORD)HRESULT
|
||
|
*/
|
||
|
DWORD CALLBACK MyRead(DWORD_PTR hfile, BYTE *pbBuffer, long cb, long *pcb)
|
||
|
{
|
||
|
if(!hfile) // No handle defined
|
||
|
return (DWORD)E_FAIL;
|
||
|
|
||
|
Assert(pcb);
|
||
|
*pcb = 0;
|
||
|
|
||
|
if(!ReadFile((HANDLE)hfile, (void *)pbBuffer, (DWORD)cb, (DWORD *)pcb, NULL))
|
||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||
|
|
||
|
return (DWORD)NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* MyWrite(hfile, pbBuffer, cb, pcb)
|
||
|
*
|
||
|
* @func
|
||
|
* Callback function for converting a file into an editstream for
|
||
|
* output.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* (DWORD)HRESULT
|
||
|
*/
|
||
|
DWORD CALLBACK MyWrite(DWORD_PTR hfile, BYTE *pbBuffer, long cb, long *pcb)
|
||
|
{
|
||
|
if(!hfile) // No handle defined
|
||
|
return (DWORD)E_FAIL;
|
||
|
|
||
|
Assert(pcb);
|
||
|
*pcb = 0;
|
||
|
|
||
|
if(!WriteFile((HANDLE)hfile, (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
|
||
|
*
|
||
|
* @todo
|
||
|
* What about 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");
|
||
|
|
||
|
CCallMgr callmgr(this);
|
||
|
|
||
|
if(_pdp)
|
||
|
{
|
||
|
CCallMgr callmgr(this);
|
||
|
|
||
|
_pdp->Freeze();
|
||
|
if(_pdp->IsFrozen())
|
||
|
_cFreeze++;
|
||
|
else
|
||
|
_cFreeze = 0;
|
||
|
}
|
||
|
|
||
|
if(pCount)
|
||
|
*pCount = _cFreeze;
|
||
|
|
||
|
return _cFreeze ? NOERROR : S_FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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 = SysAllocString(_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.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (!ppSel) ? E_INVALIDARG :
|
||
|
* (if active selection exists) ? NOERROR : S_FALSE
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetSelection (
|
||
|
ITextSelection **ppSel) //@parm Out parm to receive selection pointer
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetSelection");
|
||
|
|
||
|
if(!ppSel)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
CTxtSelection *psel = GetSel();
|
||
|
|
||
|
*ppSel = (ITextSelection *)psel;
|
||
|
|
||
|
if( psel )
|
||
|
{
|
||
|
(*ppSel)->AddRef();
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::GetStoryCount(pCount)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Get count of stories in this document.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (!<p pCount>) ? E_INVALIDARG : NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetStoryCount (
|
||
|
LONG *pCount) //@parm Out parm to receive count of stories
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetStoryCount");
|
||
|
|
||
|
if(!pCount)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*pCount = 1;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::GetStoryRanges(ITextStoryRanges **ppStories)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Property get method that gets the story collection object
|
||
|
* used to enumerate the stories in a document. Only invoke this
|
||
|
* method if GetStoryCount() returns a value greater than one.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (if Stories collection exists) ? NOERROR : E_NOTIMPL
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetStoryRanges (
|
||
|
ITextStoryRanges **ppStories) //@parm Out parm to receive stories ptr
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetStoryRanges");
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::New()
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method that closes the current document and opens a document
|
||
|
* with a default name. If changes have been made in the current
|
||
|
* document since the last save and document file information exists,
|
||
|
* the current document is saved.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::New ()
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::New");
|
||
|
|
||
|
CloseFile(TRUE); // Save and close file
|
||
|
return SetText(NULL, 0, CP_ULE);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::Open(pVar, Flags, CodePage)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method that opens the document specified by pVar.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (if success) ? NOERROR : E_OUTOFMEMORY
|
||
|
*
|
||
|
* @future
|
||
|
* Handle IStream
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::Open (
|
||
|
VARIANT * pVar, //@parm Filename or IStream
|
||
|
long Flags, //@parm Read/write, create, and share flags
|
||
|
long CodePage) //@parm Code page to use
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::Open");
|
||
|
|
||
|
LONG cb; // Byte count for RTF check
|
||
|
EDITSTREAM es = {0, NOERROR, MyRead};
|
||
|
BOOL fReplaceSel = Flags & tomPasteFile;
|
||
|
HCURSOR hcur;
|
||
|
LRESULT lres;
|
||
|
TCHAR szType[10];
|
||
|
|
||
|
if(!pVar || CodePage && !IsUnicodeCP(CodePage) && !IsValidCodePage(CodePage))
|
||
|
return E_INVALIDARG; // IsValidCodePage(0) fails
|
||
|
// even tho CP_ACP = 0 (!)
|
||
|
if((Flags & 0xF) >= tomHTML) // RichEdit only handles auto,
|
||
|
return E_NOTIMPL; // plain text, & RTF formats
|
||
|
|
||
|
if(!fReplaceSel) // If not replacing selection,
|
||
|
New(); // save current file and
|
||
|
// delete current text
|
||
|
CDocInfo * pDocInfo = GetDocInfo();
|
||
|
if(!pDocInfo)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
pDocInfo->_wFlags = (WORD)(Flags & ~0xf0); // Save flags (w/o creation)
|
||
|
|
||
|
// Process access, share, and create flags
|
||
|
DWORD dwAccess = (Flags & tomReadOnly)
|
||
|
? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE);
|
||
|
|
||
|
DWORD dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||
|
if(Flags & tomShareDenyRead)
|
||
|
dwShare &= ~FILE_SHARE_READ;
|
||
|
|
||
|
if(Flags & tomShareDenyWrite)
|
||
|
dwShare &= ~FILE_SHARE_WRITE;
|
||
|
|
||
|
DWORD dwCreate = (Flags >> 4) & 0xf;
|
||
|
if(!dwCreate) // Flags nibble 2 must contain
|
||
|
dwCreate = OPEN_ALWAYS; // CreateFile's dwCreate
|
||
|
|
||
|
if(pVar->vt == VT_BSTR && SysStringLen(pVar->bstrVal))
|
||
|
{
|
||
|
es.dwCookie = (DWORD_PTR)CreateFile(pVar->bstrVal, dwAccess, dwShare,
|
||
|
NULL, dwCreate, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
if((HANDLE)es.dwCookie == INVALID_HANDLE_VALUE)
|
||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||
|
|
||
|
if(!fReplaceSel) // If not replacing selection,
|
||
|
{ // allocate new pName
|
||
|
pDocInfo->_pName = SysAllocString(pVar->bstrVal);
|
||
|
if (!pDocInfo->_pName)
|
||
|
return E_OUTOFMEMORY;
|
||
|
pDocInfo->_hFile = (HANDLE)es.dwCookie;
|
||
|
pDocInfo->_wFlags |= tomTruncateExisting; // Setup Saves
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// FUTURE: check for IStream; if not, then fail
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
Flags &= 0xf; // Isolate conversion flags
|
||
|
|
||
|
// Get first few bytes of file to check for RTF and Unicode BOM
|
||
|
(*es.pfnCallback)(es.dwCookie, (LPBYTE)szType, 10, &cb);
|
||
|
|
||
|
Flags = (!Flags || Flags == tomRTF) && IsRTF((char *)szType, cb)
|
||
|
? tomRTF : tomText;
|
||
|
|
||
|
LONG j = 0; // Default rewind to 0
|
||
|
if (Flags == tomRTF) // RTF
|
||
|
Flags = SF_RTF; // Setup EM_STREAMIN for RTF
|
||
|
else
|
||
|
{ // If it starts with
|
||
|
Flags = SF_TEXT; // Setup EM_STREAMIN for text
|
||
|
if(cb > 1 && *(WORD *)szType == BOM) // Unicode byte-order mark
|
||
|
{ // (BOM) file is Unicode, so
|
||
|
Flags = SF_TEXT | SF_UNICODE; // use Unicode code page and
|
||
|
j = 2; // bypass the BOM
|
||
|
}
|
||
|
else if(cb > 1 && *(WORD *)szType == RBOM)// Big Endian BOM
|
||
|
{ // BOM
|
||
|
Flags = SF_TEXT | SF_USECODEPAGE | (CP_UBE << 16);
|
||
|
j = 2; // Bypass the BOM
|
||
|
}
|
||
|
else if(cb > 2 && W32->IsUTF8BOM((BYTE *)szType))
|
||
|
{
|
||
|
Flags = SF_TEXT | SF_USECODEPAGE | (CP_UTF8 << 16);
|
||
|
j = 3;
|
||
|
}
|
||
|
else if(CodePage == CP_ULE)
|
||
|
Flags = SF_TEXT | SF_UNICODE;
|
||
|
|
||
|
else if(CodePage)
|
||
|
Flags = SF_TEXT | SF_USECODEPAGE | (CodePage << 16);
|
||
|
}
|
||
|
|
||
|
SetFilePointer((HANDLE)es.dwCookie, j, NULL, FILE_BEGIN); // Rewind
|
||
|
|
||
|
if(fReplaceSel)
|
||
|
Flags |= SFF_SELECTION;
|
||
|
|
||
|
Flags |= SFF_KEEPDOCINFO;
|
||
|
|
||
|
hcur = TxSetCursor(LoadCursor(NULL, IDC_WAIT));
|
||
|
TxSendMessage(EM_STREAMIN, Flags, (LPARAM)&es, &lres);
|
||
|
TxSetCursor(hcur);
|
||
|
|
||
|
if(dwShare == (FILE_SHARE_READ | FILE_SHARE_WRITE) || fReplaceSel)
|
||
|
{ // Full sharing or replaced
|
||
|
CloseHandle((HANDLE)es.dwCookie); // selection, so close file
|
||
|
if(!fReplaceSel) // If replacing selection,
|
||
|
pDocInfo->_hFile = NULL; // leave _pDocInfo->_hFile
|
||
|
}
|
||
|
_fSaved = fReplaceSel ? FALSE : TRUE; // No changes yet unless
|
||
|
return (HRESULT)es.dwError;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::Range(long cpFirst, long cpLim, ITextRange **ppRange)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method that gets a text range on the active story of the document
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (!ppRange) ? E_INVALIDARG :
|
||
|
* (if success) ? NOERROR : E_OUTOFMEMORY
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::Range (
|
||
|
long cpFirst, //@parm Non active end of new range
|
||
|
long cpLim, //@parm Active end of new range
|
||
|
ITextRange ** ppRange) //@parm Out parm to receive range
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::Range");
|
||
|
|
||
|
if(!ppRange)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*ppRange = new CTxtRange(this, cpFirst, cpFirst - cpLim);
|
||
|
|
||
|
if( *ppRange )
|
||
|
{
|
||
|
(*ppRange)->AddRef(); // CTxtRange() doesn't AddRef() because
|
||
|
return NOERROR; // it's used internally for things
|
||
|
} // besides TOM
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::RangeFromPoint(long x, long y, ITextRange **ppRange)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method that gets the degenerate range corresponding (at or nearest)
|
||
|
* to the point with the screen coordinates x and y.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (!ppRange) ? E_INVALIDARG :
|
||
|
* (if out of RAM) ? E_OUTOFMEMORY :
|
||
|
* (if range exists) ? NOERROR : S_FALSE
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::RangeFromPoint (
|
||
|
long x, //@parm Horizontal coord of point to use
|
||
|
long y, //@parm Vertical coord of point to use
|
||
|
ITextRange **ppRange) //@parm Out parm to receive range
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::RangeFromPoint");
|
||
|
|
||
|
if(!ppRange)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*ppRange = (ITextRange *) new CTxtRange(this, 0, 0);
|
||
|
|
||
|
if(!*ppRange)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
(*ppRange)->AddRef(); // CTxtRange() doesn't AddRef()
|
||
|
return (*ppRange)->SetPoint(x, y, 0, 0);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::Redo(long Count, long *pCount)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to perform the redo operation Count times
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (if Count redos performed) ? NOERROR : S_FALSE
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::Redo (
|
||
|
long Count, //@parm Number of redo operations to perform
|
||
|
long * pCount) //@parm Number of redo operations performed
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::Redo");
|
||
|
CCallMgr callmgr(this);
|
||
|
|
||
|
LONG i = 0;
|
||
|
|
||
|
// Freeze the display during the execution of the anti-events
|
||
|
CFreezeDisplay fd(_pdp);
|
||
|
HRESULT hr = NOERROR;
|
||
|
|
||
|
for ( ; i < Count; i++) // loop does nothing
|
||
|
{
|
||
|
hr = PopAndExecuteAntiEvent(_predo, 0);
|
||
|
if(hr != NOERROR)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(pCount)
|
||
|
*pCount = i;
|
||
|
|
||
|
return hr == NOERROR && i != Count ? S_FALSE : hr;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::Save(pVar, Flags, CodePage)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method that saves this ITextDocument to the target pVar,
|
||
|
* which is a VARIANT that can be a filename, an IStream, or NULL. If
|
||
|
* NULL, the filename given by this document's name is used. It that,
|
||
|
* in turn, is NULL, the method fails. If pVar specifies a filename,
|
||
|
* that name should replace the current Name property.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (!pVar) ? E_INVALIDARG :
|
||
|
* (if success) ? NOERROR : E_FAIL
|
||
|
*
|
||
|
* @devnote
|
||
|
* This routine can be called with NULL arguments
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::Save (
|
||
|
VARIANT * pVar, //@parm Save target (filename or IStream)
|
||
|
long Flags, //@parm Read/write, create, and share flags
|
||
|
long CodePage) //@parm Code page to use
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::Save");
|
||
|
|
||
|
LONG cb; // Byte count for writing Unicode BOM
|
||
|
EDITSTREAM es = {0, NOERROR, MyWrite};
|
||
|
BOOL fChange = FALSE; // No doc info change yet
|
||
|
HCURSOR hcur;
|
||
|
CDocInfo * pDocInfo = GetDocInfo();
|
||
|
|
||
|
if(CodePage && !IsUnicodeCP(CodePage) && !IsValidCodePage(CodePage) ||
|
||
|
(DWORD)Flags > 0x1fff || Flags & tomReadOnly)
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
if((Flags & 0xf) >= tomHTML) // RichEdit only handles auto,
|
||
|
return E_NOTIMPL; // plain text, & RTF formats
|
||
|
|
||
|
if(!pDocInfo) // Doc info doesn't exist
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
if (pVar && pVar->vt == VT_BSTR && // Filename string
|
||
|
pVar->bstrVal &&
|
||
|
SysStringLen(pVar->bstrVal) && // NonNULL filename specified
|
||
|
(!pDocInfo->_pName ||
|
||
|
OLEstrcmp(pVar->bstrVal, pDocInfo->_pName)))
|
||
|
{ // Filename differs
|
||
|
fChange = TRUE; // Force write to new file
|
||
|
CloseFile(FALSE); // Close current file; no save
|
||
|
pDocInfo->_pName = SysAllocString(pVar->bstrVal);
|
||
|
if(!pDocInfo->_pName)
|
||
|
return E_OUTOFMEMORY;
|
||
|
pDocInfo->_wFlags &= ~0xf0; // Kill previous create mode
|
||
|
}
|
||
|
|
||
|
DWORD flags = pDocInfo->_wFlags;
|
||
|
if(!(Flags & 0xF)) // If convert flags are 0,
|
||
|
Flags |= flags & 0xF; // use values in doc info
|
||
|
if(!(Flags & 0xF0)) // If create flags are 0,
|
||
|
Flags |= flags & 0xF0; // use values in doc info
|
||
|
if(!(Flags & 0xF00)) // If share flags are 0,
|
||
|
Flags |= flags & 0xF00; // use values in doc info
|
||
|
if(!CodePage) // If code page is 0,
|
||
|
CodePage = pDocInfo->_wCpg; // use code page in doc info
|
||
|
|
||
|
if((DWORD)Flags != flags || // If flags or code page
|
||
|
(WORD)CodePage != pDocInfo->_wCpg) // changed, force write
|
||
|
{
|
||
|
fChange = TRUE;
|
||
|
}
|
||
|
pDocInfo->_wFlags = (WORD)Flags; // Save flags
|
||
|
|
||
|
// Yikes, nowhere to save. bail-out now
|
||
|
if(!_pDocInfo->_pName)
|
||
|
return E_FAIL;
|
||
|
|
||
|
if(_fSaved && !fChange) // No changes, so assume
|
||
|
return NOERROR; // saved file is up to date
|
||
|
|
||
|
DWORD dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||
|
if(Flags & tomShareDenyRead)
|
||
|
dwShare &= ~FILE_SHARE_READ;
|
||
|
|
||
|
if(Flags & tomShareDenyWrite)
|
||
|
dwShare &= ~FILE_SHARE_WRITE;
|
||
|
|
||
|
DWORD dwCreate = (Flags >> 4) & 0xF;
|
||
|
if(!dwCreate)
|
||
|
dwCreate = CREATE_NEW;
|
||
|
|
||
|
if(pDocInfo->_hFile)
|
||
|
{
|
||
|
CloseHandle(pDocInfo->_hFile); // Close current file handle
|
||
|
pDocInfo->_hFile = NULL;
|
||
|
}
|
||
|
|
||
|
es.dwCookie = (DWORD_PTR)CreateFile(pDocInfo->_pName, GENERIC_READ | GENERIC_WRITE, dwShare, NULL,
|
||
|
dwCreate, FILE_ATTRIBUTE_NORMAL, NULL);
|
||
|
if((HANDLE)es.dwCookie == INVALID_HANDLE_VALUE)
|
||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||
|
|
||
|
pDocInfo->_hFile = (HANDLE)es.dwCookie;
|
||
|
|
||
|
Flags &= 0xF; // Isolate conversion flags
|
||
|
if(Flags == tomRTF) // RTF
|
||
|
Flags = SF_RTF; // Setup EM_STREAMOUT for RTF
|
||
|
else
|
||
|
{
|
||
|
Flags = SF_TEXT; // Setup EM_STREAMOUT for text
|
||
|
if(IsUnicodeCP(CodePage) || CodePage == CP_UTF8)
|
||
|
{ // If Unicode, start file with
|
||
|
LONG j = 2; // Unicode byte order mark
|
||
|
WORD wBOM = BOM;
|
||
|
WORD wRBOM = RBOM;
|
||
|
BYTE *pb = (BYTE *)&wRBOM; // Default Big Endian Unicode
|
||
|
|
||
|
if(CodePage == CP_UTF8)
|
||
|
{
|
||
|
j = 3;
|
||
|
pb = szUTF8BOM;
|
||
|
}
|
||
|
else if(CodePage == CP_ULE) // Little Endian Unicode
|
||
|
{
|
||
|
Flags = SF_TEXT | SF_UNICODE;
|
||
|
pb = (BYTE *)&wBOM;
|
||
|
}
|
||
|
(*es.pfnCallback)(es.dwCookie, pb, j, &cb);
|
||
|
}
|
||
|
}
|
||
|
if(CodePage && CodePage != CP_ULE)
|
||
|
Flags |= SF_USECODEPAGE | (CodePage << 16);
|
||
|
|
||
|
hcur = TxSetCursor(LoadCursor(NULL, IDC_WAIT));
|
||
|
TxSendMessage(EM_STREAMOUT, Flags, (LPARAM)&es, NULL);
|
||
|
TxSetCursor(hcur);
|
||
|
|
||
|
if(dwShare == (FILE_SHARE_READ | FILE_SHARE_WRITE))
|
||
|
{ // Full sharing, so close
|
||
|
CloseHandle(pDocInfo->_hFile); // current file handle
|
||
|
pDocInfo->_hFile = NULL;
|
||
|
}
|
||
|
_fSaved = TRUE; // File is saved
|
||
|
return (HRESULT)es.dwError;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::SetDefaultTabStop (Value)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Property set method that sets the default tab stop to be
|
||
|
* used whenever the explicit tabs don't extend far enough.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (Value < 0) ? E_INVALIDARG : NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::SetDefaultTabStop (
|
||
|
float Value) //@parm Out parm to receive default tab stop
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::SetDefaultTabStop");
|
||
|
|
||
|
if(Value <= 0)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
|
||
|
if(!pDocInfo) // Doc info doesn't exist
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
pDocInfo->_dwDefaultTabStop = FPPTS_TO_TWIPS(Value);
|
||
|
|
||
|
_pdp->UpdateView();
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::SetSaved (Value)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Property set method that sets whether this instance has been
|
||
|
* saved, i.e., no changes since last save
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::SetSaved (
|
||
|
long Value) //@parm New value of Saved property
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::SetSaved");
|
||
|
|
||
|
_fSaved = Value ? TRUE : FALSE;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::Undo(Count, *pCount)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to perform the undo operation Count times or to control
|
||
|
* the nature of undo processing. Count = 0 stops undo processing
|
||
|
* and discards any saved undo states. Count = -1 turns on undo
|
||
|
* processing with the default undo limit. Count = tomSuspend
|
||
|
* suspends undo processing, but doesn't discard saved undo states,
|
||
|
* and Count = tomResume resumes undo processing with the undo states
|
||
|
* active when Count = tomSuspend was given.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (if Count undos performed) ? NOERROR : S_FALSE
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::Undo (
|
||
|
long Count, //@parm Count of undo operations to perform
|
||
|
// 0 stops undo processing
|
||
|
// -1 turns restores it
|
||
|
long * pCount) //@parm Number of undo operations performed
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::Undo");
|
||
|
CCallMgr callmgr(this);
|
||
|
|
||
|
LONG i = 0;
|
||
|
|
||
|
// Freeze display during execution of anti-events
|
||
|
CFreezeDisplay fd(_pdp);
|
||
|
HRESULT hr = NOERROR;
|
||
|
// Note: for Count <= 0,
|
||
|
for ( ; i < Count; i++) // loop does nothing
|
||
|
{
|
||
|
hr = PopAndExecuteAntiEvent(_pundo, 0);
|
||
|
if(hr != NOERROR)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(pCount)
|
||
|
*pCount = i;
|
||
|
|
||
|
if(Count <= 0)
|
||
|
i = HandleSetUndoLimit(Count);
|
||
|
|
||
|
return hr == NOERROR && i != Count ? S_FALSE : hr;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument::Unfreeze(pCount)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to decrement freeze count. If this count goes to zero,
|
||
|
* screen updating is enabled. This method cannot decrement the
|
||
|
* count below zero.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (screen updating enabled) ? NOERROR : S_FALSE
|
||
|
*
|
||
|
* @devnote
|
||
|
* The display maintains its own private reference count which may
|
||
|
* temporarily exceed the reference count of this method. So even
|
||
|
* if this method indicates that the display is unfrozen, it may be
|
||
|
* for a while longer.
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::Unfreeze (
|
||
|
long *pCount) //@parm Out parm to receive updated freeze count
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::Unfreeze");
|
||
|
|
||
|
CCallMgr callmgr(this);
|
||
|
|
||
|
if(_cFreeze)
|
||
|
{
|
||
|
CCallMgr callmgr(this);
|
||
|
|
||
|
AssertSz(_pdp && _pdp->IsFrozen(),
|
||
|
"CTxtEdit::Unfreeze: screen not frozen but expected to be");
|
||
|
_cFreeze--;
|
||
|
_pdp->Thaw();
|
||
|
}
|
||
|
|
||
|
if(pCount)
|
||
|
*pCount = _cFreeze;
|
||
|
|
||
|
return _cFreeze ? S_FALSE : NOERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
//----------------------- ITextDocument2 Methods -----------------------
|
||
|
/*
|
||
|
* ITextDocument2::AttachMsgFilter(pFilter)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to attach a new message filter to the edit instance.
|
||
|
* All window messages received by the edit instance will be forwarded
|
||
|
* to the message filter. The message filter must be bound to the document
|
||
|
* before it can be used (Refer to the ITextMessageFilter API).
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = filter succesfully attached ? NOERROR : QI failure.
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::AttachMsgFilter (
|
||
|
IUnknown *pFilter) //@parm the IUnknown for the new message filter
|
||
|
{
|
||
|
ITextMsgFilter *pMsgFilter = NULL;
|
||
|
|
||
|
HRESULT hr = pFilter->QueryInterface(IID_ITextMsgFilter, (void **)&pMsgFilter);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
if (_pMsgFilter)
|
||
|
_pMsgFilter->AttachMsgFilter(pMsgFilter);
|
||
|
else
|
||
|
_pMsgFilter = pMsgFilter;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetEffectColor(Index, pcr)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to retrieve the COLORREF color used in special attribute
|
||
|
* displays. The first 15 values are for special underline colors 1 - 15.
|
||
|
* Later we may define indices for other effects, e.g., URLs, strikeout.
|
||
|
* If an index between 1 and 15 hasn't been defined by an appropriate
|
||
|
* call to ITextDocument2:SetEffectColor(), the corresponding WORD
|
||
|
* default color value given by g_Colors[] is returned.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (valid active color index)
|
||
|
* ? NOERROR : E_INVALIDARG
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetEffectColor(
|
||
|
long Index, //@parm Which special color to get
|
||
|
COLORREF *pcr) //@parm Out parm for color
|
||
|
{
|
||
|
if(!pcr)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if(!IN_RANGE(1, Index, 15))
|
||
|
{
|
||
|
*pcr = (COLORREF)tomUndefined;
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
*pcr = g_Colors[Index];
|
||
|
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
if(!pDocInfo)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
Index--;
|
||
|
if (Index < pDocInfo->_cColor &&
|
||
|
pDocInfo->_prgColor[Index] != (COLORREF)tomUndefined)
|
||
|
{
|
||
|
*pcr = pDocInfo->_prgColor[Index];
|
||
|
}
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::SetEffectColor(Index, cr)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to save the Index'th special document color. Indices
|
||
|
* 1 - 15 are defined for underlining. Later we may define
|
||
|
* indices for other effects, e.g., URLs, strikeout.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (valid index)
|
||
|
* ? NOERROR : E_INVALIDARG
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::SetEffectColor(
|
||
|
long Index, //@parm Which special color to set
|
||
|
COLORREF cr) //@parm Color to use
|
||
|
{
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
if(!pDocInfo)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
Index--;
|
||
|
if(!IN_RANGE(0, Index, 14))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if(Index >= pDocInfo->_cColor)
|
||
|
{
|
||
|
LONG cColor = (Index + 4) & ~3; // Round up to 4
|
||
|
COLORREF *prgColor = (COLORREF *)PvReAlloc(pDocInfo->_prgColor,
|
||
|
cColor*sizeof(COLORREF));
|
||
|
if(!prgColor)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
for(LONG i = pDocInfo->_cColor; i < cColor; i++)
|
||
|
prgColor[i] = (COLORREF)tomUndefined;
|
||
|
|
||
|
pDocInfo->_cColor = (char)cColor;
|
||
|
pDocInfo->_prgColor = prgColor;
|
||
|
}
|
||
|
pDocInfo->_prgColor[Index] = cr;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::SetCaretType(CaretType)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to sllow programmatic control over the caret type.
|
||
|
* The form of the control is TBD as is its interaction with
|
||
|
* existing formatting (e.g. font size and italics).
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = caret type is one we understand ? NOERROR : E_INVALIDARG
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::SetCaretType(
|
||
|
long CaretType) //@parm specification of caret type to use
|
||
|
{
|
||
|
// For now, just care about Korean block craet.
|
||
|
if (CaretType == tomKoreanBlockCaret)
|
||
|
_fKoreanBlockCaret = TRUE;
|
||
|
else if (CaretType == tomNormalCaret)
|
||
|
_fKoreanBlockCaret = FALSE;
|
||
|
else
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if (_psel && _psel->IsCaretShown() && _fFocus)
|
||
|
{
|
||
|
_psel->CreateCaret();
|
||
|
TxShowCaret(TRUE);
|
||
|
}
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetCaretType(pCaretType)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to retrieve the previously set caret type.
|
||
|
* TBD. Can one get it without setting it?
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = caret info OK ? NOERROR : E_INVALIDARG
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetCaretType(
|
||
|
long *pCaretType) //@parm current caret type specification
|
||
|
{
|
||
|
if (!pCaretType)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*pCaretType = _fKoreanBlockCaret ? tomKoreanBlockCaret : tomNormalCaret;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetImmContext(pContext)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to retrieve the IMM context from our host.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = ImmContext available ? NOERROR : E_INVALIDARG
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetImmContext(
|
||
|
long *pContext) //@parm Imm context
|
||
|
{
|
||
|
if (!pContext)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*pContext = 0;
|
||
|
|
||
|
if (!_fInOurHost)
|
||
|
{
|
||
|
// ask host for Imm Context
|
||
|
HIMC hIMC = TxImmGetContext();
|
||
|
|
||
|
*pContext = (long) hIMC;
|
||
|
}
|
||
|
|
||
|
return *pContext ? NOERROR : S_FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::ReleaseImmContext(Context)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to release the IMM context.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = ImmContext available ? NOERROR : E_INVALIDARG
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::ReleaseImmContext(
|
||
|
long Context) //@parm Imm context to be release
|
||
|
{
|
||
|
if (!_fInOurHost)
|
||
|
{
|
||
|
// ask host to release Imm Context
|
||
|
TxImmReleaseContext((HIMC)Context);
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetPreferredFont(cp, lCodePage, lOption, lCurCodePage, lCurFontSize,
|
||
|
* ,pFontName, pPitchAndFamily, pNewFontSize)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to retrieve the preferred font name and pitch and family at a
|
||
|
* given cp and codepage.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = FontName available ? NOERROR : E_INVALIDARG
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetPreferredFont(
|
||
|
long cp, //@parm cp
|
||
|
long lCodepage, //@parm codepage preferred
|
||
|
long lOption, //@parm option for matching current font
|
||
|
long lCurCodePage, //@parm current codepage
|
||
|
long lCurFontSize, //@parm current font size
|
||
|
BSTR *pFontName, //@parm preferred fontname
|
||
|
long *pPitchAndFamily, //@parm pitch and family
|
||
|
long *plNewFontSize) //@parm new font size preferred
|
||
|
{
|
||
|
if (!pFontName || !IN_RANGE(IGNORE_CURRENT_FONT, lOption, MATCH_FONT_SIG))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
if (!IsAutoFont()) // EXIT if auto font is turned off
|
||
|
return S_FALSE;
|
||
|
|
||
|
CRchTxtPtr rtp(this, 0);
|
||
|
CCFRunPtr rp(rtp);
|
||
|
short iFont;
|
||
|
short yHeight;
|
||
|
BYTE bPitchAndFamily;
|
||
|
BYTE iCharRep = CharRepFromCodePage(lCodepage);
|
||
|
|
||
|
rp.Move(cp);
|
||
|
if (rp.GetPreferredFontInfo(
|
||
|
iCharRep,
|
||
|
iCharRep,
|
||
|
iFont,
|
||
|
yHeight,
|
||
|
bPitchAndFamily,
|
||
|
-1,
|
||
|
lOption))
|
||
|
{
|
||
|
if (*pFontName)
|
||
|
wcscpy(*pFontName, GetFontName((LONG)iFont));
|
||
|
else
|
||
|
{
|
||
|
*pFontName = SysAllocString(GetFontName((LONG)iFont));
|
||
|
if (!*pFontName)
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
if (pPitchAndFamily)
|
||
|
*pPitchAndFamily = bPitchAndFamily;
|
||
|
|
||
|
// Calc the new font size if needed
|
||
|
if (plNewFontSize)
|
||
|
{
|
||
|
*plNewFontSize = lCurFontSize;
|
||
|
if (_fAutoFontSizeAdjust && lCodepage != lCurCodePage)
|
||
|
*plNewFontSize = yHeight / TWIPS_PER_POINT; // Set the preferred size
|
||
|
}
|
||
|
return S_OK;
|
||
|
}
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetNotificationMode( long *plMode )
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to retrieve the current notification mode.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = notification mode available ? NOERROR : E_INVALIDARG
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetNotificationMode(
|
||
|
long *plMode) //@parm current notification mode
|
||
|
{
|
||
|
if (!plMode)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*plMode = _fSuppressNotify ? tomFalse : tomTrue;
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::SetNotificationMode(lMode)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to set the current notification mode.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = notification mode set ? NOERROR : E_INVALIDARG
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::SetNotificationMode(
|
||
|
long lMode) //@parm new notification mode
|
||
|
{
|
||
|
if (lMode == tomFalse)
|
||
|
_fSuppressNotify = 1;
|
||
|
else if (lMode == tomTrue)
|
||
|
_fSuppressNotify = 0;
|
||
|
else
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetClientRect(Type, pLeft, pTop,pRight, pBottom )
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to retrieve the client rect and inset adjustment.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = notification mode set ? NOERROR : E_INVALIDARG
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetClientRect(
|
||
|
long Type, //@parm option
|
||
|
long *pLeft, //@parm left
|
||
|
long *pTop, //@parm top
|
||
|
long *pRight, //@parm right
|
||
|
long *pBottom) //@parm bottom
|
||
|
{
|
||
|
if (!pLeft || !pTop || !pRight || !pBottom)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
RECT rcArea;
|
||
|
TxGetClientRect(&rcArea);
|
||
|
|
||
|
if ( Type & tomIncludeInset )
|
||
|
{
|
||
|
// Ajdust veiw inset
|
||
|
RECTUV rcInset;
|
||
|
TxGetViewInset( &rcInset, NULL );
|
||
|
rcArea.right -= rcInset.right;
|
||
|
rcArea.bottom -= rcInset.bottom;
|
||
|
rcArea.left += rcInset.left;
|
||
|
rcArea.top += rcInset.top;
|
||
|
}
|
||
|
|
||
|
// Caller wants screen coordinates?
|
||
|
if ( !(Type & tomClientCoord) )
|
||
|
{
|
||
|
POINT ptTopLeft = {rcArea.left, rcArea.top};
|
||
|
POINT ptBottomRight = {rcArea.right, rcArea.bottom};
|
||
|
|
||
|
if (!TxClientToScreen(&ptTopLeft) ||
|
||
|
!TxClientToScreen(&ptBottomRight))
|
||
|
return E_FAIL; // It is unexpected for this to happen
|
||
|
|
||
|
*pLeft = ptTopLeft.x;
|
||
|
*pTop = ptTopLeft.y;
|
||
|
*pRight = ptBottomRight.x;
|
||
|
*pBottom = ptBottomRight.y;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*pLeft = rcArea.left;
|
||
|
*pTop = rcArea.top;
|
||
|
*pRight = rcArea.right;
|
||
|
*pBottom = rcArea.bottom;
|
||
|
}
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetSelectionEx(ppSel)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to retrieve selection.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = selection ? NOERROR : S_FALSE
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetSelectionEx(
|
||
|
ITextSelection **ppSel) //@parm Get Selection object
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetSelectionEx");
|
||
|
|
||
|
if (_fInPlaceActive)
|
||
|
return GetSelection (ppSel);
|
||
|
|
||
|
Assert("Getting selection while not active");
|
||
|
|
||
|
if(!ppSel)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*ppSel = NULL;
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetWindow(phWnd)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to get the host window
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR if host return hWnd
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetWindow(
|
||
|
long *phWnd) //@parm hWnd
|
||
|
{
|
||
|
if (!phWnd)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
return TxGetWindow((HWND *)phWnd);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetFEFlags(pFEFlags)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to get Host FE flags
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR if host returns FE Flags
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetFEFlags(
|
||
|
long *pFEFlags) //@parm FE Flags
|
||
|
{
|
||
|
return TxGetFEFlags(pFEFlags);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::UpdateWindow(void)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to update the RE window
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::UpdateWindow(void)
|
||
|
{
|
||
|
TxUpdateWindow();
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::CheckTextLimit(long cch, long *pcch)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to check if the count of characters to be added would
|
||
|
* exceed max. text limit. The number of characters exced is returned
|
||
|
* in pcch
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::CheckTextLimit(
|
||
|
long cch, //@parm count of characters to be added
|
||
|
long *pcch) //@parm return the number of characters exced text limit
|
||
|
{
|
||
|
if(!pcch)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*pcch = 0;
|
||
|
if (cch > 0)
|
||
|
{
|
||
|
DWORD cchNew = (DWORD)(GetAdjustedTextLength() + cch);
|
||
|
if(cchNew > TxGetMaxLength())
|
||
|
*pcch = cchNew - TxGetMaxLength();
|
||
|
}
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::IMEInProgress(lMode)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method for IME message filter to inform client that IME composition
|
||
|
* is in progress.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::IMEInProgress(
|
||
|
long lMode) //@parm current IME composition status
|
||
|
{
|
||
|
if (lMode == tomFalse)
|
||
|
_fIMEInProgress = 0;
|
||
|
else if (lMode == tomTrue)
|
||
|
_fIMEInProgress = 1;
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::SysBeep(void)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method to generate system beep.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::SysBeep(void)
|
||
|
{
|
||
|
Beep();
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::Update(lMode)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method for update the selection or caret. If lMode is tomTrue, then
|
||
|
* scroll the caret into view.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::Update(
|
||
|
long lMode) //@parm current IME composition status
|
||
|
{
|
||
|
if (!_psel)
|
||
|
return S_FALSE;
|
||
|
|
||
|
_psel->Update(lMode == tomTrue ? TRUE : FALSE);
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::Notify(lNotify)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method for notifying the host for certain IME events
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::Notify(
|
||
|
long lNotify) //@parm Notification code
|
||
|
{
|
||
|
TxNotify(lNotify, NULL);
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetDocumentFont(ppITextFont)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method for getting the default document font
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetDocumentFont(
|
||
|
ITextFont **ppFont) //@parm get ITextFont object
|
||
|
{
|
||
|
CTxtFont *pTxtFont;
|
||
|
|
||
|
if(!ppFont)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
pTxtFont = new CTxtFont(NULL);
|
||
|
|
||
|
if (pTxtFont)
|
||
|
{
|
||
|
pTxtFont->_CF = *GetCharFormat(-1);
|
||
|
pTxtFont->_dwMask = CFM_ALL2;
|
||
|
}
|
||
|
|
||
|
*ppFont = (ITextFont *) pTxtFont;
|
||
|
|
||
|
return *ppFont ? NOERROR : E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetDocumentPara(ppITextPara)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method for getting the default document para
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetDocumentPara(
|
||
|
ITextPara **ppPara) //@parm get ITextPara object
|
||
|
{
|
||
|
CTxtPara *pTxtPara;
|
||
|
|
||
|
if(!ppPara)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
pTxtPara = new CTxtPara(NULL);
|
||
|
|
||
|
if (pTxtPara)
|
||
|
{
|
||
|
pTxtPara->_PF = *GetParaFormat(-1);
|
||
|
pTxtPara->_dwMask = PFM_ALL2;
|
||
|
pTxtPara->_PF._bTabCount = 0;
|
||
|
pTxtPara->_PF._iTabs = -1;
|
||
|
}
|
||
|
|
||
|
*ppPara = (ITextPara *) pTxtPara;
|
||
|
return *ppPara ? NOERROR : E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::GetCallManager(ppVoid)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method for getting the call manager
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::GetCallManager(
|
||
|
IUnknown **ppVoid) //@parm get CallMgr object
|
||
|
{
|
||
|
CCallMgr *pCallMgr;
|
||
|
|
||
|
if(!ppVoid)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
pCallMgr = new CCallMgr(this);
|
||
|
|
||
|
*ppVoid = (IUnknown *) pCallMgr;
|
||
|
return *ppVoid ? NOERROR : E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ITextDocument2::ReleaseCallManager(ppITextPara)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method for getting the default document para
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
STDMETHODIMP CTxtEdit::ReleaseCallManager(
|
||
|
IUnknown *pVoid) //@parm Call Manager object
|
||
|
{
|
||
|
CCallMgr *pCallMgr;
|
||
|
|
||
|
if(!pVoid)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
pCallMgr = (CCallMgr *)pVoid;
|
||
|
|
||
|
delete pCallMgr;
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
//----------------------- ITextDocument Helper Functions -----------------------
|
||
|
/*
|
||
|
* CTxtEdit::CloseFile (bSave)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Method that closes the current document. If changes have been made
|
||
|
* in the current document since the last save and document file
|
||
|
* information exists, the current document is saved.
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
HRESULT CTxtEdit::CloseFile (
|
||
|
BOOL bSave)
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::Close");
|
||
|
|
||
|
CDocInfo *pDocInfo = _pDocInfo;
|
||
|
|
||
|
if(pDocInfo)
|
||
|
{
|
||
|
if(bSave) // Save current file if
|
||
|
Save(NULL, 0, 0); // any changes made
|
||
|
|
||
|
// FUTURE(BradO): This code is very similar to the destructor code.
|
||
|
// We have a problem here in that some of the CDocInfo information
|
||
|
// should persist from Open to Close to Open (ex. default tab stop)
|
||
|
// mixed with other per-Open/Close info. A better job of abstracting
|
||
|
// these two types of info would really clean up this code.
|
||
|
|
||
|
if(pDocInfo->_pName)
|
||
|
{
|
||
|
SysFreeString(pDocInfo->_pName); // Free filename BSTR
|
||
|
pDocInfo->_pName = NULL;
|
||
|
}
|
||
|
|
||
|
if(pDocInfo->_hFile)
|
||
|
{
|
||
|
CloseHandle(pDocInfo->_hFile); // Close file if open
|
||
|
pDocInfo->_hFile = NULL;
|
||
|
}
|
||
|
pDocInfo->_wFlags = 0;
|
||
|
pDocInfo->_wCpg = 0;
|
||
|
|
||
|
pDocInfo->_lcid = 0;
|
||
|
pDocInfo->_lcidfe = 0;
|
||
|
|
||
|
if(pDocInfo->_lpstrLeadingPunct)
|
||
|
{
|
||
|
FreePv(pDocInfo->_lpstrLeadingPunct);
|
||
|
pDocInfo->_lpstrLeadingPunct = NULL;
|
||
|
}
|
||
|
|
||
|
if(pDocInfo->_lpstrFollowingPunct)
|
||
|
{
|
||
|
FreePv(pDocInfo->_lpstrFollowingPunct);
|
||
|
pDocInfo->_lpstrFollowingPunct = NULL;
|
||
|
}
|
||
|
}
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::SetDefaultLCID (lcid)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Property set method that sets the default LCID
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*
|
||
|
* @comm
|
||
|
* This property should be part of TOM
|
||
|
*/
|
||
|
HRESULT CTxtEdit::SetDefaultLCID (
|
||
|
LCID lcid) //@parm New default LCID value
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::SetDefaultLCID");
|
||
|
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
|
||
|
if(!pDocInfo) // Doc info doesn't exist
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
pDocInfo->_lcid = lcid;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::GetDefaultLCID (pLCID)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Property get method that gets the default LCID
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (!pLCID) ? E_INVALIDARG : NOERROR
|
||
|
*/
|
||
|
HRESULT CTxtEdit::GetDefaultLCID (
|
||
|
LCID *pLCID) //@parm Out parm with default LCID value
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetDefaultLCID");
|
||
|
|
||
|
if(!pLCID)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
|
||
|
if(!pDocInfo) // Doc info doesn't exist
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
*pLCID = _pDocInfo->_lcid;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::SetDefaultLCIDFE (lcid)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Property set method that sets the default FE LCID
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*
|
||
|
* @comm
|
||
|
* This property should be part of TOM
|
||
|
*/
|
||
|
HRESULT CTxtEdit::SetDefaultLCIDFE (
|
||
|
LCID lcid) //@parm New default LCID value
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::SetDefaultLCIDFE");
|
||
|
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
|
||
|
if(!pDocInfo) // Doc info doesn't exist
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
pDocInfo->_lcidfe = lcid;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::GetDefaultLCIDFE (pLCID)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Property get method that gets the default FE LCID
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (!pLCID) ? E_INVALIDARG : NOERROR
|
||
|
*/
|
||
|
HRESULT CTxtEdit::GetDefaultLCIDFE (
|
||
|
LCID *pLCID) //@parm Out parm with default LCID value
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetDefaultLCID");
|
||
|
|
||
|
if(!pLCID)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
|
||
|
if(!pDocInfo) // Doc info doesn't exist
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
*pLCID = _pDocInfo->_lcidfe;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::SetDocumentType(bDocType)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Property set method that sets the document's type (none-\ltrdoc-\rtldoc)
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = NOERROR
|
||
|
*/
|
||
|
HRESULT CTxtEdit::SetDocumentType (
|
||
|
LONG DocType) //@parm New document-type value
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::SetDocumentType");
|
||
|
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
|
||
|
if(!pDocInfo) // Doc info doesn't exist
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
pDocInfo->_bDocType = (BYTE)DocType;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::GetDocumentType (pDocType)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Property get method that gets the document type
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (!pDocType) ? E_INVALIDARG : NOERROR
|
||
|
*/
|
||
|
HRESULT CTxtEdit::GetDocumentType (
|
||
|
LONG *pDocType) //@parm Out parm with document type value
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetDocumentType");
|
||
|
|
||
|
if(!pDocType)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
|
||
|
if(!pDocInfo) // Doc info doesn't exist
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
*pDocType = _pDocInfo->_bDocType;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::GetLeadingPunct (plpstrLeadingPunct)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Retrieve leading kinsoku punctuation for document
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (!<p plpstrLeadingPunct>) ? E_INVALIDARG :
|
||
|
* (no leading punct) ? S_FALSE :
|
||
|
* (if not enough RAM) ? E_OUTOFMEMORY : NOERROR
|
||
|
*/
|
||
|
HRESULT CTxtEdit::GetLeadingPunct (
|
||
|
LPSTR * plpstrLeadingPunct) //@parm Out parm to receive leading
|
||
|
// kinsoku punctuation
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetLeadingPunct");
|
||
|
|
||
|
if(!plpstrLeadingPunct)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*plpstrLeadingPunct = NULL;
|
||
|
if(!_pDocInfo || !_pDocInfo->_lpstrLeadingPunct)
|
||
|
return S_FALSE;
|
||
|
|
||
|
*plpstrLeadingPunct = _pDocInfo->_lpstrLeadingPunct;
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::SetLeadingPunct (lpstrLeadingPunct)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Set leading kinsoku punctuation for document
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (if not enough RAM) ? E_OUTOFMEMORY : NOERROR
|
||
|
*/
|
||
|
HRESULT CTxtEdit::SetLeadingPunct (
|
||
|
LPSTR lpstrLeadingPunct) //@parm In parm containing leading
|
||
|
// kinsoku punctuation
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::SetLeadingPunct");
|
||
|
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
|
||
|
if(!pDocInfo)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
if(pDocInfo->_lpstrLeadingPunct)
|
||
|
FreePv(pDocInfo->_lpstrLeadingPunct);
|
||
|
|
||
|
if(lpstrLeadingPunct && *lpstrLeadingPunct)
|
||
|
pDocInfo->_lpstrLeadingPunct = lpstrLeadingPunct;
|
||
|
else
|
||
|
{
|
||
|
pDocInfo->_lpstrLeadingPunct = NULL;
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::GetFollowingPunct (plpstrFollowingPunct)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Retrieve following kinsoku punctuation for document
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (!<p plpstrFollowingPunct>) ? E_INVALIDARG :
|
||
|
* (no following punct) ? S_FALSE :
|
||
|
* (if not enough RAM) ? E_OUTOFMEMORY : NOERROR
|
||
|
*/
|
||
|
HRESULT CTxtEdit::GetFollowingPunct (
|
||
|
LPSTR * plpstrFollowingPunct) //@parm Out parm to receive following
|
||
|
// kinsoku punctuation
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::GetFollowingPunct");
|
||
|
|
||
|
if(!plpstrFollowingPunct)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
*plpstrFollowingPunct = NULL;
|
||
|
if(!_pDocInfo || !_pDocInfo->_lpstrFollowingPunct)
|
||
|
return S_FALSE;
|
||
|
|
||
|
*plpstrFollowingPunct = _pDocInfo->_lpstrFollowingPunct;
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::SetFollowingPunct (lpstrFollowingPunct)
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Set following kinsoku punctuation for document
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT = (if not enough RAM) ? E_OUTOFMEMORY : NOERROR
|
||
|
*/
|
||
|
HRESULT CTxtEdit::SetFollowingPunct (
|
||
|
LPSTR lpstrFollowingPunct) //@parm In parm containing following
|
||
|
// kinsoku punctuation
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtEdit::SetFollowingPunct");
|
||
|
|
||
|
CDocInfo *pDocInfo = GetDocInfo();
|
||
|
|
||
|
if(!pDocInfo)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
if(pDocInfo->_lpstrFollowingPunct)
|
||
|
FreePv(pDocInfo->_lpstrFollowingPunct);
|
||
|
|
||
|
if(lpstrFollowingPunct && *lpstrFollowingPunct)
|
||
|
pDocInfo->_lpstrFollowingPunct = lpstrFollowingPunct;
|
||
|
else
|
||
|
{
|
||
|
pDocInfo->_lpstrFollowingPunct = NULL;
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::InitDocInfo()
|
||
|
*
|
||
|
* @mfunc initialize doc info structure
|
||
|
*
|
||
|
* @rdesc
|
||
|
* HRESULT
|
||
|
*/
|
||
|
HRESULT CTxtEdit::InitDocInfo()
|
||
|
{
|
||
|
_wZoomNumerator = _wZoomDenominator = 0;// Turn off zoom
|
||
|
|
||
|
// Reset Vertical style
|
||
|
DWORD dwBits = 0;
|
||
|
|
||
|
_phost->TxGetPropertyBits(TXTBIT_VERTICAL, &dwBits);
|
||
|
|
||
|
if (dwBits & TXTBIT_VERTICAL)
|
||
|
{
|
||
|
_fUseAtFont = TRUE;
|
||
|
HandleSetTextFlow(tflowSW);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_fUseAtFont = FALSE;
|
||
|
HandleSetTextFlow(tflowES);
|
||
|
}
|
||
|
|
||
|
if(_pDocInfo)
|
||
|
{
|
||
|
_pDocInfo->Init();
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
return GetDocInfo() ? NOERROR : E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::GetBackgroundType()
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Get background type
|
||
|
*
|
||
|
* @rdesc
|
||
|
* Background type (only for main display)
|
||
|
*/
|
||
|
LONG CTxtEdit::GetBackgroundType()
|
||
|
{
|
||
|
return _pDocInfo ? _pDocInfo->_nFillType : -1;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::TxGetBackColor()
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Get background color
|
||
|
*
|
||
|
* @rdesc
|
||
|
* Background color (only for main display)
|
||
|
*/
|
||
|
COLORREF CTxtEdit::TxGetBackColor() const
|
||
|
{
|
||
|
return (_pDocInfo && _pDocInfo->_nFillType == 0)
|
||
|
? _pDocInfo->_crColor : _phost->TxGetSysColor(COLOR_WINDOW);
|
||
|
}
|
||
|
|
||
|
//----------------------- CDocInfo related Functions -----------------------
|
||
|
/*
|
||
|
* CDocInfo::Init()
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Initializer for CDocInfo
|
||
|
*
|
||
|
* @comment
|
||
|
* It is assumed that CDocInfo created by a new operator that zeroes
|
||
|
* the structure. This initializer is called by the constructor and
|
||
|
* by CTxtEdit::InitDocInfo().
|
||
|
*/
|
||
|
void CDocInfo::Init()
|
||
|
{
|
||
|
_wCpg = (WORD)GetACP();
|
||
|
_lcid = GetSystemDefaultLCID();
|
||
|
|
||
|
if(IsFELCID(_lcid))
|
||
|
{
|
||
|
_lcidfe = _lcid;
|
||
|
_lcid = MAKELCID(sLanguageEnglishUS, SORT_DEFAULT);
|
||
|
}
|
||
|
|
||
|
_dwDefaultTabStop = lDefaultTab;
|
||
|
_bDocType = 0;
|
||
|
InitBackground();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CDocInfo::InitBackground()
|
||
|
*
|
||
|
* @mfunc
|
||
|
* Background initializer for CDocInfo
|
||
|
*/
|
||
|
void CDocInfo::InitBackground()
|
||
|
{
|
||
|
_nFillType = -1;
|
||
|
_sFillAngle = 0;
|
||
|
if(_hBitmapBack)
|
||
|
DeleteObject(_hBitmapBack);
|
||
|
GlobalFree(_hdata);
|
||
|
_hdata = NULL;
|
||
|
_hBitmapBack = NULL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CDocInfo::~CDocInfo
|
||
|
*
|
||
|
* @mfunc destructor for the docinfo class
|
||
|
*/
|
||
|
CDocInfo::~CDocInfo()
|
||
|
{
|
||
|
if(_pName)
|
||
|
SysFreeString(_pName);
|
||
|
|
||
|
if(_hFile)
|
||
|
CloseHandle(_hFile);
|
||
|
|
||
|
FreePv(_lpstrLeadingPunct);
|
||
|
FreePv(_lpstrFollowingPunct);
|
||
|
FreePv(_prgColor);
|
||
|
if(_hBitmapBack)
|
||
|
DeleteObject(_hBitmapBack);
|
||
|
GlobalFree(_hdata);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* CTxtEdit::GetDocInfo ()
|
||
|
*
|
||
|
* @mfunc
|
||
|
* If _pDocInfo is NULL, equate it to a new CDocInfo. In either case
|
||
|
* return _pDocInfo
|
||
|
*
|
||
|
* @rdesc
|
||
|
* CTxtEdit::_pDocInfo, the ptr to the CDocInfo object
|
||
|
*/
|
||
|
CDocInfo * CTxtEdit::GetDocInfo()
|
||
|
{
|
||
|
TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CTxtEdit::GetDocInfo");
|
||
|
|
||
|
if (!_pDocInfo)
|
||
|
_pDocInfo = new CDocInfo();
|
||
|
|
||
|
// It is the caller's responsiblity to notice that an error occurred
|
||
|
// in the allocation of the CDocInfo object.
|
||
|
return _pDocInfo;
|
||
|
}
|
||
|
|