Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1456 lines
35 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"
#ifdef AFX_OLE4_SEG
#pragma code_seg(AFX_OLE4_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
//////////////////////////////////////////////////////////////////////////////
// COleServerItem implementation
COleServerItem::COleServerItem(COleServerDoc* pServerDoc, BOOL bAutoDelete)
{
if (pServerDoc != NULL)
ASSERT_VALID(pServerDoc);
m_dwRef = 0; // always start in disconnected state
m_bAutoDelete = bAutoDelete;
m_bNeedUnlock = FALSE;
// initially, item does not have an extent
m_sizeExtent.cx = 0;
m_sizeExtent.cy = 0;
// initialize advise holders
m_lpOleAdviseHolder = NULL;
m_lpDataAdviseHolder = NULL;
// add presentation formats to the data source
m_dataSource.m_nGrowBy = 1;
FORMATETC formatEtc;
formatEtc.ptd = NULL;
formatEtc.dwAspect = DVASPECT_CONTENT;
formatEtc.lindex = -1;
// by default, a COleServerItem supports CF_METAFILEPICT
formatEtc.cfFormat = CF_METAFILEPICT;
formatEtc.tymed = TYMED_MFPICT;
m_dataSource.DelayRenderData(0, &formatEtc);
// add item to server document
m_pDocument = NULL;
if (pServerDoc != NULL)
pServerDoc->AddItem(this);
ASSERT(m_pDocument == pServerDoc);
AfxOleLockApp();
}
COleServerItem::~COleServerItem()
{
m_bAutoDelete = FALSE; // no delete during destructor
// release any advise holders
RELEASE(m_lpOleAdviseHolder);
RELEASE(m_lpDataAdviseHolder);
ExternalDisconnect();
// disconnect from the document
COleServerDoc* pDoc = GetDocument();
if (pDoc != NULL)
{
// remove external lock from it
if (m_bNeedUnlock)
{
pDoc->LockExternal(FALSE, TRUE);
m_bNeedUnlock = FALSE;
}
// reset m_pEmbeddedItem if destroying embedded item
if (pDoc->m_pEmbeddedItem == this)
pDoc->m_pEmbeddedItem = NULL;
// remove from list
pDoc->RemoveItem(this);
}
// cleanup any references
AfxOleUnlockApp();
}
BOOL COleServerItem::IsBlank() const
{
// server items are blank in order to keep them from serializing when
// COleDocument::Serialize is called.
return TRUE;
}
BOOL COleServerItem::IsConnected() const
{
// if item is connected in any way, return TRUE
if (m_dwRef != 0)
return TRUE;
// otherwise check if embedded item and document is connected
if (!IsLinkedItem() && GetDocument()->m_lpClientSite != NULL)
return TRUE;
return FALSE; // not connected
}
void COleServerItem::NotifyClient(OLE_NOTIFICATION nCode, DWORD dwParam)
{
switch (nCode)
{
// IDataObject notifications
case OLE_CHANGED:
if (m_lpDataAdviseHolder != NULL)
m_lpDataAdviseHolder->SendOnDataChange(GetDataObject(), dwParam, 0);
break;
// IOleObject notifications
case OLE_SAVED:
if (m_lpOleAdviseHolder != NULL)
m_lpOleAdviseHolder->SendOnSave();
break;
case OLE_CLOSED:
if (m_lpOleAdviseHolder != NULL)
m_lpOleAdviseHolder->SendOnClose();
break;
case OLE_RENAMED:
if (m_lpOleAdviseHolder != NULL)
{
// Note: the moniker should already be updated for this to work
LPMONIKER lpMoniker = (LPMONIKER)dwParam;
m_lpOleAdviseHolder->SendOnRename(lpMoniker);
}
break;
default:
ASSERT(FALSE);
}
}
/////////////////////////////////////////////////////////////////////////////
// Helpers for getting commonly used interfaces through interface map
LPDATAOBJECT COleServerItem::GetDataObject()
{
LPDATAOBJECT lpDataObject =
(LPDATAOBJECT)GetInterface(&IID_IDataObject);
ASSERT(lpDataObject != NULL);
return lpDataObject;
}
LPOLEOBJECT COleServerItem::GetOleObject()
{
LPOLEOBJECT lpOleObject =
(LPOLEOBJECT)GetInterface(&IID_IOleObject);
ASSERT(lpOleObject != NULL);
return lpOleObject;
}
/////////////////////////////////////////////////////////////////////////////
// COleServerItem overrides
BOOL COleServerItem::OnQueryUpdateItems()
{
COleDocument* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// update all of the embedded objects
POSITION pos = pDoc->GetStartPosition();
COleClientItem* pItem;
while ((pItem = pDoc->GetNextClientItem(pos)) != NULL)
{
// if any item is out-of-date, then this item is out-of-date
if (pItem->m_lpObject->IsUpToDate() != NULL)
return TRUE; // update needed
}
return FALSE; // update not needed
}
void COleServerItem::OnUpdateItems()
{
COleDocument* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// update all of the embedded objects
POSITION pos = pDoc->GetStartPosition();
COleClientItem* pItem;
while ((pItem = pDoc->GetNextClientItem(pos)) != NULL)
{
// update any out-of-date item
if (pItem->m_lpObject->IsUpToDate() != NULL)
pItem->m_lpObject->Update();
}
}
BOOL COleServerItem::OnSetExtent(DVASPECT dwDrawAspect, const CSize& size)
{
ASSERT_VALID(this);
if (dwDrawAspect == DVASPECT_CONTENT)
{
m_sizeExtent = size; // simply remember the extent
return TRUE;
}
return FALSE; // not implemented for that dwDrawAspect
}
BOOL COleServerItem::OnGetExtent(DVASPECT /*dwDrawAspect*/, CSize& rSize)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidAddress(&rSize, sizeof(CSize)));
// the default implementation doesn't know what the extent is
rSize.cx = 0;
rSize.cy = 0;
return FALSE;
}
void COleServerItem::OnDoVerb(LONG iVerb)
{
switch (iVerb)
{
// open - maps to OnOpen
case OLEIVERB_OPEN:
case -OLEIVERB_OPEN-1: // allows positive OLEIVERB_OPEN-1 in registry
OnOpen();
break;
// primary, show, and unknown map to OnShow
case OLEIVERB_PRIMARY: // OLEIVERB_PRIMARY is 0 and "Edit" in registry
case OLEIVERB_SHOW:
OnShow();
break;
// hide maps to OnHide
case OLEIVERB_HIDE:
case -OLEIVERB_HIDE-1: // allows positive OLEIVERB_HIDE-1 in registry
OnHide();
break;
default:
// negative verbs not understood should return E_NOTIMPL
if (iVerb < 0)
AfxThrowOleException(E_NOTIMPL);
// positive verb not processed --
// according to OLE spec, primary verb should be executed
// instead.
OnDoVerb(OLEIVERB_PRIMARY);
// also, OLEOBJ_S_INVALIDVERB should be returned.
AfxThrowOleException(OLEOBJ_S_INVALIDVERB);
}
}
BOOL COleServerItem::OnDrawEx(CDC* pDC, DVASPECT nDrawAspect, CSize& rSize)
{
ASSERT_VALID(pDC);
ASSERT(AfxIsValidAddress(&rSize, sizeof(CSize)));
if (nDrawAspect != DVASPECT_CONTENT)
return FALSE;
return OnDraw(pDC, rSize);
}
void COleServerItem::OnShow()
{
ASSERT_VALID(this);
// attempt in place activation (if not supported, fall back on "Open")
COleServerDoc* pDoc = GetDocument();
if (!pDoc->ActivateInPlace())
{
// by default OnShow() maps to OnOpen() if in-place activation
// not supported
OnOpen();
}
}
void COleServerItem::OnOpen()
{
ASSERT_VALID(this);
// default implementation shows the document
COleServerDoc* pDoc = GetDocument();
ASSERT(pDoc != NULL);
pDoc->OnShowDocument(TRUE);
}
void COleServerItem::OnHide()
{
ASSERT_VALID(this);
// default implementation hides the document
COleServerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->OnShowDocument(FALSE);
}
BOOL COleServerItem::GetMetafileData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
ASSERT(lpStgMedium->tymed == TYMED_NULL); // GetDataHere not valid
ASSERT(lpStgMedium->pUnkForRelease == NULL);
// medium must be TYMED_MFPICT -- cannot fill in existing HGLOBAL
if (!(lpFormatEtc->tymed & TYMED_MFPICT) || lpStgMedium->hGlobal != NULL)
return FALSE;
// create appropriate memory metafile DC
CMetaFileDC dc;
if (!dc.Create())
return FALSE;
// create attribute DC according to lpFormatEtc->ptd
HDC hAttribDC = _AfxOleCreateDC(lpFormatEtc->ptd);
if (hAttribDC == NULL)
return FALSE;
dc.SetAttribDC(hAttribDC);
// Paint directly into the metafile.
CSize size(0, 0);
BOOL bResult = OnDrawEx(&dc, (DVASPECT)lpFormatEtc->dwAspect, size);
// attribute DC is no longer necessary
dc.SetAttribDC(NULL);
::DeleteDC(hAttribDC);
if (!bResult)
{
#ifdef _DEBUG
if (afxTraceFlags & traceOle)
TRACE0("calling COleServerItem::OnDrawEx()failed.\n");
#endif
return FALSE;
}
HMETAFILE hMF = dc.Close();
if (hMF == NULL)
return FALSE;
HGLOBAL hPict;
if ((hPict =
::GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT))) == NULL)
{
DeleteMetaFile(hMF);
return FALSE;
}
LPMETAFILEPICT lpPict;
if ((lpPict = (LPMETAFILEPICT)::GlobalLock(hPict)) == NULL)
{
DeleteMetaFile(hMF);
::GlobalFree(hPict);
return FALSE;
}
// set the metafile size
lpPict->mm = MM_ANISOTROPIC;
lpPict->hMF = hMF;
if (size.cx == 0 && size.cy == 0 &&
!OnGetExtent((DVASPECT)lpFormatEtc->dwAspect, size))
{
TRACE0("Warning: OnGetExtent failed during OnDrawEx --\n");
TRACE0("\tpresentation metafile may be badly formed!\n");
}
lpPict->xExt = size.cx;
lpPict->yExt = size.cy; // HIMETRIC height
if (lpPict->yExt < 0)
{
TRACE0("Warning: HIMETRIC natural size is negative.\n");
lpPict->yExt = -lpPict->yExt; // backward compatibility fix
}
#ifdef _DEBUG
if (lpPict->xExt == 0 || lpPict->yExt == 0)
{
// usually the natural extent is set to something interesting
TRACE0("Warning: COleServerItem has no natural size --\n");
TRACE0("\twill not work with some apps like MS Write.\n");
}
#endif
// return the medium with the hGlobal to the METAFILEPICT
::GlobalUnlock(hPict);
lpStgMedium->hGlobal = hPict;
lpStgMedium->tymed = TYMED_MFPICT;
return TRUE;
}
BOOL COleServerItem::OnSetColorScheme(const LOGPALETTE* /*lpLogPalette*/)
{
ASSERT_VALID(this);
return FALSE; // default does nothing
}
BOOL COleServerItem::OnInitFromData(
COleDataObject* /*pDataObject*/, BOOL /*bCreation*/)
{
ASSERT_VALID(this);
AfxThrowOleException(E_NOTIMPL);
return FALSE;
}
void COleServerItem::CopyToClipboard(BOOL bIncludeLink)
{
ASSERT_VALID(this);
COleDataSource* pDataSource = OnGetClipboardData(bIncludeLink, NULL, NULL);
// put it on the clipboard
pDataSource->SetClipboard();
}
COleDataSource* COleServerItem::OnGetClipboardData(BOOL bIncludeLink,
LPPOINT lpOffset, LPSIZE lpSize)
{
ASSERT_VALID(this);
COleDataSource* pDataSource = new COleDataSource;
TRY
{
GetClipboardData(pDataSource, bIncludeLink, lpOffset, lpSize);
}
CATCH_ALL(e)
{
delete pDataSource;
THROW_LAST();
}
END_CATCH_ALL
ASSERT_VALID(pDataSource);
return pDataSource;
}
DROPEFFECT COleServerItem::DoDragDrop(LPCRECT lpItemRect, CPoint ptOffset,
BOOL bIncludeLink, DWORD dwEffects, LPCRECT lpRectStartDrag)
{
ASSERT(AfxIsValidAddress(lpItemRect, sizeof(RECT)));
ASSERT_VALID(this);
ASSERT_VALID(this);
DROPEFFECT dropEffect = DROPEFFECT_NONE;
COleDataSource *pDataSource = NULL;
TRY
{
// get clipboard data for this item
CSize sizeItem(
lpItemRect->right - lpItemRect->left,
lpItemRect->bottom - lpItemRect->top);
pDataSource = OnGetClipboardData(bIncludeLink, &ptOffset, &sizeItem);
// add DROPEFFECT_LINK if link source is available
LPDATAOBJECT lpDataObject = (LPDATAOBJECT)
pDataSource->GetInterface(&IID_IDataObject);
ASSERT(lpDataObject != NULL);
FORMATETC formatEtc;
formatEtc.cfFormat = (CLIPFORMAT)_oleData.cfLinkSource;
formatEtc.ptd = NULL;
formatEtc.dwAspect = DVASPECT_CONTENT;
formatEtc.lindex = -1;
formatEtc.tymed = (TYMED)-1;
if (lpDataObject->QueryGetData(&formatEtc) == S_OK)
dwEffects |= DROPEFFECT_LINK;
// calculate default sensitivity rectangle
CRect rectDrag;
if (lpRectStartDrag == NULL)
{
rectDrag.SetRect(lpItemRect->left, lpItemRect->top, lpItemRect->left,
lpItemRect->top);
lpRectStartDrag = &rectDrag;
}
// do drag drop operation
dropEffect = pDataSource->DoDragDrop(dwEffects, lpRectStartDrag);
pDataSource->InternalRelease();
}
CATCH_ALL(e)
{
if (pDataSource != NULL)
pDataSource->InternalRelease();
THROW_LAST();
}
END_CATCH_ALL
return dropEffect;
}
void COleServerItem::GetClipboardData(COleDataSource* pDataSource,
BOOL bIncludeLink, LPPOINT lpOffset, LPSIZE lpSize)
{
ASSERT_VALID(this);
ASSERT_VALID(pDataSource);
ASSERT(lpOffset == NULL ||
AfxIsValidAddress(lpOffset, sizeof(POINT), FALSE));
// add CF_EMBEDDEDOBJECT by creating memory storage copy of the object
STGMEDIUM stgMedium;
GetEmbedSourceData(&stgMedium);
pDataSource->CacheData((CLIPFORMAT)_oleData.cfEmbedSource, &stgMedium);
// add CF_OBJECTDESCRIPTOR
GetObjectDescriptorData(lpOffset, lpSize, &stgMedium);
pDataSource->CacheData((CLIPFORMAT)_oleData.cfObjectDescriptor,
&stgMedium);
// add any presentation entries/conversion formats that the item
// can produce.
AddOtherClipboardData(pDataSource);
// add CF_LINKSOURCE if supporting links to pseudo objects
if (bIncludeLink && GetLinkSourceData(&stgMedium))
{
pDataSource->CacheData((CLIPFORMAT)_oleData.cfLinkSource, &stgMedium);
// add CF_LINKSOURCEDESCRIPTOR
GetObjectDescriptorData(lpOffset, lpSize, &stgMedium);
pDataSource->CacheData((CLIPFORMAT)_oleData.cfLinkSourceDescriptor,
&stgMedium);
}
}
void COleServerItem::GetEmbedSourceData(LPSTGMEDIUM lpStgMedium)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
LPLOCKBYTES lpLockBytes;
SCODE sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes);
if (sc != S_OK)
AfxThrowOleException(sc);
ASSERT(lpLockBytes != NULL);
LPSTORAGE lpStorage;
sc = ::StgCreateDocfileOnILockBytes(lpLockBytes,
STGM_SHARE_EXCLUSIVE|STGM_CREATE|STGM_READWRITE, 0, &lpStorage);
if (sc != S_OK)
{
VERIFY(lpLockBytes->Release() == 0);
AfxThrowOleException(sc);
}
ASSERT(lpStorage != NULL);
// setup for save copy as
COleServerDoc* pDoc = GetDocument();
pDoc->m_bSameAsLoad = FALSE;
pDoc->m_bRemember = FALSE;
TRY
{
OnSaveEmbedding(lpStorage);
pDoc->CommitItems(FALSE);
}
CATCH_ALL(e)
{
// release storage and lock bytes
VERIFY(lpStorage->Release() == 0);
VERIFY(lpLockBytes->Release() == 0);
pDoc->m_bSameAsLoad = TRUE;
pDoc->m_bRemember = TRUE;
THROW_LAST();
}
END_CATCH_ALL
pDoc->m_bSameAsLoad = TRUE;
pDoc->m_bRemember = TRUE;
lpLockBytes->Release();
// add it to the data source
lpStgMedium->tymed = TYMED_ISTORAGE;
lpStgMedium->pstg = lpStorage;
lpStgMedium->pUnkForRelease = NULL;
}
void COleServerItem::AddOtherClipboardData(COleDataSource* pDataSource)
{
ASSERT_VALID(this);
ASSERT_VALID(pDataSource);
// get IEnumFORMATETC interface for the IDataObject
LPDATAOBJECT lpDataObject = GetDataObject();
LPENUMFORMATETC lpEnumFORMATETC;
if (lpDataObject->EnumFormatEtc(DATADIR_GET, &lpEnumFORMATETC) != S_OK)
return;
ASSERT(lpEnumFORMATETC != NULL);
// get all formats that the object will give us
FORMATETC formatEtc;
while (lpEnumFORMATETC->Next(1, &formatEtc, NULL) == S_OK)
{
STGMEDIUM stgMedium;
if (lpDataObject->GetData(&formatEtc, &stgMedium) != S_OK)
{
// data is not available
CoTaskMemFree(formatEtc.ptd);
}
else if (stgMedium.pUnkForRelease != NULL)
{
// don't cache data with pUnkForRelease != NULL
::ReleaseStgMedium(&stgMedium);
CoTaskMemFree(formatEtc.ptd);
}
else
{
// cache the data (now we own the stgMedium)
pDataSource->CacheData(0, &stgMedium, &formatEtc);
}
}
// cleanup
lpEnumFORMATETC->Release();
}
LPMONIKER COleServerItem::GetMoniker(OLEGETMONIKER nAssign)
{
// get IOleObject interface for this item
LPOLEOBJECT lpOleObject = GetOleObject();
ASSERT(lpOleObject != NULL);
// get moniker from OLE object
LPMONIKER lpMoniker = NULL;
lpOleObject->GetMoniker(nAssign, OLEWHICHMK_OBJFULL, &lpMoniker);
return lpMoniker;
}
BOOL COleServerItem::GetLinkSourceData(LPSTGMEDIUM lpStgMedium)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
LPOLEOBJECT lpOleObject = GetOleObject();
ASSERT(lpOleObject != NULL);
// get moniker from ole object
LPMONIKER lpMoniker;
SCODE sc = lpOleObject->GetMoniker(OLEGETMONIKER_TEMPFORUSER,
OLEWHICHMK_OBJFULL, &lpMoniker);
if (sc != S_OK)
{
TRACE0("Warning: unable to get moniker for object.\n");
return FALSE;
}
ASSERT(lpMoniker != NULL);
// create a memory based stream to write the moniker to
LPSTREAM lpStream;
if (::CreateStreamOnHGlobal(NULL, TRUE, &lpStream) != S_OK)
{
lpMoniker->Release();
AfxThrowMemoryException();
}
ASSERT(lpStream != NULL);
// write the moniker to the stream, and add it to the clipboard
sc = ::OleSaveToStream(lpMoniker, lpStream);
lpMoniker->Release();
if (sc != S_OK)
{
lpStream->Release();
AfxThrowOleException(sc);
}
// write the class ID of the document to the stream as well
COleLinkingDoc* pDoc = GetDocument();
ASSERT(pDoc->m_pFactory != NULL);
sc = WriteClassStm(lpStream, pDoc->m_pFactory->GetClassID());
if (sc != S_OK)
{
lpStream->Release();
AfxThrowOleException(sc);
}
// setup the STGMEDIUM
lpStgMedium->tymed = TYMED_ISTREAM;
lpStgMedium->pstm = lpStream;
lpStgMedium->pUnkForRelease = NULL;
return TRUE;
}
void COleServerItem::GetObjectDescriptorData(
LPPOINT lpOffset, LPSIZE lpSize, LPSTGMEDIUM lpStgMedium)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
ASSERT(lpOffset == NULL ||
AfxIsValidAddress(lpOffset, sizeof(POINT), FALSE));
LPOLEOBJECT lpOleObject = GetOleObject();
ASSERT(lpOleObject != NULL);
// get the object descriptor for the IOleObject
POINTL pointl = { 0, 0 };
if (lpOffset != NULL)
{
CSize ptOffset(lpOffset->x, lpOffset->y);
#ifndef _MAC
((CDC*)NULL)->DPtoHIMETRIC(&ptOffset);
#endif
pointl.x = ptOffset.cx;
pointl.y = ptOffset.cy;
}
SIZEL sizel;
if (lpSize != NULL)
{
sizel.cx = lpSize->cx;
sizel.cy = lpSize->cy;
#ifndef _MAC
((CDC*)NULL)->DPtoHIMETRIC(&sizel);
#endif
}
else
{
sizel.cx = 0;
sizel.cy = 0;
}
InterlockedIncrement(&m_dwRef); // protect against destruction during this call
HGLOBAL hGlobal = _AfxOleGetObjectDescriptorData(
lpOleObject, NULL, DVASPECT_CONTENT, pointl, &sizel);
InterlockedDecrement(&m_dwRef);
if (hGlobal == NULL)
AfxThrowMemoryException();
// setup the STGMEDIUM
lpStgMedium->tymed = TYMED_HGLOBAL;
lpStgMedium->hGlobal = hGlobal;
lpStgMedium->pUnkForRelease = NULL;
}
void COleServerItem::OnSaveEmbedding(LPSTORAGE lpStorage)
{
ASSERT(lpStorage != NULL);
// always (logically) a "File.Save Copy As" operation
COleServerDoc* pDoc = GetDocument();
LPSTORAGE lpOrigStg = pDoc->m_lpRootStg;
pDoc->m_lpRootStg = lpStorage;
TRY
{
ASSERT(pDoc->m_lpRootStg != NULL);
pDoc->SaveToStorage(this); // use helper to serialize to storage
}
CATCH_ALL(e)
{
// save as failed: re-attach original storage
pDoc->m_lpRootStg = lpOrigStg;
THROW_LAST();
}
END_CATCH_ALL
// re-attach original storage
pDoc->m_lpRootStg = lpOrigStg;
}
/////////////////////////////////////////////////////////////////////////////
// COleServerItem data-object callback default implementation
BOOL COleServerItem::OnRenderGlobalData(
LPFORMATETC /*lpFormatEtc*/, HGLOBAL* /*phGlobal*/)
{
ASSERT_VALID(this);
return FALSE; // default does nothing
}
BOOL COleServerItem::OnRenderFileData(
LPFORMATETC /*lpFormatEtc*/, CFile* /*pFile*/)
{
ASSERT_VALID(this);
return FALSE; // default does nothing
}
BOOL COleServerItem::OnRenderData(LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidAddress(lpFormatEtc, sizeof(FORMATETC), FALSE));
ASSERT(AfxIsValidAddress(lpStgMedium, sizeof(STGMEDIUM)));
// default implementation does not support extended layout
if (lpFormatEtc->lindex != -1)
return FALSE;
// default implementation supports both types of metafiles
if (lpFormatEtc->cfFormat == CF_METAFILEPICT)
return GetMetafileData(lpFormatEtc, lpStgMedium);
return FALSE; // cfFormat not supported
}
BOOL COleServerItem::OnSetData(
LPFORMATETC /*lpFormatEtc*/, LPSTGMEDIUM /*lpStgMedium*/, BOOL /*bRelease*/)
{
ASSERT_VALID(this);
return FALSE; // default does nothing
}
/////////////////////////////////////////////////////////////////////////////
// COleServerItem OLE interface implementation
BEGIN_INTERFACE_MAP(COleServerItem, CDocItem)
INTERFACE_PART(COleServerItem, IID_IOleObject, OleObject)
INTERFACE_PART(COleServerItem, IID_IDataObject, DataObject)
END_INTERFACE_MAP()
/////////////////////////////////////////////////////////////////////////////
// COleServerItem::XOleObject
STDMETHODIMP_(ULONG) COleServerItem::XOleObject::AddRef()
{
METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) COleServerItem::XOleObject::Release()
{
METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
return pThis->ExternalRelease();
}
STDMETHODIMP COleServerItem::XOleObject::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
return pThis->ExternalQueryInterface(&iid, ppvObj);
}
// COleServerItem has special Release semantics. In particular, the item
// is only deleted from memory if m_bAutoDelete is TRUE.
// Also, it unlocks the document if the reference count reaches zero.
void COleServerItem::OnFinalRelease()
{
ASSERT_VALID(this);
COleServerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->InternalAddRef(); // make document stable
// if connected to a document -- remove external lock from it
if (m_bNeedUnlock)
{
pDoc->LockExternal(FALSE, TRUE);
m_bNeedUnlock = FALSE;
}
// delete this item if no longer needed
if (m_bAutoDelete)
delete this;
// release artificial reference (may destroy the document)
pDoc->InternalRelease();
}
STDMETHODIMP COleServerItem::XOleObject::SetClientSite(
LPOLECLIENTSITE /*pClientSite*/)
{
// linked objects do not support SetClientSite
return E_NOTIMPL;
}
STDMETHODIMP COleServerItem::XOleObject::GetClientSite(
LPOLECLIENTSITE* ppClientSite)
{
// linked objects do not support GetClientSite
*ppClientSite = NULL;
return E_NOTIMPL;
}
STDMETHODIMP COleServerItem::XOleObject::SetHostNames(
LPCOLESTR /*szContainerApp*/, LPCOLESTR /*szContainerObj*/)
{
// linked objects do not support SetHostNames
return E_NOTIMPL;
}
STDMETHODIMP COleServerItem::XOleObject::Close(DWORD /*dwSaveOption*/)
{
// linked objects do not support close
return E_NOTIMPL;
}
STDMETHODIMP COleServerItem::XOleObject::SetMoniker(
DWORD /*dwWhichMoniker*/, LPMONIKER /*pmk*/)
{
// linked objects do not support SetMoniker
return E_NOTIMPL;
}
STDMETHODIMP COleServerItem::XOleObject::GetMoniker(
DWORD dwAssign, DWORD dwWhichMoniker, LPMONIKER* ppMoniker)
{
USES_CONVERSION;
METHOD_PROLOGUE_EX(COleServerItem, OleObject)
ASSERT_VALID(pThis);
COleServerDoc* pDoc = pThis->GetDocument();
ASSERT_VALID(pDoc);
ASSERT_KINDOF(COleServerDoc, pDoc);
ASSERT(ppMoniker != NULL);
*ppMoniker = NULL;
switch (dwWhichMoniker)
{
case OLEWHICHMK_CONTAINER:
// simply return the moniker of the container document
*ppMoniker = pDoc->GetMoniker((OLEGETMONIKER)dwAssign);
break;
case OLEWHICHMK_OBJREL:
{
// no relative moniker if no item name
if (pThis->m_strItemName.IsEmpty())
break;
// don't return relative moniker if no document moniker
LPMONIKER lpMoniker = pDoc->GetMoniker((OLEGETMONIKER)dwAssign);
if (lpMoniker == NULL)
break;
lpMoniker->Release(); // don't need document moniker
// relative monikers have to handle assignment correctly
switch (dwAssign)
{
case OLEGETMONIKER_TEMPFORUSER:
case OLEGETMONIKER_ONLYIFTHERE:
case OLEGETMONIKER_FORCEASSIGN:
// create item moniker from name
CreateItemMoniker(OLESTDDELIMOLE, T2COLE(pThis->m_strItemName),
ppMoniker);
break;
case OLEGETMONIKER_UNASSIGN:
ASSERT(FALSE); // should never get UNASSIGN
break;
}
}
break;
case OLEWHICHMK_OBJFULL:
{
// get each sub-moniker: item & document
LPMONIKER lpMoniker1, lpMoniker2;
GetMoniker(dwAssign, OLEWHICHMK_CONTAINER, &lpMoniker1);
GetMoniker(dwAssign, OLEWHICHMK_OBJREL, &lpMoniker2);
if (lpMoniker1 != NULL && lpMoniker2 != NULL)
{
// create composite from two parts
::CreateGenericComposite(lpMoniker1, lpMoniker2, ppMoniker);
}
else if (lpMoniker1 != NULL)
{
// just use container moniker
*ppMoniker = lpMoniker1;
lpMoniker1 = NULL;
}
// release sub-monikers
RELEASE(lpMoniker1);
RELEASE(lpMoniker2);
}
break;
}
return *ppMoniker == NULL ? E_FAIL : S_OK;
}
STDMETHODIMP COleServerItem::XOleObject::InitFromData(
LPDATAOBJECT /*pDataObject*/, BOOL /*fCreation*/, DWORD /*dwReserved*/)
{
// linked objects do not support InitFromData
return E_NOTIMPL;
}
STDMETHODIMP COleServerItem::XOleObject::GetClipboardData(
DWORD /*dwReserved*/, LPDATAOBJECT* ppDataObject)
{
METHOD_PROLOGUE_EX(COleServerItem, OleObject)
ASSERT_VALID(pThis);
*ppDataObject = NULL;
SCODE sc;
TRY
{
COleDataSource* pDataSource = pThis->OnGetClipboardData(TRUE, NULL, NULL);
ASSERT(pDataSource != NULL);
*ppDataObject =
(LPDATAOBJECT)pDataSource->GetInterface(&IID_IDataObject);
ASSERT(*ppDataObject != NULL);
sc = S_OK;
}
CATCH_ALL(e)
{
sc = COleException::Process(e);
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
return sc;
}
STDMETHODIMP COleServerItem::XOleObject::DoVerb(
LONG iVerb, LPMSG /*lpmsg*/, LPOLECLIENTSITE /*pActiveSite*/, LONG /*lindex*/,
HWND /*hwndParent*/, LPCRECT /*lpPosRect*/)
{
METHOD_PROLOGUE_EX(COleServerItem, OleObject)
ASSERT_VALID(pThis);
pThis->InternalAddRef(); // protect this object
SCODE sc;
TRY
{
pThis->OnDoVerb(iVerb);
sc = S_OK;
}
CATCH_ALL(e)
{
sc = COleException::Process(e);
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
pThis->InternalRelease(); // may 'delete this'
return sc;
}
STDMETHODIMP COleServerItem::XOleObject::EnumVerbs(
IEnumOLEVERB** ppenumOleVerb)
{
METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
*ppenumOleVerb = NULL;
CLSID clsid;
pThis->GetOleObject()->GetUserClassID(&clsid);
return OleRegEnumVerbs(clsid, ppenumOleVerb);
}
STDMETHODIMP COleServerItem::XOleObject::Update()
{
METHOD_PROLOGUE_EX(COleServerItem, OleObject)
ASSERT_VALID(pThis);
SCODE sc;
TRY
{
pThis->OnUpdateItems();
sc = S_OK;
}
CATCH_ALL(e)
{
sc = COleException::Process(e);
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
return sc;
}
STDMETHODIMP COleServerItem::XOleObject::IsUpToDate()
{
METHOD_PROLOGUE_EX(COleServerItem, OleObject)
ASSERT_VALID(pThis);
SCODE sc;
TRY
{
sc = pThis->OnQueryUpdateItems() ? S_FALSE : S_OK;
}
CATCH_ALL(e)
{
sc = COleException::Process(e);
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
return sc;
}
STDMETHODIMP COleServerItem::XOleObject::GetUserClassID(CLSID* pClsid)
{
METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
COleServerDoc* pDoc = pThis->GetDocument();
return pDoc->m_xPersistFile.GetClassID(pClsid);
}
STDMETHODIMP COleServerItem::XOleObject::GetUserType(
DWORD dwFormOfType, LPOLESTR* ppszUserType)
{
METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
*ppszUserType = NULL;
CLSID clsid;
pThis->GetOleObject()->GetUserClassID(&clsid);
return OleRegGetUserType(clsid, dwFormOfType, ppszUserType);
}
STDMETHODIMP COleServerItem::XOleObject::SetExtent(
DWORD /*dwDrawAspect*/, LPSIZEL /*lpsizel*/)
{
// linked objects do not support SetExtent
return E_FAIL;
}
STDMETHODIMP COleServerItem::XOleObject::GetExtent(
DWORD dwDrawAspect, LPSIZEL lpsizel)
{
METHOD_PROLOGUE_EX(COleServerItem, OleObject)
ASSERT_VALID(pThis);
SCODE sc = E_INVALIDARG;
TRY
{
// call to get regular windows size
CSize size;
if (pThis->OnGetExtent((DVASPECT)dwDrawAspect, size))
{
if (size.cy < 0)
size.cy = -size.cy; // extents are always positive
lpsizel->cx = size.cx;
lpsizel->cy = size.cy;
sc = S_OK;
}
}
CATCH_ALL(e)
{
sc = COleException::Process(e);
DELETE_EXCEPTION(e);
}
END_CATCH_ALL
return sc;
}
STDMETHODIMP COleServerItem::XOleObject::Advise(
IAdviseSink* pAdvSink, DWORD* pdwConnection)
{
METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
*pdwConnection = 0;
if (pThis->m_lpOleAdviseHolder == NULL &&
::CreateOleAdviseHolder(&pThis->m_lpOleAdviseHolder) != S_OK)
{
return E_OUTOFMEMORY;
}
ASSERT(pThis->m_lpOleAdviseHolder != NULL);
return pThis->m_lpOleAdviseHolder->Advise(pAdvSink, pdwConnection);
}
STDMETHODIMP COleServerItem::XOleObject::Unadvise(DWORD dwConnection)
{
METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
if (pThis->m_lpOleAdviseHolder == NULL)
return E_FAIL;
ASSERT(pThis->m_lpOleAdviseHolder != NULL);
return pThis->m_lpOleAdviseHolder->Unadvise(dwConnection);
}
STDMETHODIMP COleServerItem::XOleObject::EnumAdvise(
LPENUMSTATDATA* ppenumAdvise)
{
METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
*ppenumAdvise = NULL;
if (pThis->m_lpOleAdviseHolder == NULL)
return E_FAIL;
ASSERT(pThis->m_lpOleAdviseHolder != NULL);
return pThis->m_lpOleAdviseHolder->EnumAdvise(ppenumAdvise);
}
STDMETHODIMP COleServerItem::XOleObject::GetMiscStatus(
DWORD dwAspect, DWORD* pdwStatus)
{
METHOD_PROLOGUE_EX_(COleServerItem, OleObject)
*pdwStatus = 0;
CLSID clsid;
pThis->GetOleObject()->GetUserClassID(&clsid);
return OleRegGetMiscStatus(clsid, dwAspect, pdwStatus);
}
STDMETHODIMP COleServerItem::XOleObject::SetColorScheme(LPLOGPALETTE lpLogpal)
{
METHOD_PROLOGUE_EX(COleServerItem, OleObject)
ASSERT_VALID(pThis);
SCODE sc = E_NOTIMPL;
TRY
{
// delegate to embedded item
if (pThis->OnSetColorScheme(lpLogpal))
sc = S_OK;
}
END_TRY
return sc;
}
/////////////////////////////////////////////////////////////////////////////
// COleServerItem::XDataObject
STDMETHODIMP_(ULONG) COleServerItem::XDataObject::AddRef()
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
return pThis->ExternalAddRef();
}
STDMETHODIMP_(ULONG) COleServerItem::XDataObject::Release()
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
return pThis->ExternalRelease();
}
STDMETHODIMP COleServerItem::XDataObject::QueryInterface(
REFIID iid, LPVOID* ppvObj)
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
return pThis->ExternalQueryInterface(&iid, ppvObj);
}
STDMETHODIMP COleServerItem::XDataObject::GetData(
LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
return pThis->m_dataSource.m_xDataObject.GetData(lpFormatEtc, lpStgMedium);
}
STDMETHODIMP COleServerItem::XDataObject::GetDataHere(
LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
return pThis->m_dataSource.m_xDataObject.GetDataHere(
lpFormatEtc, lpStgMedium);
}
STDMETHODIMP COleServerItem::XDataObject::QueryGetData(LPFORMATETC lpFormatEtc)
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
return pThis->m_dataSource.m_xDataObject.QueryGetData(lpFormatEtc);
}
STDMETHODIMP COleServerItem::XDataObject::GetCanonicalFormatEtc(
LPFORMATETC /*lpFormatEtcIn*/, LPFORMATETC /*lpFormatEtcOut*/)
{
// because we support the target-device (ptd) for server metafile format,
// all members of the FORMATETC are significant.
return DATA_S_SAMEFORMATETC;
}
STDMETHODIMP COleServerItem::XDataObject::SetData(
LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium, BOOL bRelease)
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
return pThis->m_dataSource.m_xDataObject.SetData(
lpFormatEtc, lpStgMedium, bRelease);
}
STDMETHODIMP COleServerItem::XDataObject::EnumFormatEtc(
DWORD dwDirection, LPENUMFORMATETC* ppenumFormatEtc)
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
return pThis->m_dataSource.m_xDataObject.EnumFormatEtc(
dwDirection, ppenumFormatEtc);
}
STDMETHODIMP COleServerItem::XDataObject::DAdvise(
FORMATETC* pFormatEtc, DWORD advf,
LPADVISESINK pAdvSink, DWORD* pdwConnection)
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
*pdwConnection = 0;
// this special case is for apps like Excel which ask for DAdvise
// on CF_METAFILEPICT, DVASPECT_ICON for insert as icon.
FORMATETC formatEtc = *pFormatEtc;
if (formatEtc.cfFormat == CF_METAFILEPICT &&
formatEtc.dwAspect == DVASPECT_ICON)
{
formatEtc.dwAspect = DVASPECT_CONTENT;
}
// make sure the FORMATETC is valid
if (!(pFormatEtc->cfFormat == 0 && pFormatEtc->ptd == NULL &&
pFormatEtc->dwAspect == -1 && pFormatEtc->lindex == -1 &&
pFormatEtc->tymed == -1) &&
pThis->GetDataObject()->QueryGetData(&formatEtc) != S_OK)
{
// it is not a wildcard advise -and- the format is not acceptable
return DATA_E_FORMATETC;
}
// create the advise holder, if necessary
if (pThis->m_lpDataAdviseHolder == NULL &&
CreateDataAdviseHolder(&pThis->m_lpDataAdviseHolder) != S_OK)
{
return E_OUTOFMEMORY;
}
ASSERT(pThis->m_lpDataAdviseHolder != NULL);
return pThis->m_lpDataAdviseHolder->Advise(this, pFormatEtc, advf,
pAdvSink, pdwConnection);
}
STDMETHODIMP COleServerItem::XDataObject::DUnadvise(DWORD dwConnection)
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
if (pThis->m_lpDataAdviseHolder == NULL)
return E_FAIL;
ASSERT(pThis->m_lpDataAdviseHolder != NULL);
return pThis->m_lpDataAdviseHolder->Unadvise(dwConnection);
}
STDMETHODIMP COleServerItem::XDataObject::EnumDAdvise(
LPENUMSTATDATA* ppenumAdvise)
{
METHOD_PROLOGUE_EX_(COleServerItem, DataObject)
*ppenumAdvise = NULL;
if (pThis->m_lpDataAdviseHolder == NULL)
return E_FAIL;
ASSERT(pThis->m_lpDataAdviseHolder != NULL);
return pThis->m_lpDataAdviseHolder->EnumAdvise(ppenumAdvise);
}
//////////////////////////////////////////////////////////////////////////////
// special CItemDataSource implementation
BOOL COleServerItem::CItemDataSource::OnRenderGlobalData(
LPFORMATETC lpFormatEtc, HGLOBAL* phGlobal)
{
ASSERT_VALID(this);
COleServerItem* pItem = (COleServerItem*)
((BYTE*)this - offsetof(COleServerItem, m_dataSource));
return pItem->OnRenderGlobalData(lpFormatEtc, phGlobal);
// Note: COleDataSource has no implementation
}
BOOL COleServerItem::CItemDataSource::OnRenderFileData(
LPFORMATETC lpFormatEtc, CFile* pFile)
{
ASSERT_VALID(this);
COleServerItem* pItem = (COleServerItem*)
((BYTE*)this - offsetof(COleServerItem, m_dataSource));
return pItem->OnRenderFileData(lpFormatEtc, pFile);
// Note: COleDataSource has no implementation
}
BOOL COleServerItem::CItemDataSource::OnRenderData(
LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium)
{
ASSERT_VALID(this);
COleServerItem* pItem = (COleServerItem*)
((BYTE*)this - offsetof(COleServerItem, m_dataSource));
if (pItem->OnRenderData(lpFormatEtc, lpStgMedium))
return TRUE;
return COleDataSource::OnRenderData(lpFormatEtc, lpStgMedium);
}
BOOL COleServerItem::CItemDataSource::OnSetData(
LPFORMATETC lpFormatEtc, LPSTGMEDIUM lpStgMedium, BOOL bRelease)
{
ASSERT_VALID(this);
COleServerItem* pItem = (COleServerItem*)
((BYTE*)this - offsetof(COleServerItem, m_dataSource));
return pItem->OnSetData(lpFormatEtc, lpStgMedium, bRelease);
// Note: COleDataSource has no implementation
}
//////////////////////////////////////////////////////////////////////////////
// COleServerItem Diagnostics
#ifdef _DEBUG
void COleServerItem::AssertValid() const
{
CDocItem::AssertValid();
// must be attached to a document
ASSERT(m_pDocument != NULL);
m_dataSource.AssertValid();
}
void COleServerItem::Dump(CDumpContext& dc) const
{
CDocItem::Dump(dc);
dc << "m_bNeedUnlock = " << m_bNeedUnlock;
dc << "\nm_bAutoDelete = " << m_bAutoDelete;
dc << "\nm_strItemName = " << m_strItemName;
dc << "\nm_lpOleAdviseHolder = " << m_lpOleAdviseHolder;
dc << "\nm_lpDataAdviseHolder = " << m_lpDataAdviseHolder;
dc << "\nwith m_dataSource: " << &m_dataSource;
}
#endif
/////////////////////////////////////////////////////////////////////////////