//+---------------------------------------------------------------------------- // // File: // cachenode.cpp // // Classes: // CCacheNode // // Functions: // // History: // Gopalk Creation Aug 23, 1996 //----------------------------------------------------------------------------- #include #include #include #include #include #include // forward declaration HRESULT wGetData(LPDATAOBJECT lpSrcDataObj, LPFORMATETC lpforetc, LPSTGMEDIUM lpmedium); //+---------------------------------------------------------------------------- // // Member: // CCacheNode::Initialize, private // // Synopsis: // Routine used by the CCacheNode constructors to do common // initialization. // // Arguments: // [advf] -- ADVF flag // [pOleCache] -- COleCache this cache node belongs to // // Notes: // [pOleCache] is not reference counted; the cache node is // considered to be a part of the implementation of COleCache, // and is owned by COleCache. // // History: // 13-Feb-95 t-ScottH initialize m_dwPresBitsPos and new // data member m_dwPresFlag // 11/05/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- void CCacheNode::Initialize(DWORD advf, LPSTORAGE pStg) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Initialize(%lx, %p)\n", this, advf, pStg)); // initialize member variables m_clsid = CLSID_NULL; m_advf = advf; m_lWidth = 0; m_lHeight = 0; m_dwFlags = 0; m_pStg = pStg; m_iStreamNum = OLE_INVALID_STREAMNUM; m_dwPresBitsPos = 0; m_fConvert = FALSE; m_pPresObj = NULL; m_pPresObjAfterFreeze = NULL; m_pDataObject = NULL; m_dwAdvConnId = 0; #ifdef _DEBUG m_dwPresFlag = 0; #endif // _DEBUG LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Initialize()\n", this)); return; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::CCacheNode, public // // Synopsis: // Constructor - use this constructor when the cache node is // to be loaded later // // Arguments: // [pOleCache] -- pointer to the COleCache that owns this node // // Notes: // // History: // 11/05/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- CCacheNode::CCacheNode() { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::CacheNode()\n", this)); m_foretc.cfFormat = 0; m_foretc.ptd = NULL; m_foretc.dwAspect = 0; m_foretc.lindex = DEF_LINDEX; m_foretc.tymed = TYMED_HGLOBAL; Initialize(0, NULL); LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::CacheNode()\n", this)); } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::CCacheNode, public // // Synopsis: // constructor - use this constructor when all the data to // initialize the cache node is available now // // Arguments: // [lpFormatEtc] - the format for the presentation that this // cache node will hold // [advf] - the advise control flags, from ADVF_* // [pOleCache] -- pointer to the COleCache that owns this node // // Notes: // // History: // 11/05/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- CCacheNode::CCacheNode(LPFORMATETC lpFormatEtc, DWORD advf, LPSTORAGE pStg) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::CacheNode(%p, %lx, %p)\n", this, lpFormatEtc, advf, pStg)); UtCopyFormatEtc(lpFormatEtc, &m_foretc); BITMAP_TO_DIB(m_foretc); Initialize(advf, pStg); LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::CacheNode()\n", this)); } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::~CCacheNode, private // // Synopsis: // destructor // // Notes: // // History: // 11/05/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- CCacheNode::~CCacheNode() { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::~CacheNode()\n", this )); // Destroy the presentation objects if(m_pPresObj) { m_pPresObj->Release(); m_pPresObj = NULL; } if(m_pPresObjAfterFreeze) { m_pPresObjAfterFreeze->Release(); m_pPresObjAfterFreeze = NULL; } // Delete the ptd if it is non-null if(m_foretc.ptd) { PubMemFree(m_foretc.ptd); m_foretc.ptd = NULL; } // Assert that there is no pending advise connection Win4Assert(!m_dwAdvConnId); if(m_dwAdvConnId) { Win4Assert(m_pDataObject); TearDownAdviseConnection(m_pDataObject); } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::~CacheNode()\n", this)); } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::SetStg, public // // Synopsis: // Set storage in which the presentation gets saved // // Arguments: // [pStg] -- Storage pointer // // Returns: // OLE_E_ALREADY_INITIALIZED or NOERROR // // History: // Gopalk Creation Aug 26, 1996 // //----------------------------------------------------------------------------- HRESULT CCacheNode::SetStg(LPSTORAGE pStg) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::SetStg(%p)\n", this, pStg)); HRESULT error; if(m_pStg) { error = CO_E_ALREADYINITIALIZED; Win4Assert(FALSE); } else { // Save the storage without addref m_pStg = pStg; error = NOERROR; } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::SetStg(%lx)\n", this, error)); return(error); } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::Load, public // // Synopsis: // Load a cache node from a stream; only loads the presentation // header. (REVIEW, need to see presentation object::Load) // // Arguments: // [lpstream] -- the stream to load the presentation out of // [iStreamNum] -- the stream number // // Returns: // REVIEW // DV_E_LINDEX, for invalid lindex in stream // S_OK // // Notes: // As part of the loading, the presentation object gets created, // and loaded from the stream. // // History: // 11/06/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- HRESULT CCacheNode::Load(LPSTREAM lpstream, int iStreamNum, BOOL fDelayLoad) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Load(%lx, %d)\n", this, lpstream, iStreamNum)); HRESULT error = NOERROR; if(IsNativeCache()) { // Native Cache node // Update state SetLoadedStateFlag(); ClearFrozenStateFlag(); // We make the conservative assumption that the native cache // is not blank SetDataPresentFlag(); } else { // Normal cache node. // Read the presentation stream header m_foretc.ptd = NULL; m_fConvert = FALSE; error = UtReadOlePresStmHeader(lpstream, &m_foretc, &m_advf, &m_fConvert); if(error==NOERROR) { // Set the starting position of pres object data SetPresBitsPos(lpstream, m_dwPresBitsPos); // Assume that the presentation is blank ClearDataPresentFlag(); m_lWidth = 0; m_lHeight = 0; // Load desired state if(m_foretc.cfFormat) { if(fDelayLoad) { DWORD dwBuf[4]; // Read the extent and size of presentation data dwBuf[0] = 0L; dwBuf[1] = 0L; dwBuf[2] = 0L; dwBuf[3] = 0L; error = lpstream->Read(dwBuf, sizeof(dwBuf), NULL); if(error == NOERROR) { Win4Assert(!dwBuf[0]); m_lWidth = dwBuf[1]; m_lHeight = dwBuf[2]; if(dwBuf[3]) { SetDataPresentFlag(); Win4Assert(m_lWidth!=0 && m_lHeight!=0); } else { Win4Assert(m_lWidth==0 && m_lHeight==0); } } } else { // Create the pres object error = CreateOlePresObj(&m_pPresObj, m_fConvert); // Load the data into pres object if(error == NOERROR) error = m_pPresObj->Load(lpstream, FALSE); // Update data present flag if(!m_pPresObj->IsBlank()) SetDataPresentFlag(); } } // Update rest of state if(error == NOERROR) { SetLoadedStateFlag(); SetLoadedCacheFlag(); ClearFrozenStateFlag(); m_iStreamNum = iStreamNum; } } // Clean up if presentation could not be loaded if(error != NOERROR) { // Delete the ptd if it is non-null if(m_foretc.ptd) PubMemFree(m_foretc.ptd); if(m_pPresObj) { m_pPresObj->Release(); m_pPresObj = NULL; } // Initialize. Gopalk INIT_FORETC(m_foretc); m_advf = 0; m_fConvert = FALSE; m_iStreamNum = OLE_INVALID_STREAMNUM; ClearLoadedStateFlag(); ClearLoadedCacheFlag(); ClearFrozenStateFlag(); ClearDataPresentFlag(); } } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Load ( %lx )\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::Save, public // // Synopsis: // Saves a cache node, including its presentation object, // to a stream. // // Arguments: // [pstgSave] -- the storage that will contain the stream // [fSameAsLoad] -- is this storage the same one we loaded from // [iStreamNum] -- the stream number to save to // [fDrawCache] -- used to indicate whether or not the cached // presentation is to be used for drawing; if false, // the presentation is discarded after saving // [fSaveIfSavedBefore] -- instructs the method to save this // cache node, even if it's been saved before // [lpCntCachesNotSaved] -- a running count of the number of // caches that have not been saved // // Returns: // REVIEW // S_OK // // Notes: // // History: // 03/10/94 - AlexT - Don't call SaveCompleted if we don't save! // (see logRtn, below) // 01/11/94 - AlexGo - fixed compile error (signed/unsigned // mismatch) // 11/06/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- HRESULT CCacheNode::Save(LPSTORAGE pstgSave, BOOL fSameAsLoad, int iStreamNum) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Save(%p, %lu, %d)\n", this, pstgSave, fSameAsLoad, iStreamNum)); HRESULT error = NOERROR; OLECHAR szNewName[sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR)]; // Create the new presentation stream name if(IsNormalCache()) { _xstrcpy(szNewName, OLE_PRESENTATION_STREAM); if(iStreamNum) UtGetPresStreamName(szNewName, iStreamNum); } if(InLoadedState() && (IsNativeCache() || m_iStreamNum>0)) { // The cache node is in loaded state // The CONTENTS stream need not be updated for both Save and SaveAs cases // when the native cache node is in loaded state because the container // does copy the CONTENTS stream before invoking SaveAs on the cache. if(IsNormalCache()) { if(fSameAsLoad) { // We are being asked to save to the current storage if(m_iStreamNum!=iStreamNum) { // We are being asked to save in to a different stream // We can rename the old stream to a new name OLECHAR szOldName[sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR)]; // Assert that the new stream number is less // than the current stream number Win4Assert(m_iStreamNum>iStreamNum); // Create the old presentation stream name _xstrcpy(szOldName, OLE_PRESENTATION_STREAM); if(m_iStreamNum!=0) UtGetPresStreamName(szOldName, m_iStreamNum); // Delete the stream with the new name, if there is one pstgSave->DestroyElement(szNewName); // Rename the old stream error = pstgSave->RenameElement(szOldName, szNewName); // If NOERROR, update the state if(error==NOERROR) { m_iStreamNum = iStreamNum; SetLoadedStateFlag(); } } } else { // We are being asked to save to a new storage and // we are in loaded state. We can do efficient stream copy LPSTREAM lpstream; // Open or Create the new stream in the given storage error = OpenOrCreateStream(pstgSave, szNewName, &lpstream); if(error==NOERROR) { LPSTREAM pstmSrc; // Get source stream if(pstmSrc = GetStm(FALSE /*fSeekToPresBits*/, STGM_READ)) { ULARGE_INTEGER ularge_int; // initialize to copy all of stream ULISet32(ularge_int, (DWORD)-1L); error = pstmSrc->CopyTo(lpstream, ularge_int, NULL, NULL); // release the source stream pstmSrc->Release(); } // Remember the starting position of presentation bits m_dwSavedPresBitsPos = m_dwPresBitsPos; // Assuming that we opened an existing pres stream, // truncate the rest of it before releasing it StSetSize(lpstream, 0, TRUE); lpstream->Release(); } } } } else { // Either the node is not in loaded state or it represents presentation 0 LPOLEPRESOBJECT pPresObj; if(IsNativeCache()) { // Native cache needs to be saved in CONTENTS stream STGMEDIUM stgmed; FORMATETC foretc; // Open or Create "CONTENTS" stream error = OpenOrCreateStream(pstgSave, OLE_CONTENTS_STREAM, &stgmed.pstm); if(error==NOERROR) { stgmed.pUnkForRelease = NULL; stgmed.tymed = TYMED_ISTREAM; foretc = m_foretc; foretc.tymed = TYMED_ISTREAM; // Get the latest presentation. if(m_pPresObjAfterFreeze && !m_pPresObjAfterFreeze->IsBlank()) { Win4Assert(InFrozenState()); pPresObj = m_pPresObjAfterFreeze; } else if(m_pPresObj) pPresObj = m_pPresObj; else { // PresObj has not yet been created. This happens // for newly created static presentation without a // corresponding set data. BOOL bIsBlank = IsBlank(); Win4Assert(bIsBlank); if(!bIsBlank && fSameAsLoad) { error = NO_ERROR; goto scoop; } error = CreateOlePresObj(&m_pPresObj, FALSE /* fConvert */); pPresObj = m_pPresObj; } // Save the native presentation if(error==NOERROR) error = pPresObj->GetDataHere(&foretc, &stgmed); // Assuming that we opened an existing CONTENTS stream, // truncate the rest of it before releasing it StSetSize(stgmed.pstm, 0, TRUE); scoop: stgmed.pstm->Release(); } } else { // Normal cache needs to be saved in PRESENTATION stream LPSTREAM lpstream; // Ensure that PresObj exists for presentation 0 if(m_iStreamNum==0 && InLoadedState() && m_foretc.cfFormat && !m_pPresObj) { // This can happen only after a discard cache. We force // load the presentation for the following save to succeed error = CreateAndLoadPresObj(FALSE); Win4Assert(error == NOERROR); } if(error == NOERROR) { // Open or Create the new stream in the given storage error = OpenOrCreateStream(pstgSave, szNewName, &lpstream); if(error == NOERROR) { // Write the presentation stream header error = UtWriteOlePresStmHeader(lpstream, &m_foretc, m_advf); if(error == NOERROR) { // Remember the starting position of presentation bits if(fSameAsLoad) SetPresBitsPos(lpstream, m_dwPresBitsPos); else SetPresBitsPos(lpstream, m_dwSavedPresBitsPos); if(m_foretc.cfFormat != NULL) { // Get the latest presentation. if(m_pPresObjAfterFreeze && !m_pPresObjAfterFreeze->IsBlank()) { Win4Assert(InFrozenState()); pPresObj = m_pPresObjAfterFreeze; } else pPresObj = m_pPresObj; // Save the presentation if(pPresObj) error = pPresObj->Save(lpstream); else { // This happens for newly created presentations that // are blank. Write header that represents blank // presentation Win4Assert(IsBlank()); Win4Assert(m_iStreamNum!=0); DWORD dwBuf[4]; dwBuf[0] = 0L; dwBuf[1] = 0L; dwBuf[2] = 0L; dwBuf[3] = 0L; error = lpstream->Write(dwBuf, sizeof(dwBuf), NULL); } } } // Assuming that we opened an existing pres stream, truncate the // stream to the current position and release it StSetSize(lpstream, 0, TRUE); lpstream->Release(); } } } // If NOERROR and fSameAsLoad, update state if(error==NOERROR && fSameAsLoad) { SetLoadedStateFlag(); if(IsNormalCache()) m_iStreamNum = iStreamNum; } } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Save(%lx)\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::SetPresBitsPos, private // // Synopsis: // Sets CCacheNode::m_dwPresBitsPos to the point where the // presentation begins in the stream associated with this cache // node. // // Arguments: // [lpStream] -- the stream the cache node is being saved to // // Notes: // // History: // 11/06/93 - ChrisWe - created // //----------------------------------------------------------------------------- void CCacheNode::SetPresBitsPos(LPSTREAM lpStream, DWORD& dwPresBitsPos) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::SetPresBitsPos(%p)\n", this, lpStream)); LARGE_INTEGER large_int; ULARGE_INTEGER ularge_int; // Retrieve the current position at which the pres object data starts LISet32(large_int, 0); lpStream->Seek(large_int, STREAM_SEEK_CUR, &ularge_int); dwPresBitsPos = ularge_int.LowPart; LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::SetPresBitsPos()\n", this)); return; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::CreatePresObject, public // // Synopsis: // Create the presentation object for the cache node. If there // is no clipboard format (cfFormat), then query the source data // object for one of our preferred formats. If there is no // source data object, no error is returned, but no presentation // is created // // Arguments: // [lpSrcDataObj] -- data object to use as the basis for the // new presentation // [fConvert] -- REVIEW, what's this for? // // Returns: // // Notes: // // History: // 11/06/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- /* HRESULT CCacheNode::CreatePresObject(LPDATAOBJECT lpSrcDataObj, BOOL fConvert) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::CreatePresObject(%p, %lu)\n", this, lpSrcDataObj, fConvert)); // Is the nodes formatetc supported by the data object BOOL fFormatSupported = TRUE; HRESULT error = NOERROR; // Assert that pres object has not yet been created Win4Assert(!m_pPresObj); // Check whether object supports the cachenode's format. If the // cachenode format field is NULL, the query will be made for // standard formats if(lpSrcDataObj) fFormatSupported = QueryFormatSupport(lpSrcDataObj); // Create the pres object if we know the format of this node if(m_foretc.cfFormat!=NULL) { // Change BITMAP to DIB BITMAP_TO_DIB(m_foretc); error = CreateOlePresObject(&m_pPresObj, fConvert); if(error==NOERROR && !fFormatSupported) error = ResultFromScode(CACHE_S_FORMATETC_NOTSUPPORTED); } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::CreatePresObj(%lx)\n", this, error)); return error; } */ //+---------------------------------------------------------------------------- // // Member: // CCacheNode::CreateOlePresObj, private // // Synopsis: // Creates a presentation object, according to the clipboard // format m_foretc.cfFormat // // Arguments: // [ppPresObject] -- pointer to where to return the pointer to // the newly created presentation object // [fConvert] -- REVIEW, what's this for? // // Returns: // DV_E_CLIPFORMAT, if object doesn't support one of the standard // formats // E_OUTOFMEMORY, if we can't allocate the presentation object // S_OK // // Notes: // // History: // 13-Feb-95 t-ScottH added m_dwPresFlag to track type of // IOlePresObject // 11/06/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- HRESULT CCacheNode::CreateOlePresObj(LPOLEPRESOBJECT* ppPresObj, BOOL fConvert) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::CreateOlePresObj(%p,%lu)\n", this, ppPresObj, fConvert)); HRESULT error = NOERROR; switch(m_foretc.cfFormat) { case NULL: // Pres object cannot be created *ppPresObj = NULL; error = DV_E_CLIPFORMAT; break; case CF_METAFILEPICT: *ppPresObj = new CMfObject(NULL, m_foretc.dwAspect, fConvert); #ifdef _DEBUG // for use with debugger extensions and dump method m_dwPresFlag = CN_PRESOBJ_MF; #endif // _DEBUG break; case CF_ENHMETAFILE: *ppPresObj = new CEMfObject(NULL, m_foretc.dwAspect); #ifdef _DEBUG // for use with debugger extensions and dump method m_dwPresFlag = CN_PRESOBJ_EMF; #endif // _DEBUG break; default: *ppPresObj = new CGenObject(NULL, m_foretc.cfFormat, m_foretc.dwAspect); #ifdef _DEBUG // for use with debugger extensions and dump method m_dwPresFlag = CN_PRESOBJ_GEN; #endif // _DEBUG } if(error==NOERROR && !*ppPresObj) error = ResultFromScode(E_OUTOFMEMORY); LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::CreateOlePresObj(%lx)\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::GetStm, public // // Synopsis: // Get the stream the presentation is stored in. Optionally // position the stream at the point where the presentation // data begins // // Arguments: // [fSeekToPresBits] -- position the stream so that the // presentation bits would be the next read/written // [dwStgAccess] -- the access mode (STGM_*) to open the stream // with // // Returns: // NULL, if there is no stream, or the stream cannot be opened // // Notes: // // History: // 11/06/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- LPSTREAM CCacheNode::GetStm(BOOL fSeekToPresBits, DWORD dwStgAccess) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::GetStm(%lu, %lx)\n", this, fSeekToPresBits, dwStgAccess)); LPSTREAM pstm = NULL; OLECHAR szName[sizeof(OLE_PRESENTATION_STREAM)/sizeof(OLECHAR)]; // This function should only get called for normal cache nodes Win4Assert(IsNormalCache()); Win4Assert(this!=NULL); // There has to be a valid stream number and storage if(m_iStreamNum!=OLE_INVALID_STREAMNUM && m_pStg) { // Generate the stream name _xstrcpy(szName, OLE_PRESENTATION_STREAM); if(m_iStreamNum) UtGetPresStreamName(szName, m_iStreamNum); // Attempt to open the stream if(m_pStg->OpenStream(szName, NULL, (dwStgAccess | STGM_SHARE_EXCLUSIVE), NULL, &pstm) == NOERROR) { // if we're to position the stream at the presentation, do so if(fSeekToPresBits) { LARGE_INTEGER large_int; LISet32(large_int, m_dwPresBitsPos); if(pstm->Seek(large_int, STREAM_SEEK_SET, NULL)!=NOERROR) { // We could not seek to pres object bits // Release the stream and return null pstm->Release(); pstm = NULL; } } } } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::GetStm(%p)\n", this, pstm)); return(pstm); } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::Update, public // // Synopsis: // Updates the presentation object in this cache node from // the given data object. The update is only done if the // [grfUpdf] flags match m_advf specifications, and if // there is actually a presentation to update. // // Arguments: // [lpDataObj] -- the data object to use as a source of data // [grfUpdf] -- the update control flags // // Returns: // S_FALSE // S_OK // // Notes: // // History: // 11/06/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- HRESULT CCacheNode::Update(LPDATAOBJECT lpDataObj, DWORD grfUpdf, BOOL& fUpdated) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Update(%p, %lx)\n", this, lpDataObj, grfUpdf)); STGMEDIUM medium; // the medium of the presentation FORMATETC foretc; // the format of the presentation HRESULT error = ResultFromScode(CACHE_S_SAMECACHE); // There should be a data object for updating if(!lpDataObj) { error = ResultFromScode(E_INVALIDARG); goto errRtn; } // If cfFormat is NULL, try setting it if(!m_foretc.cfFormat) { if(QueryFormatSupport(lpDataObj)) { // We could update our cfFormat ClearLoadedStateFlag(); } else { // We still could not set the cfFormat error = ResultFromScode(OLE_E_BLANK); goto errRtn; } } // Check the flags and update // If the update flag is UPDFCACHE_ONLYIFBLANK and the pres object is // is not blank, simply return if((grfUpdf & UPDFCACHE_ONLYIFBLANK) && (!IsBlank())) goto errRtn; // If the update flag UPDFCACHE_NODATACACHE is not set and the pres object // flag is ADVF_NODATA, simply return if(!(grfUpdf & UPDFCACHE_NODATACACHE) && (m_advf & ADVF_NODATA)) goto errRtn; // Update if both NODATA flags are set if((grfUpdf & UPDFCACHE_NODATACACHE) && (m_advf & ADVF_NODATA)) goto update; // Update if both ONSAVE flags are set if((grfUpdf & UPDFCACHE_ONSAVECACHE) && (m_advf & ADVFCACHE_ONSAVE)) goto update; // Update if both ONSTOP flags are set if((grfUpdf & UPDFCACHE_ONSTOPCACHE) && (m_advf & ADVF_DATAONSTOP)) goto update; // Update if this cache node is blank if((grfUpdf & UPDFCACHE_IFBLANK) && IsBlank()) goto update; // Update if this is a normal cache node that gets live updates if((grfUpdf & UPDFCACHE_NORMALCACHE) && !(m_advf & (ADVF_NODATA | ADVFCACHE_ONSAVE | ADVF_DATAONSTOP))) goto update; // If we have reached here, do not update goto errRtn; update: // Initialize the medium medium.tymed = TYMED_NULL; medium.hGlobal = NULL; medium.pUnkForRelease = NULL; // Make a copy of the desired format; this may mutate below foretc = m_foretc; // Let the object create the medium. if(wGetData(lpDataObj, &foretc, &medium) == NOERROR) { // Make the cache take the ownership of the data error = SetDataWDO(&foretc, &medium, TRUE, fUpdated, lpDataObj); if(error != NOERROR) ReleaseStgMedium(&medium); } else error = ResultFromScode(E_FAIL); errRtn: LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Update(%lx)\n",this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::SetDataWDO, public // // Synopsis: // Data is set into the presentation object, if this cache node // is not frozen. If the cache node is frozen, then the // new presentation data is stashed into the m_pPresObjAfterFreeze // presentation object, which is created, if there isn't already // one. If data is successfully set in the presentation object, // and the node is not frozen, the cache is notified that this // is dirty. // // Arguments: // [lpForetc] -- the format of the new data // [lpStgmed] -- the storage medium the new data is one // [fRelease] -- passed on to the presentation object; indicates // whether or not to release the storage medium // [pDataObj] -- pointer to the revelant source data object // // Returns: // E_FAIL // REVIEW, result from presentationObject::SetData // S_OK // // Notes: // // History: // 11/06/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- HRESULT CCacheNode::SetDataWDO(LPFORMATETC lpForetc, LPSTGMEDIUM lpStgmed, BOOL fRelease, BOOL& fUpdated, IDataObject *pDataObj) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::SetDataWDO(%p, %p, %lu, %p)\n", this, lpForetc, lpStgmed, fRelease, pDataObj)); HRESULT hresult = NOERROR; // Initialize fUpdated = FALSE; // If the cache node is in frozen state, save the data in the // m_pPresObjAfterFreeze if(InFrozenState()) { // If PresObjAfterFreeze has not yet been created, create it if(!m_pPresObjAfterFreeze) hresult = CreateOlePresObj(&m_pPresObjAfterFreeze, FALSE); // Hold the data in PresObjAfterFreeze if(hresult == NOERROR) hresult = m_pPresObjAfterFreeze->SetDataWDO(lpForetc, lpStgmed, fRelease, pDataObj); } else { // If PresObj has not yet been created, create it if(!m_pPresObj) hresult = CreateOlePresObj(&m_pPresObj, FALSE /* fConvert */); // Hold the data in PresObj if(hresult == NOERROR) hresult = m_pPresObj->SetDataWDO(lpForetc, lpStgmed, fRelease, pDataObj); // Update state if(hresult == NOERROR) { // Set or clear the data present flag if(m_pPresObj->IsBlank()) ClearDataPresentFlag(); else SetDataPresentFlag(); // Indicate that the cache node has been updated fUpdated = TRUE; } } // If suceeded in holding the data, clear loaded state flag if(hresult == NOERROR) ClearLoadedStateFlag(); LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::SetDataWDO(%lx)\n", this, hresult)); return hresult; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::GetExtent, public // // Synopsis: // Extents of this cache node presentation // // Arguments: // [dwAspect][in] -- Aspect for which the extent is desired // [pSizel] [in/out] -- Sizel structure for returning the extent // // // Returns: // NOERROR on success // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- HRESULT CCacheNode::GetExtent(DWORD dwAspect, SIZEL* pSizel) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::GetExtent(%lx, %p)\n", this, dwAspect, pSizel)); HRESULT error = NOERROR; if(!(dwAspect & m_foretc.dwAspect)) error = ResultFromScode(DV_E_DVASPECT); else if(IsBlank()) { // This case also catches new blank presentation caches pSizel->cx = 0; pSizel->cy = 0; error = ResultFromScode(OLE_E_BLANK); } else { // Check for existence of pres object if(!m_pPresObj && IsNormalCache()) { // The Presobj has not yet been created // This happens for old presentation caches only Win4Assert(InLoadedState()); pSizel->cx = m_lWidth; pSizel->cy = m_lHeight; } else { // If PresObj has not yet been created for native cache, // create and load the PresObj if(!m_pPresObj && IsNativeCache()) error = CreateAndLoadPresObj(FALSE); // Get extent information from PresObj if(error == NOERROR) error = m_pPresObj->GetExtent(dwAspect, pSizel); } // Ensure extents are positive if(error == NOERROR) { pSizel->cx = LONG_ABS(pSizel->cx); pSizel->cy = LONG_ABS(pSizel->cy); // Sanity check Win4Assert(pSizel->cx != 1234567890); Win4Assert(pSizel->cx != 1234567890); } } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::GetExtent(%lx)\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::GetData, public // // Synopsis: // Obtains the cache node presentation data // // Arguments: // [pforetc] [in] -- FormatEtc of the presentation desired // [pmedium] [out] -- Storage medium in which data is returned // // // Returns: // NOERROR on success // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- HRESULT CCacheNode::GetData(LPFORMATETC pforetc, LPSTGMEDIUM pmedium) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::GetData(%p, %p)\n", this, pforetc, pmedium)); HRESULT error = NOERROR; if(IsBlank()) { // This case also catches new blank presentation caches error = ResultFromScode(OLE_E_BLANK); } else { // Check for existence of pres object if(!m_pPresObj) { // The PresObj has not yet been created, create and load it // This happens for old presentation caches only Win4Assert(InLoadedState()); error = CreateAndLoadPresObj(FALSE); } // Get data from pres object if(error == NOERROR) error = m_pPresObj->GetData(pforetc, pmedium); } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::GetData(%lx)\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::GetDataHere, public // // Synopsis: // Obtains the cache node presentation data // // Arguments: // [pforetc] [in] -- FormatEtc of the presentation desired // [pmedium] [in/out] -- Storage medium in which data is returned // // // Returns: // NOERROR on success // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- HRESULT CCacheNode::GetDataHere(LPFORMATETC pforetc, LPSTGMEDIUM pmedium) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::GetData(%p, %p)\n", this, pforetc, pmedium)); HRESULT error = NOERROR; if(IsBlank()) { // This case also catches new blank presentation caches error = ResultFromScode(OLE_E_BLANK); } else { // Check for existence of pres object if(!m_pPresObj) { // The PresObj has not yet been created, create and load it // This happens for old presentation caches only Win4Assert(InLoadedState()); error = CreateAndLoadPresObj(FALSE); } // Get data from pres object if(error == NOERROR) error = m_pPresObj->GetDataHere(pforetc, pmedium); } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::GetDataHere(%lx)\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::Draw, public // // Synopsis: // Draws the presentation data on the specified hDC // // Arguments: // // // Returns: // NOERROR on success // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- HRESULT CCacheNode::Draw(void* pvAspect, HDC hicTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds, BOOL (CALLBACK *pfnContinue)(ULONG_PTR), ULONG_PTR dwContinue) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Draw(%p, %p, %p, %p, %p, %p)\n", this, pvAspect, lprcBounds, lprcWBounds, pfnContinue, dwContinue)); HRESULT error = NOERROR; if(IsBlank()) { // This case also catches new blank presentation caches error = ResultFromScode(OLE_E_BLANK); } else { // Check for existence of pres object if(!m_pPresObj) { // The PresObj has not yet been created, create and load it // This happens for old presentation caches only Win4Assert(InLoadedState()); error = CreateAndLoadPresObj(FALSE); } // Get draw from pres object if(error == NOERROR) error = m_pPresObj->Draw(pvAspect, hicTargetDev, hdcDraw, lprcBounds, lprcWBounds, pfnContinue, dwContinue); } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Draw(%lx)\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::GetColorSet, public // // Synopsis: // Draws the presentation data on the specified hDC // // Arguments: // // // Returns: // NOERROR on success // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- HRESULT CCacheNode::GetColorSet(void* pvAspect, HDC hicTargetDev, LPLOGPALETTE* ppColorSet) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::GetColorSet(%p, %p)\n", this, pvAspect, ppColorSet)); HRESULT error = NOERROR; if(IsBlank()) { // This case also catches new blank presentation caches error = ResultFromScode(OLE_E_BLANK); } else { // Check for existence of pres object if(!m_pPresObj) { // The PresObj has not yet been created, create and load it // This happens for old presentation caches only Win4Assert(InLoadedState()); error = CreateAndLoadPresObj(FALSE); } // Get color set from pres object if(error == NOERROR) error = m_pPresObj->GetColorSet(pvAspect, hicTargetDev, ppColorSet); } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::GetColorSet(%lx)\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::CreateAndLoadPresObj, private // // Synopsis: // Creates and loads the pres object // // Arguments: // [fHeaderOnly] - True if only pres obj header needs to be loaded // This option is used for GetExtent as there is no // need to load entire pres obj for getting extents // Further, this routine should be called only for // previously cached presentations // Returns: // NOERROR on success // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- HRESULT CCacheNode::CreateAndLoadPresObj(BOOL fHeaderOnly) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::CreateAndLoadPresObj(%lx)\n", this, fHeaderOnly)); HRESULT error = NOERROR; // Check for existence of pres object if(!m_pPresObj) { if(IsNativeCache()) { // Native cache node // Check if cache has storage if(m_pStg) { BOOL fOle10Native, fUpdated; STGMEDIUM stgmed; // Is the native an Ole 1.0 class if(CoIsOle1Class(m_clsid)) fOle10Native = TRUE; else fOle10Native = FALSE; // Obtain global with the native data. // Due to auto convert case, the native stream may be in the // old CfFormat and consequently, trying to read in the new // CfFormat can fail. Gopalk stgmed.pUnkForRelease = NULL; stgmed.tymed = m_foretc.tymed; stgmed.hGlobal = UtGetHPRESFromNative(m_pStg, NULL, m_foretc.cfFormat, fOle10Native); // We may be dealing with old-styled static object. Such // objects are supposed to be converted during loading, but // some are not, for reasons such as lack of access rights. if(!stgmed.hGlobal) { // Convert OlePres to CONTENTS in-memory. IStream *pMemStm = NULL; HRESULT hr; hr = CreateStreamOnHGlobal(NULL, TRUE, &pMemStm); if(SUCCEEDED(hr) && pMemStm) { UINT uiStatus = 0; hr = UtOlePresStmToContentsStm(m_pStg, OLE_PRESENTATION_STREAM, pMemStm, &uiStatus); if(SUCCEEDED(hr) && uiStatus == 0) { // rewind the stream LARGE_INTEGER dlibMove = {0}; pMemStm->Seek(dlibMove, STREAM_SEEK_SET, NULL); // 2nd try stgmed.hGlobal = UtGetHPRESFromNative(NULL, pMemStm, m_foretc.cfFormat, fOle10Native); } pMemStm->Release(); } } // Set the data on native cache node if(stgmed.hGlobal) { error = SetData(&m_foretc, &stgmed, TRUE, fUpdated); if(error != NOERROR) ReleaseStgMedium(&stgmed); } else { // This happens when the native data is not in the correct format Win4Assert(FALSE); error = ResultFromScode(DV_E_CLIPFORMAT); } } else { Win4Assert(FALSE); error = ResultFromScode(OLE_E_BLANK); } } else { // Normal cache node error = CreateOlePresObj(&m_pPresObj, m_fConvert); // Load the data into pres object if(error == NOERROR) { LPSTREAM pStream; // Open presentation stream and seek to the pres obj bits pStream = GetStm(TRUE, STGM_READ); if(pStream) { // Load pres object error = m_pPresObj->Load(pStream, fHeaderOnly); pStream->Release(); } else { // This can happen only when m_pStg is NULL Win4Assert(!m_pStg); Win4Assert(FALSE); error = ResultFromScode(OLE_E_BLANK); } } // Assert that the state matches current state if(error == NOERROR) { SIZEL extent; Win4Assert(m_pPresObj->IsBlank()==IsBlank()); m_pPresObj->GetExtent(m_foretc.dwAspect, &extent); Win4Assert(extent.cx==m_lWidth && extent.cy==m_lHeight); } } } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::CreateAndLoadPresObj(%lx)\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::DiscardPresentation, public // // Synopsis: // Discards the presentation objects so that we hit the storage // for presentation data in future // // Arguments: // NONE // // Returns: // NOERROR on success // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- HRESULT CCacheNode::DiscardPresentation(LPSTREAM pGivenStream) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::DiscardPresentation()\n", this)); HRESULT error = NOERROR; LPSTREAM pStream; // We are being forced to destroy presentation object rather than // discarding its presentation data due to a flaw in the current design // of presentation objects. The presentation objects do not discard their // extent information along with their presentation data. This causes us // to get latest extent information in future IOleCache::GetExtent() calls // which is not the desired behavior. Gopalk // Revert state if(IsNativeCache()) { // Native Cache node // Update state SetLoadedStateFlag(); ClearFrozenStateFlag(); // We make the conservative assumption that the native cache // is not blank SetDataPresentFlag(); } else { // Normal cache node if(m_iStreamNum == OLE_INVALID_STREAMNUM) { // New cache node Win4Assert(!InLoadedState()); // Simply update state ClearFrozenStateFlag(); ClearDataPresentFlag(); m_lWidth = 0; m_lHeight = 0; } else { // Old cache node if(InLoadedState()) { // The cache node is still in loaded state BOOL fUpdated; SIZEL Extent; // Unfreeze the cache node to get the latest saved presentation if(InFrozenState()) Unfreeze(fUpdated); Win4Assert(!m_pPresObjAfterFreeze); Win4Assert(!InFrozenState()); // Obtain the latest extent. // This could happen due to Unfreeze above if(m_pPresObj) { error = m_pPresObj->GetExtent(m_foretc.dwAspect, &Extent); m_lWidth = Extent.cx; m_lHeight = Extent.cy; } // Update state if(error == NOERROR) SetLoadedCacheFlag(); } else { // Open presentation stream and read header from it pStream = GetStm(TRUE, STGM_READ); if(pStream) { // Read presentation header if(m_foretc.cfFormat) { DWORD dwBuf[4]; // Read the extent and size of presentation data dwBuf[0] = 0L; dwBuf[1] = 0L; dwBuf[2] = 0L; dwBuf[3] = 0L; error = pStream->Read(dwBuf, sizeof(dwBuf), NULL); if(error == NOERROR) { Win4Assert(!dwBuf[0]); m_lWidth = dwBuf[1]; m_lHeight = dwBuf[2]; if(dwBuf[3]) { SetDataPresentFlag(); Win4Assert(m_lWidth!=0 && m_lHeight!=0); } else { ClearDataPresentFlag(); Win4Assert(m_lWidth==0 && m_lHeight==0); } } } else { // Assume that the presentation is blank ClearDataPresentFlag(); m_lWidth = 0; m_lHeight = 0; } // Update rest of the state if(error == NOERROR) { SetLoadedStateFlag(); SetLoadedCacheFlag(); ClearFrozenStateFlag(); } // Release the stream pStream->Release(); } else { // This can happen only when m_pStg is NULL Win4Assert(!m_pStg); error = ResultFromScode(E_UNEXPECTED); } } } } // Destroy both presentation objects if(m_pPresObj && error==NOERROR) { m_pPresObj->Release(); m_pPresObj = NULL; } if(m_pPresObjAfterFreeze && error==NOERROR) { m_pPresObjAfterFreeze->Release(); m_pPresObjAfterFreeze = NULL; } LEDebugOut((DEB_ITRACE, "%p _OUT CCacheNode::DiscardPresentation(%lx)\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::Freeze, public // // Synopsis: // Freeze the cachenode. From here on, OnDataChange() is ignored // until this node is unfrozen (Unfreeze().) This is not // persistent across Save/Load. (If we receive OnDataChange(), // the new data is stashed away in m_pPresAfterFreeze, but is // not exported to the outside of the cache node.) // // Arguments: // none // // Returns: // VIEW_S_ALREADY_FROZEN // S_OK // // Notes: // // History: // 11/06/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- HRESULT CCacheNode::Freeze() { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::Freeze()\n", this)); HRESULT hresult = NOERROR; if(InFrozenState()) hresult = ResultFromScode(VIEW_S_ALREADY_FROZEN); else SetFrozenStateFlag(); LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::Freeze(%lx)\n", this, hresult)); return hresult; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::Unfreeze, public // // Synopsis: // Unfreeze the cachenode. If there have been changes to // the presentation data since the node was frozen, the node // is updated to reflect those changes. From this point on, // OnDataChange() notifications are no longer ignored. // // Arguments: // fChanged [out] - set to TRUE when cache node is updated // // Returns: // OLE_E_NOCONNECTION, if the node was not frozen (REVIEW scode) // S_OK // // Notes: // // History: // 11/06/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- HRESULT CCacheNode::Unfreeze(BOOL& fUpdated) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::UnFreeze(%p)\n", this, &fUpdated)); HRESULT hresult = NOERROR; // Initilaize fUpdated = FALSE; if(InFrozenState()) { // Cache node is no longer in frozen state ClearFrozenStateFlag(); // Check to see if we have m_pPresObjAfterFreeze if(m_pPresObjAfterFreeze) { // Check if the frozen presentation object is blank if(m_pPresObjAfterFreeze->IsBlank()) { // Release and reset the frozen presentation object m_pPresObjAfterFreeze->Release(); m_pPresObjAfterFreeze = NULL; } else { // Release the original presentation object if(m_pPresObj) m_pPresObj->Release(); // Make m_pPresObjAfterFreeze the current one and set // data present flag m_pPresObj = m_pPresObjAfterFreeze; SetDataPresentFlag(); // Cache node is updated fUpdated = TRUE; // Reset the m_pPresObjAfterFreeze to NULL m_pPresObjAfterFreeze = NULL; } } } else { // The cachenode is not frozen hresult = ResultFromScode(OLE_E_NOCONNECTION); } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::UnFreeze(%lx)\n", this, hresult)); return hresult; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::QueryFormatSupport, private // // Synopsis: // Check to see if the data object supports the presentation // format specified for this cache node. If no format is // specified, check for any of our preferred formats. If // the format is CF_DIB, and that is not available, check for // CF_BITMAP. // // Arguments: // [lpDataObj] -- the data object // // Returns: // TRUE if the format is supported, FALSE otherwise // // Notes: // // History: // 11/09/93 - ChrisWe - no longer necessary to reset format // after UtQueryPictFormat, since that leaves descriptor // untouched now // 11/09/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- BOOL CCacheNode::QueryFormatSupport(LPDATAOBJECT lpDataObj) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::QueryFormatSupport(%p)\n", this, lpDataObj)); BOOL fRet = FALSE; if(lpDataObj) { if(m_foretc.cfFormat) { // Check to see if cachenode format is supported if(lpDataObj->QueryGetData(&m_foretc) == NOERROR) fRet = TRUE; else { // If the cachenode format was DIB that was not supported, // check to see if BITMAP is supported instead if(m_foretc.cfFormat == CF_DIB) { FORMATETC foretc = m_foretc; foretc.cfFormat = CF_BITMAP; foretc.tymed = TYMED_GDI; if (lpDataObj->QueryGetData(&foretc) == NOERROR) fRet = TRUE; } } } else { // Check for our preferred formats fRet = UtQueryPictFormat(lpDataObj, &m_foretc); if(fRet) BITMAP_TO_DIB(m_foretc); } } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::QueryFormatSupport(%lu)\n", this, fRet)); return fRet; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::SetupAdviseConnection, private // // Synopsis: // Set up data advise sourced by the server object, and sunk // by this cache node, if there is a valid data object. // // Arguments: // none // // Returns: // OLE_E_BLANK, if no presentation object exists or can be // created // DATA_E_FORMATETC // OLE_E_ADVISENOTSUPPORTED // S_OK, indicates successful advise, or no data object // // Notes: // // History: // 11/09/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- HRESULT CCacheNode::SetupAdviseConnection(LPDATAOBJECT pDataObj, IAdviseSink* pAdviseSink) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::SetupAdviseConnection(%p, %p)\n", this, pDataObj, pAdviseSink)); DWORD grfAdvf; HRESULT hresult = NOERROR; if(pDataObj && pAdviseSink) { // Assert that there is no pending advise connection Win4Assert(!m_pDataObject && !m_dwAdvConnId); // If cfFormat is NULL, try setting it if(!m_foretc.cfFormat) { if(QueryFormatSupport(pDataObj)) { // We could update our cfFormat ClearLoadedStateFlag(); } else { // We still could not set the cfFormat hresult = ResultFromScode(OLE_E_BLANK); } } // Check if cfFormat is set and ADVF_NODATA is not set in advise flags if(m_foretc.cfFormat && !(m_advf & ADVF_NODATA)) { // copy and massage the base advise control flags grfAdvf = m_advf; // only the DDE layer looks for these 2 bits grfAdvf |= (ADVFDDE_ONSAVE | ADVFDDE_ONCLOSE); // If we were to get data when it is saved, get it instead when // the object is stopped if(grfAdvf & ADVFCACHE_ONSAVE) { grfAdvf &= (~ADVFCACHE_ONSAVE); grfAdvf |= ADVF_DATAONSTOP; } // These two flags are not meaningful to the cache // REVIEW, why not? grfAdvf &= (~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN)); // If we already have data, then remove the ADVF_PRIMEFIRST if(!IsBlank()) grfAdvf &= (~ADVF_PRIMEFIRST); // Set up the advise with the data object, using massaged flags hresult = pDataObj->DAdvise(&m_foretc, grfAdvf, pAdviseSink, &m_dwAdvConnId); if(hresult!=NOERROR) { // The advise failed. If the requested format was CF_DIB, // try for CF_BITMAP instead. if(m_foretc.cfFormat == CF_DIB) { FORMATETC foretc; // create new format descriptor foretc = m_foretc; foretc.cfFormat = CF_BITMAP; foretc.tymed = TYMED_GDI; // request advise hresult = pDataObj->DAdvise(&foretc, grfAdvf, pAdviseSink, &m_dwAdvConnId); } } // Save the data object for future sanity check if(hresult == NOERROR) m_pDataObject = pDataObj; } } else { Win4Assert(FALSE); hresult = ResultFromScode(E_INVALIDARG); } LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::SetupAdviseConnection(%lx)\n", this, hresult)); return hresult; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::TearDownAdviseConnection, private // // Synopsis: // Remove advise connection from data object to this sink. Returns // immediately if there is no advise connection. // // Arguments: // none // // Returns: // S_OK // // Notes: // // History: // 11/09/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- HRESULT CCacheNode::TearDownAdviseConnection(LPDATAOBJECT pDataObj) { LEDebugOut((DEB_ITRACE, "%p _IN CCacheNode::TearDownAdviseConnection(%p)\n", this, pDataObj)); HRESULT error = NOERROR; // Check if currently there is an advisory connection if(m_dwAdvConnId) { // Check for valid data object if(pDataObj) { // Assert that Advise and Unadvise are on the same dataobject Win4Assert(pDataObj==m_pDataObject); // UnAdvise pDataObj->DUnadvise(m_dwAdvConnId); } // clear the connection ID m_dwAdvConnId = 0; m_pDataObject = NULL; } else Win4Assert(!m_pDataObject); LEDebugOut((DEB_ITRACE, "%p OUT CCacheNode::TearDownAdviseConnection(%lx)\n", this, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::SaveTOCEntry, private // // Synopsis: // Saves the TOC information in the given stream // // Arguments: // pStream [in] - Stream in which to save TOC // // Returns: // NOERROR on success // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- HRESULT CCacheNode::SaveTOCEntry(LPSTREAM pStream, BOOL fSameAsLoad) { LEDebugOut((DEB_ITRACE, "%p _IN SaveTOCEntry(%p)\n", pStream)); HRESULT error; DWORD dwBuf[9]; SIZEL Extent; // Save the clipboard format error = WriteClipformatStm(pStream, m_foretc.cfFormat); if(error == NOERROR) { // Obtain rest of formatetc if(m_foretc.ptd) dwBuf[0] = m_foretc.ptd->tdSize; else dwBuf[0] = 0; dwBuf[1] = m_foretc.dwAspect; dwBuf[2] = m_foretc.lindex; dwBuf[3] = m_foretc.tymed; // Initialize extents dwBuf[4] = 1234567890; dwBuf[5] = 1234567890; // Obtain latest extent if this is a normal cache if(IsNormalCache()) { if(m_pPresObjAfterFreeze && !m_pPresObjAfterFreeze->IsBlank()) { Win4Assert(InFrozenState()); error = m_pPresObjAfterFreeze->GetExtent(m_foretc.dwAspect, &Extent); } else if(m_pPresObj) error = m_pPresObj->GetExtent(m_foretc.dwAspect, &Extent); else { Extent.cx = m_lWidth; Extent.cy = m_lHeight; } // Gen PresObj returns OLE_E_BLANK for cfformats other than DIB and BITMAP if(error == NOERROR) { dwBuf[4] = Extent.cx; dwBuf[5] = Extent.cy; } else if(error == ResultFromScode(OLE_E_BLANK)) { Win4Assert(m_foretc.cfFormat != CF_DIB); Win4Assert(m_foretc.cfFormat != CF_METAFILEPICT); Win4Assert(m_foretc.cfFormat != CF_ENHMETAFILE); dwBuf[4] = 0; dwBuf[5] = 0; } } // Obtain cache node flags, advise flags and presentation bits position dwBuf[6] = m_dwFlags; dwBuf[7] = m_advf; if(fSameAsLoad) dwBuf[8] = m_dwPresBitsPos; else dwBuf[8] = m_dwSavedPresBitsPos; #if DBG==1 if (IsNormalCache()) { Win4Assert(dwBuf[8]); } #endif // Save the obtained state error = pStream->Write(dwBuf, sizeof(dwBuf), NULL); // Finally, save target device if(error==NOERROR && m_foretc.ptd) error = pStream->Write(m_foretc.ptd, m_foretc.ptd->tdSize, NULL); } LEDebugOut((DEB_ITRACE, "%p OUT SaveTOCEntry(%lx)\n", NULL, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::LoadTOCEntry, private // // Synopsis: // Loads the TOC information in the given stream // // Arguments: // pStream [in] - Stream from which to load TOC // iStreamNum [in/out] - Presentation stream number of the cache // // Returns: // NOERROR on success // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- HRESULT CCacheNode::LoadTOCEntry(LPSTREAM pStream, int& iStreamNum) { LEDebugOut((DEB_ITRACE, "%p _IN LoadTOCEntry(%p)\n", pStream)); HRESULT error; DWORD cfFormat, dwBuf[9]; ULONG ulBytesRead; // Load the clipboard format error = ReadClipformatStm(pStream, &cfFormat); if(error == NOERROR) { // Load remaining state error = pStream->Read(dwBuf, sizeof(dwBuf), &ulBytesRead); if(ulBytesRead == sizeof(dwBuf)) { // Load target device if(dwBuf[0]) { m_foretc.ptd = (DVTARGETDEVICE *) PubMemAlloc(dwBuf[0]); if(m_foretc.ptd) { error = pStream->Read(m_foretc.ptd, dwBuf[0], &ulBytesRead); if(ulBytesRead != dwBuf[0]) { PubMemFree(m_foretc.ptd); m_foretc.ptd = NULL; error = ResultFromScode(E_FAIL); } } else error = ResultFromScode(E_OUTOFMEMORY); } else m_foretc.ptd = NULL; // Check if TOC data was read successfully if(error == NOERROR) { // Update cache node data m_foretc.cfFormat = (CLIPFORMAT) cfFormat; m_foretc.dwAspect = dwBuf[1]; m_foretc.lindex = dwBuf[2]; m_foretc.tymed = dwBuf[3]; m_lWidth = dwBuf[4]; m_lHeight = dwBuf[5]; m_dwFlags = dwBuf[6]; m_advf = dwBuf[7]; m_dwPresBitsPos = dwBuf[8]; // Update state on the node SetLoadedStateFlag(); ClearFrozenStateFlag(); if(IsNormalCache()) { SetLoadedCacheFlag(); m_iStreamNum = iStreamNum++; } #if DBG==1 // Sanity Checks if (IsNormalCache()) { Win4Assert(m_lWidth!=1234567890); Win4Assert(m_lHeight!=1234567890); Win4Assert(m_dwPresBitsPos); } #endif } } else error = ResultFromScode(E_FAIL); } LEDebugOut((DEB_ITRACE, "%p OUT LoadTOCEntry(%lx)\n", NULL, error)); return error; } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::operator=, public // // Synopsis: // Assignment operator implementation for cache node // // Arguments: // [rCN] -- CacheNode object that is on the RHS // of assignment statement // // Returns: // CacheNode object that is on the LHS of the assignment // statement so that chaining of assinments is possible // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- const CCacheNode& CCacheNode::operator=(const CCacheNode& rCN) { // Check to see, if this a=a case if(this==&rCN) return(*this); // Self destroy CCacheNode::~CCacheNode(); // Now, make a copy if(!UtCopyFormatEtc((LPFORMATETC) &rCN.m_foretc, &m_foretc)) SetOutOfMemoryFlag(); m_advf = rCN.m_advf; m_lWidth = rCN.m_lWidth; m_lHeight = rCN.m_lHeight; m_dwFlags = rCN.m_dwFlags; m_pStg = rCN.m_pStg; m_iStreamNum = rCN.m_iStreamNum; m_dwPresBitsPos = rCN.m_dwPresBitsPos; m_pPresObj = rCN.m_pPresObj; if(m_pPresObj) m_pPresObj->AddRef(); m_pPresObjAfterFreeze = rCN.m_pPresObjAfterFreeze; if(m_pPresObjAfterFreeze) m_pPresObjAfterFreeze->AddRef(); m_pDataObject = rCN.m_pDataObject; m_dwAdvConnId = rCN.m_dwAdvConnId; #ifdef _DEBUG m_dwPresFlag = rCN.m_dwPresFlag; #endif // _DEBUG return(*this); } //+---------------------------------------------------------------------------- // // Member: // CCacheNode::operator==, public // // Synopsis: // Equality operator implementation for cache node // // Arguments: // [rCN] -- CacheNode object that is on the RHS // of the equality expression // // Returns: // 1 if both the CacheNode objects are equal, 0 otherwise // // History: // Gopalk Creation Sep 04, 96 // //----------------------------------------------------------------------------- /*int CCacheNode::operator==(CCacheNode& rCN) { if(m_foretc.cfFormat == rCN.m_foretc.cfFormat) if(m_foretc.dwAspect == rCN.m_foretc.dwAspect) if(m_foretc.lindex == rCN.m_foretc.lindex) if(UtCompareTargetDevice(m_foretc.ptd, rCN.m_foretc.ptd)) return(1); return(0); } */ //+---------------------------------------------------------------------------- // // Function: // wGetData, internal // // Synopsis: // Fetch the data from the data object in the requested format. // If the fetch fails, and the requested format was CF_DIB, // try CF_BITMAP as an alternative. // // Arguments: // [lpSrcDataObj] -- source data object // [lpforetc] -- desired data format // [lpmedium] -- if successful, the storage medium containing // the requested data // // Returns: // DATA_E_FORMATETC // S_OK // // Notes: // // History: // 11/09/93 - ChrisWe - modified to not alter the requested // format unless the subsequent CF_BITMAP request succeeds. // 11/09/93 - ChrisWe - file inspection and cleanup // //----------------------------------------------------------------------------- HRESULT wGetData(LPDATAOBJECT lpSrcDataObj, LPFORMATETC lpforetc, LPSTGMEDIUM lpmedium) { LEDebugOut((DEB_ITRACE, "%p _IN wGetData(%p, %p, %p)\n", NULL, lpSrcDataObj, lpforetc, lpmedium)); HRESULT hresult; // Get the data in the requested format hresult = lpSrcDataObj->GetData(lpforetc, lpmedium); if(hresult!=NOERROR) { // GetData failed. If the requested format was CF_DIB, // then try CF_BITMAP instead. if(lpforetc->cfFormat == CF_DIB) { FORMATETC foretc; // copy the base format descriptor; try CF_BITMAP foretc = *lpforetc; foretc.cfFormat = CF_BITMAP; foretc.tymed = TYMED_GDI; hresult = lpSrcDataObj->GetData(&foretc, lpmedium); if(hresult == NOERROR) { lpforetc->cfFormat = CF_BITMAP; lpforetc->tymed = TYMED_GDI; } } // GetData failed. If the requested format was CF_ENHMETAFILE, // retry for metafilepict instead. if(lpforetc->cfFormat == CF_ENHMETAFILE) { FORMATETC foretc; foretc = *lpforetc; foretc.cfFormat = CF_METAFILEPICT; foretc.tymed = TYMED_MFPICT; hresult = lpSrcDataObj->GetData(&foretc, lpmedium); if(hresult == NOERROR) { lpforetc->cfFormat = CF_METAFILEPICT; lpforetc->tymed = TYMED_MFPICT; } } } AssertOutStgmedium(hresult, lpmedium); LEDebugOut((DEB_ITRACE, "%p OUT wGetData(%lx)\n", NULL, hresult)); return hresult; }