windows-nt/Source/XPSP1/NT/multimedia/media/sndrec32/o2base/sdv.cxx
2020-09-26 16:20:57 +08:00

1998 lines
57 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//+---------------------------------------------------------------------
//
// File: sdv.cxx
//
//------------------------------------------------------------------------
//[ srvrdv_overview
/*
SrvrDV Overview
The SrvrDV base class implements the persistent data and view aspects common
to most OLE Compound Document objects. It implements the IDataObject,
IViewObject, and IPersist family of interfaces.
The set of formats supported in IDataObject::GetData and SetData methods is
very object dependent. SrvrDV uses a table approach to allow each derived
class to specify precisely exactly the set of formats supported. For each
of GetData and SetData there is a pair of tables. One is a table of FORMATETC
structures that specify information about the format supported. A parallel
table contains a pointer to a function that implements each format supported.
SrvrDV has a set of static methods that implement the standard OLE clipboard
formats. The derived class can include these methods in its Get/Set tables.
*/
//]
#include "headers.hxx"
#pragma hdrstop
OLECHAR szContents[] = OLETEXT("contents");
//+---------------------------------------------------------------
//
// Member: SrvrDV::SrvrDV, protected
//
// Synopsis: Constructor for SrvrCtrl object
//
// Notes: To create a properly initialized object you must
// call the Init method immediately after construction.
//
//---------------------------------------------------------------
SrvrDV::SrvrDV(void)
{
DOUT(TEXT("SrvrDV: Constructing\r\n"));
_pmk = NULL;
_lpstrDisplayName = NULL;
_sizel.cx = 0; _sizel.cy = 0;
_pDataAdviseHolder = NULL;
_fFrozen = FALSE;
_pViewAdviseHolder = NULL;
_fDirty = FALSE;
_fNoScribble = FALSE;
_pStg = NULL;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Init, protected
//
// Synopsis: Fully initializes a SrvrCtrl object as part of a compound
// document server aggregate
//
// Arguments: [pClass] -- The initialized class descriptor for the server
// [pCtrl] -- The control subobject of the server we are a part of.
//
// Returns: NOERROR if successful
//
// Notes: The Init method of the control subobject creates the data/view and
// inplace subobjects of the object and calls the respective Init methods
// on each, including this one.
// The class descriptor pointer is saved in the protected _pClass
// member variable where it is accessible during the lifetime
// of the object.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::Init(LPCLASSDESCRIPTOR pClass, LPSRVRCTRL pCtrl)
{
_pClass = pClass;
_pCtrl = pCtrl;
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Init, protected
//
// Synopsis: Fully initializes a SrvrCtrl object from an existing object
// to be used as a data transfer object
//
// Arguments: [pClass] -- The initialized class descriptor for the server
// [pDV] -- The data/view subobject of the object that is the source
// of this transfer data object
//
// Returns: NOERROR if successful
//
// Notes: This method is used in the process of the GetClipboardCopy method
// for obtaining a transfer data object from an existing object.
// The class descriptor pointer is saved in the protected _pClass
// member variable where it is accessible during the lifetime
// of the object.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::Init(LPCLASSDESCRIPTOR pClass, LPSRVRDV pDV)
{
_pClass = pClass; // stash the class descriptor pointer
_pCtrl = NULL; // we are a free-floating transfer data object
// copy over member variables as appropriate
_pmk = pDV->_pmk;
if (_pmk != NULL)
_pmk->AddRef();
TaskAllocString(pDV->_lpstrDisplayName, &_lpstrDisplayName);
_sizel = pDV->_sizel;
// we create a temporary IStorage and take a snapshot of the storage.
// The temporary IStorage will be automatically deleted when this
// data object is released
// What happens when we run out of memory?
// Should re-try with disk-based docfile?
//
HRESULT hr;
LPSTORAGE pStg;
if (OK(hr = CreateStorageOnHGlobal(NULL, &pStg)))
{
// do a "Save Copy As" into our storage instance.
if (OK(hr = OleSave((LPPERSISTSTORAGE)pDV, pStg, FALSE)))
{
if (OK(hr = pStg->Commit(STGC_DEFAULT)))
{
if (OK(hr = ((LPPERSISTSTORAGE)pDV)->SaveCompleted(NULL)))
(_pStg = pStg)->AddRef();
}
}
pStg->Release();
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::~SrvrDV, protected
//
// Synopsis: Destructor for the SrvrDV object
//
// Notes: The destructor is called as a result of the servers
// reference count going to 0. It releases any held resources
// including advise holders and storages.
//
//---------------------------------------------------------------
SrvrDV::~SrvrDV(void)
{
if (_pmk != NULL)
_pmk->Release();
if (_lpstrDisplayName != NULL)
TaskFreeString(_lpstrDisplayName);
if (_pDataAdviseHolder != NULL)
_pDataAdviseHolder->Release();
if (_pViewAdviseHolder != NULL)
_pViewAdviseHolder->Release();
if (_pStg != NULL)
_pStg->Release();
DOUT(TEXT("SrvrDV: Destructed\r\n"));
}
#ifdef DOCGEN // documentation for pure virtual function
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetClipboardCopy, public
//
// Synopsis: Produces a data-transfer object representing a snapshot
// of this data/view object
//
// Arguments: [ppDV] -- The place where the data-transfer object is returned
//
// Returns: Success if the data-transfer object was created.
//
// Notes: This method is called
// as a result of an IOleObject::GetClipboardData call on the
// control subobject. The overridden method should create a new
// instance of itself and call the appropriate Init method on
// the new instance passing the `this' pointer. This way the
// new instance can initialize itself as a snapshot of this object.
// All servers must override this pure virtual method.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::GetClipboardCopy(LPSRVRDV FAR* ppDV)
{}
#endif // DOCGEN
//+---------------------------------------------------------------
//
// Member: SrvrDV::SetExtent, public
//
// Synopsis: Informs the object that it has a new expected size
//
// Notes: IOleObject::SetExtent and GetExtent methods are passed
// directly from the control subobject to the data/view subobject
// via these methods. See OLE documentation for the
// arguments and return values.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::SetExtent(DWORD dwAspect, SIZEL& sizel)
{
HRESULT hr = NOERROR;
switch(dwAspect)
{
case DVASPECT_CONTENT:
case DVASPECT_DOCPRINT:
#if 1
// NTBug #20692: Fail Metafile setextent, because
// Powerpoint tries to resize things in weird ways.
hr = E_FAIL; // icon aspect is fixed size
#else
_sizel = sizel;
#endif
break;
case DVASPECT_THUMBNAIL: //REVIEW: what size is a thumbnail?
case DVASPECT_ICON:
DOUT(TEXT("SrvrDV::SetExtent E_FAIL\r\n"));
hr = E_FAIL; // icon aspect is fixed size
break;
default:
DOUT(TEXT("SrvrDV::SetExtent E_INVALIDARG\r\n"));
hr = E_INVALIDARG;
break;
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetExtent, public
//
// Synopsis: Requests the current size for some draw aspect of the object
//
// Notes: IOleObject::SetExtent and GetExtent methods are passed
// directly from the control subobject to the data/view subobject
// via these methods. See OLE documentation for the
// arguments and return values.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::GetExtent(DWORD dwAspect, LPSIZEL lpsizel)
{
#if DBG
TCHAR achTemp[256];
wsprintf(achTemp,TEXT("SrvrDV::GetExtent (dwApsect = %ld, cx = %ld, cy = %ld)\r\n"),
dwAspect, _sizel.cx, _sizel.cy);
DOUT(achTemp);
#endif
HRESULT hr = NOERROR;
switch(dwAspect) {
default:
DOUT(TEXT("SrvrDV::GetExtent INVALIDARG\r\n"));
case DVASPECT_CONTENT:
case DVASPECT_DOCPRINT:
*lpsizel = _sizel;
break;
case DVASPECT_THUMBNAIL:
case DVASPECT_ICON:
// The iconic view is actually a metafile of the
// icon with a text-string underneath.
// This isn't the right calculation...
lpsizel->cx = HimetricFromHPix(32);
lpsizel->cy = HimetricFromVPix(32);
break;
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::OnDataChange, public
//
// Synopsis: Sets the dirty flag and raises data and view changed
// to all registered advises
//
// Arguments: [dwAdvf] -- from the ADVF Data Advise flags.
// Usually this is 0. ADVF_DATAONSTOP is used
// when the object is closing down.
// Notes: This function should be called whenever the native
// data of the object is modified.
//
//---------------------------------------------------------------
void
SrvrDV::OnDataChange(DWORD dwAdvf)
{
_fDirty = TRUE;
if (_pViewAdviseHolder != NULL)
_pViewAdviseHolder->SendOnViewChange(DVASPECT_CONTENT);
if (_pDataAdviseHolder != NULL)
_pDataAdviseHolder->SendOnDataChange((LPDATAOBJECT)this, 0, dwAdvf);
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::SetMoniker, public
//
// Synopsis: Informs the object of its new, full moniker
//
// Arguments: [pmk] -- full moniker to the object
//
// Notes: The data/view subobject records the full moniker to the
// object so it can properly dispense the standard OLE
// Object Descriptor and Link Source clipboard formats.
// This method is called whenever the IOleObject::SetMoniker
// method is called on the control subobject.
//
//---------------------------------------------------------------
void
SrvrDV::SetMoniker(LPMONIKER pmk)
{
if (_pmk != NULL)
{
_pmk->Release();
if (_lpstrDisplayName != NULL) // flush our cached display name
{
TaskFreeString(_lpstrDisplayName);
_lpstrDisplayName = NULL;
}
}
_pmk = pmk;
if (_pmk != NULL)
{
_pmk->AddRef();
}
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetMoniker, public
//
// Synopsis: Returns the full moniker to the object
//
// Arguments: [dwAssign] -- See IOleObject::GetMoniker
// [ppmk] -- The place where the moniker is returned
//
// Returns: Success if the moniker is available.
//
// Notes: This returns the moniker that this data/view subobject has
// previously recorded. If no moniker is yet assigned
// then the moniker is requested from the client site
// via the IOleObject::GetMoniker method on the control subobject.
// This method is used by the GetOBJECTDESCRIPTOR and GetLINKSOURCE
// methods.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::GetMoniker(DWORD dwAssign, LPMONIKER FAR* ppmk)
{
*ppmk = NULL; // set out params to NULL
HRESULT hr = NOERROR;
if (_pmk == NULL)
{
if (_pCtrl == NULL)
{
DOUT(TEXT("SrvrDV::GetMoniker E_INVALIDARG\r\n"));
hr = MK_E_UNAVAILABLE;
}
else
{
hr = _pCtrl->GetMoniker(dwAssign, OLEWHICHMK_OBJFULL, &_pmk);
}
}
if (OK(hr))
(*ppmk = _pmk)->AddRef();
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetMonikerDisplayName, public
//
// Synopsis: Returns the display name from the object's moniker
//
// Notes: The display name of the object is used in for
// dispensing the Object Descriptor clipboard format.
// The caller must not free the string returned.
//
//---------------------------------------------------------------
LPOLESTR
SrvrDV::GetMonikerDisplayName(DWORD dwAssign)
{
//
// NOTE: default dwAssign is OLEGETMONIKER_ONLYIFTHERE
//
// we maintain a moniker display name cache in the form of member
// variable _lpstrDisplayName.
//
// If we don't have a display name cached then take our moniker and
// squeeze a display name out of it
//
if (!_lpstrDisplayName)
{
LPMONIKER pmk;
if (OK(GetMoniker(dwAssign, &pmk)))
{
::GetMonikerDisplayName(pmk, &_lpstrDisplayName);
pmk->Release();
}
}
return _lpstrDisplayName;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetEMBEDDEDOBJECT, public
//
// Synopsis: Implementation of IDataObject::GetData and GetDataHere
// for the standard Embedded Object clipboard format
//
// Arguments: [pv] -- pointer to a SrvrDV object
// [pformatetc] -- as in IDataObject::GetData, GetDataHere
// [pmedium] -- as in IDataObject::GetData, GetDataHere
// [fHere] -- TRUE for GetDataHere, FALSE for GetData
//
// Returns: Success if the clipboard format could be dispensed
//
// Notes: This and the other static GetXXX methods are for use
// in the server's Get format tables.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::GetEMBEDDEDOBJECT( LPSRVRDV pDV,
LPFORMATETC pformatetc,
LPSTGMEDIUM pmedium,
BOOL fHere)
{
LPPERSISTSTORAGE pPStg = (LPPERSISTSTORAGE)(LPSRVRDV)pDV;
HRESULT hr = NOERROR;
if (!fHere && pmedium)
{
// fill in the pmedium structure
pmedium->tymed = TYMED_ISTORAGE;
hr = StgCreateDocfile(NULL,
STGM_DFRALL | STGM_CREATE | STGM_DELETEONRELEASE,
0L,
&pmedium->pstg);
pmedium->pUnkForRelease = NULL;
}
if (OK(hr) && pmedium && pPStg)
{
if (OK(hr = OleSave(pPStg, pmedium->pstg, FALSE)))
hr = pPStg->SaveCompleted(NULL);
// if we failed somehow and yet created a docfile, then we will
// release the docfile to delete it
//
if (!OK(hr) && !fHere)
pmedium->pstg->Release();
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetMETAFILEPICT, public
//
// Synopsis: Implementation of IDataObject::GetData and GetDataHere
// for the standard Metafilepict clipboard format
//
// Arguments: [pv] -- pointer to a SrvrDV object
// [pformatetc] -- as in IDataObject::GetData, GetDataHere
// [pmedium] -- as in IDataObject::GetData, GetDataHere
// [fHere] -- TRUE for GetDataHere, FALSE for GetData
//
// Returns: Success if the clipboard format could be dispensed
//
// Notes: This member function uses IViewObject::Draw to construct
// the metafile pict.
// This and the other static GetXXX methods are for use
// in the server's Get format tables.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::GetMETAFILEPICT( LPSRVRDV pDV,
LPFORMATETC pformatetc,
LPSTGMEDIUM pmedium,
BOOL fHere)
{
DOUT(TEXT("o2base/SrvrDV::GetMETAFILEPICT\r\n"));
LPVIEWOBJECT pView = (LPVIEWOBJECT)pDV;
SIZEL sizel;
pDV->GetExtent(pformatetc->dwAspect, &sizel);
RECT rc = { 0, 0, sizel.cx, sizel.cy };
HRESULT hr = NOERROR;
if (!fHere)
{
// fill in the pmedium structure
pmedium->tymed = TYMED_MFPICT;
pmedium->hGlobal = GlobalAlloc(GMEM_SHARE, sizeof(METAFILEPICT));
if (pmedium->hGlobal == NULL)
{
DOUT(TEXT("o2base/SrvrDV::GetMETAFILEPICT failed\r\n"));
hr = E_OUTOFMEMORY;
}
pmedium->pUnkForRelease = NULL;
}
if (OK(hr))
{
HMETAFILE hmf;
if (OK(hr = DrawMetafile(pView, rc, pformatetc->dwAspect, &hmf)))
{
LPMETAFILEPICT pPict = (LPMETAFILEPICT)GlobalLock(pmedium->hGlobal);
if (pPict == NULL)
{
DOUT(TEXT("SrvrDV::GetMETAFILEPICT E_INVALIDARG\r\n"));
DeleteMetaFile(hmf);
hr = E_INVALIDARG;
}
else
{
// fill in the object descriptor
pPict->mm = MM_ANISOTROPIC;
pPict->hMF = hmf;
pPict->xExt = rc.right;
pPict->yExt = rc.bottom;
GlobalUnlock(pmedium->hGlobal);
}
}
// if we failed somehow and yet allocated memory,
// then we will release it here...
//
if (!OK(hr) && !fHere)
{
GlobalFree(pmedium->hGlobal);
pmedium->hGlobal = NULL;
}
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetOBJECTDESCRIPTOR, public
//
// Synopsis: Implementation of IDataObject::GetData and GetDataHere
// for the standard Object Descriptor clipboard format
//
// Arguments: [pv] -- pointer to a SrvrDV object
// [pformatetc] -- as in IDataObject::GetData, GetDataHere
// [pmedium] -- as in IDataObject::GetData, GetDataHere
// [fHere] -- TRUE for GetDataHere, FALSE for GetData
//
// Returns: Success if the clipboard format could be dispensed
//
// Notes: This and the other static GetXXX methods are for use
// in the server's Get format tables.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::GetOBJECTDESCRIPTOR( LPSRVRDV pDV,
LPFORMATETC pformatetc,
LPSTGMEDIUM pmedium,
BOOL fHere)
{
HRESULT hr = NOERROR;
LPCLASSDESCRIPTOR pClass = pDV->_pClass;
//
//REVIEW: what's the best display name for the OBJECTDESCRIPTOR?
//
OLECHAR achDisplay[256];
ostrcpy(achDisplay, OLETEXT("Microsoft "));
ostrcat(achDisplay, pClass->_szUserClassType[USERCLASSTYPE_FULL]);
LPOLESTR lpstrDisplay = achDisplay;
DWORD dwDisplay = lpstrDisplay ?
(ostrlen(lpstrDisplay) + 1) * sizeof(OLECHAR) : 0;
LPOLESTR lpstrUserTypeFull = pClass->_szUserClassType[USERCLASSTYPE_FULL];
DWORD dwUserTypeFull = lpstrUserTypeFull ?
(ostrlen(lpstrUserTypeFull) + 1) * sizeof(OLECHAR) : 0;
DWORD dwSize = sizeof(OBJECTDESCRIPTOR) + dwUserTypeFull + dwDisplay;
if (!fHere)
{
// compute the amount of memory required
// fill in the pmedium structure
pmedium->tymed = TYMED_HGLOBAL;
pmedium->hGlobal = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, dwSize);
if (pmedium->hGlobal == NULL)
{
DOUT(TEXT("o2base/SrvrDV::GetOBJECTDESCRIPTOR failed (pmedium)\r\n"));
hr = E_OUTOFMEMORY;
}
pmedium->pUnkForRelease = NULL;
}
if (OK(hr) && (GlobalSize(pmedium->hGlobal) >= dwSize))
{
LPOBJECTDESCRIPTOR pObjDesc =
(LPOBJECTDESCRIPTOR)GlobalLock(pmedium->hGlobal);
if (pObjDesc == NULL)
{
DOUT(TEXT("o2base/SrvrDV::GetOBJECTDESCRIPTOR failed\r\n"));
hr = E_OUTOFMEMORY;
}
else
{
//
// fill in the object descriptor
//
pObjDesc->cbSize = dwSize;
pObjDesc->clsid = pClass->_clsid;
pObjDesc->dwDrawAspect = DVASPECT_CONTENT;
pObjDesc->sizel = pDV->_sizel;
pObjDesc->pointl.y = pObjDesc->pointl.x = 0;
pObjDesc->dwStatus = pClass->_dwMiscStatus;
LPOLESTR lpstrDest = (LPOLESTR)(pObjDesc + 1);
if(lpstrUserTypeFull)
{
ostrcpy(lpstrDest, lpstrUserTypeFull);
#if DBG
#if !defined(UNICODE) && !defined(OLE2ANSI)
LPSTR lp = ConvertOLESTRToMB(lpstrDest, -1);
OutputDebugStringA(lp);
OutputDebugStringA("\r\n");
TaskFreeMem(lp);
#endif
#endif
pObjDesc->dwFullUserTypeName = sizeof(OBJECTDESCRIPTOR);
lpstrDest += ostrlen(lpstrUserTypeFull) + 1;
}
else
pObjDesc->dwFullUserTypeName = 0;
if (lpstrDisplay)
{
pObjDesc->dwSrcOfCopy = pObjDesc->dwFullUserTypeName + dwUserTypeFull;
ostrcpy(lpstrDest, lpstrDisplay);
#if DBG
#if !defined(UNICODE) && !defined(OLE2ANSI)
LPSTR lp = ConvertOLESTRToMB(lpstrDest, -1);
OutputDebugStringA(lp);
OutputDebugStringA("\r\n");
TaskFreeMem(lp);
#endif
#endif
}
else
pObjDesc->dwSrcOfCopy = 0;
GlobalUnlock(pmedium->hGlobal);
hr = NOERROR;
}
// if we failed somehow and yet allocated memory,
// then we will release it here...
if (!OK(hr) && !fHere)
{
GlobalFree(pmedium->hGlobal);
pmedium->hGlobal = NULL;
}
}
else
hr = E_OUTOFMEMORY;
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetLINKSOURCE, public
//
// Synopsis: Implementation of IDataObject::GetData and GetDataHere
// for the standard Link Source clipboard format
//
// Arguments: [pv] -- pointer to a SrvrDV object
// [pformatetc] -- as in IDataObject::GetData, GetDataHere
// [pmedium] -- as in IDataObject::GetData, GetDataHere
// [fHere] -- TRUE for GetDataHere, FALSE for GetData
//
// Returns: Success if the clipboard format could be dispensed
//
// Notes: This method uses the moniker cached by the data/view
// object.
// This and the other static GetXXX methods are for use
// in the server's Get format tables.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::GetLINKSOURCE( LPSRVRDV pDV,
LPFORMATETC pformatetc,
LPSTGMEDIUM pmedium,
BOOL fHere)
{
LPMONIKER pmk;
HRESULT hr;
if (OK(hr = pDV->GetMoniker(OLEGETMONIKER_FORCEASSIGN, &pmk)))
{
if (!fHere)
{
pmedium->tymed = TYMED_ISTREAM;
HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pmedium->pstm);
pmedium->pUnkForRelease = NULL;
}
if (OK(hr))
{
CLSID clsid;
if (OK(hr = pmk->GetClassID(&clsid)))
{
if (OK(hr = WriteClassStm(pmedium->pstm, clsid)))
hr = pmk->Save(pmedium->pstm, FALSE);
pDV->GetClassID(&clsid);
WriteClassStm(pmedium->pstm, clsid);
}
}
pmk->Release();
}
return hr;
}
//+--------------------------------------------------------------
//
// Member: SrvrDV::GetData, public
//
// Synopsis: Method of IDataObject interface
//
// Notes: This method searches the server's Get format table
// for a compatible format. If one is found it calls
// the corresponding Get function.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
{
DOUT(TEXT("SrvrDV:GetData\r\n"));
if (pformatetc == NULL || pmedium == NULL)
{
DOUT(TEXT("SrvrDV::GetData E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
HRESULT hr;
int i = FindCompatibleFormat(_pClass->_pGetFmtTable,
_pClass->_cGetFmtTable,
*pformatetc);
if (i < 0)
{
DOUT(TEXT("SrvrDV::GetData DV_E_FORMATETC\r\n"));
hr = DV_E_FORMATETC;
}
else
{
hr = (*_pGetFuncs[i]) (this, pformatetc, pmedium, FALSE);
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetDataHere, public
//
// Synopsis: Method of IDataObject interface
//
// Notes: This method searches the server's Get format table
// for a compatible format. If one is found it calls
// the corresponding Get function.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::GetDataHere(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
{
DOUT(TEXT("SrvrDV:GetDataHere\r\n"));
HRESULT hr;
int i = FindCompatibleFormat(_pClass->_pGetFmtTable,
_pClass->_cGetFmtTable,
*pformatetc);
if (i < 0)
{
DOUT(TEXT("SrvrDV::GetDataHere DV_E_FORMATETC\r\n"));
hr = DV_E_FORMATETC;
}
else
{
hr = (*_pGetFuncs[i]) (this, pformatetc, pmedium, TRUE);
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::QueryGetData, public
//
// Synopsis: Method of IDataObject interface
//
// Notes: This method searches the server's Get format table
// for a compatible format. The return value indicates
// whether or not a compatible format was found.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::QueryGetData(LPFORMATETC pformatetc)
{
return FindCompatibleFormat(_pClass->_pGetFmtTable,
_pClass->_cGetFmtTable,
*pformatetc) >=0 ? NOERROR : DV_E_FORMATETC;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetCanonicalFormatEtc, public
//
// Synopsis: Method of IDataObject interface
//
// Notes: This method returns DATA_S_SAMEFORMATETC assuming
// that each format the server dispenses is its own
// canonical format. If this is not the case then this
// method should be overridden.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::GetCanonicalFormatEtc(LPFORMATETC pformatetc,
LPFORMATETC pformatetcOut)
{
return DATA_S_SAMEFORMATETC;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::SetData, public
//
// Synopsis: Method of IDataObject interface
//
// Notes: This method searches the server's Set format table
// for a compatible format. If one is found it calls
// the corresponding Set function.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::SetData(LPFORMATETC pformatetc, STGMEDIUM FAR *pmedium, BOOL fRelease)
{
DOUT(TEXT("SrvrDV:SetData\r\n"));
HRESULT hr;
int i = FindCompatibleFormat(_pClass->_pSetFmtTable,
_pClass->_cSetFmtTable,
*pformatetc);
if (i < 0)
{
DOUT(TEXT("SrvrDV::SetData DV_E_FORMATETC\r\n"));
hr = DV_E_FORMATETC;
}
else
{
hr = (*_pSetFuncs[i]) (this, pformatetc, pmedium);
}
if (fRelease)
{
ReleaseStgMedium(pmedium);
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::EnumFormatEtc, public
//
// Synopsis: Method of IDataObject interface
//
// Notes: This method creates an enumerator over the Get or
// Set format tables depending on the value of the
// dwDirection argument.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)
{
if (ppenumFormatEtc == NULL)
{
DOUT(TEXT("SrvrDV::EnumFormatEtc E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*ppenumFormatEtc = NULL; // set out params to NULL
// create an enumerator over our static format table.
HRESULT hr = E_INVALIDARG;
switch (dwDirection)
{
case DATADIR_GET:
hr = CreateFORMATETCEnum(_pClass->_pGetFmtTable,
_pClass->_cGetFmtTable,
ppenumFormatEtc);
break;
case DATADIR_SET:
hr = CreateFORMATETCEnum(_pClass->_pSetFmtTable,
_pClass->_cSetFmtTable,
ppenumFormatEtc);
break;
default:
DOUT(TEXT("SrvrDV::EnumFormatEtc E_INVALIDARG (2)\r\n"));
break;
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::DAdvise, public
//
// Synopsis: Method of IDataObject interface
//
// Notes: This method uses the standard OLE data advise holder.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::DAdvise(FORMATETC FAR* pFormatetc,
DWORD advf,
LPADVISESINK pAdvSink,
DWORD FAR* pdwConnection)
{
if (pdwConnection == NULL)
{
DOUT(TEXT("SrvrDV::DAdvise E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*pdwConnection = NULL; // set out params to NULL
HRESULT hr = NOERROR;
if (_pDataAdviseHolder == NULL)
hr = CreateDataAdviseHolder(&_pDataAdviseHolder);
if (OK(hr))
{
hr = _pDataAdviseHolder->Advise((LPDATAOBJECT)this,
pFormatetc,
advf,
pAdvSink,
pdwConnection);
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::DUnadvise, public
//
// Synopsis: Method of IDataObject interface
//
// Notes: This method uses the standard OLE data advise holder.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::DUnadvise(DWORD dwConnection)
{
if (_pDataAdviseHolder == NULL)
return NOERROR;
return _pDataAdviseHolder->Unadvise(dwConnection);
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::EnumDAdvise, public
//
// Synopsis: Method of IDataObject interface
//
// Notes: This method uses the standard OLE data advise holder.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::EnumDAdvise(LPENUMSTATDATA FAR* ppenumAdvise)
{
if (ppenumAdvise == NULL)
{
DOUT(TEXT("SrvrDV::EnumDAdvise E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*ppenumAdvise = NULL; // set out params to NULL
HRESULT hr;
if (_pDataAdviseHolder == NULL)
hr = NOERROR;
else
hr = _pDataAdviseHolder->EnumAdvise(ppenumAdvise);
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::RenderContent, public
//
// Synopsis: Used to draw the content aspect of the object
//
// Notes: This method is used by the implementation of IViewObject::Draw
// when the content aspect is requested. The parameters are
// identical to those of IViewObject::Draw.
// All objects should override this method.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::RenderContent(DWORD dwDrawAspect,
LONG lindex,
void FAR* pvAspect,
DVTARGETDEVICE FAR * ptd,
HDC hicTargetDev,
HDC hdcDraw,
LPCRECTL lprectl,
LPCRECTL lprcWBounds,
BOOL (CALLBACK * pfnContinue) (ULONG_PTR),
ULONG_PTR dwContinue)
{
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::RenderPrint, public
//
// Synopsis: Used to draw the print aspect of the object
//
// Notes: This method is used by the implementation of IViewObject::Draw
// when the docprint aspect is requested. The parameters are
// identical to those of IViewObject::Draw.
// By default this method calls RenderContent. If the
// server has special processing for the print case then
// this method should be overridden.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::RenderPrint(DWORD dwDrawAspect,
LONG lindex,
void FAR* pvAspect,
DVTARGETDEVICE FAR * ptd,
HDC hicTargetDev,
HDC hdcDraw,
LPCRECTL lprectl,
LPCRECTL lprcWBounds,
BOOL (CALLBACK * pfnContinue) (ULONG_PTR),
ULONG_PTR dwContinue)
{
return RenderContent(dwDrawAspect,
lindex,
pvAspect,
ptd,
hicTargetDev,
hdcDraw,
lprectl,
lprcWBounds,
pfnContinue,
dwContinue);
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::RenderThumbnail, public
//
// Synopsis: Used to draw the thumbnail aspect of the object
//
// Notes: This method is used by the implementation of IViewObject::Draw
// when the thumbnail aspect is requested. The parameters are
// identical to those of IViewObject::Draw.
// All objects should override this method.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::RenderThumbnail(DWORD dwDrawAspect,
LONG lindex,
void FAR* pvAspect,
DVTARGETDEVICE FAR * ptd,
HDC hicTargetDev,
HDC hdcDraw,
LPCRECTL lprectl,
LPCRECTL lprcWBounds,
BOOL (CALLBACK * pfnContinue) (ULONG_PTR),
ULONG_PTR dwContinue)
{
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Draw, public
//
// Synopsis: Method of IViewObject interface
//
// Notes: This method calls RenderContent/Print/Thumbnail for
// those respective aspects. It handles the icon aspect
// automatically using the icon found in the class descriptor
// indicated by the _pClass member.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::Draw(DWORD dwDrawAspect,
LONG lindex,
void FAR* pvAspect,
DVTARGETDEVICE FAR * ptd,
HDC hicTargetDev,
HDC hdcDraw,
LPCRECTL lprectl,
LPCRECTL lprcWBounds,
BOOL (CALLBACK * pfnContinue) (ULONG_PTR),
ULONG_PTR dwContinue)
{
HRESULT hr;
switch(dwDrawAspect) {
case DVASPECT_CONTENT:
hr = RenderContent(dwDrawAspect,
lindex,
pvAspect,
ptd,
hicTargetDev,
hdcDraw,
lprectl,
lprcWBounds,
pfnContinue,
dwContinue);
break;
case DVASPECT_DOCPRINT:
hr = RenderPrint(dwDrawAspect,
lindex,
pvAspect,
ptd,
hicTargetDev,
hdcDraw,
lprectl,
lprcWBounds,
pfnContinue,
dwContinue);
break;
case DVASPECT_THUMBNAIL:
hr = RenderThumbnail(dwDrawAspect,
lindex,
pvAspect,
ptd,
hicTargetDev,
hdcDraw,
lprectl,
lprcWBounds,
pfnContinue,
dwContinue);
break;
case DVASPECT_ICON:
{
// This is not the right way to do iconic aspect rendering!
RECT rc;
RECTL rcTemp = *lprectl;
RECTLtoRECT(rcTemp, &rc);
DrawIcon(hdcDraw, rc.left, rc.top, _pClass->_hicon);
hr = NOERROR;
}
break;
default:
DOUT(TEXT("SrvrDV::Draw E_INVALIDARG\r\n"));
hr = E_INVALIDARG;
break;
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetColorSet, public
//
// Synopsis: Method of IViewObject interface
//
// Notes: This method returns S_FALSE indicating the server
// does not support this functionality. Server's that
// wish to support it should override this method.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::GetColorSet(DWORD dwDrawAspect,
LONG lindex,
void FAR* pvAspect,
DVTARGETDEVICE FAR * ptd,
HDC hicTargetDev,
LPLOGPALETTE FAR* ppColorSet)
{
if (ppColorSet == NULL)
{
DOUT(TEXT("SrvrDV::GetColorSet E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*ppColorSet = NULL; //set out params to NULL
return S_FALSE;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Freeze, public
//
// Synopsis: Method of IViewObject interface
//
// Notes: This method sets the frozen flag, _fFrozen.
// The derived class must pay attention to this flag
// and not allow any modifications that would change
// the current rendering.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::Freeze(DWORD dwDrawAspect,
LONG lindex,
void FAR* pvAspect,
DWORD FAR* pdwFreeze)
{
if (pdwFreeze == NULL)
{
DOUT(TEXT("SrvrDV::Freeze E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*pdwFreeze = 0; //set out params to NULL
_fFrozen = TRUE;
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Unfreeze, public
//
// Synopsis: Method of IViewObject interface
//
// Notes: This method clears the frozen flag, _fFrozen.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::Unfreeze(DWORD dwFreeze)
{
_fFrozen = FALSE;
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::SetAdvise, public
//
// Synopsis: Method of IViewObject interface
//
// Notes: This method implements an advise holder for the view
// advise.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::SetAdvise(DWORD aspects, DWORD advf, LPADVISESINK pAdvSink)
{
HRESULT hr = NOERROR;
if (_pViewAdviseHolder == NULL)
hr = CreateViewAdviseHolder(&_pViewAdviseHolder);
if (OK(hr))
hr = _pViewAdviseHolder->SetAdvise(aspects, advf, pAdvSink);
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetAdvise, public
//
// Synopsis: Method of IViewObject interface
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::GetAdvise(DWORD FAR* pAspects,
DWORD FAR* pAdvf,
LPADVISESINK FAR* ppAdvSink)
{
if (ppAdvSink == NULL)
{
DOUT(TEXT("SrvrDV::GetAdvise E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*ppAdvSink = NULL; // set out params to NULL
HRESULT hr;
if (_pViewAdviseHolder==NULL)
hr = NOERROR;
else
hr = _pViewAdviseHolder->GetAdvise(pAspects, pAdvf, ppAdvSink);
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::LoadFromStream, protected
//
// Synopsis: Loads the object's persistent state from a stream
//
// Arguments: [pStrm] -- stream to load from
//
// Returns: Success iff persistent state was read
//
// Notes: This function is used in the implementation of
// IPersistStream::Load and IPersistFile::Load when
// the file is not a docfile.
// All objects should override this method.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::LoadFromStream(LPSTREAM pStrm)
{
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::SaveToStream, protected
//
// Synopsis: Saves the object's persistent state to a stream
//
// Arguments: [pStrm] -- stream to save to
//
// Returns: Success iff persistent state was written
//
// Notes: This function is used in the implementation of
// IPersistStream::Save and IPersistFile::Save when
// the file is not a docfile.
// All objects should override this method.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::SaveToStream(LPSTREAM pStrm)
{
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetStreamSizeMax, protected
//
// Synopsis: Returns the number of bytes required to serialize object
//
// Notes: This function is used in the implementation of
// IPersistStream::GetSizeMax.
// All objects should override this method.
//
//---------------------------------------------------------------
DWORD
SrvrDV::GetStreamSizeMax(void)
{
return 0;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetClassID, public
//
// Synopsis: Method of IPersist interface
//
// Notes: This method uses the class id in the class descriptor.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::GetClassID(LPCLSID lpClassID)
{
if (lpClassID == NULL)
{
DOUT(TEXT("SrvrDV::GetClassID E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*lpClassID = _pClass->_clsid;
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::IsDirty, public
//
// Synopsis: Method of IPersistStream/Storage/File interface
//
// Notes: This method uses the dirty flag, _fDirty.
// Objects should not set the _fDirty flag directly
// but instead call the OnDataChange method to set the
// flag.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::IsDirty(void)
{
return (_fDirty ? NOERROR : S_FALSE);
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Load, public
//
// Synopsis: Method of IPersistStream interface
//
// Notes: This function uses the LoadFromStream method and
// transitions the object to the loaded state if the
// load was successful.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::Load(LPSTREAM pStrm)
{
// object can be loaded only once!
if (_pCtrl->State() != OS_PASSIVE)
{
DOUT(TEXT("SrvrDV::Load E_FAIL\r\n"));
return E_FAIL;
}
HRESULT hr;
if (OK(hr = LoadFromStream(pStrm)))
hr = _pCtrl->TransitionTo(OS_LOADED);
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Save, public
//
// Synopsis: Method of IPersistStream interface
//
// Notes: This method uses the SaveToStream method and
// clears the _fDirty flag as appropriate.
// Containers that have nonserializeable embeddings can
// override this method and return STG_E_CANTSAVE
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::Save(LPSTREAM pStrm, BOOL fClearDirty)
{
HRESULT hr;
if (OK(hr = SaveToStream(pStrm)))
{
if (fClearDirty)
{
_fDirty = FALSE;
}
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetSizeMax
//
// Synopsis: Method of IPersistStream interface
//
// Notes:
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::GetSizeMax(ULARGE_INTEGER FAR * pcbSize)
{
if (pcbSize == NULL)
{
DOUT(TEXT("SrvrDV::GetSizeMax E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
ULISet32(*pcbSize, GetStreamSizeMax());
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::LoadFromStorage, protected
//
// Synopsis: Loads the object's persistent state from a storage
//
// Arguments: [pSg] -- storage to load from
//
// Returns: Success iff persistent state was read
//
// Notes: This function is used in the implementation of
// IPersistStorage::Load and IPersistFile::Load when
// the file is a docfile.
// This method opens a stream, "CONTENTS", and uses
// method LoadFromStream to complete the load.
// Servers that do more sophisticated loading will want
// to override this method.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::LoadFromStorage(LPSTORAGE pStg)
{
LPSTREAM pStrm;
HRESULT hr;
if (OK(hr = pStg->OpenStream(szContents, NULL, STGM_SRO, 0, &pStrm)))
{
hr = LoadFromStream(pStrm);
pStrm->Release();
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::SaveToStorage
//
// Synopsis: Saves the object's persistent state to a storage
//
// Arguments: [pSg] -- storage to save to
//
// Returns: Success iff persistent state was written
//
// Notes: This function is used in the implementation of
// IPersistStorage::Save and IPersistFile::Save when
// the file is a docfile.
// This method opens a stream, "CONTENTS", and uses
// method SaveToStream to complete the save.
// Servers that do more sophisticated saving will want
// to override this method.
//
//---------------------------------------------------------------
HRESULT
SrvrDV::SaveToStorage(LPSTORAGE pStg, BOOL fSameAsLoad)
{
// write our native data stream
HRESULT hr;
LPSTREAM pStrm;
hr = pStg->CreateStream(szContents, STGM_SALL|STGM_CREATE, 0L, 0L, &pStrm);
if (OK(hr))
{
hr = SaveToStream(pStrm);
pStrm->Release();
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::InitNew
//
// Synopsis: IPersistStorage Method
//
// Notes: This method transitions the object to loaded.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::InitNew(LPSTORAGE pStg)
{
//
//REVIEW: what happens if we attempt to load the same ctrl more than once?
//
if (pStg == NULL)
{
DOUT(TEXT("SrvrDV::InitNew E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
HRESULT hr;
if (OK(hr = _pCtrl->TransitionTo(OS_LOADED)))
(_pStg = pStg)->AddRef(); // hold on to the storage
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Load
//
// Synopsis: IPersistStorage Method
//
// Notes: This method loads the object using LoadFromStorage and
// then transitions the object to loaded.
// A pointer to our storage is maintained in member variable
// _pStg.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::Load(LPSTORAGE pStg)
{
// object can be loaded only once!
if (_pCtrl->State() != OS_PASSIVE)
{
DOUT(TEXT("SrvrDV::Load E_FAIL\r\n"));
return E_FAIL;
}
if (pStg == NULL)
{
DOUT(TEXT("SrvrDV::Load E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
// do the load and move to the loaded state
HRESULT hr;
if (OK(hr = LoadFromStorage(pStg)))
{
if (OK(hr = _pCtrl->TransitionTo(OS_LOADED)))
{
(_pStg = pStg)->AddRef();
}
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Save
//
// Synopsis: Method of IPersistStorage interface
//
// Notes: This method uses SaveToStorage to write the persistent
// state. It also writes the full user type string to the
// storage as is required.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::Save(LPSTORAGE pStg, BOOL fSameAsLoad)
{
if (pStg == NULL)
{
DOUT(TEXT("SrvrDV::Save E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
// write our native data stream
HRESULT hr;
if (OK(hr = SaveToStorage(pStg, fSameAsLoad)))
{
// Write the UserType string. We don't let this fail the operation.
WriteFmtUserTypeStg(pStg,
0,
_pClass->_szUserClassType[USERCLASSTYPE_FULL]);
_fNoScribble = TRUE;
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::SaveCompleted
//
// Synopsis: Method of IPersistStorage interface
//
// Notes: This method clears the dirty flag and updates our
// storage pointer, _pStg, if required.
// Servers that are also containers will want to override
// this method to pass the call recursively to all loaded
// embeddings.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::SaveCompleted(LPSTORAGE pStg)
{
// if pStg is non-null then we are coming out of HANDS-OFF mode,
// otherwise we are coming out of NO-SCRIBBLE mode.
if (pStg != NULL)
{
// We should be in HANDS-OFF mode and hence able to Assert that
// _pStg is NULL here by virtue of the HandsOffStorage call.
// However, the official OLE sample container app "Outline"
// fail to make the HandsOffStorage call.
// In order to be robust we release our _pStg handle if it is
// "illegally" NON-NULL
//
if (_pStg != NULL)
{
DOUT(TEXT("SrvrDV: WARNING! SaveCompleted: "));
DOUT(TEXT("SrvrDV: Container failed to make required HandsOffStorage call.\n"));
_pStg->Release();
}
(_pStg = pStg)->AddRef(); // hold on to the new storage
}
_fDirty = FALSE; // clear our dirty flag
_fNoScribble = FALSE; // we are out of NO-SCRIBBLE mode
//REVIEW: should we advise in the case we are not fRemembering?
if (_pCtrl != NULL)
_pCtrl->OnSave(); // and notify any advises that we have saved
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::HandsOffStorage
//
// Synopsis: Method of IPersistStorage interface
//
// Notes: This method releases the storage we are holding on to.
// Servers that are also containers will want to override
// this method to pass the call recursively to all loaded
// embeddings.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::HandsOffStorage(void)
{
if (_pStg != NULL)
_pStg->Release();
_pStg = NULL;
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Load, public
//
// Synopsis: Method of IPersistFile interface
//
// Notes: This opens the file as a docfile and uses IPersistStorage::Load
// to complete the operation.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::Load(LPCOLESTR lpstrFile, DWORD grfMode)
{
// use the default storage modes if no flags were specified
if (grfMode == 0)
grfMode = STGM_DFRALL;
// if they didn't specify a share mode then use deny-write
if ( (grfMode & STGM_SHARE) == 0)
grfMode |= STGM_SHARE_DENY_WRITE;
// of course, we use transacted mode
grfMode |= STGM_TRANSACTED;
HRESULT hr;
if (lpstrFile == NULL)
{
// lpstrFile NULL is a special-case indicating that we should
// create a temporary docfile for the new file case
//
grfMode |= STGM_CREATE | STGM_DELETEONRELEASE;
LPSTORAGE pStg;
if (OK(hr = StgCreateDocfile(NULL, grfMode, 0L, &pStg)))
{
hr = InitNew(pStg);
// IPersistStorage::InitNew will hold on to the pStg
pStg->Release();
}
return hr;
}
LPSTORAGE pStg;
if (OK(hr = StgOpenStorage(lpstrFile, NULL, grfMode, NULL, 0L, &pStg)))
{
hr = Load(pStg);
// IPersistStorage::Load will hold on to the pStg
pStg->Release();
}
//REVIEW: Is the first SetMoniker happening correctly?
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::Save, public
//
// Synopsis: Method of IPersistFile interface
//
// Notes: If a file is specified then this creates a docfile and
// uses IPersistStorage::Save to complete the operation.
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::Save(LPCOLESTR lpstrFile, BOOL fRemember)
{
// if lpstrFile is NULL that means that we should save from where we
// loaded. Otherwise create a docfile with the specified name
HRESULT hr = NOERROR;
LPSTORAGE pStg;
if (lpstrFile == NULL)
(pStg = _pStg)->AddRef();
else
hr = StgCreateDocfile(lpstrFile, STGM_DFRALL|STGM_CREATE, 0L, &pStg);
if (OK(hr))
{
hr = OleSave((LPPERSISTSTORAGE)this, pStg, pStg == _pStg);
if (OK(hr))
{
// if we are to remember this storage then release our old
// storage and hold on to the new.
// Otherwise, wrap up a storage save by the usual SaveCompleted.
if (lpstrFile != NULL && fRemember)
{
// release our previous storage or stream
// and hold on to our new
HandsOffStorage();
((LPPERSISTSTORAGE)this)->SaveCompleted(pStg);
}
else
{
// If we did a storage save and we are not switching to a new
// storage then we complete the transaction with a SaveCompleted.
((LPPERSISTSTORAGE)this)->SaveCompleted(NULL);
}
}
// Release the storage. If we are supposed to hold on
// to it then we have already add-ref'd it.
pStg->Release();
}
// if we have renamed then
if (lpstrFile != NULL)
{
// TBD: Send On_Renamed advise?
//
// inform our object of its new moniker
//
LPMONIKER pmk;
if (OK(CreateFileMoniker(lpstrFile, &pmk)))
{
_pCtrl->SetMoniker(OLEWHICHMK_OBJFULL, pmk);
pmk->Release();
}
}
return hr;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::SaveCompleted, public
//
// Synopsis: Method of IPersistFile interface
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::SaveCompleted(LPCOLESTR lpstrFile)
{
//REVIEW: should we launch advise in the case we are not fRemembering?
if (_pCtrl != NULL)
_pCtrl->OnSave(); // and notify any advises that we have saved
return NOERROR;
}
//+---------------------------------------------------------------
//
// Member: SrvrDV::GetCurFile, public
//
// Synopsis: Method of IPersistFile interface
//
//---------------------------------------------------------------
STDMETHODIMP
SrvrDV::GetCurFile(LPOLESTR FAR * ppstrFile)
{
if (ppstrFile == NULL)
{
DOUT(TEXT("SrvrDV::GetCurFile E_INVALIDARG\r\n"));
return E_INVALIDARG;
}
*ppstrFile = 0; //set out params to NULL
HRESULT hr;
// if we don't currently have a file then return the default filename
if (_pStg == NULL)
{
// the default filename is *.ext where ext is our docfile extension
OLECHAR szDefault[6];
#if defined(OLE2ANSI)
wsprintf(szDefault, TEXT("*%s"), _pClass->_szDocfileExt);
#else
wsprintfW(szDefault, OLETEXT("*%ws"), _pClass->_szDocfileExt);
#endif
hr = TaskAllocString(szDefault, ppstrFile);
}
else
{
// the caller will free the task-allocated file name
STATSTG statstg;
if (OK(hr = _pStg->Stat(&statstg, STATFLAG_DEFAULT)))
*ppstrFile = statstg.pwcsName;
}
return hr;
}