📄 datacache.c
字号:
cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc);
if (!cache_entry)
hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry);
if (SUCCEEDED(hr))
{
DataCacheEntry_DiscardData(cache_entry);
if (cache_entry->storage) IStorage_Release(cache_entry->storage);
cache_entry->storage = pStg;
IStorage_AddRef(pStg);
cache_entry->dirty = FALSE;
}
}
IStream_Release(pStm);
}
}
CoTaskMemFree(elem.pwcsName);
}
This->dirty = FALSE;
IEnumSTATSTG_Release(pEnum);
IStorage_AddRef(This->presentationStorage);
return S_OK;
}
/************************************************************************
* DataCache_Save (IPersistStorage)
*
* Until we actually connect to a running object and retrieve new
* information to it, we never have to save anything. However, it is
* our responsibility to copy the information when saving to a new
* storage.
*
* See Windows documentation for more details on IPersistStorage methods.
*/
static HRESULT WINAPI DataCache_Save(
IPersistStorage* iface,
IStorage* pStg,
BOOL fSameAsLoad)
{
DataCache *This = impl_from_IPersistStorage(iface);
DataCacheEntry *cache_entry;
BOOL dirty = FALSE;
HRESULT hr = S_OK;
unsigned short stream_number = 0;
TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
dirty = This->dirty;
if (!dirty)
{
LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
{
dirty = cache_entry->dirty;
if (dirty)
break;
}
}
/* this is a shortcut if nothing changed */
if (!dirty && !fSameAsLoad && This->presentationStorage)
{
return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg);
}
/* assign stream numbers to the cache entries */
LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
{
if (cache_entry->stream_number != stream_number)
{
cache_entry->dirty = TRUE; /* needs to be written out again */
cache_entry->stream_number = stream_number;
}
stream_number++;
}
/* write out the cache entries */
LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
{
if (!fSameAsLoad || cache_entry->dirty)
{
hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad);
if (FAILED(hr))
break;
cache_entry->dirty = FALSE;
}
}
This->dirty = FALSE;
return hr;
}
/************************************************************************
* DataCache_SaveCompleted (IPersistStorage)
*
* This method is called to tell the cache to release the storage
* pointer it's currently holding.
*
* See Windows documentation for more details on IPersistStorage methods.
*/
static HRESULT WINAPI DataCache_SaveCompleted(
IPersistStorage* iface,
IStorage* pStgNew)
{
TRACE("(%p, %p)\n", iface, pStgNew);
if (pStgNew)
{
/*
* First, make sure we get our hands off any storage we have.
*/
IPersistStorage_HandsOffStorage(iface);
/*
* Then, attach to the new storage.
*/
DataCache_Load(iface, pStgNew);
}
return S_OK;
}
/************************************************************************
* DataCache_HandsOffStorage (IPersistStorage)
*
* This method is called to tell the cache to release the storage
* pointer it's currently holding.
*
* See Windows documentation for more details on IPersistStorage methods.
*/
static HRESULT WINAPI DataCache_HandsOffStorage(
IPersistStorage* iface)
{
DataCache *this = impl_from_IPersistStorage(iface);
DataCacheEntry *cache_entry;
TRACE("(%p)\n", iface);
if (this->presentationStorage != NULL)
{
IStorage_Release(this->presentationStorage);
this->presentationStorage = NULL;
}
LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry)
DataCacheEntry_HandsOffStorage(cache_entry);
return S_OK;
}
/*********************************************************
* Method implementation for the IViewObject2
* part of the DataCache class.
*/
/************************************************************************
* DataCache_IViewObject2_QueryInterface (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
IViewObject2* iface,
REFIID riid,
void** ppvObject)
{
DataCache *this = impl_from_IViewObject2(iface);
return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject);
}
/************************************************************************
* DataCache_IViewObject2_AddRef (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
static ULONG WINAPI DataCache_IViewObject2_AddRef(
IViewObject2* iface)
{
DataCache *this = impl_from_IViewObject2(iface);
return IUnknown_AddRef(this->outerUnknown);
}
/************************************************************************
* DataCache_IViewObject2_Release (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*/
static ULONG WINAPI DataCache_IViewObject2_Release(
IViewObject2* iface)
{
DataCache *this = impl_from_IViewObject2(iface);
return IUnknown_Release(this->outerUnknown);
}
/************************************************************************
* DataCache_Draw (IViewObject2)
*
* This method will draw the cached representation of the object
* to the given device context.
*
* See Windows documentation for more details on IViewObject2 methods.
*/
static HRESULT WINAPI DataCache_Draw(
IViewObject2* iface,
DWORD dwDrawAspect,
LONG lindex,
void* pvAspect,
DVTARGETDEVICE* ptd,
HDC hdcTargetDev,
HDC hdcDraw,
LPCRECTL lprcBounds,
LPCRECTL lprcWBounds,
BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue),
ULONG_PTR dwContinue)
{
DataCache *This = impl_from_IViewObject2(iface);
HRESULT hres;
DataCacheEntry *cache_entry;
TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
iface,
dwDrawAspect,
lindex,
pvAspect,
hdcTargetDev,
hdcDraw,
lprcBounds,
lprcWBounds,
pfnContinue,
dwContinue);
/*
* Sanity check
*/
if (lprcBounds==NULL)
return E_INVALIDARG;
LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry)
{
/* FIXME: compare ptd too */
if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) ||
(cache_entry->fmtetc.lindex != lindex))
continue;
/* if the data hasn't been loaded yet, do it now */
if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage)
{
hres = DataCacheEntry_LoadData(cache_entry);
if (FAILED(hres))
continue;
}
/* no data */
if (cache_entry->stgmedium.tymed == TYMED_NULL)
continue;
switch (cache_entry->data_cf)
{
case CF_METAFILEPICT:
{
/*
* We have to be careful not to modify the state of the
* DC.
*/
INT prevMapMode;
SIZE oldWindowExt;
SIZE oldViewportExt;
POINT oldViewportOrg;
METAFILEPICT *mfpict;
if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) ||
!((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict))))
continue;
prevMapMode = SetMapMode(hdcDraw, mfpict->mm);
SetWindowExtEx(hdcDraw,
mfpict->xExt,
mfpict->yExt,
&oldWindowExt);
SetViewportExtEx(hdcDraw,
lprcBounds->right - lprcBounds->left,
lprcBounds->bottom - lprcBounds->top,
&oldViewportExt);
SetViewportOrgEx(hdcDraw,
lprcBounds->left,
lprcBounds->top,
&oldViewportOrg);
PlayMetaFile(hdcDraw, mfpict->hMF);
SetWindowExtEx(hdcDraw,
oldWindowExt.cx,
oldWindowExt.cy,
NULL);
SetViewportExtEx(hdcDraw,
oldViewportExt.cx,
oldViewportExt.cy,
NULL);
SetViewportOrgEx(hdcDraw,
oldViewportOrg.x,
oldViewportOrg.y,
NULL);
SetMapMode(hdcDraw, prevMapMode);
GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict);
return S_OK;
}
}
}
WARN("no data could be found to be drawn\n");
return OLE_E_BLANK;
}
static HRESULT WINAPI DataCache_GetColorSet(
IViewObject2* iface,
DWORD dwDrawAspect,
LONG lindex,
void* pvAspect,
DVTARGETDEVICE* ptd,
HDC hicTargetDevice,
LOGPALETTE** ppColorSet)
{
FIXME("stub\n");
return E_NOTIMPL;
}
static HRESULT WINAPI DataCache_Freeze(
IViewObject2* iface,
DWORD dwDrawAspect,
LONG lindex,
void* pvAspect,
DWORD* pdwFreeze)
{
FIXME("stub\n");
return E_NOTIMPL;
}
static HRESULT WINAPI DataCache_Unfreeze(
IViewObject2* iface,
DWORD dwFreeze)
{
FIXME("stub\n");
return E_NOTIMPL;
}
/************************************************************************
* DataCache_SetAdvise (IViewObject2)
*
* This sets-up an advisory sink with the data cache. When the object's
* view changes, this sink is called.
*
* See Windows documentation for more details on IViewObject2 methods.
*/
static HRESULT WINAPI DataCache_SetAdvise(
IViewObject2* iface,
DWORD aspects,
DWORD advf,
IAdviseSink* pAdvSink)
{
DataCache *this = impl_from_IViewObject2(iface);
TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink);
/*
* A call to this function removes the previous sink
*/
if (this->sinkInterface != NULL)
{
IAdviseSink_Release(this->sinkInterface);
this->sinkInterface = NULL;
this->sinkAspects = 0;
this->sinkAdviseFlag = 0;
}
/*
* Now, setup the new one.
*/
if (pAdvSink!=NULL)
{
this->sinkInterface = pAdvSink;
this->sinkAspects = aspects;
this->sinkAdviseFlag = advf;
IAdviseSink_AddRef(this->sinkInterface);
}
/*
* When the ADVF_PRIMEFIRST flag is set, we have to advise the
* sink immediately.
*/
if (advf & ADVF_PRIMEFIRST)
{
DataCache_FireOnViewChange(this, aspects, -1);
}
return S_OK;
}
/************************************************************************
* DataCache_GetAdvise (IViewObject2)
*
* This method queries the current state of the advise sink
* installed on the data cache.
*
* See Windows documentation for more details on IViewObject2 methods.
*/
static HRESULT WINAPI DataCache_GetAdvise(
IViewObject2* iface,
DWORD* pAspects,
DWORD* pAdvf,
IAdviseSink** ppAdvSink)
{
DataCache *this = impl_from_IViewObject2(iface);
TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
/*
* Just copy all the requested values.
*/
if (pAspects!=NULL)
*pAspects = this->sinkAspects;
if (pAdvf!=NULL)
*pAdvf = this->sinkAdviseFlag;
if (ppAdvSink!=NULL)
{
if (this->sinkInterface != NULL)
IAdviseSink_QueryInterface(this->sinkInterface,
&IID_IAdviseSink,
(void**)ppAdvSink);
else *ppAdvSink = NULL;
}
return S_OK;
}
/************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -