📄 datacache.c
字号:
* If a fallback is desired, just opening the first presentation stream
* is a possibility.
*/
static HRESULT DataCacheEntry_OpenPresStream(
DataCacheEntry *This,
IStream **ppStm)
{
STATSTG elem;
IEnumSTATSTG *pEnum;
HRESULT hr;
if (!ppStm) return E_POINTER;
hr = IStorage_EnumElements(This->storage, 0, NULL, 0, &pEnum);
if (FAILED(hr)) return hr;
while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK)
{
if (DataCache_IsPresentationStream(&elem))
{
IStream *pStm;
hr = IStorage_OpenStream(This->storage, elem.pwcsName,
NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0,
&pStm);
if (SUCCEEDED(hr))
{
PresentationDataHeader header;
ULONG actual_read;
CLIPFORMAT clipformat;
hr = read_clipformat(pStm, &clipformat);
if (hr == S_OK)
hr = IStream_Read(pStm, &header, sizeof(header), &actual_read);
/* can't use SUCCEEDED(hr): S_FALSE counts as an error */
if (hr == S_OK && actual_read == sizeof(header)
&& header.dvAspect == This->fmtetc.dwAspect)
{
/* Rewind the stream before returning it. */
LARGE_INTEGER offset;
offset.u.LowPart = 0;
offset.u.HighPart = 0;
IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL);
*ppStm = pStm;
CoTaskMemFree(elem.pwcsName);
IEnumSTATSTG_Release(pEnum);
return S_OK;
}
IStream_Release(pStm);
}
}
CoTaskMemFree(elem.pwcsName);
}
IEnumSTATSTG_Release(pEnum);
return (hr == S_FALSE ? OLE_E_BLANK : hr);
}
/************************************************************************
* DataCacheEntry_LoadData
*
* This method will read information for the requested presentation
* into the given structure.
*
* Param:
* This - The entry to load the data from.
*
* Returns:
* This method returns a metafile handle if it is successful.
* it will return 0 if not.
*/
static HRESULT DataCacheEntry_LoadData(DataCacheEntry *This)
{
IStream* presStream = NULL;
HRESULT hres;
ULARGE_INTEGER current_pos;
STATSTG streamInfo;
void* metafileBits;
METAFILEPICT *mfpict;
HGLOBAL hmfpict;
PresentationDataHeader header;
CLIPFORMAT clipformat;
static const LARGE_INTEGER offset_zero;
/*
* Open the presentation stream.
*/
hres = DataCacheEntry_OpenPresStream(
This,
&presStream);
if (FAILED(hres))
return hres;
/*
* Get the size of the stream.
*/
hres = IStream_Stat(presStream,
&streamInfo,
STATFLAG_NONAME);
/*
* Read the header.
*/
hres = read_clipformat(presStream, &clipformat);
if (FAILED(hres))
{
IStream_Release(presStream);
return hres;
}
hres = IStream_Read(
presStream,
&header,
sizeof(PresentationDataHeader),
NULL);
if (hres != S_OK)
{
IStream_Release(presStream);
return E_FAIL;
}
hres = IStream_Seek(presStream, offset_zero, STREAM_SEEK_CUR, ¤t_pos);
streamInfo.cbSize.QuadPart -= current_pos.QuadPart;
hmfpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
if (!hmfpict)
{
IStream_Release(presStream);
return E_OUTOFMEMORY;
}
mfpict = GlobalLock(hmfpict);
/*
* Allocate a buffer for the metafile bits.
*/
metafileBits = HeapAlloc(GetProcessHeap(),
0,
streamInfo.cbSize.u.LowPart);
/*
* Read the metafile bits.
*/
hres = IStream_Read(
presStream,
metafileBits,
streamInfo.cbSize.u.LowPart,
NULL);
/*
* Create a metafile with those bits.
*/
if (SUCCEEDED(hres))
{
/* FIXME: get this from the stream */
mfpict->mm = MM_ANISOTROPIC;
mfpict->xExt = header.dwObjectExtentX;
mfpict->yExt = header.dwObjectExtentY;
mfpict->hMF = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits);
if (!mfpict->hMF)
hres = E_FAIL;
}
GlobalUnlock(hmfpict);
if (SUCCEEDED(hres))
{
This->data_cf = This->fmtetc.cfFormat;
This->stgmedium.tymed = TYMED_MFPICT;
This->stgmedium.u.hMetaFilePict = hmfpict;
}
else
GlobalFree(hmfpict);
/*
* Cleanup.
*/
HeapFree(GetProcessHeap(), 0, metafileBits);
IStream_Release(presStream);
return hres;
}
static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *This,
IStorage *storage, IStream **stream)
{
HRESULT hr;
WCHAR wszName[] = {2,'O','l','e','P','r','e','s',
'0' + (This->stream_number / 100) % 10,
'0' + (This->stream_number / 10) % 10,
'0' + This->stream_number % 10, 0};
/* FIXME: cache the created stream in This? */
hr = IStorage_CreateStream(storage, wszName,
STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
0, 0, stream);
return hr;
}
static HRESULT DataCacheEntry_Save(DataCacheEntry *This, IStorage *storage,
BOOL same_as_load)
{
PresentationDataHeader header;
HRESULT hr;
IStream *pres_stream;
void *data = NULL;
TRACE("stream_number = %d, fmtetc = %s\n", This->stream_number, debugstr_formatetc(&This->fmtetc));
hr = DataCacheEntry_CreateStream(This, storage, &pres_stream);
if (FAILED(hr))
return hr;
hr = write_clipformat(pres_stream, This->data_cf);
if (FAILED(hr))
return hr;
if (This->fmtetc.ptd)
FIXME("ptd not serialized\n");
header.unknown3 = 4;
header.dvAspect = This->fmtetc.dwAspect;
header.lindex = This->fmtetc.lindex;
header.tymed = This->stgmedium.tymed;
header.unknown7 = 0;
header.dwObjectExtentX = 0;
header.dwObjectExtentY = 0;
header.dwSize = 0;
/* size the data */
switch (This->data_cf)
{
case CF_METAFILEPICT:
{
if (This->stgmedium.tymed != TYMED_NULL)
{
const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict);
if (!mfpict)
{
IStream_Release(pres_stream);
return DV_E_STGMEDIUM;
}
header.dwObjectExtentX = mfpict->xExt;
header.dwObjectExtentY = mfpict->yExt;
header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL);
GlobalUnlock(This->stgmedium.u.hMetaFilePict);
}
break;
}
default:
break;
}
/*
* Write the header.
*/
hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader),
NULL);
if (FAILED(hr))
{
IStream_Release(pres_stream);
return hr;
}
/* get the data */
switch (This->data_cf)
{
case CF_METAFILEPICT:
{
if (This->stgmedium.tymed != TYMED_NULL)
{
const METAFILEPICT *mfpict = GlobalLock(This->stgmedium.u.hMetaFilePict);
if (!mfpict)
{
IStream_Release(pres_stream);
return DV_E_STGMEDIUM;
}
data = HeapAlloc(GetProcessHeap(), 0, header.dwSize);
GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data);
GlobalUnlock(This->stgmedium.u.hMetaFilePict);
}
break;
}
default:
break;
}
if (data)
hr = IStream_Write(pres_stream, data, header.dwSize, NULL);
IStream_Release(pres_stream);
return hr;
}
/* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
* does no checking of whether src_stgm has a supported tymed, so this should be
* done in the caller */
static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm,
const STGMEDIUM *src_stgm)
{
if (src_stgm->tymed == TYMED_MFPICT)
{
const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict);
METAFILEPICT *dest_mfpict;
if (!src_mfpict)
return DV_E_STGMEDIUM;
dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict);
if (!dest_mfpict)
{
GlobalUnlock(src_stgm->u.hMetaFilePict);
return E_OUTOFMEMORY;
}
*dest_mfpict = *src_mfpict;
dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL);
GlobalUnlock(src_stgm->u.hMetaFilePict);
GlobalUnlock(dest_stgm->u.hMetaFilePict);
}
else if (src_stgm->tymed != TYMED_NULL)
{
dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf,
GMEM_MOVEABLE);
if (!dest_stgm->u.hGlobal)
return E_OUTOFMEMORY;
}
dest_stgm->tymed = src_stgm->tymed;
dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease;
if (dest_stgm->pUnkForRelease)
IUnknown_AddRef(dest_stgm->pUnkForRelease);
return S_OK;
}
static HRESULT DataCacheEntry_SetData(DataCacheEntry *This,
const FORMATETC *formatetc,
const STGMEDIUM *stgmedium,
BOOL fRelease)
{
if ((!This->fmtetc.cfFormat && !formatetc->cfFormat) ||
(This->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) ||
stgmedium->tymed == TYMED_NULL)
{
WARN("invalid formatetc\n");
return DV_E_FORMATETC;
}
This->dirty = TRUE;
ReleaseStgMedium(&This->stgmedium);
This->data_cf = This->fmtetc.cfFormat ? This->fmtetc.cfFormat : formatetc->cfFormat;
if (fRelease)
{
This->stgmedium = *stgmedium;
return S_OK;
}
else
return copy_stg_medium(This->data_cf,
&This->stgmedium, stgmedium);
}
static HRESULT DataCacheEntry_GetData(DataCacheEntry *This,
STGMEDIUM *stgmedium)
{
if (stgmedium->tymed == TYMED_NULL && This->storage)
{
HRESULT hr = DataCacheEntry_LoadData(This);
if (FAILED(hr))
return hr;
}
if (stgmedium->tymed == TYMED_NULL)
return OLE_E_BLANK;
return copy_stg_medium(This->data_cf, stgmedium, &This->stgmedium);
}
static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *This)
{
ReleaseStgMedium(&This->stgmedium);
This->data_cf = This->fmtetc.cfFormat;
return S_OK;
}
static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *This)
{
if (This->storage)
{
IStorage_Release(This->storage);
This->storage = NULL;
}
}
/*********************************************************
* Method implementation for the non delegating IUnknown
* part of the DataCache class.
*/
/************************************************************************
* DataCache_NDIUnknown_QueryInterface (IUnknown)
*
* See Windows documentation for more details on IUnknown methods.
*
* This version of QueryInterface will not delegate it's implementation
* to the outer unknown.
*/
static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
IUnknown* iface,
REFIID riid,
void** ppvObject)
{
DataCache *this = impl_from_NDIUnknown(iface);
/*
* Perform a sanity check on the parameters.
*/
if ( (this==0) || (ppvObject==0) )
return E_INVALIDARG;
/*
* Initialize the return parameter.
*/
*ppvObject = 0;
/*
* Compare the riid with the interface IDs implemented by this object.
*/
if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
{
*ppvObject = iface;
}
else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0)
{
*ppvObject = (IDataObject*)&(this->lpVtbl);
}
else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0) ||
(memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) )
{
*ppvObject = (IPersistStorage*)&(this->lpvtblIPersistStorage);
}
else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) ||
(memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) )
{
*ppvObject = (IViewObject2*)&(this->lpvtblIViewObject);
}
else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) ||
(memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) )
{
*ppvObject = (IOleCache2*)&(this->lpvtblIOleCache2);
}
else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -