Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2446 lines
70 KiB

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "stdafx2.h"
#include "wordpad.h"
// See Win98 HACKHACK below
#ifdef _CHICAGO_
#include <initguid.h>
#include <tom.h>
#pragma comment (lib, "oleaut32.lib")
#endif // _CHICAGO_
// Hack multimon to work with NT4 headers but NT5 libs
#if _WIN32_WINNT < 0x0500
#include <multimon.h>
#undef GetSystemMetrics
#undef MonitorFromWindow
#undef MonitorFromRect
#undef MonitorFromPoint
#undef GetMonitorInfo
#undef EnumDisplayMonitors
#undef EnumDisplayDevices
extern "C"
{
WINUSERAPI
HMONITOR
WINAPI
MonitorFromWindow( IN HWND hwnd, IN DWORD dwFlags);
WINUSERAPI BOOL WINAPI GetMonitorInfoA( IN HMONITOR hMonitor, OUT LPMONITORINFO lpmi);
WINUSERAPI BOOL WINAPI GetMonitorInfoW( IN HMONITOR hMonitor, OUT LPMONITORINFO lpmi);
#ifdef UNICODE
#define GetMonitorInfo GetMonitorInfoW
#else
#define GetMonitorInfo GetMonitorInfoA
#endif // !UNICODE
}
#endif
#ifdef AFX_CORE4_SEG
#pragma code_seg(AFX_CORE4_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
/////////////////////////////////////////////////////////////////////////////
// CRe2Object
class CRe2Object : public _reobject
{
public:
CRe2Object();
CRe2Object(CRichEdit2CntrItem* pItem);
~CRe2Object();
};
CRe2Object::CRe2Object()
{
cbStruct = sizeof(REOBJECT);
poleobj = NULL;
pstg = NULL;
polesite = NULL;
}
CRe2Object::CRe2Object(CRichEdit2CntrItem* pItem)
{
ASSERT(pItem != NULL);
cbStruct = sizeof(REOBJECT);
pItem->GetClassID(&clsid);
poleobj = pItem->m_lpObject;
pstg = pItem->m_lpStorage;
polesite = pItem->m_lpClientSite;
ASSERT(poleobj != NULL);
ASSERT(pstg != NULL);
ASSERT(polesite != NULL);
poleobj->AddRef();
pstg->AddRef();
polesite->AddRef();
sizel.cx = sizel.cy = 0; // let richedit determine initial size
dvaspect = pItem->GetDrawAspect();
dwFlags = REO_RESIZABLE;
dwUser = 0;
}
CRe2Object::~CRe2Object()
{
if (poleobj != NULL)
poleobj->Release();
if (pstg != NULL)
pstg->Release();
if (polesite != NULL)
polesite->Release();
}
//+-------------------------------------------------------------------------
//
// HACKHACK:
//
// The Richedit2 control is Unicode internally so it needs to convert
// strings from Ansi to Unicode when it recieves a EM_FINDTEXTEX message.
// Unfortunately it seems to set the code page for the conversion based
// on the current keyboard layout. This breaks in the following scenario:
//
// Start Wordpad on FE Win98 and type some DBCS chars. Pull up the find
// dialog and enter one of the DBCS chars that you typed before. Set the
// keyboard layout to US and try to find the character - it will fail.
// Now set it to non-US and try the find - it will work.
//
// The hack is to do the conversion ourselves using the system default
// codepage and then do the find using the TOM interfaces.
//
// Richedit3 is supposed to be smarter about this whole issue and hopefully
// this hack can be removed then.
//
//--------------------------------------------------------------------------
#ifdef _CHICAGO_
long CRichEdit2Ctrl::FindText(DWORD dwFlags, FINDTEXTEX* pFindText) const
{
long index = -1;
ITextRange *range = NULL;
HRESULT hr = S_OK;
UINT cchFind = _tcslen(pFindText->lpstrText) + 1;
LPWSTR lpwszFind = NULL;
long length;
//
// Get the base richedit ole interface
//
IUnknown *unk = GetIRichEditOle();
if (NULL == unk)
hr = E_NOINTERFACE;
//
// Get a range object
//
if (S_OK == hr)
{
ITextDocument *doc;
hr = unk->QueryInterface(IID_ITextDocument, (void **) &doc);
if (S_OK == hr)
{
hr = doc->Range(
pFindText->chrg.cpMin,
pFindText->chrg.cpMax,
&range);
doc->Release();
}
unk->Release();
}
//
// Convert the text-to-find to Unicode using the system default code page
//
if (S_OK == hr)
{
try
{
lpwszFind = (LPWSTR) alloca(cchFind * sizeof(WCHAR));
}
catch (...)
{
_resetstkoflw();
hr = E_OUTOFMEMORY; // alloca failed
}
if (S_OK == hr)
{
int error = MultiByteToWideChar(
CP_ACP,
MB_ERR_INVALID_CHARS,
pFindText->lpstrText,
-1,
lpwszFind,
cchFind);
if (0 != error)
lpwszFind = SysAllocString(lpwszFind);
else
hr = E_FAIL;
if (S_OK == hr && NULL == lpwszFind)
hr = E_OUTOFMEMORY;
}
}
//
// Try to find the text
//
if (S_OK == hr)
{
long flags = 0;
flags |= (dwFlags & FR_MATCHCASE) ? tomMatchCase : 0;
flags |= (dwFlags & FR_WHOLEWORD) ? tomMatchWord : 0;
hr = range->FindText((BSTR) lpwszFind, 0, flags, &length);
SysFreeString(lpwszFind);
if (S_OK == hr)
{
hr = range->GetIndex(tomCharacter, &index);
if (S_OK == hr)
{
// GetIndex returns 1-based indices, EM_FINDTEXTEX returns
// 0-based indices.
--index;
pFindText->chrgText.cpMin = index;
pFindText->chrgText.cpMax = index + length;
}
}
}
if (NULL != range)
range->Release();
//
// If all else fails, fall back to EM_FINDTEXTEX
//
if (S_OK != hr)
index = (long)::SendMessage(
m_hWnd,
EM_FINDTEXTEX,
dwFlags,
(LPARAM)pFindText);
return index;
}
#endif // _CHICAGO
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View
static const UINT nMsgFindReplace = ::RegisterWindowMessage(FINDMSGSTRING);
BEGIN_MESSAGE_MAP(CRichEdit2View, CCtrlView)
//{{AFX_MSG_MAP(CRichEdit2View)
ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateNeedSel)
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateNeedClip)
ON_UPDATE_COMMAND_UI(ID_EDIT_FIND, OnUpdateNeedText)
ON_UPDATE_COMMAND_UI(ID_EDIT_REPEAT, OnUpdateNeedFind)
ON_UPDATE_COMMAND_UI(ID_EDIT_UNDO, OnUpdateEditUndo)
ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE_SPECIAL, OnUpdateEditPasteSpecial)
ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_PROPERTIES, OnUpdateEditProperties)
ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateNeedSel)
ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR, OnUpdateNeedSel)
ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateNeedText)
ON_UPDATE_COMMAND_UI(ID_EDIT_REPLACE, OnUpdateNeedText)
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
ON_COMMAND(ID_EDIT_CLEAR, OnEditClear)
ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
ON_COMMAND(ID_EDIT_FIND, OnEditFind)
ON_COMMAND(ID_EDIT_REPLACE, OnEditReplace)
ON_COMMAND(ID_EDIT_REPEAT, OnEditRepeat)
ON_COMMAND(ID_EDIT_PASTE_SPECIAL, OnEditPasteSpecial)
ON_COMMAND(ID_OLE_EDIT_PROPERTIES, OnEditProperties)
ON_COMMAND(ID_OLE_INSERT_NEW, OnInsertObject)
ON_COMMAND(ID_FORMAT_FONT, OnFormatFont)
ON_WM_SIZE()
ON_WM_CREATE()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_NOTIFY_REFLECT(EN_SELCHANGE, OnSelChange)
ON_REGISTERED_MESSAGE(nMsgFindReplace, OnFindReplaceCmd)
END_MESSAGE_MAP()
// richedit buffer limit -- let's set it at 16M
AFX_DATADEF ULONG CRichEdit2View::lMaxSize = 0xffffff;
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View construction/destruction
CRichEdit2View::CRichEdit2View() : CCtrlView(MSFTEDIT_CLASS, AFX_WS_DEFAULT_VIEW |
WS_HSCROLL | WS_VSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL |
ES_MULTILINE | ES_NOHIDESEL | ES_SAVESEL | ES_SELECTIONBAR)
{
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
m_lpRichEditOle = NULL;
m_nBulletIndent = 720; // 1/2 inch
m_nWordWrap = WrapToWindow;
m_nPasteType = 0;
SetPaperSize(CSize(8*1440+720, 11*1440));
SetMargins(CRect(0,0,0,0));
m_charformat.cbSize = sizeof(CHARFORMAT);
m_paraformat.cbSize = sizeof(PARAFORMAT);
}
BOOL CRichEdit2View::PreCreateWindow(CREATESTRUCT& cs)
{
_AFX_RICHEDIT2_STATE* pState = AfxGetRichEdit2State();
BOOL bRet = TRUE;
if (pState->m_hInstRichEdit == NULL)
{
bRet = FALSE;
pState->m_hInstRichEdit = LoadLibrary(L"MSFTEDIT.DLL");
if (!pState->m_hInstRichEdit)
{
pState->m_hInstRichEdit = LoadLibrary(L"RICHED20.DLL");
}
if (pState->m_hInstRichEdit)
{
bRet = TRUE;
}
}
CCtrlView::PreCreateWindow(cs);
cs.lpszName = &afxChNil;
cs.cx = cs.cy = 100; // necessary to avoid bug with ES_SELECTIONBAR and zero for cx and cy
cs.style |= WS_CLIPSIBLINGS;
return bRet;
}
int CRichEdit2View::OnCreate(LPCREATESTRUCT lpcs)
{
if (CCtrlView::OnCreate(lpcs) != 0)
return -1;
GetRichEditCtrl().LimitText(lMaxSize);
GetRichEditCtrl().SetEventMask(ENM_SELCHANGE | ENM_CHANGE | ENM_SCROLL);
VERIFY(GetRichEditCtrl().SetOLECallback(&m_xRichEditOleCallback));
m_lpRichEditOle = GetRichEditCtrl().GetIRichEditOle();
DragAcceptFiles();
GetRichEditCtrl().SetOptions(ECOOP_OR, ECO_AUTOWORDSELECTION);
WrapChanged();
ASSERT(m_lpRichEditOle != NULL);
DWORD_PTR dwOptions = GetRichEditCtrl().SendMessage(EM_GETLANGOPTIONS, 0, 0);
dwOptions &= ~IMF_DUALFONT;
GetRichEditCtrl().SendMessage(EM_SETLANGOPTIONS, 0, dwOptions);
dwOptions = (SES_USECTF | SES_CTFALLOWEMBED | SES_CTFALLOWSMARTTAG | SES_CTFALLOWPROOFING);
GetRichEditCtrl().SendMessage(EM_SETEDITSTYLE, dwOptions, dwOptions);
return 0;
}
void CRichEdit2View::OnInitialUpdate()
{
CCtrlView::OnInitialUpdate();
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View document like functions
void CRichEdit2View::DeleteContents()
{
ASSERT_VALID(this);
ASSERT(m_hWnd != NULL);
SetWindowText(_T(""));
GetRichEditCtrl().EmptyUndoBuffer();
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
ASSERT_VALID(this);
}
void CRichEdit2View::WrapChanged()
{
CWaitCursor wait;
CRichEdit2Ctrl& ctrl = GetRichEditCtrl();
if (m_nWordWrap == WrapNone)
ctrl.SetTargetDevice(NULL, 1);
else if (m_nWordWrap == WrapToWindow)
ctrl.SetTargetDevice(NULL, 0);
else if (m_nWordWrap == WrapToTargetDevice) // wrap to ruler
{
AfxGetApp()->CreatePrinterDC(m_dcTarget);
if (m_dcTarget.m_hDC == NULL)
m_dcTarget.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
ctrl.SetTargetDevice(m_dcTarget, GetPrintWidth());
}
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View serialization support
class _afxRichEditCookie
{
public:
CArchive& m_ar;
DWORD m_dwError;
_afxRichEditCookie(CArchive& ar) : m_ar(ar) {m_dwError=0;}
};
void CRichEdit2View::Serialize(CArchive& ar)
// Read and write CRichEdit2View object to archive, with length prefix.
{
ASSERT_VALID(this);
ASSERT(m_hWnd != NULL);
Stream(ar, FALSE);
ASSERT_VALID(this);
}
void CRichEdit2View::Stream(CArchive& ar, BOOL bSelection)
{
EDITSTREAM es = {0, 0, EditStreamCallBack};
_afxRichEditCookie cookie(ar);
es.dwCookie = (DWORD_PTR)&cookie;
int nFormat = GetDocument()->GetStreamFormat();
if (bSelection)
nFormat |= SFF_SELECTION;
if (GetDocument()->IsUnicode())
nFormat |= SF_UNICODE;
if (ar.IsStoring())
GetRichEditCtrl().StreamOut(nFormat, es);
else
{
GetRichEditCtrl().StreamIn(nFormat, es);
Invalidate();
}
if (cookie.m_dwError != 0)
AfxThrowFileException(cookie.m_dwError);
}
// return 0 for no error, otherwise return error code
DWORD CALLBACK CRichEdit2View::EditStreamCallBack(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
_afxRichEditCookie* pCookie = (_afxRichEditCookie*)dwCookie;
CArchive& ar = pCookie->m_ar;
ar.Flush();
DWORD dw = 0;
*pcb = cb;
TRY
{
if (ar.IsStoring())
ar.GetFile()->WriteHuge(pbBuff, cb);
else
*pcb = ar.GetFile()->ReadHuge(pbBuff, cb);
}
CATCH(CFileException, e)
{
*pcb = 0;
pCookie->m_dwError = (DWORD)e->m_cause;
dw = 1;
DELETE_EXCEPTION(e);
}
AND_CATCH_ALL(e)
{
*pcb = 0;
pCookie->m_dwError = (DWORD)CFileException::generic;
dw = 1;
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
return dw;
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View Printing support
void CRichEdit2View::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo*)
{
ASSERT_VALID(this);
// ASSERT_VALID(pDC);
// initialize page start vector
ASSERT(m_aPageStart.GetSize() == 0);
m_aPageStart.Add(0);
ASSERT(m_aPageStart.GetSize() > 0);
GetRichEditCtrl().FormatRange(NULL, FALSE); // required by RichEdit to clear out cache
ASSERT_VALID(this);
}
BOOL CRichEdit2View::PaginateTo(CDC* pDC, CPrintInfo* pInfo)
// attempts pagination to pInfo->m_nCurPage, TRUE == success
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
CRect rectSave = pInfo->m_rectDraw;
UINT nPageSave = pInfo->m_nCurPage;
ASSERT(nPageSave > 1);
ASSERT(nPageSave >= (UINT)m_aPageStart.GetSize());
VERIFY(pDC->SaveDC() != 0);
pDC->IntersectClipRect(0, 0, 0, 0);
pInfo->m_nCurPage = (UINT)m_aPageStart.GetSize();
while (pInfo->m_nCurPage < nPageSave)
{
ASSERT(pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize());
OnPrepareDC(pDC, pInfo);
ASSERT(pInfo->m_bContinuePrinting);
pInfo->m_rectDraw.SetRect(0, 0,
pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
pDC->DPtoLP(&pInfo->m_rectDraw);
OnPrint(pDC, pInfo);
if (pInfo->m_nCurPage == (UINT)m_aPageStart.GetSize())
break;
++pInfo->m_nCurPage;
}
BOOL bResult = pInfo->m_nCurPage == nPageSave;
pDC->RestoreDC(-1);
pInfo->m_nCurPage = nPageSave;
pInfo->m_rectDraw = rectSave;
ASSERT_VALID(this);
return bResult;
}
void CRichEdit2View::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
ASSERT(pInfo != NULL); // overriding OnPaint -- never get this.
pDC->SetMapMode(MM_TEXT);
if (pInfo->m_nCurPage > (UINT)m_aPageStart.GetSize() &&
!PaginateTo(pDC, pInfo))
{
// can't paginate to that page, thus cannot print it.
pInfo->m_bContinuePrinting = FALSE;
}
ASSERT_VALID(this);
}
long CRichEdit2View::PrintPage(CDC* pDC, long nIndexStart, long nIndexStop)
// worker function for laying out text in a rectangle.
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
FORMATRANGE fr;
// offset by printing offset
pDC->SetViewportOrg(-pDC->GetDeviceCaps(PHYSICALOFFSETX),
-pDC->GetDeviceCaps(PHYSICALOFFSETY));
// adjust DC because richedit doesn't do things like MFC
if (::GetDeviceCaps(pDC->m_hDC, TECHNOLOGY) != DT_METAFILE && pDC->m_hAttribDC != NULL)
{
::ScaleWindowExtEx(pDC->m_hDC,
::GetDeviceCaps(pDC->m_hDC, LOGPIXELSX),
::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSX),
::GetDeviceCaps(pDC->m_hDC, LOGPIXELSY),
::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSY), NULL);
}
fr.hdcTarget = pDC->m_hAttribDC;
fr.hdc = pDC->m_hDC;
fr.rcPage = GetPageRect();
fr.rc = GetPrintRect();
fr.chrg.cpMin = nIndexStart;
fr.chrg.cpMax = nIndexStop;
long lRes = GetRichEditCtrl().FormatRange(&fr,TRUE);
return lRes;
}
long CRichEdit2View::PrintInsideRect(CDC* pDC, RECT& rectLayout,
long nIndexStart, long nIndexStop, BOOL bOutput)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
FORMATRANGE fr;
// adjust DC because richedit doesn't do things like MFC
if (::GetDeviceCaps(pDC->m_hDC, TECHNOLOGY) != DT_METAFILE && pDC->m_hAttribDC != NULL)
{
::ScaleWindowExtEx(pDC->m_hDC,
::GetDeviceCaps(pDC->m_hDC, LOGPIXELSX),
::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSX),
::GetDeviceCaps(pDC->m_hDC, LOGPIXELSY),
::GetDeviceCaps(pDC->m_hAttribDC, LOGPIXELSY), NULL);
}
fr.hdcTarget = pDC->m_hAttribDC;
fr.hdc = pDC->m_hDC;
// convert rect to twips
fr.rcPage = rectLayout;
fr.rc = rectLayout;
fr.chrg.cpMin = nIndexStart;
fr.chrg.cpMax = nIndexStop;
GetRichEditCtrl().FormatRange(NULL, FALSE); // required by RichEdit to clear out cache
// if bOutput is FALSE, we only measure
long lres = GetRichEditCtrl().FormatRange(&fr, bOutput);
GetRichEditCtrl().FormatRange(NULL, FALSE); // required by RichEdit to clear out cache
rectLayout = fr.rc;
return lres;
}
void CRichEdit2View::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
ASSERT(pInfo != NULL);
ASSERT(pInfo->m_bContinuePrinting);
UINT nPage = pInfo->m_nCurPage;
ASSERT(nPage <= (UINT)m_aPageStart.GetSize());
long nIndex = (long) m_aPageStart[nPage-1];
// print as much as possible in the current page.
nIndex = PrintPage(pDC, nIndex, 0xFFFFFFFF);
if (nIndex >= GetTextLength())
{
TRACE0("End of Document\n");
pInfo->SetMaxPage(nPage);
}
// update pagination information for page just printed
if (nPage == (UINT)m_aPageStart.GetSize())
{
if (nIndex < GetTextLength())
m_aPageStart.Add(nIndex);
}
else
{
ASSERT(nPage+1 <= (UINT)m_aPageStart.GetSize());
ASSERT(nIndex == (long)m_aPageStart[nPage+1-1]);
}
}
void CRichEdit2View::OnEndPrinting(CDC*, CPrintInfo*)
{
ASSERT_VALID(this);
GetRichEditCtrl().FormatRange(NULL, FALSE); // required by RichEdit to clear out cache
m_aPageStart.RemoveAll();
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View::XRichEditOleCallback
BEGIN_INTERFACE_MAP(CRichEdit2View, CCtrlView)
// we use IID_IUnknown because richedit doesn't define an IID
INTERFACE_PART(CRichEdit2View, IID_IUnknown, RichEditOleCallback)
END_INTERFACE_MAP()
STDMETHODIMP_(ULONG) CRichEdit2View::XRichEditOleCallback::AddRef()
{
METHOD_PROLOGUE_EX_(CRichEdit2View, RichEditOleCallback)
return (ULONG)pThis->InternalAddRef();
}
STDMETHODIMP_(ULONG) CRichEdit2View::XRichEditOleCallback::Release()
{
METHOD_PROLOGUE_EX_(CRichEdit2View, RichEditOleCallback)
return (ULONG)pThis->InternalRelease();
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(CRichEdit2View, RichEditOleCallback)
return (HRESULT)pThis->InternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::GetNewStorage(LPSTORAGE* ppstg)
{
METHOD_PROLOGUE_EX_(CRichEdit2View, RichEditOleCallback)
// Create a flat storage and steal it from the client item
// the client item is only used for creating the storage
COleClientItem item;
item.GetItemStorageFlat();
*ppstg = item.m_lpStorage;
HRESULT hRes = E_OUTOFMEMORY;
if (item.m_lpStorage != NULL)
{
item.m_lpStorage = NULL;
hRes = S_OK;
}
pThis->GetDocument()->InvalidateObjectCache();
return hRes;
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::GetInPlaceContext(
LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc,
LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
METHOD_PROLOGUE_EX(CRichEdit2View, RichEditOleCallback)
return pThis->GetWindowContext(lplpFrame, lplpDoc, lpFrameInfo);
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::ShowContainerUI(BOOL fShow)
{
METHOD_PROLOGUE_EX(CRichEdit2View, RichEditOleCallback)
return pThis->ShowContainerUI(fShow);
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::QueryInsertObject(
LPCLSID /*lpclsid*/, LPSTORAGE /*pstg*/, LONG /*cp*/)
{
METHOD_PROLOGUE_EX(CRichEdit2View, RichEditOleCallback)
pThis->GetDocument()->InvalidateObjectCache();
return S_OK;
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::DeleteObject(LPOLEOBJECT /*lpoleobj*/)
{
METHOD_PROLOGUE_EX_(CRichEdit2View, RichEditOleCallback)
pThis->GetDocument()->InvalidateObjectCache();
return S_OK;
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::QueryAcceptData(
LPDATAOBJECT lpdataobj, CLIPFORMAT* lpcfFormat, DWORD reco,
BOOL fReally, HGLOBAL hMetaPict)
{
METHOD_PROLOGUE_EX(CRichEdit2View, RichEditOleCallback)
return pThis->QueryAcceptData(lpdataobj, lpcfFormat, reco,
fReally, hMetaPict);
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::ContextSensitiveHelp(BOOL /*fEnterMode*/)
{
return E_NOTIMPL;
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::GetClipboardData(
CHARRANGE* lpchrg, DWORD reco, LPDATAOBJECT* lplpdataobj)
{
METHOD_PROLOGUE_EX(CRichEdit2View, RichEditOleCallback)
LPDATAOBJECT lpOrigDataObject = NULL;
// get richedit's data object
if (FAILED(pThis->m_lpRichEditOle->GetClipboardData(lpchrg, reco,
&lpOrigDataObject)))
{
return E_NOTIMPL;
}
// allow changes
HRESULT hRes = pThis->GetClipboardData(lpchrg, reco, lpOrigDataObject,
lplpdataobj);
// if changed then free original object
if (SUCCEEDED(hRes))
{
if (lpOrigDataObject!=NULL)
lpOrigDataObject->Release();
return hRes;
}
else
{
// use richedit's data object
*lplpdataobj = lpOrigDataObject;
return S_OK;
}
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::GetDragDropEffect(
BOOL fDrag, DWORD grfKeyState, LPDWORD pdwEffect)
{
if (!fDrag) // allowable dest effects
{
DWORD dwEffect;
// check for force link
if ((grfKeyState & (MK_CONTROL|MK_SHIFT)) == (MK_CONTROL|MK_SHIFT))
dwEffect = DROPEFFECT_LINK;
// check for force copy
else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
dwEffect = DROPEFFECT_COPY;
// check for force move
else if ((grfKeyState & MK_ALT) == MK_ALT)
dwEffect = DROPEFFECT_MOVE;
// default -- recommended action is move
else
dwEffect = DROPEFFECT_MOVE;
if (dwEffect & *pdwEffect) // make sure allowed type
*pdwEffect = dwEffect;
}
return S_OK;
}
STDMETHODIMP CRichEdit2View::XRichEditOleCallback::GetContextMenu(
WORD seltype, LPOLEOBJECT lpoleobj, CHARRANGE* lpchrg,
HMENU* lphmenu)
{
METHOD_PROLOGUE_EX(CRichEdit2View, RichEditOleCallback)
HMENU hMenu = pThis->GetContextMenu(seltype, lpoleobj, lpchrg);
if (hMenu == NULL)
return E_NOTIMPL;
*lphmenu = hMenu;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View command helpers
void CRichEdit2View::OnCharEffect(DWORD dwMask, DWORD dwEffect)
{
GetCharFormatSelection();
if (m_charformat.dwMask & dwMask) // selection is all the same
m_charformat.dwEffects ^= dwEffect;
else
m_charformat.dwEffects |= dwEffect;
m_charformat.dwMask = dwMask;
SetCharFormat(m_charformat);
}
void CRichEdit2View::OnUpdateCharEffect(CCmdUI* pCmdUI, DWORD dwMask, DWORD dwEffect)
{
GetCharFormatSelection();
pCmdUI->SetCheck((m_charformat.dwMask & dwMask) ?
((m_charformat.dwEffects & dwEffect) ? 1 : 0) : 2);
}
void CRichEdit2View::OnParaAlign(WORD wAlign)
{
GetParaFormatSelection();
m_paraformat.dwMask = PFM_ALIGNMENT;
m_paraformat.wAlignment = wAlign;
SetParaFormat(m_paraformat);
}
void CRichEdit2View::OnUpdateParaAlign(CCmdUI* pCmdUI, WORD wAlign)
{
GetParaFormatSelection();
// disable if no word wrap since alignment is meaningless
pCmdUI->Enable( (m_nWordWrap == WrapNone) ?
FALSE : TRUE);
pCmdUI->SetCheck( (m_paraformat.dwMask & PFM_ALIGNMENT) ?
((m_paraformat.wAlignment == wAlign) ? 1 : 0) : 2);
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View commands
void CRichEdit2View::OnUpdateNeedSel(CCmdUI* pCmdUI)
{
ASSERT_VALID(this);
long nStartChar, nEndChar;
GetRichEditCtrl().GetSel(nStartChar, nEndChar);
pCmdUI->Enable(nStartChar != nEndChar);
ASSERT_VALID(this);
}
void CRichEdit2View::OnUpdateNeedClip(CCmdUI* pCmdUI)
{
ASSERT_VALID(this);
pCmdUI->Enable(CanPaste());
}
void CRichEdit2View::OnUpdateNeedText(CCmdUI* pCmdUI)
{
ASSERT_VALID(this);
pCmdUI->Enable(GetTextLength() != 0);
}
void CRichEdit2View::OnUpdateNeedFind(CCmdUI* pCmdUI)
{
ASSERT_VALID(this);
_AFX_RICHEDIT2_STATE* pEditState = _afxRichEdit2State;
pCmdUI->Enable(GetTextLength() != 0 &&
!pEditState->strFind.IsEmpty());
}
void CRichEdit2View::OnUpdateEditUndo(CCmdUI* pCmdUI)
{
ASSERT_VALID(this);
pCmdUI->Enable(GetRichEditCtrl().CanUndo());
}
void CRichEdit2View::OnEditCut()
{
ASSERT_VALID(this);
GetRichEditCtrl().Cut();
}
void CRichEdit2View::OnEditCopy()
{
ASSERT_VALID(this);
GetRichEditCtrl().Copy();
}
void CRichEdit2View::OnEditPaste()
{
ASSERT_VALID(this);
m_nPasteType = 0;
GetRichEditCtrl().Paste();
}
void CRichEdit2View::OnEditClear()
{
ASSERT_VALID(this);
GetRichEditCtrl().Clear();
}
void CRichEdit2View::OnEditUndo()
{
ASSERT_VALID(this);
GetRichEditCtrl().Undo();
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
}
void CRichEdit2View::OnEditSelectAll()
{
ASSERT_VALID(this);
GetRichEditCtrl().SetSel(0, -1);
}
void CRichEdit2View::OnEditFind()
{
ASSERT_VALID(this);
OnEditFindReplace(TRUE);
}
void CRichEdit2View::OnEditReplace()
{
ASSERT_VALID(this);
OnEditFindReplace(FALSE);
}
void CRichEdit2View::OnEditRepeat()
{
ASSERT_VALID(this);
_AFX_RICHEDIT2_STATE* pEditState = _afxRichEdit2State;
if (!FindText(pEditState))
TextNotFound(pEditState->strFind);
}
void CRichEdit2View::OnCancelEditCntr()
{
m_lpRichEditOle->InPlaceDeactivate();
}
void CRichEdit2View::OnInsertObject()
{
// Invoke the standard Insert Object dialog box to obtain information
COleInsertDialog dlg;
if (dlg.DoModal() != IDOK)
return;
CWaitCursor wait;
CRichEdit2CntrItem* pItem = NULL;
TRY
{
// create item from dialog results
pItem = GetDocument()->CreateClientItem();
pItem->m_bLock = TRUE;
if (!dlg.CreateItem(pItem))
{
pItem->m_bLock = FALSE;
AfxThrowMemoryException(); // any exception will do
}
HRESULT hr = InsertItem(pItem);
pItem->UpdateItemType();
pItem->m_bLock = FALSE;
if (hr != NOERROR)
AfxThrowOleException(hr);
// if insert new object -- initially show the object
if (dlg.GetSelectionType() == COleInsertDialog::createNewItem)
pItem->DoVerb(OLEIVERB_SHOW, this);
}
CATCH(CException, e)
{
if (pItem != NULL)
{
ASSERT_VALID(pItem);
pItem->Delete();
}
AfxMessageBox(AFX_IDP_FAILED_TO_CREATE);
}
END_CATCH
}
void CRichEdit2View::OnSelChange(NMHDR* pNMHDR, LRESULT* pResult)
{
ASSERT(pNMHDR->code == EN_SELCHANGE);
UNUSED(pNMHDR); // not used in release builds
m_bSyncCharFormat = m_bSyncParaFormat = TRUE;
*pResult = 0;
}
void CRichEdit2View::OnDestroy()
{
if (m_lpRichEditOle != NULL)
m_lpRichEditOle->Release();
CCtrlView::OnDestroy();
}
void CRichEdit2View::OnEditProperties()
{
ASSERT(m_lpRichEditOle != NULL);
CRichEdit2CntrItem* pSelection = GetSelectedItem();
// make sure item is in sync with richedit's item
CRe2Object reo;
m_lpRichEditOle->GetObject(REO_IOB_SELECTION, &reo, REO_GETOBJ_NO_INTERFACES);
pSelection->SyncToRichEditObject(reo);
//
// HACKHACK: Due to a mismatch between the NT build environment and MFC
// wrt to the setting of _WIN32_IE, Wordpad and MFC have
// different views of how large a COlePropertiesDialog is. The
// result is that MFC ends up wiping part of the stack in it's
// initialization code. Hack some extra space until the
// mismatch is resolved.
//
// COlePropertiesDialog dlg(pSelection);
struct Hack
{
COlePropertiesDialog dlg;
BYTE space[128];
Hack(CRichEdit2CntrItem *pSelection) : dlg(pSelection) {}
}
hack(pSelection);
COlePropertiesDialog &dlg = hack.dlg;
//
// The Object Properties dialog doesn't display a help button even if
// you tell it to. The dialogs under it (e.g. Change Icon) will display
// the help button though. We never want a help button but MFC turns it
// on by default. If the Ole dialogs are fixed to not display the help
// button then this can be removed.
//
dlg.m_op.dwFlags &= ~OPF_SHOWHELP;
dlg.DoModal();
}
void CRichEdit2View::OnUpdateEditProperties(CCmdUI* pCmdUI)
{
pCmdUI->Enable(GetSelectedItem() != NULL);
}
void CRichEdit2View::OnCharBold()
{
OnCharEffect(CFM_BOLD, CFE_BOLD);
}
void CRichEdit2View::OnUpdateCharBold(CCmdUI* pCmdUI)
{
OnUpdateCharEffect(pCmdUI, CFM_BOLD, CFE_BOLD);
}
void CRichEdit2View::OnCharItalic()
{
OnCharEffect(CFM_ITALIC, CFE_ITALIC);
}
void CRichEdit2View::OnUpdateCharItalic(CCmdUI* pCmdUI)
{
OnUpdateCharEffect(pCmdUI, CFM_ITALIC, CFE_ITALIC);
}
void CRichEdit2View::OnCharUnderline()
{
OnCharEffect(CFM_UNDERLINE, CFE_UNDERLINE);
}
void CRichEdit2View::OnUpdateCharUnderline(CCmdUI* pCmdUI)
{
OnUpdateCharEffect(pCmdUI, CFM_UNDERLINE, CFE_UNDERLINE);
}
void CRichEdit2View::OnParaCenter()
{
OnParaAlign(PFA_CENTER);
}
void CRichEdit2View::OnUpdateParaCenter(CCmdUI* pCmdUI)
{
OnUpdateParaAlign(pCmdUI, PFA_CENTER);
}
void CRichEdit2View::OnParaLeft()
{
OnParaAlign(PFA_LEFT);
}
void CRichEdit2View::OnUpdateParaLeft(CCmdUI* pCmdUI)
{
OnUpdateParaAlign(pCmdUI, PFA_LEFT);
}
void CRichEdit2View::OnParaRight()
{
OnParaAlign(PFA_RIGHT);
}
void CRichEdit2View::OnUpdateParaRight(CCmdUI* pCmdUI)
{
OnUpdateParaAlign(pCmdUI, PFA_RIGHT);
}
void CRichEdit2View::OnBullet()
{
GetParaFormatSelection();
if (m_paraformat.dwMask & PFM_NUMBERING && m_paraformat.wNumbering == PFN_BULLET)
{
m_paraformat.wNumbering = 0;
m_paraformat.dxOffset = 0;
m_paraformat.dxStartIndent = 0;
m_paraformat.dwMask = PFM_NUMBERING | PFM_STARTINDENT | PFM_OFFSET;
}
else
{
m_paraformat.wNumbering = PFN_BULLET;
m_paraformat.dwMask = PFM_NUMBERING;
if (m_paraformat.dxOffset == 0)
{
m_paraformat.dxOffset = m_nBulletIndent;
m_paraformat.dwMask = PFM_NUMBERING | PFM_STARTINDENT | PFM_OFFSET;
}
}
SetParaFormat(m_paraformat);
}
void CRichEdit2View::OnUpdateBullet(CCmdUI* pCmdUI)
{
GetParaFormatSelection();
pCmdUI->SetCheck( (m_paraformat.dwMask & PFM_NUMBERING) ? ((m_paraformat.wNumbering & PFN_BULLET) ? 1 : 0) : 2);
}
void CRichEdit2View::OnFormatFont()
{
GetCharFormatSelection();
CFontDialog2 dlg(m_charformat, CF_BOTH|CF_NOOEMFONTS);
if (dlg.DoModal() == IDOK)
{
dlg.GetCharFormat(m_charformat);
SetCharFormat(m_charformat);
}
}
void CRichEdit2View::OnColorPick(COLORREF cr)
{
GetCharFormatSelection();
m_charformat.dwMask = CFM_COLOR;
m_charformat.dwEffects = NULL;
m_charformat.crTextColor = cr;
SetCharFormat(m_charformat);
}
void CRichEdit2View::OnColorDefault()
{
GetCharFormatSelection();
m_charformat.dwMask = CFM_COLOR;
m_charformat.dwEffects = CFE_AUTOCOLOR;
SetCharFormat(m_charformat);
}
void CRichEdit2View::OnEditPasteSpecial()
{
COlePasteSpecialDialog dlg;
dlg.AddStandardFormats();
dlg.AddFormat(_oleData.cfRichTextFormat, TYMED_HGLOBAL, AFX_IDS_RTF_FORMAT, FALSE, FALSE);
dlg.AddFormat(CF_TEXT, TYMED_HGLOBAL, AFX_IDS_TEXT_FORMAT, FALSE, FALSE);
if (dlg.DoModal() != IDOK)
return;
DVASPECT dv = dlg.GetDrawAspect();
HMETAFILE hMF = (HMETAFILE)dlg.GetIconicMetafile();
CLIPFORMAT cf =
dlg.m_ps.arrPasteEntries[dlg.m_ps.nSelectedIndex].fmtetc.cfFormat;
CWaitCursor wait;
SetCapture();
// we set the target type so that QueryAcceptData know what to paste
m_nPasteType = dlg.GetSelectionType();
GetRichEditCtrl().PasteSpecial(cf, dv, hMF);
m_nPasteType = 0;
ReleaseCapture();
}
void CRichEdit2View::OnUpdateEditPasteSpecial(CCmdUI* pCmdUI)
{
pCmdUI->Enable(CanPaste());
}
void CRichEdit2View::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar == VK_F10 && GetKeyState(VK_SHIFT) < 0)
{
CRect rect;
GetClientRect(rect);
CPoint pt = rect.CenterPoint();
SendMessage(WM_CONTEXTMENU, (WPARAM)m_hWnd, MAKELPARAM(pt.x, pt.y));
}
else
CCtrlView::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CRichEdit2View::OnDropFiles(HDROP hDropInfo)
{
TCHAR szFileName[_MAX_PATH];
UINT nFileCount = ::DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0);
ASSERT(nFileCount != 0);
CHARRANGE cr;
GetRichEditCtrl().GetSel(cr);
int nMin = cr.cpMin;
for (UINT i=0;i<nFileCount;i++)
{
::DragQueryFile(hDropInfo, i, szFileName, ARRAYSIZE(szFileName));
InsertFileAsObject(szFileName);
GetRichEditCtrl().GetSel(cr);
cr.cpMin = cr.cpMax;
GetRichEditCtrl().SetSel(cr);
UpdateWindow();
}
cr.cpMin = nMin;
GetRichEditCtrl().SetSel(cr);
::DragFinish(hDropInfo);
}
void CRichEdit2View::OnDevModeChange(LPTSTR /*lpDeviceName*/)
{
// WM_DEVMODECHANGE forwarded by the main window of the app
CDC dc;
AfxGetApp()->CreatePrinterDC(dc);
OnPrinterChanged(dc);
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View attributes
BOOL AFX_CDECL CRichEdit2View::IsRichEdit2Format(CLIPFORMAT cf)
{
return ((cf == _oleData.cfRichTextFormat) ||
(cf == _oleData.cfRichTextAndObjects) ||
(cf == CF_TEXT) ||
(cf == CF_UNICODETEXT));
}
BOOL CRichEdit2View::CanPaste() const
{
return (CountClipboardFormats() != 0) &&
(IsClipboardFormatAvailable(CF_TEXT) ||
IsClipboardFormatAvailable(_oleData.cfRichTextFormat) ||
IsClipboardFormatAvailable(_oleData.cfEmbedSource) ||
IsClipboardFormatAvailable(_oleData.cfEmbeddedObject) ||
IsClipboardFormatAvailable(_oleData.cfFileName) ||
IsClipboardFormatAvailable(_oleData.cfFileNameW) ||
IsClipboardFormatAvailable(CF_METAFILEPICT) ||
IsClipboardFormatAvailable(CF_DIB) ||
IsClipboardFormatAvailable(CF_BITMAP) ||
GetRichEditCtrl().CanPaste());
}
CHARFORMAT& CRichEdit2View::GetCharFormatSelection()
{
if (m_bSyncCharFormat)
{
GetRichEditCtrl().GetSelectionCharFormat(m_charformat);
m_bSyncCharFormat = FALSE;
}
return m_charformat;
}
PARAFORMAT& CRichEdit2View::GetParaFormatSelection()
{
if (m_bSyncParaFormat)
{
GetRichEditCtrl().GetParaFormat(m_paraformat);
m_bSyncParaFormat = FALSE;
}
return m_paraformat;
}
void CRichEdit2View::SetCharFormat(CHARFORMAT cf)
{
CWaitCursor wait;
GetRichEditCtrl().SetSelectionCharFormat(cf);
m_bSyncCharFormat = TRUE;
}
void CRichEdit2View::SetParaFormat(PARAFORMAT& pf)
{
CWaitCursor wait;
GetRichEditCtrl().SetParaFormat(pf);
m_bSyncParaFormat = TRUE;
}
CRichEdit2CntrItem* CRichEdit2View::GetSelectedItem() const
{
ASSERT(m_lpRichEditOle != NULL);
CRichEdit2Doc* pDoc = GetDocument();
CRichEdit2CntrItem* pItem = NULL;
CRe2Object reo;
HRESULT hr = m_lpRichEditOle->GetObject(REO_IOB_SELECTION, &reo,
REO_GETOBJ_ALL_INTERFACES);
//reo's interfaces are all in UNICODE
if (GetScode(hr) == S_OK)
{
pItem = pDoc->LookupItem(reo.poleobj);
if (pItem == NULL)
pItem = pDoc->CreateClientItem(&reo);
ASSERT(pItem != NULL);
}
return pItem;
}
CRichEdit2CntrItem* CRichEdit2View::GetInPlaceActiveItem() const
{
ASSERT(m_lpRichEditOle != NULL);
CRichEdit2Doc* pDoc = GetDocument();
CRichEdit2CntrItem* pItem = NULL;
CRe2Object reo;
HRESULT hr = m_lpRichEditOle->GetObject(REO_IOB_SELECTION, &reo,
REO_GETOBJ_ALL_INTERFACES);
//reo's interfaces are all in UNICODE
if (GetScode(hr) == S_OK && (reo.dwFlags & REO_INPLACEACTIVE))
{
pItem = pDoc->LookupItem(reo.poleobj);
if (pItem == NULL)
pItem = pDoc->CreateClientItem(&reo);
ASSERT(pItem != NULL);
}
return pItem;
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View operations
HRESULT CRichEdit2View::InsertItem(CRichEdit2CntrItem* pItem)
{
ASSERT(m_lpRichEditOle != NULL);
CRe2Object reo(pItem);
reo.cp = REO_CP_SELECTION;
HRESULT hr = m_lpRichEditOle->InsertObject(&reo);
CHARRANGE cr;
GetRichEditCtrl().GetSel(cr);
cr.cpMin = cr.cpMax -1;
GetRichEditCtrl().SetSel(cr);
return hr;
}
void CRichEdit2View::InsertFileAsObject(LPCTSTR lpszFileName)
{
CString str = lpszFileName;
CWaitCursor wait;
CRichEdit2CntrItem* pItem = NULL;
TRY
{
// create item from dialog results
pItem = GetDocument()->CreateClientItem();
pItem->m_bLock = TRUE;
if (!pItem->CreateFromFile(str))
AfxThrowMemoryException(); // any exception will do
pItem->UpdateLink();
InsertItem(pItem);
pItem->m_bLock = FALSE;
}
CATCH(CException, e)
{
if (pItem != NULL)
{
pItem->m_bLock = FALSE;
ASSERT_VALID(pItem);
pItem->Delete();
}
}
END_CATCH
}
//
// CRichEditView::DoPaste doesn't return an error but we need it to...
//
HRESULT g_hrPaste;
void CRichEdit2View::DoPaste(COleDataObject& dataobj, CLIPFORMAT cf, HMETAFILEPICT hMetaPict)
{
CWaitCursor wait;
g_hrPaste = S_FALSE;
CRichEdit2CntrItem* pItem = NULL;
TRY
{
// create item from dialog results
pItem = GetDocument()->CreateClientItem();
pItem->m_bLock = TRUE;
if (m_nPasteType == COlePasteSpecialDialog::pasteLink) // paste link
{
if (!pItem->CreateLinkFromData(&dataobj))
AfxThrowMemoryException(); // any exception will do
}
else if (m_nPasteType == COlePasteSpecialDialog::pasteNormal)
{
if (!pItem->CreateFromData(&dataobj))
AfxThrowMemoryException(); // any exception will do
}
else if (m_nPasteType == COlePasteSpecialDialog::pasteStatic)
{
if (!pItem->CreateStaticFromData(&dataobj))
AfxThrowMemoryException(); // any exception will do
}
else
{
// paste embedded
if (!pItem->CreateFromData(&dataobj) &&
!pItem->CreateStaticFromData(&dataobj))
{
AfxThrowMemoryException(); // any exception will do
}
}
if (cf == 0)
{
// copy the current iconic representation
FORMATETC fmtetc;
fmtetc.cfFormat = CF_METAFILEPICT;
fmtetc.dwAspect = DVASPECT_ICON;
fmtetc.ptd = NULL;
fmtetc.tymed = TYMED_MFPICT;
fmtetc.lindex = 1;
HGLOBAL hObj = dataobj.GetGlobalData(CF_METAFILEPICT, &fmtetc);
if (hObj != NULL)
{
pItem->SetIconicMetafile(hObj);
// the following code is an easy way to free a metafile pict
STGMEDIUM stgMed;
memset(&stgMed, 0, sizeof(stgMed));
stgMed.tymed = TYMED_MFPICT;
stgMed.hGlobal = hObj;
ReleaseStgMedium(&stgMed);
}
// set the current drawing aspect
hObj = dataobj.GetGlobalData((CLIPFORMAT)_oleData.cfObjectDescriptor);
if (hObj != NULL)
{
ASSERT(hObj != NULL);
// got CF_OBJECTDESCRIPTOR ok. Lock it down and extract size.
LPOBJECTDESCRIPTOR pObjDesc = (LPOBJECTDESCRIPTOR)GlobalLock(hObj);
ASSERT(pObjDesc != NULL);
((COleClientItem*)pItem)->SetDrawAspect((DVASPECT)pObjDesc->dwDrawAspect);
GlobalUnlock(hObj);
GlobalFree(hObj);
}
}
else
{
if (hMetaPict != NULL)
{
pItem->SetIconicMetafile(hMetaPict);
((COleClientItem*)pItem)->SetDrawAspect(DVASPECT_ICON);
}
else
((COleClientItem*)pItem)->SetDrawAspect(DVASPECT_CONTENT);
}
/////////
HRESULT hr = InsertItem(pItem);
pItem->UpdateItemType();
pItem->m_bLock = FALSE;
if (hr != NOERROR)
AfxThrowOleException(hr);
}
CATCH(CException, e)
{
if (pItem != NULL)
{
pItem->m_bLock = FALSE;
ASSERT_VALID(pItem);
pItem->Delete();
}
g_hrPaste = E_FAIL;
}
END_CATCH
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View virtuals
void CRichEdit2View::OnPrinterChanged(const CDC& dcPrinter)
{
// this is typically called by the view when it gets a WM_DEVMODECHANGE
// also called during page setup
CSize size;
if (dcPrinter.m_hDC != NULL)
{
// this will fill in the page size
size.cx = MulDiv(dcPrinter.GetDeviceCaps(PHYSICALWIDTH), 1440,
dcPrinter.GetDeviceCaps(LOGPIXELSX));
size.cy = MulDiv(dcPrinter.GetDeviceCaps(PHYSICALHEIGHT), 1440,
dcPrinter.GetDeviceCaps(LOGPIXELSY));
}
else
size = CSize(8*1440+720, 11*1440); // 8.5" by 11"
if (GetPaperSize() != size)
{
SetPaperSize(size);
if (m_nWordWrap == WrapToTargetDevice) //wrap to ruler
WrapChanged();
}
}
BOOL CRichEdit2View::OnPasteNativeObject(LPSTORAGE)
{
// use this function to pull out native data from an embedded object
// one would typically do this by create a COleStreamFile and attaching it
// to an archive
return FALSE;
}
HMENU CRichEdit2View::GetContextMenu(WORD, LPOLEOBJECT, CHARRANGE* )
{
return NULL;
}
HRESULT CRichEdit2View::GetClipboardData(CHARRANGE* /*lpchrg*/, DWORD /*reco*/,
LPDATAOBJECT /*lpRichDataObj*/, LPDATAOBJECT* /*lplpdataobj*/)
{
return E_NOTIMPL;
}
HRESULT CRichEdit2View::QueryAcceptData(LPDATAOBJECT lpdataobj,
CLIPFORMAT* lpcfFormat, DWORD /*dwReco*/, BOOL bReally, HGLOBAL hMetaPict)
{
ASSERT(lpcfFormat != NULL);
if (!bReally) // not actually pasting
return S_OK;
// if direct pasting a particular native format allow it
if (IsRichEdit2Format(*lpcfFormat))
return S_OK;
COleDataObject dataobj;
dataobj.Attach(lpdataobj, FALSE);
// if format is 0, then force particular formats if available
if (*lpcfFormat == 0 && (m_nPasteType == 0))
{
if (dataobj.IsDataAvailable((CLIPFORMAT)_oleData.cfRichTextAndObjects)) // native avail, let richedit do as it wants
return S_OK;
else if (dataobj.IsDataAvailable((CLIPFORMAT)_oleData.cfRichTextFormat))
{
*lpcfFormat = (CLIPFORMAT)_oleData.cfRichTextFormat;
return S_OK;
}
else if (dataobj.IsDataAvailable(CF_UNICODETEXT))
{
*lpcfFormat = CF_UNICODETEXT;
return S_OK;
}
else if (dataobj.IsDataAvailable(CF_TEXT))
{
*lpcfFormat = CF_TEXT;
return S_OK;
}
}
// paste OLE formats
DoPaste(dataobj, *lpcfFormat, hMetaPict);
return g_hrPaste;
}
HRESULT CRichEdit2View::GetWindowContext(LPOLEINPLACEFRAME* lplpFrame,
LPOLEINPLACEUIWINDOW* lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
CRichEdit2CntrItem* pItem = GetSelectedItem();
if (pItem == NULL)
return E_FAIL;
pItem->m_pView = this;
HRESULT hr = pItem->GetWindowContext(lplpFrame, lplpDoc, lpFrameInfo);
pItem->m_pView = NULL;
return hr;
}
HRESULT CRichEdit2View::ShowContainerUI(BOOL b)
{
CRichEdit2CntrItem* pItem = GetSelectedItem();
if (pItem == NULL)
return E_FAIL;
if (b)
pItem->m_pView = this;
HRESULT hr = pItem->ShowContainerUI(b);
if (FAILED(hr) || !b)
pItem->m_pView = NULL;
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View Find & Replace
void CRichEdit2View::AdjustDialogPosition(CDialog* pDlg)
{
ASSERT(pDlg != NULL);
long lStart, lEnd;
GetRichEditCtrl().GetSel(lStart, lEnd);
CPoint point = GetRichEditCtrl().GetCharPos(lStart);
ClientToScreen(&point);
CRect rectDlg;
pDlg->GetWindowRect(&rectDlg);
if (rectDlg.PtInRect(point))
{
if (point.y > rectDlg.Height())
rectDlg.OffsetRect(0, point.y - rectDlg.bottom - 20);
else
{
HMONITOR hMonitor = MonitorFromWindow(*pDlg, MONITOR_DEFAULTTONEAREST);
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(monitorInfo);
GetMonitorInfo(hMonitor, &monitorInfo);
int nVertExt = monitorInfo.rcMonitor.bottom
- monitorInfo.rcMonitor.top;
if (point.y + rectDlg.Height() < nVertExt)
rectDlg.OffsetRect(0, 40 + point.y - rectDlg.top);
}
pDlg->MoveWindow(&rectDlg);
}
}
void CRichEdit2View::OnEditFindReplace(BOOL bFindOnly)
{
ASSERT_VALID(this);
m_bFirstSearch = TRUE;
_AFX_RICHEDIT2_STATE* pEditState = _afxRichEdit2State;
if (pEditState->pFindReplaceDlg != NULL)
{
if (pEditState->bFindOnly == bFindOnly)
{
pEditState->pFindReplaceDlg->SetActiveWindow();
pEditState->pFindReplaceDlg->ShowWindow(SW_SHOW);
return;
}
else
{
ASSERT(pEditState->bFindOnly != bFindOnly);
pEditState->pFindReplaceDlg->SendMessage(WM_CLOSE);
ASSERT(pEditState->pFindReplaceDlg == NULL);
ASSERT_VALID(this);
}
}
CString strFind = GetRichEditCtrl().GetSelText();
// if selection is empty or spans multiple lines use old find text
if (strFind.IsEmpty() || (strFind.FindOneOf(_T("\n\r")) != -1))
strFind = pEditState->strFind;
CString strReplace = pEditState->strReplace;
pEditState->pFindReplaceDlg = new CFindReplaceDialog;
ASSERT(pEditState->pFindReplaceDlg != NULL);
DWORD dwFlags = NULL;
if (pEditState->bNext)
dwFlags |= FR_DOWN;
if (pEditState->bCase)
dwFlags |= FR_MATCHCASE;
if (pEditState->bWord)
dwFlags |= FR_WHOLEWORD;
// hide stuff that RichEdit doesn't support
dwFlags |= FR_HIDEUPDOWN;
if (!pEditState->pFindReplaceDlg->Create(bFindOnly, strFind,
strReplace, dwFlags, this))
{
pEditState->pFindReplaceDlg = NULL;
ASSERT_VALID(this);
return;
}
ASSERT(pEditState->pFindReplaceDlg != NULL);
pEditState->bFindOnly = bFindOnly;
pEditState->pFindReplaceDlg->SetActiveWindow();
pEditState->pFindReplaceDlg->ShowWindow(SW_SHOW);
ASSERT_VALID(this);
}
void CRichEdit2View::OnFindNext(LPCTSTR lpszFind, BOOL bNext, BOOL bCase, BOOL bWord)
{
ASSERT_VALID(this);
_AFX_RICHEDIT2_STATE* pEditState = _afxRichEdit2State;
pEditState->strFind = lpszFind;
pEditState->bCase = bCase;
pEditState->bWord = bWord;
pEditState->bNext = bNext;
if (!FindText(pEditState))
TextNotFound(pEditState->strFind);
else
AdjustDialogPosition(pEditState->pFindReplaceDlg);
ASSERT_VALID(this);
}
void CRichEdit2View::OnReplaceSel(LPCTSTR lpszFind, BOOL bNext, BOOL bCase,
BOOL bWord, LPCTSTR lpszReplace)
{
ASSERT_VALID(this);
_AFX_RICHEDIT2_STATE* pEditState = _afxRichEdit2State;
pEditState->strFind = lpszFind;
pEditState->strReplace = lpszReplace;
pEditState->bCase = bCase;
pEditState->bWord = bWord;
pEditState->bNext = bNext;
if (!SameAsSelected(pEditState->strFind, pEditState->bCase, pEditState->bWord))
{
if (!FindText(pEditState))
TextNotFound(pEditState->strFind);
else
AdjustDialogPosition(pEditState->pFindReplaceDlg);
return;
}
long start;
long end;
long length1;
long length2;
GetRichEditCtrl().GetSel(start, end);
length1 = end - start;
GetRichEditCtrl().ReplaceSel(pEditState->strReplace, TRUE);
if (!FindText(pEditState))
{
TextNotFound(pEditState->strFind);
}
else
{
GetRichEditCtrl().GetSel(start, end);
length2 = end - start;
if (m_lInitialSearchPos < 0)
m_lInitialSearchPos += (length2 - length1);
AdjustDialogPosition(pEditState->pFindReplaceDlg);
}
ASSERT_VALID(this);
}
void CRichEdit2View::OnReplaceAll(LPCTSTR lpszFind, LPCTSTR lpszReplace, BOOL bCase, BOOL bWord)
{
ASSERT_VALID(this);
_AFX_RICHEDIT2_STATE* pEditState = _afxRichEdit2State;
pEditState->strFind = lpszFind;
pEditState->strReplace = lpszReplace;
pEditState->bCase = bCase;
pEditState->bWord = bWord;
pEditState->bNext = TRUE;
CWaitCursor wait;
// no selection or different than what looking for
if (!SameAsSelected(pEditState->strFind, pEditState->bCase, pEditState->bWord))
{
if (!FindText(pEditState))
{
TextNotFound(pEditState->strFind);
return;
}
}
GetRichEditCtrl().HideSelection(TRUE, FALSE);
do
{
GetRichEditCtrl().ReplaceSel(pEditState->strReplace, TRUE);
} while (FindTextSimple(pEditState));
TextNotFound(pEditState->strFind);
GetRichEditCtrl().HideSelection(FALSE, FALSE);
ASSERT_VALID(this);
}
LRESULT CRichEdit2View::OnFindReplaceCmd(WPARAM, LPARAM lParam)
{
ASSERT_VALID(this);
CFindReplaceDialog* pDialog = CFindReplaceDialog::GetNotifier(lParam);
ASSERT(pDialog != NULL);
_AFX_RICHEDIT2_STATE* pEditState = _afxRichEdit2State;
ASSERT(pDialog == pEditState->pFindReplaceDlg);
if (pDialog->IsTerminating())
pEditState->pFindReplaceDlg = NULL;
else if (pDialog->FindNext())
{
OnFindNext(pDialog->GetFindString(), pDialog->SearchDown(),
pDialog->MatchCase(), pDialog->MatchWholeWord());
}
else if (pDialog->ReplaceCurrent())
{
ASSERT(!pEditState->bFindOnly);
OnReplaceSel(pDialog->GetFindString(),
pDialog->SearchDown(), pDialog->MatchCase(), pDialog->MatchWholeWord(),
pDialog->GetReplaceString());
}
else if (pDialog->ReplaceAll())
{
ASSERT(!pEditState->bFindOnly);
OnReplaceAll(pDialog->GetFindString(), pDialog->GetReplaceString(),
pDialog->MatchCase(), pDialog->MatchWholeWord());
}
ASSERT_VALID(this);
return 0;
}
BOOL CRichEdit2View::SameAsSelected(LPCTSTR lpszCompare, BOOL bCase, BOOL /*bWord*/)
{
CString strSelect = GetRichEditCtrl().GetSelText();
return (bCase && lstrcmp(lpszCompare, strSelect) == 0) ||
(!bCase && lstrcmpi(lpszCompare, strSelect) == 0);
}
BOOL CRichEdit2View::FindText(_AFX_RICHEDIT2_STATE* pEditState)
{
ASSERT(pEditState != NULL);
return FindText(pEditState->strFind, pEditState->bCase, pEditState->bWord);
}
BOOL CRichEdit2View::FindText(LPCTSTR lpszFind, BOOL bCase, BOOL bWord)
{
ASSERT_VALID(this);
CWaitCursor wait;
return FindTextSimple(lpszFind, bCase, bWord);
}
BOOL CRichEdit2View::FindTextSimple(_AFX_RICHEDIT2_STATE* pEditState)
{
ASSERT(pEditState != NULL);
return FindTextSimple(pEditState->strFind, pEditState->bCase, pEditState->bWord);
}
BOOL CRichEdit2View::FindTextSimple(LPCTSTR lpszFind, BOOL bCase, BOOL bWord)
{
USES_CONVERSION;
ASSERT(lpszFind != NULL);
FINDTEXTEX ft;
long cchText;
GETTEXTLENGTHEX textlen;
textlen.flags = GTL_NUMCHARS;
#ifdef UNICODE
textlen.codepage = 1200; // Unicode code page
#else
textlen.codepage = CP_ACP;
#endif
cchText = (long)GetRichEditCtrl().SendMessage(
EM_GETTEXTLENGTHEX,
(WPARAM) &textlen,
0);
GetRichEditCtrl().GetSel(ft.chrg);
if (m_bFirstSearch)
{
m_lInitialSearchPos = ft.chrg.cpMin;
m_bFirstSearch = FALSE;
}
//REVIEW: Is this cast safe?
ft.lpstrText = (LPTSTR)lpszFind;
if (ft.chrg.cpMin != ft.chrg.cpMax) // i.e. there is a selection
ft.chrg.cpMin++;
DWORD dwFlags = bCase ? FR_MATCHCASE : 0;
dwFlags |= bWord ? FR_WHOLEWORD : 0;
dwFlags |= FR_DOWN;
ft.chrg.cpMax = cchText;
long index = GetRichEditCtrl().FindText(dwFlags, &ft);
if (-1 == index && m_lInitialSearchPos > 0)
{
//
// m_lInitialSearchPos pulls double duty as the point at which we
// started searching and a flag which says if we've wrapped back
// to the beginning of the text during a search. If it's negative
// (biased by the number of characters) then we've already wrapped
//
m_lInitialSearchPos = m_lInitialSearchPos - cchText;
ft.chrg.cpMin = 0;
ft.chrg.cpMax = cchText;
index = GetRichEditCtrl().FindText(dwFlags, &ft);
}
if (-1 != index && m_lInitialSearchPos < 0)
if (index >= (m_lInitialSearchPos + cchText) )
index = -1;
if (-1 != index)
GetRichEditCtrl().SetSel(ft.chrgText);
return (-1 != index);
}
long CRichEdit2View::FindAndSelect(DWORD dwFlags, FINDTEXTEX& ft)
{
long index = GetRichEditCtrl().FindText(dwFlags, &ft);
if (index != -1) // i.e. we found something
GetRichEditCtrl().SetSel(ft.chrgText);
return index;
}
void CRichEdit2View::TextNotFound(LPCTSTR lpszFind)
{
ASSERT_VALID(this);
m_bFirstSearch = TRUE;
OnTextNotFound(lpszFind);
}
void CRichEdit2View::OnTextNotFound(LPCTSTR)
{
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2View diagnostics
#ifdef _DEBUG
void CRichEdit2View::AssertValid() const
{
CCtrlView::AssertValid();
ASSERT_VALID(&m_aPageStart);
_AFX_RICHEDIT2_STATE* pEditState = _afxRichEdit2State;
if (pEditState->pFindReplaceDlg != NULL)
ASSERT_VALID(pEditState->pFindReplaceDlg);
}
void CRichEdit2View::Dump(CDumpContext& dc) const
{
CCtrlView::Dump(dc);
AFX_DUMP1(dc, "\nm_aPageStart ", &m_aPageStart);
AFX_DUMP0(dc, "\n Static Member Data:");
_AFX_RICHEDIT2_STATE* pEditState = _afxRichEdit2State;
if (pEditState->pFindReplaceDlg != NULL)
{
AFX_DUMP1(dc, "\npFindReplaceDlg = ",
(void*)pEditState->pFindReplaceDlg);
AFX_DUMP1(dc, "\nbFindOnly = ", pEditState->bFindOnly);
}
AFX_DUMP1(dc, "\nstrFind = ", pEditState->strFind);
AFX_DUMP1(dc, "\nstrReplace = ", pEditState->strReplace);
AFX_DUMP1(dc, "\nbCase = ", pEditState->bCase);
AFX_DUMP1(dc, "\nbWord = ", pEditState->bWord);
AFX_DUMP1(dc, "\nbNext = ", pEditState->bNext);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// OLE Client support and commands
BOOL CRichEdit2View::IsSelected(const CObject* pDocItem) const
{
return (pDocItem == GetSelectedItem());
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2Doc
CRichEdit2Doc::CRichEdit2Doc()
{
m_bRTF = TRUE;
m_bUnicode = FALSE;
m_bUpdateObjectCache = FALSE;
ASSERT_VALID(this);
}
CRichEdit2View* CRichEdit2Doc::GetView() const
{
// find the first view - if there are no views
// we must return NULL
POSITION pos = GetFirstViewPosition();
if (pos == NULL)
return NULL;
// find the first view that is a CRichEdit2View
CView* pView;
while (pos != NULL)
{
pView = GetNextView(pos);
if (pView->IsKindOf(RUNTIME_CLASS(CRichEdit2View)))
return (CRichEdit2View*) pView;
}
// can't find one--return NULL
return NULL;
}
BOOL CRichEdit2Doc::IsModified()
{
return GetView()->GetRichEditCtrl().GetModify();
}
void CRichEdit2Doc::SetModifiedFlag(BOOL bModified)
{
GetView()->GetRichEditCtrl().SetModify(bModified);
ASSERT(!!GetView()->GetRichEditCtrl().GetModify() == !!bModified);
}
COleClientItem* CRichEdit2Doc::GetInPlaceActiveItem(CWnd* pWnd)
{
ASSERT_KINDOF(CRichEdit2View, pWnd);
CRichEdit2View* pView = (CRichEdit2View*)pWnd;
return pView->GetInPlaceActiveItem();
}
void CRichEdit2Doc::SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU)
{
// we call CDocument and not COleServerDoc because we don't want to do the
// SetHostNames stuff here. The richedit will do it. And we tell the richedit
// in SetTitle
CDocument::SetPathName(lpszPathName, bAddToMRU);
}
void CRichEdit2Doc::SetTitle(LPCTSTR pwszTitle)
{
USES_CONVERSION;
COleServerDoc::SetTitle(pwszTitle);
CRichEdit2View *pView = GetView();
ASSERT(pView != NULL);
ASSERT(pView->m_lpRichEditOle != NULL);
LPCSTR pszAppName = WideToAnsiNewArray(AfxGetAppName());
if (pszAppName)
{
LPCSTR pszTitle = WideToAnsiNewArray(pwszTitle);
if (pszTitle)
{
pView->m_lpRichEditOle->SetHostNames(pszAppName, pszTitle);
delete [] pszTitle;
}
delete [] pszAppName;
}
}
CRichEdit2CntrItem* CRichEdit2Doc::LookupItem(LPOLEOBJECT lpobj) const
{
POSITION pos = COleServerDoc::GetStartPosition();
CRichEdit2CntrItem* pItem;
while (pos != NULL)
{
pItem = (CRichEdit2CntrItem*) COleServerDoc::GetNextItem(pos);
// delete item is right type and not under construction
if (pItem->IsKindOf(RUNTIME_CLASS(CRichEdit2CntrItem)) &&
pItem->m_lpObject == lpobj)
{
return pItem;
}
}
return NULL;
}
CRichEdit2CntrItem* CRichEdit2Doc::CreateClientItem(REOBJECT* preo) const
{
// cast away constness of this
return new CRichEdit2CntrItem(preo, (CRichEdit2Doc*)this);
// a derived class typically needs to return its own item of a class
// derived from CRichEdit2CntrItem
}
void CRichEdit2Doc::MarkItemsClear() const
{
POSITION pos = COleServerDoc::GetStartPosition();
CRichEdit2CntrItem* pItem;
while (pos != NULL)
{
pItem = (CRichEdit2CntrItem*) COleServerDoc::GetNextItem(pos);
// Mark item as not in use unless under construction (i.e. m_lpObject == NULL)
if (pItem->IsKindOf(RUNTIME_CLASS(CRichEdit2CntrItem)))
pItem->Mark( (pItem->m_lpObject == NULL) ? TRUE : FALSE);
}
}
void CRichEdit2Doc::DeleteUnmarkedItems() const
{
POSITION pos = COleServerDoc::GetStartPosition();
CRichEdit2CntrItem* pItem;
while (pos != NULL)
{
pItem = (CRichEdit2CntrItem*) COleServerDoc::GetNextItem(pos);
// Mark item as not in use unless under construction (i.e. m_lpObject == NULL)
if (pItem->IsKindOf(RUNTIME_CLASS(CRichEdit2CntrItem)) && !pItem->IsMarked())
delete pItem;
}
}
POSITION CRichEdit2Doc::GetStartPosition() const
{
if (m_bUpdateObjectCache)
((CRichEdit2Doc*)this)->UpdateObjectCache(); //cast away const
return COleServerDoc::GetStartPosition();
}
void CRichEdit2Doc::UpdateObjectCache()
{
CRichEdit2View* pView = GetView();
CRichEdit2CntrItem* pItem;
if (pView != NULL)
{
ASSERT(pView->m_lpRichEditOle != NULL);
MarkItemsClear();
long i,nCount = pView->m_lpRichEditOle->GetObjectCount();
for (i=0;i<nCount;i++)
{
CRe2Object reo; // needs to be in here so destructor called to release interfaces
HRESULT hr = pView->m_lpRichEditOle->GetObject(i, &reo, REO_GETOBJ_ALL_INTERFACES);
//reo interfaces are UNICODE
ASSERT(SUCCEEDED(hr));
if (GetScode(hr) == S_OK)
{
pItem = LookupItem(reo.poleobj);
if (pItem == NULL)
{
pItem = ((CRichEdit2Doc*)this)->CreateClientItem(&reo);
pItem->UpdateItemType();
}
ASSERT(pItem != NULL);
pItem->Mark(TRUE);
}
}
DeleteUnmarkedItems();
}
m_bUpdateObjectCache = FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2Doc Attributes
COleClientItem* CRichEdit2Doc::GetPrimarySelectedItem(CView* pView)
{
ASSERT(pView->IsKindOf(RUNTIME_CLASS(CRichEdit2View)));
return ((CRichEdit2View*)pView)->GetSelectedItem();
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2Doc Operations
void CRichEdit2Doc::DeleteContents()
{
COleServerDoc::DeleteContents();
CWaitCursor wait;
CRichEdit2View *pView = GetView();
if (pView != NULL)
{
pView->DeleteContents();
pView->GetRichEditCtrl().SetModify(FALSE);
ASSERT(pView->GetRichEditCtrl().GetModify() == FALSE);
}
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2Doc serialization
void CRichEdit2Doc::Serialize(CArchive& ar)
{
CRichEdit2View *pView = GetView();
if (pView != NULL)
pView->Serialize(ar);
// we don't call the base class COleServerDoc::Serialize
// because we don't want the client items serialized
// the client items are handled directly by the RichEdit control
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2Doc diagnostics
#ifdef _DEBUG
void CRichEdit2Doc::AssertValid() const
{
COleServerDoc::AssertValid();
}
void CRichEdit2Doc::Dump(CDumpContext& dc) const
{
COleServerDoc::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2Doc commands
void CRichEdit2Doc::PreCloseFrame(CFrameWnd* pFrameArg)
{
ASSERT_VALID(this);
ASSERT_VALID(pFrameArg);
// turn off redraw so the user doesn't see the deactivation happening
BOOL bSetRedraw = FALSE;
if (pFrameArg->GetStyle() & WS_VISIBLE)
{
pFrameArg->SendMessage(WM_SETREDRAW, (WPARAM)FALSE);
bSetRedraw = TRUE;
}
// deactivate any inplace active items on this frame
GetView()->m_lpRichEditOle->InPlaceDeactivate();
POSITION pos = GetStartPosition();
CRichEdit2CntrItem* pItem;
while (pos != NULL)
{
pItem = (CRichEdit2CntrItem*) GetNextClientItem(pos);
if (pItem == NULL)
break;
ASSERT(pItem->IsKindOf(RUNTIME_CLASS(CRichEdit2CntrItem)));
pItem->Close();
}
// turn redraw back on
if (bSetRedraw)
pFrameArg->SendMessage(WM_SETREDRAW, (WPARAM)TRUE);
}
void CRichEdit2Doc::UpdateModifiedFlag()
{
// don't do anything here
// let the richedit handle all of this
}
COleServerItem* CRichEdit2Doc::OnGetEmbeddedItem()
{
ASSERT(FALSE);
return NULL;
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2CntrItem implementation
CRichEdit2CntrItem::CRichEdit2CntrItem(REOBJECT *preo, CRichEdit2Doc* pContainer)
: COleClientItem(pContainer)
{
m_bMark = FALSE;
m_bLock = FALSE;
if (preo != NULL)
{
ASSERT(preo->poleobj != NULL);
ASSERT(preo->pstg != NULL);
ASSERT(preo->polesite != NULL);
m_lpObject = preo->poleobj;
m_lpStorage = preo->pstg;
m_lpClientSite = preo->polesite;
m_lpObject->AddRef();
m_lpStorage->AddRef();
m_lpClientSite->AddRef();
}
else
{
m_lpObject = NULL;
m_lpStorage = NULL;
m_lpClientSite = NULL;
}
}
CRichEdit2CntrItem::~CRichEdit2CntrItem()
{
if (m_lpClientSite != NULL)
m_lpClientSite->Release();
}
void CRichEdit2CntrItem::OnDeactivateUI(BOOL bUndoable)
{
CView* pView = GetActiveView();
if (pView != NULL)
{
ASSERT(pView->GetParentFrame() != NULL);
pView->GetParentFrame()->SendMessage(WM_SETMESSAGESTRING,
(WPARAM)AFX_IDS_IDLEMESSAGE);
}
COleClientItem::OnDeactivateUI(bUndoable);
}
HRESULT CRichEdit2CntrItem::ShowContainerUI(BOOL b)
{
if (!CanActivate())
return E_NOTIMPL;
if (b)
{
OnDeactivateUI(FALSE);
OnDeactivate();
}
else
{
OnActivate();
OnActivateUI();
}
return S_OK;
}
BOOL CRichEdit2CntrItem::OnChangeItemPosition(const CRect& /*rectPos*/)
{
ASSERT_VALID(this);
// richedit handles this
return FALSE;
}
BOOL CRichEdit2CntrItem::CanActivate()
{
// Editing in-place while the server itself is being edited in-place
// does not work and is not supported. So, disable in-place
// activation in this case.
COleServerDoc* pDoc = DYNAMIC_DOWNCAST(COleServerDoc, GetDocument());
if (pDoc != NULL && pDoc->IsInPlaceActive())
return FALSE;
// otherwise, rely on default behavior
return COleClientItem::CanActivate();
}
HRESULT CRichEdit2CntrItem::GetWindowContext(LPOLEINPLACEFRAME* lplpFrame,
LPOLEINPLACEUIWINDOW* lplpDoc, LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
CRect rc1,rc2;
if (!CanActivate())
return E_NOTIMPL;
return m_xOleIPSite.GetWindowContext(lplpFrame, lplpDoc, &rc1, &rc2, lpFrameInfo);
}
BOOL CRichEdit2CntrItem::ConvertTo(REFCLSID clsidNew)
{
USES_CONVERSION;
LPRICHEDITOLE preole = GetDocument()->GetView()->m_lpRichEditOle;
LPOLESTR lpOleStr;
OleRegGetUserType(clsidNew, USERCLASSTYPE_FULL, &lpOleStr);
LPCTSTR pwsz = OLE2CT(lpOleStr);
BOOL bRet;
LPSTR psz = WideToAnsiNewArray(pwsz);
if (psz)
{
bRet = SUCCEEDED(preole->ConvertObject(REO_IOB_SELECTION, clsidNew, psz));
delete [] psz;
}
else
{
bRet = FALSE;
}
CoTaskMemFree(lpOleStr);
return (bRet);
}
BOOL CRichEdit2CntrItem::ActivateAs(LPCTSTR, REFCLSID clsidOld,
REFCLSID clsidNew)
{
LPRICHEDITOLE preole = GetDocument()->GetView()->m_lpRichEditOle;
HRESULT hRes = preole->ActivateAs(clsidOld, clsidNew);
return (SUCCEEDED(hRes));
}
void CRichEdit2CntrItem::SetDrawAspect(DVASPECT nDrawAspect)
{
LPRICHEDITOLE preole = GetDocument()->GetView()->m_lpRichEditOle;
preole->SetDvaspect(REO_IOB_SELECTION, nDrawAspect);
COleClientItem::SetDrawAspect(nDrawAspect);
}
void CRichEdit2CntrItem::SyncToRichEditObject(REOBJECT& reo)
{
COleClientItem::SetDrawAspect((DVASPECT)reo.dvaspect);
}
/////////////////////////////////////////////////////////////////////////////
// CRichEdit2CntrItem diagnostics
#ifdef _DEBUG
void CRichEdit2CntrItem::AssertValid() const
{
COleClientItem::AssertValid();
}
void CRichEdit2CntrItem::Dump(CDumpContext& dc) const
{
COleClientItem::Dump(dc);
}
#endif
/////////////////////////////////////////////////////////////////////////////
LPOLECLIENTSITE CRichEdit2CntrItem::GetClientSite()
{
if (m_lpClientSite == NULL)
{
CRichEdit2Doc* pDoc = DYNAMIC_DOWNCAST(CRichEdit2Doc, GetDocument());
CRichEdit2View* pView = DYNAMIC_DOWNCAST(CRichEdit2View, pDoc->GetView());
ASSERT(pView->m_lpRichEditOle != NULL);
HRESULT hr = pView->m_lpRichEditOle->GetClientSite(&m_lpClientSite);
if (hr != S_OK)
AfxThrowOleException(hr);
}
ASSERT(m_lpClientSite != NULL);
return m_lpClientSite;
}
/////////////////////////////////////////////////////////////////////////////
#ifndef _AFX_ENABLE_INLINES
static const char _szAfxWinInl[] = "afxrich2.inl";
#undef THIS_FILE
#define THIS_FILE _szAfxWinInl
#define _AFXRICH_INLINE
#include "afxrich2.inl"
#endif //_AFX_ENABLE_INLINES
/////////////////////////////////////////////////////////////////////////////
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif
IMPLEMENT_SERIAL(CRichEdit2CntrItem, COleClientItem, 0)
IMPLEMENT_DYNAMIC(CRichEdit2Doc, COleServerDoc)
IMPLEMENT_DYNCREATE(CRichEdit2View, CCtrlView)
/////////////////////////////////////////////////////////////////////////////