Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendatacache.c
Go to the documentation of this file.
00001 /* 00002 * OLE 2 Data cache 00003 * 00004 * Copyright 1999 Francis Beaudet 00005 * Copyright 2000 Abey George 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 * 00021 * NOTES: 00022 * The OLE2 data cache supports a whole whack of 00023 * interfaces including: 00024 * IDataObject, IPersistStorage, IViewObject2, 00025 * IOleCache2 and IOleCacheControl. 00026 * 00027 * Most of the implementation details are taken from: Inside OLE 00028 * second edition by Kraig Brockschmidt, 00029 * 00030 * NOTES 00031 * - This implementation of the datacache will let your application 00032 * load documents that have embedded OLE objects in them and it will 00033 * also retrieve the metafile representation of those objects. 00034 * - This implementation of the datacache will also allow your 00035 * application to save new documents with OLE objects in them. 00036 * - The main thing that it doesn't do is allow you to activate 00037 * or modify the OLE objects in any way. 00038 * - I haven't found any good documentation on the real usage of 00039 * the streams created by the data cache. In particular, How to 00040 * determine what the XXX stands for in the stream name 00041 * "\002OlePresXXX". It appears to just be a counter. 00042 * - Also, I don't know the real content of the presentation stream 00043 * header. I was able to figure-out where the extent of the object 00044 * was stored and the aspect, but that's about it. 00045 */ 00046 #include <stdarg.h> 00047 #include <string.h> 00048 00049 #define COBJMACROS 00050 #define NONAMELESSUNION 00051 #define NONAMELESSSTRUCT 00052 00053 #include "windef.h" 00054 #include "winbase.h" 00055 #include "wingdi.h" 00056 #include "winuser.h" 00057 #include "winerror.h" 00058 #include "wine/unicode.h" 00059 #include "ole2.h" 00060 #include "wine/list.h" 00061 #include "wine/debug.h" 00062 00063 WINE_DEFAULT_DEBUG_CHANNEL(ole); 00064 00065 /**************************************************************************** 00066 * PresentationDataHeader 00067 * 00068 * This structure represents the header of the \002OlePresXXX stream in 00069 * the OLE object storage. 00070 */ 00071 typedef struct PresentationDataHeader 00072 { 00073 /* clipformat: 00074 * - standard clipformat: 00075 * DWORD length = 0xffffffff; 00076 * DWORD cfFormat; 00077 * - or custom clipformat: 00078 * DWORD length; 00079 * CHAR format_name[length]; (null-terminated) 00080 */ 00081 DWORD unknown3; /* 4, possibly TYMED_ISTREAM */ 00082 DVASPECT dvAspect; 00083 DWORD lindex; 00084 DWORD tymed; 00085 DWORD unknown7; /* 0 */ 00086 DWORD dwObjectExtentX; 00087 DWORD dwObjectExtentY; 00088 DWORD dwSize; 00089 } PresentationDataHeader; 00090 00091 typedef struct DataCacheEntry 00092 { 00093 struct list entry; 00094 /* format of this entry */ 00095 FORMATETC fmtetc; 00096 /* the clipboard format of the data */ 00097 CLIPFORMAT data_cf; 00098 /* cached data */ 00099 STGMEDIUM stgmedium; 00100 /* 00101 * This storage pointer is set through a call to 00102 * IPersistStorage_Load. This is where the visual 00103 * representation of the object is stored. 00104 */ 00105 IStorage *storage; 00106 /* connection ID */ 00107 DWORD id; 00108 /* dirty flag */ 00109 BOOL dirty; 00110 /* stream number (-1 if not set ) */ 00111 unsigned short stream_number; 00112 /* sink id set when object is running */ 00113 DWORD sink_id; 00114 /* Advise sink flags */ 00115 DWORD advise_flags; 00116 } DataCacheEntry; 00117 00118 /**************************************************************************** 00119 * DataCache 00120 */ 00121 struct DataCache 00122 { 00123 /* 00124 * List all interface here 00125 */ 00126 IDataObject IDataObject_iface; 00127 IUnknown IUnknown_iface; 00128 IPersistStorage IPersistStorage_iface; 00129 IViewObject2 IViewObject2_iface; 00130 IOleCache2 IOleCache2_iface; 00131 IOleCacheControl IOleCacheControl_iface; 00132 00133 /* The sink that is connected to a remote object. 00134 The other interfaces are not available by QI'ing the sink and vice-versa */ 00135 IAdviseSink IAdviseSink_iface; 00136 00137 /* 00138 * Reference count of this object 00139 */ 00140 LONG ref; 00141 00142 /* 00143 * IUnknown implementation of the outer object. 00144 */ 00145 IUnknown* outerUnknown; 00146 00147 /* 00148 * The user of this object can setup ONE advise sink 00149 * connection with the object. These parameters describe 00150 * that connection. 00151 */ 00152 DWORD sinkAspects; 00153 DWORD sinkAdviseFlag; 00154 IAdviseSink* sinkInterface; 00155 IStorage *presentationStorage; 00156 00157 /* list of cache entries */ 00158 struct list cache_list; 00159 /* last id assigned to an entry */ 00160 DWORD last_cache_id; 00161 /* dirty flag */ 00162 BOOL dirty; 00163 /* running object set by OnRun */ 00164 IDataObject *running_object; 00165 }; 00166 00167 typedef struct DataCache DataCache; 00168 00169 /* 00170 * Here, I define utility macros to help with the casting of the 00171 * "this" parameter. 00172 * There is a version to accommodate all of the VTables implemented 00173 * by this object. 00174 */ 00175 00176 static inline DataCache *impl_from_IDataObject( IDataObject *iface ) 00177 { 00178 return CONTAINING_RECORD(iface, DataCache, IDataObject_iface); 00179 } 00180 00181 static inline DataCache *impl_from_IUnknown( IUnknown *iface ) 00182 { 00183 return CONTAINING_RECORD(iface, DataCache, IUnknown_iface); 00184 } 00185 00186 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface ) 00187 { 00188 return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface); 00189 } 00190 00191 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface ) 00192 { 00193 return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface); 00194 } 00195 00196 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface ) 00197 { 00198 return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface); 00199 } 00200 00201 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface ) 00202 { 00203 return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface); 00204 } 00205 00206 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface ) 00207 { 00208 return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface); 00209 } 00210 00211 static const char * debugstr_formatetc(const FORMATETC *formatetc) 00212 { 00213 return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }", 00214 formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect, 00215 formatetc->lindex, formatetc->tymed); 00216 } 00217 00218 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry) 00219 { 00220 list_remove(&cache_entry->entry); 00221 if (cache_entry->storage) 00222 IStorage_Release(cache_entry->storage); 00223 HeapFree(GetProcessHeap(), 0, cache_entry->fmtetc.ptd); 00224 ReleaseStgMedium(&cache_entry->stgmedium); 00225 if(cache_entry->sink_id) 00226 IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id); 00227 00228 HeapFree(GetProcessHeap(), 0, cache_entry); 00229 } 00230 00231 static void DataCache_Destroy( 00232 DataCache* ptrToDestroy) 00233 { 00234 DataCacheEntry *cache_entry, *next_cache_entry; 00235 00236 TRACE("()\n"); 00237 00238 if (ptrToDestroy->sinkInterface != NULL) 00239 { 00240 IAdviseSink_Release(ptrToDestroy->sinkInterface); 00241 ptrToDestroy->sinkInterface = NULL; 00242 } 00243 00244 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry) 00245 DataCacheEntry_Destroy(ptrToDestroy, cache_entry); 00246 00247 if (ptrToDestroy->presentationStorage != NULL) 00248 { 00249 IStorage_Release(ptrToDestroy->presentationStorage); 00250 ptrToDestroy->presentationStorage = NULL; 00251 } 00252 00253 /* 00254 * Free the datacache pointer. 00255 */ 00256 HeapFree(GetProcessHeap(), 0, ptrToDestroy); 00257 } 00258 00259 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc) 00260 { 00261 DataCacheEntry *cache_entry; 00262 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 00263 { 00264 /* FIXME: also compare DVTARGETDEVICEs */ 00265 if ((!cache_entry->fmtetc.cfFormat || !formatetc->cfFormat || (formatetc->cfFormat == cache_entry->fmtetc.cfFormat)) && 00266 (formatetc->dwAspect == cache_entry->fmtetc.dwAspect) && 00267 (formatetc->lindex == cache_entry->fmtetc.lindex) && 00268 (!cache_entry->fmtetc.tymed || !formatetc->tymed || (formatetc->tymed == cache_entry->fmtetc.tymed))) 00269 return cache_entry; 00270 } 00271 return NULL; 00272 } 00273 00274 /* checks that the clipformat and tymed are valid and returns an error if they 00275 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by 00276 * DataCache_Draw */ 00277 static HRESULT check_valid_clipformat_and_tymed(CLIPFORMAT cfFormat, DWORD tymed) 00278 { 00279 if (!cfFormat || !tymed || 00280 (cfFormat == CF_METAFILEPICT && tymed == TYMED_MFPICT) || 00281 (cfFormat == CF_BITMAP && tymed == TYMED_GDI) || 00282 (cfFormat == CF_DIB && tymed == TYMED_HGLOBAL) || 00283 (cfFormat == CF_ENHMETAFILE && tymed == TYMED_ENHMF)) 00284 return S_OK; 00285 else if (tymed == TYMED_HGLOBAL) 00286 return CACHE_S_FORMATETC_NOTSUPPORTED; 00287 else 00288 { 00289 WARN("invalid clipformat/tymed combination: %d/%d\n", cfFormat, tymed); 00290 return DV_E_TYMED; 00291 } 00292 } 00293 00294 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DataCacheEntry **cache_entry) 00295 { 00296 HRESULT hr; 00297 00298 hr = check_valid_clipformat_and_tymed(formatetc->cfFormat, formatetc->tymed); 00299 if (FAILED(hr)) 00300 return hr; 00301 if (hr == CACHE_S_FORMATETC_NOTSUPPORTED) 00302 TRACE("creating unsupported format %d\n", formatetc->cfFormat); 00303 00304 *cache_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(**cache_entry)); 00305 if (!*cache_entry) 00306 return E_OUTOFMEMORY; 00307 00308 (*cache_entry)->fmtetc = *formatetc; 00309 if (formatetc->ptd) 00310 { 00311 (*cache_entry)->fmtetc.ptd = HeapAlloc(GetProcessHeap(), 0, formatetc->ptd->tdSize); 00312 memcpy((*cache_entry)->fmtetc.ptd, formatetc->ptd, formatetc->ptd->tdSize); 00313 } 00314 (*cache_entry)->data_cf = 0; 00315 (*cache_entry)->stgmedium.tymed = TYMED_NULL; 00316 (*cache_entry)->stgmedium.pUnkForRelease = NULL; 00317 (*cache_entry)->storage = NULL; 00318 (*cache_entry)->id = This->last_cache_id++; 00319 (*cache_entry)->dirty = TRUE; 00320 (*cache_entry)->stream_number = -1; 00321 (*cache_entry)->sink_id = 0; 00322 (*cache_entry)->advise_flags = 0; 00323 list_add_tail(&This->cache_list, &(*cache_entry)->entry); 00324 return hr; 00325 } 00326 00327 /************************************************************************ 00328 * DataCache_FireOnViewChange 00329 * 00330 * This method will fire an OnViewChange notification to the advise 00331 * sink registered with the datacache. 00332 * 00333 * See IAdviseSink::OnViewChange for more details. 00334 */ 00335 static void DataCache_FireOnViewChange( 00336 DataCache* this, 00337 DWORD aspect, 00338 LONG lindex) 00339 { 00340 TRACE("(%p, %x, %d)\n", this, aspect, lindex); 00341 00342 /* 00343 * The sink supplies a filter when it registers 00344 * we make sure we only send the notifications when that 00345 * filter matches. 00346 */ 00347 if ((this->sinkAspects & aspect) != 0) 00348 { 00349 if (this->sinkInterface != NULL) 00350 { 00351 IAdviseSink_OnViewChange(this->sinkInterface, 00352 aspect, 00353 lindex); 00354 00355 /* 00356 * Some sinks want to be unregistered automatically when 00357 * the first notification goes out. 00358 */ 00359 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0) 00360 { 00361 IAdviseSink_Release(this->sinkInterface); 00362 00363 this->sinkInterface = NULL; 00364 this->sinkAspects = 0; 00365 this->sinkAdviseFlag = 0; 00366 } 00367 } 00368 } 00369 } 00370 00371 /* Helper for DataCacheEntry_OpenPresStream */ 00372 static BOOL DataCache_IsPresentationStream(const STATSTG *elem) 00373 { 00374 /* The presentation streams have names of the form "\002OlePresXXX", 00375 * where XXX goes from 000 to 999. */ 00376 static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' }; 00377 00378 LPCWSTR name = elem->pwcsName; 00379 00380 return (elem->type == STGTY_STREAM) 00381 && (strlenW(name) == 11) 00382 && (strncmpW(name, OlePres, 8) == 0) 00383 && (name[8] >= '0') && (name[8] <= '9') 00384 && (name[9] >= '0') && (name[9] <= '9') 00385 && (name[10] >= '0') && (name[10] <= '9'); 00386 } 00387 00388 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat) 00389 { 00390 DWORD length; 00391 HRESULT hr; 00392 ULONG read; 00393 00394 *clipformat = 0; 00395 00396 hr = IStream_Read(stream, &length, sizeof(length), &read); 00397 if (hr != S_OK || read != sizeof(length)) 00398 return DV_E_CLIPFORMAT; 00399 if (length == -1) 00400 { 00401 DWORD cf; 00402 hr = IStream_Read(stream, &cf, sizeof(cf), 0); 00403 if (hr != S_OK || read != sizeof(cf)) 00404 return DV_E_CLIPFORMAT; 00405 *clipformat = cf; 00406 } 00407 else 00408 { 00409 char *format_name = HeapAlloc(GetProcessHeap(), 0, length); 00410 if (!format_name) 00411 return E_OUTOFMEMORY; 00412 hr = IStream_Read(stream, format_name, length, &read); 00413 if (hr != S_OK || read != length || format_name[length - 1] != '\0') 00414 { 00415 HeapFree(GetProcessHeap(), 0, format_name); 00416 return DV_E_CLIPFORMAT; 00417 } 00418 *clipformat = RegisterClipboardFormatA(format_name); 00419 HeapFree(GetProcessHeap(), 0, format_name); 00420 } 00421 return S_OK; 00422 } 00423 00424 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat) 00425 { 00426 DWORD length; 00427 HRESULT hr; 00428 00429 if (clipformat < 0xc000) 00430 length = -1; 00431 else 00432 length = GetClipboardFormatNameA(clipformat, NULL, 0); 00433 hr = IStream_Write(stream, &length, sizeof(length), NULL); 00434 if (FAILED(hr)) 00435 return hr; 00436 if (clipformat < 0xc000) 00437 { 00438 DWORD cf = clipformat; 00439 hr = IStream_Write(stream, &cf, sizeof(cf), NULL); 00440 } 00441 else 00442 { 00443 char *format_name = HeapAlloc(GetProcessHeap(), 0, length); 00444 if (!format_name) 00445 return E_OUTOFMEMORY; 00446 GetClipboardFormatNameA(clipformat, format_name, length); 00447 hr = IStream_Write(stream, format_name, length, NULL); 00448 HeapFree(GetProcessHeap(), 0, format_name); 00449 } 00450 return hr; 00451 } 00452 00453 /************************************************************************ 00454 * DataCacheEntry_OpenPresStream 00455 * 00456 * This method will find the stream for the given presentation. It makes 00457 * no attempt at fallback. 00458 * 00459 * Param: 00460 * this - Pointer to the DataCache object 00461 * drawAspect - The aspect of the object that we wish to draw. 00462 * pStm - A returned stream. It points to the beginning of the 00463 * - presentation data, including the header. 00464 * 00465 * Errors: 00466 * S_OK The requested stream has been opened. 00467 * OLE_E_BLANK The requested stream could not be found. 00468 * Quite a few others I'm too lazy to map correctly. 00469 * 00470 * Notes: 00471 * Algorithm: Scan the elements of the presentation storage, looking 00472 * for presentation streams. For each presentation stream, 00473 * load the header and check to see if the aspect matches. 00474 * 00475 * If a fallback is desired, just opening the first presentation stream 00476 * is a possibility. 00477 */ 00478 static HRESULT DataCacheEntry_OpenPresStream(DataCacheEntry *cache_entry, IStream **ppStm) 00479 { 00480 STATSTG elem; 00481 IEnumSTATSTG *pEnum; 00482 HRESULT hr; 00483 00484 if (!ppStm) return E_POINTER; 00485 00486 hr = IStorage_EnumElements(cache_entry->storage, 0, NULL, 0, &pEnum); 00487 if (FAILED(hr)) return hr; 00488 00489 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK) 00490 { 00491 if (DataCache_IsPresentationStream(&elem)) 00492 { 00493 IStream *pStm; 00494 00495 hr = IStorage_OpenStream(cache_entry->storage, elem.pwcsName, 00496 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, 00497 &pStm); 00498 if (SUCCEEDED(hr)) 00499 { 00500 PresentationDataHeader header; 00501 ULONG actual_read; 00502 CLIPFORMAT clipformat; 00503 00504 hr = read_clipformat(pStm, &clipformat); 00505 00506 if (hr == S_OK) 00507 hr = IStream_Read(pStm, &header, sizeof(header), &actual_read); 00508 00509 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */ 00510 if (hr == S_OK && actual_read == sizeof(header) 00511 && header.dvAspect == cache_entry->fmtetc.dwAspect) 00512 { 00513 /* Rewind the stream before returning it. */ 00514 LARGE_INTEGER offset; 00515 offset.u.LowPart = 0; 00516 offset.u.HighPart = 0; 00517 IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL); 00518 00519 *ppStm = pStm; 00520 00521 CoTaskMemFree(elem.pwcsName); 00522 IEnumSTATSTG_Release(pEnum); 00523 00524 return S_OK; 00525 } 00526 00527 IStream_Release(pStm); 00528 } 00529 } 00530 00531 CoTaskMemFree(elem.pwcsName); 00532 } 00533 00534 IEnumSTATSTG_Release(pEnum); 00535 00536 return (hr == S_FALSE ? OLE_E_BLANK : hr); 00537 } 00538 00539 /************************************************************************ 00540 * DataCacheEntry_LoadData 00541 * 00542 * This method will read information for the requested presentation 00543 * into the given structure. 00544 * 00545 * Param: 00546 * This - The entry to load the data from. 00547 * 00548 * Returns: 00549 * This method returns a metafile handle if it is successful. 00550 * it will return 0 if not. 00551 */ 00552 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry) 00553 { 00554 IStream* presStream = NULL; 00555 HRESULT hres; 00556 ULARGE_INTEGER current_pos; 00557 STATSTG streamInfo; 00558 void* metafileBits; 00559 METAFILEPICT *mfpict; 00560 HGLOBAL hmfpict; 00561 PresentationDataHeader header; 00562 CLIPFORMAT clipformat; 00563 static const LARGE_INTEGER offset_zero; 00564 00565 /* 00566 * Open the presentation stream. 00567 */ 00568 hres = DataCacheEntry_OpenPresStream(cache_entry, &presStream); 00569 00570 if (FAILED(hres)) 00571 return hres; 00572 00573 /* 00574 * Get the size of the stream. 00575 */ 00576 hres = IStream_Stat(presStream, 00577 &streamInfo, 00578 STATFLAG_NONAME); 00579 00580 /* 00581 * Read the header. 00582 */ 00583 00584 hres = read_clipformat(presStream, &clipformat); 00585 if (FAILED(hres)) 00586 { 00587 IStream_Release(presStream); 00588 return hres; 00589 } 00590 00591 hres = IStream_Read( 00592 presStream, 00593 &header, 00594 sizeof(PresentationDataHeader), 00595 NULL); 00596 if (hres != S_OK) 00597 { 00598 IStream_Release(presStream); 00599 return E_FAIL; 00600 } 00601 00602 hres = IStream_Seek(presStream, offset_zero, STREAM_SEEK_CUR, ¤t_pos); 00603 00604 streamInfo.cbSize.QuadPart -= current_pos.QuadPart; 00605 00606 hmfpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT)); 00607 if (!hmfpict) 00608 { 00609 IStream_Release(presStream); 00610 return E_OUTOFMEMORY; 00611 } 00612 mfpict = GlobalLock(hmfpict); 00613 00614 /* 00615 * Allocate a buffer for the metafile bits. 00616 */ 00617 metafileBits = HeapAlloc(GetProcessHeap(), 00618 0, 00619 streamInfo.cbSize.u.LowPart); 00620 00621 /* 00622 * Read the metafile bits. 00623 */ 00624 hres = IStream_Read( 00625 presStream, 00626 metafileBits, 00627 streamInfo.cbSize.u.LowPart, 00628 NULL); 00629 00630 /* 00631 * Create a metafile with those bits. 00632 */ 00633 if (SUCCEEDED(hres)) 00634 { 00635 /* FIXME: get this from the stream */ 00636 mfpict->mm = MM_ANISOTROPIC; 00637 mfpict->xExt = header.dwObjectExtentX; 00638 mfpict->yExt = header.dwObjectExtentY; 00639 mfpict->hMF = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits); 00640 if (!mfpict->hMF) 00641 hres = E_FAIL; 00642 } 00643 00644 GlobalUnlock(hmfpict); 00645 if (SUCCEEDED(hres)) 00646 { 00647 cache_entry->data_cf = cache_entry->fmtetc.cfFormat; 00648 cache_entry->stgmedium.tymed = TYMED_MFPICT; 00649 cache_entry->stgmedium.u.hMetaFilePict = hmfpict; 00650 } 00651 else 00652 GlobalFree(hmfpict); 00653 00654 /* 00655 * Cleanup. 00656 */ 00657 HeapFree(GetProcessHeap(), 0, metafileBits); 00658 IStream_Release(presStream); 00659 00660 return hres; 00661 } 00662 00663 static HRESULT DataCacheEntry_CreateStream(DataCacheEntry *cache_entry, 00664 IStorage *storage, IStream **stream) 00665 { 00666 WCHAR wszName[] = {2,'O','l','e','P','r','e','s', 00667 '0' + (cache_entry->stream_number / 100) % 10, 00668 '0' + (cache_entry->stream_number / 10) % 10, 00669 '0' + cache_entry->stream_number % 10, 0}; 00670 00671 /* FIXME: cache the created stream in This? */ 00672 return IStorage_CreateStream(storage, wszName, 00673 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 00674 0, 0, stream); 00675 } 00676 00677 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage, 00678 BOOL same_as_load) 00679 { 00680 PresentationDataHeader header; 00681 HRESULT hr; 00682 IStream *pres_stream; 00683 void *data = NULL; 00684 00685 TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->stream_number, debugstr_formatetc(&cache_entry->fmtetc)); 00686 00687 hr = DataCacheEntry_CreateStream(cache_entry, storage, &pres_stream); 00688 if (FAILED(hr)) 00689 return hr; 00690 00691 hr = write_clipformat(pres_stream, cache_entry->data_cf); 00692 if (FAILED(hr)) 00693 return hr; 00694 00695 if (cache_entry->fmtetc.ptd) 00696 FIXME("ptd not serialized\n"); 00697 header.unknown3 = 4; 00698 header.dvAspect = cache_entry->fmtetc.dwAspect; 00699 header.lindex = cache_entry->fmtetc.lindex; 00700 header.tymed = cache_entry->stgmedium.tymed; 00701 header.unknown7 = 0; 00702 header.dwObjectExtentX = 0; 00703 header.dwObjectExtentY = 0; 00704 header.dwSize = 0; 00705 00706 /* size the data */ 00707 switch (cache_entry->data_cf) 00708 { 00709 case CF_METAFILEPICT: 00710 { 00711 if (cache_entry->stgmedium.tymed != TYMED_NULL) 00712 { 00713 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict); 00714 if (!mfpict) 00715 { 00716 IStream_Release(pres_stream); 00717 return DV_E_STGMEDIUM; 00718 } 00719 header.dwObjectExtentX = mfpict->xExt; 00720 header.dwObjectExtentY = mfpict->yExt; 00721 header.dwSize = GetMetaFileBitsEx(mfpict->hMF, 0, NULL); 00722 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict); 00723 } 00724 break; 00725 } 00726 default: 00727 break; 00728 } 00729 00730 /* 00731 * Write the header. 00732 */ 00733 hr = IStream_Write(pres_stream, &header, sizeof(PresentationDataHeader), 00734 NULL); 00735 if (FAILED(hr)) 00736 { 00737 IStream_Release(pres_stream); 00738 return hr; 00739 } 00740 00741 /* get the data */ 00742 switch (cache_entry->data_cf) 00743 { 00744 case CF_METAFILEPICT: 00745 { 00746 if (cache_entry->stgmedium.tymed != TYMED_NULL) 00747 { 00748 const METAFILEPICT *mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict); 00749 if (!mfpict) 00750 { 00751 IStream_Release(pres_stream); 00752 return DV_E_STGMEDIUM; 00753 } 00754 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize); 00755 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data); 00756 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict); 00757 } 00758 break; 00759 } 00760 default: 00761 break; 00762 } 00763 00764 if (data) 00765 hr = IStream_Write(pres_stream, data, header.dwSize, NULL); 00766 HeapFree(GetProcessHeap(), 0, data); 00767 00768 IStream_Release(pres_stream); 00769 return hr; 00770 } 00771 00772 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL. 00773 * does no checking of whether src_stgm has a supported tymed, so this should be 00774 * done in the caller */ 00775 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm, 00776 const STGMEDIUM *src_stgm) 00777 { 00778 if (src_stgm->tymed == TYMED_MFPICT) 00779 { 00780 const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict); 00781 METAFILEPICT *dest_mfpict; 00782 00783 if (!src_mfpict) 00784 return DV_E_STGMEDIUM; 00785 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT)); 00786 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict); 00787 if (!dest_mfpict) 00788 { 00789 GlobalUnlock(src_stgm->u.hMetaFilePict); 00790 return E_OUTOFMEMORY; 00791 } 00792 *dest_mfpict = *src_mfpict; 00793 dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL); 00794 GlobalUnlock(src_stgm->u.hMetaFilePict); 00795 GlobalUnlock(dest_stgm->u.hMetaFilePict); 00796 } 00797 else if (src_stgm->tymed != TYMED_NULL) 00798 { 00799 dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf, 00800 GMEM_MOVEABLE); 00801 if (!dest_stgm->u.hGlobal) 00802 return E_OUTOFMEMORY; 00803 } 00804 dest_stgm->tymed = src_stgm->tymed; 00805 dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease; 00806 if (dest_stgm->pUnkForRelease) 00807 IUnknown_AddRef(dest_stgm->pUnkForRelease); 00808 return S_OK; 00809 } 00810 00811 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry, 00812 const FORMATETC *formatetc, 00813 const STGMEDIUM *stgmedium, 00814 BOOL fRelease) 00815 { 00816 if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) || 00817 (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) || 00818 stgmedium->tymed == TYMED_NULL) 00819 { 00820 WARN("invalid formatetc\n"); 00821 return DV_E_FORMATETC; 00822 } 00823 00824 cache_entry->dirty = TRUE; 00825 ReleaseStgMedium(&cache_entry->stgmedium); 00826 cache_entry->data_cf = cache_entry->fmtetc.cfFormat ? cache_entry->fmtetc.cfFormat : formatetc->cfFormat; 00827 if (fRelease) 00828 { 00829 cache_entry->stgmedium = *stgmedium; 00830 return S_OK; 00831 } 00832 else 00833 return copy_stg_medium(cache_entry->data_cf, 00834 &cache_entry->stgmedium, stgmedium); 00835 } 00836 00837 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, STGMEDIUM *stgmedium) 00838 { 00839 if (stgmedium->tymed == TYMED_NULL && cache_entry->storage) 00840 { 00841 HRESULT hr = DataCacheEntry_LoadData(cache_entry); 00842 if (FAILED(hr)) 00843 return hr; 00844 } 00845 if (cache_entry->stgmedium.tymed == TYMED_NULL) 00846 return OLE_E_BLANK; 00847 return copy_stg_medium(cache_entry->data_cf, stgmedium, &cache_entry->stgmedium); 00848 } 00849 00850 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry) 00851 { 00852 ReleaseStgMedium(&cache_entry->stgmedium); 00853 cache_entry->data_cf = cache_entry->fmtetc.cfFormat; 00854 return S_OK; 00855 } 00856 00857 static inline void DataCacheEntry_HandsOffStorage(DataCacheEntry *cache_entry) 00858 { 00859 if (cache_entry->storage) 00860 { 00861 IStorage_Release(cache_entry->storage); 00862 cache_entry->storage = NULL; 00863 } 00864 } 00865 00866 /********************************************************* 00867 * Method implementation for the non delegating IUnknown 00868 * part of the DataCache class. 00869 */ 00870 00871 /************************************************************************ 00872 * DataCache_NDIUnknown_QueryInterface (IUnknown) 00873 * 00874 * This version of QueryInterface will not delegate its implementation 00875 * to the outer unknown. 00876 */ 00877 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface( 00878 IUnknown* iface, 00879 REFIID riid, 00880 void** ppvObject) 00881 { 00882 DataCache *this = impl_from_IUnknown(iface); 00883 00884 if ( ppvObject==0 ) 00885 return E_INVALIDARG; 00886 00887 *ppvObject = 0; 00888 00889 if (IsEqualIID(&IID_IUnknown, riid)) 00890 { 00891 *ppvObject = iface; 00892 } 00893 else if (IsEqualIID(&IID_IDataObject, riid)) 00894 { 00895 *ppvObject = &this->IDataObject_iface; 00896 } 00897 else if ( IsEqualIID(&IID_IPersistStorage, riid) || 00898 IsEqualIID(&IID_IPersist, riid) ) 00899 { 00900 *ppvObject = &this->IPersistStorage_iface; 00901 } 00902 else if ( IsEqualIID(&IID_IViewObject, riid) || 00903 IsEqualIID(&IID_IViewObject2, riid) ) 00904 { 00905 *ppvObject = &this->IViewObject2_iface; 00906 } 00907 else if ( IsEqualIID(&IID_IOleCache, riid) || 00908 IsEqualIID(&IID_IOleCache2, riid) ) 00909 { 00910 *ppvObject = &this->IOleCache2_iface; 00911 } 00912 else if ( IsEqualIID(&IID_IOleCacheControl, riid) ) 00913 { 00914 *ppvObject = &this->IOleCacheControl_iface; 00915 } 00916 00917 if ((*ppvObject)==0) 00918 { 00919 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); 00920 return E_NOINTERFACE; 00921 } 00922 00923 IUnknown_AddRef((IUnknown*)*ppvObject); 00924 00925 return S_OK; 00926 } 00927 00928 /************************************************************************ 00929 * DataCache_NDIUnknown_AddRef (IUnknown) 00930 * 00931 * This version of QueryInterface will not delegate its implementation 00932 * to the outer unknown. 00933 */ 00934 static ULONG WINAPI DataCache_NDIUnknown_AddRef( 00935 IUnknown* iface) 00936 { 00937 DataCache *this = impl_from_IUnknown(iface); 00938 return InterlockedIncrement(&this->ref); 00939 } 00940 00941 /************************************************************************ 00942 * DataCache_NDIUnknown_Release (IUnknown) 00943 * 00944 * This version of QueryInterface will not delegate its implementation 00945 * to the outer unknown. 00946 */ 00947 static ULONG WINAPI DataCache_NDIUnknown_Release( 00948 IUnknown* iface) 00949 { 00950 DataCache *this = impl_from_IUnknown(iface); 00951 ULONG ref; 00952 00953 ref = InterlockedDecrement(&this->ref); 00954 00955 if (ref == 0) DataCache_Destroy(this); 00956 00957 return ref; 00958 } 00959 00960 /********************************************************* 00961 * Method implementation for the IDataObject 00962 * part of the DataCache class. 00963 */ 00964 00965 /************************************************************************ 00966 * DataCache_IDataObject_QueryInterface (IUnknown) 00967 */ 00968 static HRESULT WINAPI DataCache_IDataObject_QueryInterface( 00969 IDataObject* iface, 00970 REFIID riid, 00971 void** ppvObject) 00972 { 00973 DataCache *this = impl_from_IDataObject(iface); 00974 00975 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); 00976 } 00977 00978 /************************************************************************ 00979 * DataCache_IDataObject_AddRef (IUnknown) 00980 */ 00981 static ULONG WINAPI DataCache_IDataObject_AddRef( 00982 IDataObject* iface) 00983 { 00984 DataCache *this = impl_from_IDataObject(iface); 00985 00986 return IUnknown_AddRef(this->outerUnknown); 00987 } 00988 00989 /************************************************************************ 00990 * DataCache_IDataObject_Release (IUnknown) 00991 */ 00992 static ULONG WINAPI DataCache_IDataObject_Release( 00993 IDataObject* iface) 00994 { 00995 DataCache *this = impl_from_IDataObject(iface); 00996 00997 return IUnknown_Release(this->outerUnknown); 00998 } 00999 01000 /************************************************************************ 01001 * DataCache_GetData 01002 * 01003 * Get Data from a source dataobject using format pformatetcIn->cfFormat 01004 */ 01005 static HRESULT WINAPI DataCache_GetData( 01006 IDataObject* iface, 01007 LPFORMATETC pformatetcIn, 01008 STGMEDIUM* pmedium) 01009 { 01010 DataCache *This = impl_from_IDataObject(iface); 01011 DataCacheEntry *cache_entry; 01012 01013 memset(pmedium, 0, sizeof(*pmedium)); 01014 01015 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn); 01016 if (!cache_entry) 01017 return OLE_E_BLANK; 01018 01019 return DataCacheEntry_GetData(cache_entry, pmedium); 01020 } 01021 01022 static HRESULT WINAPI DataCache_GetDataHere( 01023 IDataObject* iface, 01024 LPFORMATETC pformatetc, 01025 STGMEDIUM* pmedium) 01026 { 01027 FIXME("stub\n"); 01028 return E_NOTIMPL; 01029 } 01030 01031 static HRESULT WINAPI DataCache_QueryGetData( 01032 IDataObject* iface, 01033 LPFORMATETC pformatetc) 01034 { 01035 FIXME("stub\n"); 01036 return E_NOTIMPL; 01037 } 01038 01039 /************************************************************************ 01040 * DataCache_EnumFormatEtc (IDataObject) 01041 * 01042 * The data cache doesn't implement this method. 01043 */ 01044 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc( 01045 IDataObject* iface, 01046 LPFORMATETC pformatectIn, 01047 LPFORMATETC pformatetcOut) 01048 { 01049 TRACE("()\n"); 01050 return E_NOTIMPL; 01051 } 01052 01053 /************************************************************************ 01054 * DataCache_IDataObject_SetData (IDataObject) 01055 * 01056 * This method is delegated to the IOleCache2 implementation. 01057 */ 01058 static HRESULT WINAPI DataCache_IDataObject_SetData( 01059 IDataObject* iface, 01060 LPFORMATETC pformatetc, 01061 STGMEDIUM* pmedium, 01062 BOOL fRelease) 01063 { 01064 IOleCache2* oleCache = NULL; 01065 HRESULT hres; 01066 01067 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease); 01068 01069 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache); 01070 01071 if (FAILED(hres)) 01072 return E_UNEXPECTED; 01073 01074 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease); 01075 01076 IOleCache2_Release(oleCache); 01077 01078 return hres; 01079 } 01080 01081 /************************************************************************ 01082 * DataCache_EnumFormatEtc (IDataObject) 01083 * 01084 * The data cache doesn't implement this method. 01085 */ 01086 static HRESULT WINAPI DataCache_EnumFormatEtc( 01087 IDataObject* iface, 01088 DWORD dwDirection, 01089 IEnumFORMATETC** ppenumFormatEtc) 01090 { 01091 TRACE("()\n"); 01092 return E_NOTIMPL; 01093 } 01094 01095 /************************************************************************ 01096 * DataCache_DAdvise (IDataObject) 01097 * 01098 * The data cache doesn't support connections. 01099 */ 01100 static HRESULT WINAPI DataCache_DAdvise( 01101 IDataObject* iface, 01102 FORMATETC* pformatetc, 01103 DWORD advf, 01104 IAdviseSink* pAdvSink, 01105 DWORD* pdwConnection) 01106 { 01107 TRACE("()\n"); 01108 return OLE_E_ADVISENOTSUPPORTED; 01109 } 01110 01111 /************************************************************************ 01112 * DataCache_DUnadvise (IDataObject) 01113 * 01114 * The data cache doesn't support connections. 01115 */ 01116 static HRESULT WINAPI DataCache_DUnadvise( 01117 IDataObject* iface, 01118 DWORD dwConnection) 01119 { 01120 TRACE("()\n"); 01121 return OLE_E_NOCONNECTION; 01122 } 01123 01124 /************************************************************************ 01125 * DataCache_EnumDAdvise (IDataObject) 01126 * 01127 * The data cache doesn't support connections. 01128 */ 01129 static HRESULT WINAPI DataCache_EnumDAdvise( 01130 IDataObject* iface, 01131 IEnumSTATDATA** ppenumAdvise) 01132 { 01133 TRACE("()\n"); 01134 return OLE_E_ADVISENOTSUPPORTED; 01135 } 01136 01137 /********************************************************* 01138 * Method implementation for the IDataObject 01139 * part of the DataCache class. 01140 */ 01141 01142 /************************************************************************ 01143 * DataCache_IPersistStorage_QueryInterface (IUnknown) 01144 */ 01145 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface( 01146 IPersistStorage* iface, 01147 REFIID riid, 01148 void** ppvObject) 01149 { 01150 DataCache *this = impl_from_IPersistStorage(iface); 01151 01152 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); 01153 } 01154 01155 /************************************************************************ 01156 * DataCache_IPersistStorage_AddRef (IUnknown) 01157 */ 01158 static ULONG WINAPI DataCache_IPersistStorage_AddRef( 01159 IPersistStorage* iface) 01160 { 01161 DataCache *this = impl_from_IPersistStorage(iface); 01162 01163 return IUnknown_AddRef(this->outerUnknown); 01164 } 01165 01166 /************************************************************************ 01167 * DataCache_IPersistStorage_Release (IUnknown) 01168 */ 01169 static ULONG WINAPI DataCache_IPersistStorage_Release( 01170 IPersistStorage* iface) 01171 { 01172 DataCache *this = impl_from_IPersistStorage(iface); 01173 01174 return IUnknown_Release(this->outerUnknown); 01175 } 01176 01177 /************************************************************************ 01178 * DataCache_GetClassID (IPersistStorage) 01179 * 01180 * The data cache doesn't implement this method. 01181 */ 01182 static HRESULT WINAPI DataCache_GetClassID( 01183 IPersistStorage* iface, 01184 CLSID* pClassID) 01185 { 01186 DataCache *This = impl_from_IPersistStorage(iface); 01187 DataCacheEntry *cache_entry; 01188 01189 TRACE("(%p, %p)\n", iface, pClassID); 01190 01191 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 01192 { 01193 if (cache_entry->storage != NULL) 01194 { 01195 STATSTG statstg; 01196 HRESULT hr = IStorage_Stat(cache_entry->storage, &statstg, STATFLAG_NONAME); 01197 if (SUCCEEDED(hr)) 01198 { 01199 *pClassID = statstg.clsid; 01200 return S_OK; 01201 } 01202 } 01203 } 01204 01205 *pClassID = CLSID_NULL; 01206 01207 return S_OK; 01208 } 01209 01210 /************************************************************************ 01211 * DataCache_IsDirty (IPersistStorage) 01212 */ 01213 static HRESULT WINAPI DataCache_IsDirty( 01214 IPersistStorage* iface) 01215 { 01216 DataCache *This = impl_from_IPersistStorage(iface); 01217 DataCacheEntry *cache_entry; 01218 01219 TRACE("(%p)\n", iface); 01220 01221 if (This->dirty) 01222 return S_OK; 01223 01224 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 01225 if (cache_entry->dirty) 01226 return S_OK; 01227 01228 return S_FALSE; 01229 } 01230 01231 /************************************************************************ 01232 * DataCache_InitNew (IPersistStorage) 01233 * 01234 * The data cache implementation of IPersistStorage_InitNew simply stores 01235 * the storage pointer. 01236 */ 01237 static HRESULT WINAPI DataCache_InitNew( 01238 IPersistStorage* iface, 01239 IStorage* pStg) 01240 { 01241 DataCache *This = impl_from_IPersistStorage(iface); 01242 01243 TRACE("(%p, %p)\n", iface, pStg); 01244 01245 if (This->presentationStorage != NULL) 01246 IStorage_Release(This->presentationStorage); 01247 01248 This->presentationStorage = pStg; 01249 01250 IStorage_AddRef(This->presentationStorage); 01251 This->dirty = TRUE; 01252 01253 return S_OK; 01254 } 01255 01256 /************************************************************************ 01257 * DataCache_Load (IPersistStorage) 01258 * 01259 * The data cache implementation of IPersistStorage_Load doesn't 01260 * actually load anything. Instead, it holds on to the storage pointer 01261 * and it will load the presentation information when the 01262 * IDataObject_GetData or IViewObject2_Draw methods are called. 01263 */ 01264 static HRESULT WINAPI DataCache_Load( 01265 IPersistStorage* iface, 01266 IStorage* pStg) 01267 { 01268 DataCache *This = impl_from_IPersistStorage(iface); 01269 STATSTG elem; 01270 IEnumSTATSTG *pEnum; 01271 HRESULT hr; 01272 01273 TRACE("(%p, %p)\n", iface, pStg); 01274 01275 if (This->presentationStorage != NULL) 01276 IStorage_Release(This->presentationStorage); 01277 01278 This->presentationStorage = pStg; 01279 01280 hr = IStorage_EnumElements(pStg, 0, NULL, 0, &pEnum); 01281 if (FAILED(hr)) return hr; 01282 01283 while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK) 01284 { 01285 if (DataCache_IsPresentationStream(&elem)) 01286 { 01287 IStream *pStm; 01288 01289 hr = IStorage_OpenStream(This->presentationStorage, elem.pwcsName, 01290 NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, 01291 &pStm); 01292 if (SUCCEEDED(hr)) 01293 { 01294 PresentationDataHeader header; 01295 ULONG actual_read; 01296 CLIPFORMAT clipformat; 01297 01298 hr = read_clipformat(pStm, &clipformat); 01299 01300 if (hr == S_OK) 01301 hr = IStream_Read(pStm, &header, sizeof(header), 01302 &actual_read); 01303 01304 /* can't use SUCCEEDED(hr): S_FALSE counts as an error */ 01305 if (hr == S_OK && actual_read == sizeof(header)) 01306 { 01307 DataCacheEntry *cache_entry; 01308 FORMATETC fmtetc; 01309 01310 fmtetc.cfFormat = clipformat; 01311 fmtetc.ptd = NULL; /* FIXME */ 01312 fmtetc.dwAspect = header.dvAspect; 01313 fmtetc.lindex = header.lindex; 01314 fmtetc.tymed = header.tymed; 01315 01316 TRACE("loading entry with formatetc: %s\n", debugstr_formatetc(&fmtetc)); 01317 01318 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmtetc); 01319 if (!cache_entry) 01320 hr = DataCache_CreateEntry(This, &fmtetc, &cache_entry); 01321 if (SUCCEEDED(hr)) 01322 { 01323 DataCacheEntry_DiscardData(cache_entry); 01324 if (cache_entry->storage) IStorage_Release(cache_entry->storage); 01325 cache_entry->storage = pStg; 01326 IStorage_AddRef(pStg); 01327 cache_entry->dirty = FALSE; 01328 } 01329 } 01330 01331 IStream_Release(pStm); 01332 } 01333 } 01334 01335 CoTaskMemFree(elem.pwcsName); 01336 } 01337 01338 This->dirty = FALSE; 01339 01340 IEnumSTATSTG_Release(pEnum); 01341 01342 IStorage_AddRef(This->presentationStorage); 01343 return S_OK; 01344 } 01345 01346 /************************************************************************ 01347 * DataCache_Save (IPersistStorage) 01348 * 01349 * Until we actually connect to a running object and retrieve new 01350 * information to it, we never have to save anything. However, it is 01351 * our responsibility to copy the information when saving to a new 01352 * storage. 01353 */ 01354 static HRESULT WINAPI DataCache_Save( 01355 IPersistStorage* iface, 01356 IStorage* pStg, 01357 BOOL fSameAsLoad) 01358 { 01359 DataCache *This = impl_from_IPersistStorage(iface); 01360 DataCacheEntry *cache_entry; 01361 BOOL dirty = FALSE; 01362 HRESULT hr = S_OK; 01363 unsigned short stream_number = 0; 01364 01365 TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad); 01366 01367 dirty = This->dirty; 01368 if (!dirty) 01369 { 01370 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 01371 { 01372 dirty = cache_entry->dirty; 01373 if (dirty) 01374 break; 01375 } 01376 } 01377 01378 /* this is a shortcut if nothing changed */ 01379 if (!dirty && !fSameAsLoad && This->presentationStorage) 01380 { 01381 return IStorage_CopyTo(This->presentationStorage, 0, NULL, NULL, pStg); 01382 } 01383 01384 /* assign stream numbers to the cache entries */ 01385 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 01386 { 01387 if (cache_entry->stream_number != stream_number) 01388 { 01389 cache_entry->dirty = TRUE; /* needs to be written out again */ 01390 cache_entry->stream_number = stream_number; 01391 } 01392 stream_number++; 01393 } 01394 01395 /* write out the cache entries */ 01396 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 01397 { 01398 if (!fSameAsLoad || cache_entry->dirty) 01399 { 01400 hr = DataCacheEntry_Save(cache_entry, pStg, fSameAsLoad); 01401 if (FAILED(hr)) 01402 break; 01403 01404 cache_entry->dirty = FALSE; 01405 } 01406 } 01407 01408 This->dirty = FALSE; 01409 return hr; 01410 } 01411 01412 /************************************************************************ 01413 * DataCache_SaveCompleted (IPersistStorage) 01414 * 01415 * This method is called to tell the cache to release the storage 01416 * pointer it's currently holding. 01417 */ 01418 static HRESULT WINAPI DataCache_SaveCompleted( 01419 IPersistStorage* iface, 01420 IStorage* pStgNew) 01421 { 01422 TRACE("(%p, %p)\n", iface, pStgNew); 01423 01424 if (pStgNew) 01425 { 01426 IPersistStorage_HandsOffStorage(iface); 01427 01428 DataCache_Load(iface, pStgNew); 01429 } 01430 01431 return S_OK; 01432 } 01433 01434 /************************************************************************ 01435 * DataCache_HandsOffStorage (IPersistStorage) 01436 * 01437 * This method is called to tell the cache to release the storage 01438 * pointer it's currently holding. 01439 */ 01440 static HRESULT WINAPI DataCache_HandsOffStorage( 01441 IPersistStorage* iface) 01442 { 01443 DataCache *this = impl_from_IPersistStorage(iface); 01444 DataCacheEntry *cache_entry; 01445 01446 TRACE("(%p)\n", iface); 01447 01448 if (this->presentationStorage != NULL) 01449 { 01450 IStorage_Release(this->presentationStorage); 01451 this->presentationStorage = NULL; 01452 } 01453 01454 LIST_FOR_EACH_ENTRY(cache_entry, &this->cache_list, DataCacheEntry, entry) 01455 DataCacheEntry_HandsOffStorage(cache_entry); 01456 01457 return S_OK; 01458 } 01459 01460 /********************************************************* 01461 * Method implementation for the IViewObject2 01462 * part of the DataCache class. 01463 */ 01464 01465 /************************************************************************ 01466 * DataCache_IViewObject2_QueryInterface (IUnknown) 01467 */ 01468 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface( 01469 IViewObject2* iface, 01470 REFIID riid, 01471 void** ppvObject) 01472 { 01473 DataCache *this = impl_from_IViewObject2(iface); 01474 01475 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); 01476 } 01477 01478 /************************************************************************ 01479 * DataCache_IViewObject2_AddRef (IUnknown) 01480 */ 01481 static ULONG WINAPI DataCache_IViewObject2_AddRef( 01482 IViewObject2* iface) 01483 { 01484 DataCache *this = impl_from_IViewObject2(iface); 01485 01486 return IUnknown_AddRef(this->outerUnknown); 01487 } 01488 01489 /************************************************************************ 01490 * DataCache_IViewObject2_Release (IUnknown) 01491 */ 01492 static ULONG WINAPI DataCache_IViewObject2_Release( 01493 IViewObject2* iface) 01494 { 01495 DataCache *this = impl_from_IViewObject2(iface); 01496 01497 return IUnknown_Release(this->outerUnknown); 01498 } 01499 01500 /************************************************************************ 01501 * DataCache_Draw (IViewObject2) 01502 * 01503 * This method will draw the cached representation of the object 01504 * to the given device context. 01505 */ 01506 static HRESULT WINAPI DataCache_Draw( 01507 IViewObject2* iface, 01508 DWORD dwDrawAspect, 01509 LONG lindex, 01510 void* pvAspect, 01511 DVTARGETDEVICE* ptd, 01512 HDC hdcTargetDev, 01513 HDC hdcDraw, 01514 LPCRECTL lprcBounds, 01515 LPCRECTL lprcWBounds, 01516 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue), 01517 ULONG_PTR dwContinue) 01518 { 01519 DataCache *This = impl_from_IViewObject2(iface); 01520 HRESULT hres; 01521 DataCacheEntry *cache_entry; 01522 01523 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n", 01524 iface, 01525 dwDrawAspect, 01526 lindex, 01527 pvAspect, 01528 hdcTargetDev, 01529 hdcDraw, 01530 lprcBounds, 01531 lprcWBounds, 01532 pfnContinue, 01533 dwContinue); 01534 01535 if (lprcBounds==NULL) 01536 return E_INVALIDARG; 01537 01538 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 01539 { 01540 /* FIXME: compare ptd too */ 01541 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) || 01542 (cache_entry->fmtetc.lindex != lindex)) 01543 continue; 01544 01545 /* if the data hasn't been loaded yet, do it now */ 01546 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage) 01547 { 01548 hres = DataCacheEntry_LoadData(cache_entry); 01549 if (FAILED(hres)) 01550 continue; 01551 } 01552 01553 /* no data */ 01554 if (cache_entry->stgmedium.tymed == TYMED_NULL) 01555 continue; 01556 01557 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT; 01558 01559 switch (cache_entry->data_cf) 01560 { 01561 case CF_METAFILEPICT: 01562 { 01563 /* 01564 * We have to be careful not to modify the state of the 01565 * DC. 01566 */ 01567 INT prevMapMode; 01568 SIZE oldWindowExt; 01569 SIZE oldViewportExt; 01570 POINT oldViewportOrg; 01571 METAFILEPICT *mfpict; 01572 01573 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) || 01574 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict)))) 01575 continue; 01576 01577 prevMapMode = SetMapMode(hdcDraw, mfpict->mm); 01578 01579 SetWindowExtEx(hdcDraw, 01580 mfpict->xExt, 01581 mfpict->yExt, 01582 &oldWindowExt); 01583 01584 SetViewportExtEx(hdcDraw, 01585 lprcBounds->right - lprcBounds->left, 01586 lprcBounds->bottom - lprcBounds->top, 01587 &oldViewportExt); 01588 01589 SetViewportOrgEx(hdcDraw, 01590 lprcBounds->left, 01591 lprcBounds->top, 01592 &oldViewportOrg); 01593 01594 PlayMetaFile(hdcDraw, mfpict->hMF); 01595 01596 SetWindowExtEx(hdcDraw, 01597 oldWindowExt.cx, 01598 oldWindowExt.cy, 01599 NULL); 01600 01601 SetViewportExtEx(hdcDraw, 01602 oldViewportExt.cx, 01603 oldViewportExt.cy, 01604 NULL); 01605 01606 SetViewportOrgEx(hdcDraw, 01607 oldViewportOrg.x, 01608 oldViewportOrg.y, 01609 NULL); 01610 01611 SetMapMode(hdcDraw, prevMapMode); 01612 01613 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict); 01614 01615 return S_OK; 01616 } 01617 } 01618 } 01619 01620 WARN("no data could be found to be drawn\n"); 01621 01622 return OLE_E_BLANK; 01623 } 01624 01625 static HRESULT WINAPI DataCache_GetColorSet( 01626 IViewObject2* iface, 01627 DWORD dwDrawAspect, 01628 LONG lindex, 01629 void* pvAspect, 01630 DVTARGETDEVICE* ptd, 01631 HDC hicTargetDevice, 01632 LOGPALETTE** ppColorSet) 01633 { 01634 FIXME("stub\n"); 01635 return E_NOTIMPL; 01636 } 01637 01638 static HRESULT WINAPI DataCache_Freeze( 01639 IViewObject2* iface, 01640 DWORD dwDrawAspect, 01641 LONG lindex, 01642 void* pvAspect, 01643 DWORD* pdwFreeze) 01644 { 01645 FIXME("stub\n"); 01646 return E_NOTIMPL; 01647 } 01648 01649 static HRESULT WINAPI DataCache_Unfreeze( 01650 IViewObject2* iface, 01651 DWORD dwFreeze) 01652 { 01653 FIXME("stub\n"); 01654 return E_NOTIMPL; 01655 } 01656 01657 /************************************************************************ 01658 * DataCache_SetAdvise (IViewObject2) 01659 * 01660 * This sets-up an advisory sink with the data cache. When the object's 01661 * view changes, this sink is called. 01662 */ 01663 static HRESULT WINAPI DataCache_SetAdvise( 01664 IViewObject2* iface, 01665 DWORD aspects, 01666 DWORD advf, 01667 IAdviseSink* pAdvSink) 01668 { 01669 DataCache *this = impl_from_IViewObject2(iface); 01670 01671 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink); 01672 01673 /* 01674 * A call to this function removes the previous sink 01675 */ 01676 if (this->sinkInterface != NULL) 01677 { 01678 IAdviseSink_Release(this->sinkInterface); 01679 this->sinkInterface = NULL; 01680 this->sinkAspects = 0; 01681 this->sinkAdviseFlag = 0; 01682 } 01683 01684 /* 01685 * Now, setup the new one. 01686 */ 01687 if (pAdvSink!=NULL) 01688 { 01689 this->sinkInterface = pAdvSink; 01690 this->sinkAspects = aspects; 01691 this->sinkAdviseFlag = advf; 01692 01693 IAdviseSink_AddRef(this->sinkInterface); 01694 } 01695 01696 /* 01697 * When the ADVF_PRIMEFIRST flag is set, we have to advise the 01698 * sink immediately. 01699 */ 01700 if (advf & ADVF_PRIMEFIRST) 01701 { 01702 DataCache_FireOnViewChange(this, aspects, -1); 01703 } 01704 01705 return S_OK; 01706 } 01707 01708 /************************************************************************ 01709 * DataCache_GetAdvise (IViewObject2) 01710 * 01711 * This method queries the current state of the advise sink 01712 * installed on the data cache. 01713 */ 01714 static HRESULT WINAPI DataCache_GetAdvise( 01715 IViewObject2* iface, 01716 DWORD* pAspects, 01717 DWORD* pAdvf, 01718 IAdviseSink** ppAdvSink) 01719 { 01720 DataCache *this = impl_from_IViewObject2(iface); 01721 01722 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink); 01723 01724 /* 01725 * Just copy all the requested values. 01726 */ 01727 if (pAspects!=NULL) 01728 *pAspects = this->sinkAspects; 01729 01730 if (pAdvf!=NULL) 01731 *pAdvf = this->sinkAdviseFlag; 01732 01733 if (ppAdvSink!=NULL) 01734 { 01735 if (this->sinkInterface != NULL) 01736 IAdviseSink_QueryInterface(this->sinkInterface, 01737 &IID_IAdviseSink, 01738 (void**)ppAdvSink); 01739 else *ppAdvSink = NULL; 01740 } 01741 01742 return S_OK; 01743 } 01744 01745 /************************************************************************ 01746 * DataCache_GetExtent (IViewObject2) 01747 * 01748 * This method retrieves the "natural" size of this cached object. 01749 */ 01750 static HRESULT WINAPI DataCache_GetExtent( 01751 IViewObject2* iface, 01752 DWORD dwDrawAspect, 01753 LONG lindex, 01754 DVTARGETDEVICE* ptd, 01755 LPSIZEL lpsizel) 01756 { 01757 DataCache *This = impl_from_IViewObject2(iface); 01758 HRESULT hres = E_FAIL; 01759 DataCacheEntry *cache_entry; 01760 01761 TRACE("(%p, %x, %d, %p, %p)\n", 01762 iface, dwDrawAspect, lindex, ptd, lpsizel); 01763 01764 if (lpsizel==NULL) 01765 return E_POINTER; 01766 01767 lpsizel->cx = 0; 01768 lpsizel->cy = 0; 01769 01770 if (lindex!=-1) 01771 FIXME("Unimplemented flag lindex = %d\n", lindex); 01772 01773 /* 01774 * Right now, we support only the callback from 01775 * the default handler. 01776 */ 01777 if (ptd!=NULL) 01778 FIXME("Unimplemented ptd = %p\n", ptd); 01779 01780 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 01781 { 01782 /* FIXME: compare ptd too */ 01783 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) || 01784 (cache_entry->fmtetc.lindex != lindex)) 01785 continue; 01786 01787 /* if the data hasn't been loaded yet, do it now */ 01788 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && cache_entry->storage) 01789 { 01790 hres = DataCacheEntry_LoadData(cache_entry); 01791 if (FAILED(hres)) 01792 continue; 01793 } 01794 01795 /* no data */ 01796 if (cache_entry->stgmedium.tymed == TYMED_NULL) 01797 continue; 01798 01799 01800 switch (cache_entry->data_cf) 01801 { 01802 case CF_METAFILEPICT: 01803 { 01804 METAFILEPICT *mfpict; 01805 01806 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) || 01807 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict)))) 01808 continue; 01809 01810 lpsizel->cx = mfpict->xExt; 01811 lpsizel->cy = mfpict->yExt; 01812 01813 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict); 01814 01815 return S_OK; 01816 } 01817 } 01818 } 01819 01820 WARN("no data could be found to get the extents from\n"); 01821 01822 /* 01823 * This method returns OLE_E_BLANK when it fails. 01824 */ 01825 return OLE_E_BLANK; 01826 } 01827 01828 01829 /********************************************************* 01830 * Method implementation for the IOleCache2 01831 * part of the DataCache class. 01832 */ 01833 01834 /************************************************************************ 01835 * DataCache_IOleCache2_QueryInterface (IUnknown) 01836 */ 01837 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface( 01838 IOleCache2* iface, 01839 REFIID riid, 01840 void** ppvObject) 01841 { 01842 DataCache *this = impl_from_IOleCache2(iface); 01843 01844 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); 01845 } 01846 01847 /************************************************************************ 01848 * DataCache_IOleCache2_AddRef (IUnknown) 01849 */ 01850 static ULONG WINAPI DataCache_IOleCache2_AddRef( 01851 IOleCache2* iface) 01852 { 01853 DataCache *this = impl_from_IOleCache2(iface); 01854 01855 return IUnknown_AddRef(this->outerUnknown); 01856 } 01857 01858 /************************************************************************ 01859 * DataCache_IOleCache2_Release (IUnknown) 01860 */ 01861 static ULONG WINAPI DataCache_IOleCache2_Release( 01862 IOleCache2* iface) 01863 { 01864 DataCache *this = impl_from_IOleCache2(iface); 01865 01866 return IUnknown_Release(this->outerUnknown); 01867 } 01868 01869 /***************************************************************************** 01870 * setup_sink 01871 * 01872 * Set up the sink connection to the running object. 01873 */ 01874 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry) 01875 { 01876 HRESULT hr = S_FALSE; 01877 DWORD flags; 01878 01879 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */ 01880 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE); 01881 01882 if(This->running_object) 01883 if(!(flags & ADVF_NODATA)) 01884 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags, 01885 &This->IAdviseSink_iface, &cache_entry->sink_id); 01886 return hr; 01887 } 01888 01889 static HRESULT WINAPI DataCache_Cache( 01890 IOleCache2* iface, 01891 FORMATETC* pformatetc, 01892 DWORD advf, 01893 DWORD* pdwConnection) 01894 { 01895 DataCache *This = impl_from_IOleCache2(iface); 01896 DataCacheEntry *cache_entry; 01897 HRESULT hr; 01898 01899 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection); 01900 01901 if (!pformatetc || !pdwConnection) 01902 return E_INVALIDARG; 01903 01904 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc)); 01905 01906 *pdwConnection = 0; 01907 01908 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc); 01909 if (cache_entry) 01910 { 01911 TRACE("found an existing cache entry\n"); 01912 *pdwConnection = cache_entry->id; 01913 return CACHE_S_SAMECACHE; 01914 } 01915 01916 hr = DataCache_CreateEntry(This, pformatetc, &cache_entry); 01917 01918 if (SUCCEEDED(hr)) 01919 { 01920 *pdwConnection = cache_entry->id; 01921 cache_entry->advise_flags = advf; 01922 setup_sink(This, cache_entry); 01923 } 01924 01925 return hr; 01926 } 01927 01928 static HRESULT WINAPI DataCache_Uncache( 01929 IOleCache2* iface, 01930 DWORD dwConnection) 01931 { 01932 DataCache *This = impl_from_IOleCache2(iface); 01933 DataCacheEntry *cache_entry; 01934 01935 TRACE("(%d)\n", dwConnection); 01936 01937 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 01938 if (cache_entry->id == dwConnection) 01939 { 01940 DataCacheEntry_Destroy(This, cache_entry); 01941 return S_OK; 01942 } 01943 01944 WARN("no connection found for %d\n", dwConnection); 01945 01946 return OLE_E_NOCONNECTION; 01947 } 01948 01949 static HRESULT WINAPI DataCache_EnumCache( 01950 IOleCache2* iface, 01951 IEnumSTATDATA** ppenumSTATDATA) 01952 { 01953 FIXME("stub\n"); 01954 return E_NOTIMPL; 01955 } 01956 01957 static HRESULT WINAPI DataCache_InitCache( 01958 IOleCache2* iface, 01959 IDataObject* pDataObject) 01960 { 01961 FIXME("stub\n"); 01962 return E_NOTIMPL; 01963 } 01964 01965 static HRESULT WINAPI DataCache_IOleCache2_SetData( 01966 IOleCache2* iface, 01967 FORMATETC* pformatetc, 01968 STGMEDIUM* pmedium, 01969 BOOL fRelease) 01970 { 01971 DataCache *This = impl_from_IOleCache2(iface); 01972 DataCacheEntry *cache_entry; 01973 HRESULT hr; 01974 01975 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE"); 01976 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc)); 01977 01978 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc); 01979 if (cache_entry) 01980 { 01981 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease); 01982 01983 if (SUCCEEDED(hr)) 01984 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect, 01985 cache_entry->fmtetc.lindex); 01986 01987 return hr; 01988 } 01989 WARN("cache entry not found\n"); 01990 01991 return OLE_E_BLANK; 01992 } 01993 01994 static HRESULT WINAPI DataCache_UpdateCache( 01995 IOleCache2* iface, 01996 LPDATAOBJECT pDataObject, 01997 DWORD grfUpdf, 01998 LPVOID pReserved) 01999 { 02000 FIXME("(%p, 0x%x, %p): stub\n", pDataObject, grfUpdf, pReserved); 02001 return E_NOTIMPL; 02002 } 02003 02004 static HRESULT WINAPI DataCache_DiscardCache( 02005 IOleCache2* iface, 02006 DWORD dwDiscardOptions) 02007 { 02008 DataCache *This = impl_from_IOleCache2(iface); 02009 DataCacheEntry *cache_entry; 02010 HRESULT hr = S_OK; 02011 02012 TRACE("(%d)\n", dwDiscardOptions); 02013 02014 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY) 02015 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE); 02016 02017 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 02018 { 02019 hr = DataCacheEntry_DiscardData(cache_entry); 02020 if (FAILED(hr)) 02021 break; 02022 } 02023 02024 return hr; 02025 } 02026 02027 02028 /********************************************************* 02029 * Method implementation for the IOleCacheControl 02030 * part of the DataCache class. 02031 */ 02032 02033 /************************************************************************ 02034 * DataCache_IOleCacheControl_QueryInterface (IUnknown) 02035 */ 02036 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface( 02037 IOleCacheControl* iface, 02038 REFIID riid, 02039 void** ppvObject) 02040 { 02041 DataCache *this = impl_from_IOleCacheControl(iface); 02042 02043 return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); 02044 } 02045 02046 /************************************************************************ 02047 * DataCache_IOleCacheControl_AddRef (IUnknown) 02048 */ 02049 static ULONG WINAPI DataCache_IOleCacheControl_AddRef( 02050 IOleCacheControl* iface) 02051 { 02052 DataCache *this = impl_from_IOleCacheControl(iface); 02053 02054 return IUnknown_AddRef(this->outerUnknown); 02055 } 02056 02057 /************************************************************************ 02058 * DataCache_IOleCacheControl_Release (IUnknown) 02059 */ 02060 static ULONG WINAPI DataCache_IOleCacheControl_Release( 02061 IOleCacheControl* iface) 02062 { 02063 DataCache *this = impl_from_IOleCacheControl(iface); 02064 02065 return IUnknown_Release(this->outerUnknown); 02066 } 02067 02068 /************************************************************************ 02069 * DataCache_OnRun (IOleCacheControl) 02070 */ 02071 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj) 02072 { 02073 DataCache *This = impl_from_IOleCacheControl(iface); 02074 DataCacheEntry *cache_entry; 02075 02076 TRACE("(%p)->(%p)\n", iface, data_obj); 02077 02078 if(This->running_object) return S_OK; 02079 02080 /* No reference is taken on the data object */ 02081 This->running_object = data_obj; 02082 02083 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 02084 { 02085 setup_sink(This, cache_entry); 02086 } 02087 02088 return S_OK; 02089 } 02090 02091 /************************************************************************ 02092 * DataCache_OnStop (IOleCacheControl) 02093 */ 02094 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface) 02095 { 02096 DataCache *This = impl_from_IOleCacheControl(iface); 02097 DataCacheEntry *cache_entry; 02098 02099 TRACE("(%p)\n", iface); 02100 02101 if(!This->running_object) return S_OK; 02102 02103 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 02104 { 02105 if(cache_entry->sink_id) 02106 { 02107 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id); 02108 cache_entry->sink_id = 0; 02109 } 02110 } 02111 02112 /* No ref taken in OnRun, so no Release call here */ 02113 This->running_object = NULL; 02114 return S_OK; 02115 } 02116 02117 /************************************************************************ 02118 * IAdviseSink methods. 02119 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't 02120 * give access to the cache's other interfaces. We don't maintain a ref count, 02121 * the object exists as long as the cache is around. 02122 */ 02123 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj) 02124 { 02125 *obj = NULL; 02126 if (IsEqualIID(&IID_IUnknown, iid) || 02127 IsEqualIID(&IID_IAdviseSink, iid)) 02128 { 02129 *obj = iface; 02130 } 02131 02132 if(*obj) 02133 { 02134 IAdviseSink_AddRef(iface); 02135 return S_OK; 02136 } 02137 return E_NOINTERFACE; 02138 } 02139 02140 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface) 02141 { 02142 return 2; 02143 } 02144 02145 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface) 02146 { 02147 return 1; 02148 } 02149 02150 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med) 02151 { 02152 DataCache *This = impl_from_IAdviseSink(iface); 02153 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med); 02154 IOleCache_SetData(&This->IOleCache2_iface, fmt, med, FALSE); 02155 } 02156 02157 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index) 02158 { 02159 FIXME("stub\n"); 02160 } 02161 02162 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk) 02163 { 02164 FIXME("stub\n"); 02165 } 02166 02167 static void WINAPI DataCache_OnSave(IAdviseSink *iface) 02168 { 02169 FIXME("stub\n"); 02170 } 02171 02172 static void WINAPI DataCache_OnClose(IAdviseSink *iface) 02173 { 02174 FIXME("stub\n"); 02175 } 02176 02177 /* 02178 * Virtual function tables for the DataCache class. 02179 */ 02180 static const IUnknownVtbl DataCache_NDIUnknown_VTable = 02181 { 02182 DataCache_NDIUnknown_QueryInterface, 02183 DataCache_NDIUnknown_AddRef, 02184 DataCache_NDIUnknown_Release 02185 }; 02186 02187 static const IDataObjectVtbl DataCache_IDataObject_VTable = 02188 { 02189 DataCache_IDataObject_QueryInterface, 02190 DataCache_IDataObject_AddRef, 02191 DataCache_IDataObject_Release, 02192 DataCache_GetData, 02193 DataCache_GetDataHere, 02194 DataCache_QueryGetData, 02195 DataCache_GetCanonicalFormatEtc, 02196 DataCache_IDataObject_SetData, 02197 DataCache_EnumFormatEtc, 02198 DataCache_DAdvise, 02199 DataCache_DUnadvise, 02200 DataCache_EnumDAdvise 02201 }; 02202 02203 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable = 02204 { 02205 DataCache_IPersistStorage_QueryInterface, 02206 DataCache_IPersistStorage_AddRef, 02207 DataCache_IPersistStorage_Release, 02208 DataCache_GetClassID, 02209 DataCache_IsDirty, 02210 DataCache_InitNew, 02211 DataCache_Load, 02212 DataCache_Save, 02213 DataCache_SaveCompleted, 02214 DataCache_HandsOffStorage 02215 }; 02216 02217 static const IViewObject2Vtbl DataCache_IViewObject2_VTable = 02218 { 02219 DataCache_IViewObject2_QueryInterface, 02220 DataCache_IViewObject2_AddRef, 02221 DataCache_IViewObject2_Release, 02222 DataCache_Draw, 02223 DataCache_GetColorSet, 02224 DataCache_Freeze, 02225 DataCache_Unfreeze, 02226 DataCache_SetAdvise, 02227 DataCache_GetAdvise, 02228 DataCache_GetExtent 02229 }; 02230 02231 static const IOleCache2Vtbl DataCache_IOleCache2_VTable = 02232 { 02233 DataCache_IOleCache2_QueryInterface, 02234 DataCache_IOleCache2_AddRef, 02235 DataCache_IOleCache2_Release, 02236 DataCache_Cache, 02237 DataCache_Uncache, 02238 DataCache_EnumCache, 02239 DataCache_InitCache, 02240 DataCache_IOleCache2_SetData, 02241 DataCache_UpdateCache, 02242 DataCache_DiscardCache 02243 }; 02244 02245 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable = 02246 { 02247 DataCache_IOleCacheControl_QueryInterface, 02248 DataCache_IOleCacheControl_AddRef, 02249 DataCache_IOleCacheControl_Release, 02250 DataCache_OnRun, 02251 DataCache_OnStop 02252 }; 02253 02254 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable = 02255 { 02256 DataCache_IAdviseSink_QueryInterface, 02257 DataCache_IAdviseSink_AddRef, 02258 DataCache_IAdviseSink_Release, 02259 DataCache_OnDataChange, 02260 DataCache_OnViewChange, 02261 DataCache_OnRename, 02262 DataCache_OnSave, 02263 DataCache_OnClose 02264 }; 02265 02266 /********************************************************* 02267 * Method implementation for DataCache class. 02268 */ 02269 static DataCache* DataCache_Construct( 02270 REFCLSID clsid, 02271 LPUNKNOWN pUnkOuter) 02272 { 02273 DataCache* newObject = 0; 02274 02275 /* 02276 * Allocate space for the object. 02277 */ 02278 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache)); 02279 02280 if (newObject==0) 02281 return newObject; 02282 02283 /* 02284 * Initialize the virtual function table. 02285 */ 02286 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable; 02287 newObject->IUnknown_iface.lpVtbl = &DataCache_NDIUnknown_VTable; 02288 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable; 02289 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable; 02290 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable; 02291 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable; 02292 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable; 02293 02294 /* 02295 * Start with one reference count. The caller of this function 02296 * must release the interface pointer when it is done. 02297 */ 02298 newObject->ref = 1; 02299 02300 /* 02301 * Initialize the outer unknown 02302 * We don't keep a reference on the outer unknown since, the way 02303 * aggregation works, our lifetime is at least as large as its 02304 * lifetime. 02305 */ 02306 if (pUnkOuter==NULL) 02307 pUnkOuter = &newObject->IUnknown_iface; 02308 02309 newObject->outerUnknown = pUnkOuter; 02310 02311 /* 02312 * Initialize the other members of the structure. 02313 */ 02314 newObject->sinkAspects = 0; 02315 newObject->sinkAdviseFlag = 0; 02316 newObject->sinkInterface = 0; 02317 newObject->presentationStorage = NULL; 02318 list_init(&newObject->cache_list); 02319 newObject->last_cache_id = 1; 02320 newObject->dirty = FALSE; 02321 newObject->running_object = NULL; 02322 02323 return newObject; 02324 } 02325 02326 /****************************************************************************** 02327 * CreateDataCache [OLE32.@] 02328 * 02329 * Creates a data cache to allow an object to render one or more of its views, 02330 * whether running or not. 02331 * 02332 * PARAMS 02333 * pUnkOuter [I] Outer unknown for the object. 02334 * rclsid [I] 02335 * riid [I] IID of interface to return. 02336 * ppvObj [O] Address where the data cache object will be stored on return. 02337 * 02338 * RETURNS 02339 * Success: S_OK. 02340 * Failure: HRESULT code. 02341 * 02342 * NOTES 02343 * The following interfaces are supported by the returned data cache object: 02344 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject, 02345 * IViewObject and IViewObject2. 02346 */ 02347 HRESULT WINAPI CreateDataCache( 02348 LPUNKNOWN pUnkOuter, 02349 REFCLSID rclsid, 02350 REFIID riid, 02351 LPVOID* ppvObj) 02352 { 02353 DataCache* newCache = NULL; 02354 HRESULT hr = S_OK; 02355 02356 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj); 02357 02358 /* 02359 * Sanity check 02360 */ 02361 if (ppvObj==0) 02362 return E_POINTER; 02363 02364 *ppvObj = 0; 02365 02366 /* 02367 * If this cache is constructed for aggregation, make sure 02368 * the caller is requesting the IUnknown interface. 02369 * This is necessary because it's the only time the non-delegating 02370 * IUnknown pointer can be returned to the outside. 02371 */ 02372 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) ) 02373 return CLASS_E_NOAGGREGATION; 02374 02375 /* 02376 * Try to construct a new instance of the class. 02377 */ 02378 newCache = DataCache_Construct(rclsid, 02379 pUnkOuter); 02380 02381 if (newCache == 0) 02382 return E_OUTOFMEMORY; 02383 02384 /* 02385 * Make sure it supports the interface required by the caller. 02386 */ 02387 hr = IUnknown_QueryInterface(&newCache->IUnknown_iface, riid, ppvObj); 02388 02389 /* 02390 * Release the reference obtained in the constructor. If 02391 * the QueryInterface was unsuccessful, it will free the class. 02392 */ 02393 IUnknown_Release(&newCache->IUnknown_iface); 02394 02395 return hr; 02396 } Generated on Fri May 25 2012 04:23:44 for ReactOS by
1.7.6.1
|