1 /* 2 * OLE 2 Data cache 3 * 4 * Copyright 1999 Francis Beaudet 5 * Copyright 2000 Abey George 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 * 21 * NOTES: 22 * The OLE2 data cache supports a whole whack of 23 * interfaces including: 24 * IDataObject, IPersistStorage, IViewObject2, 25 * IOleCache2 and IOleCacheControl. 26 * 27 * Most of the implementation details are taken from: Inside OLE 28 * second edition by Kraig Brockschmidt, 29 * 30 * NOTES 31 * - This implementation of the datacache will let your application 32 * load documents that have embedded OLE objects in them and it will 33 * also retrieve the metafile representation of those objects. 34 * - This implementation of the datacache will also allow your 35 * application to save new documents with OLE objects in them. 36 * - The main thing that it doesn't do is allow you to activate 37 * or modify the OLE objects in any way. 38 * - I haven't found any good documentation on the real usage of 39 * the streams created by the data cache. In particular, How to 40 * determine what the XXX stands for in the stream name 41 * "\002OlePresXXX". It appears to just be a counter. 42 * - Also, I don't know the real content of the presentation stream 43 * header. I was able to figure-out where the extent of the object 44 * was stored and the aspect, but that's about it. 45 */ 46 47 #include <stdarg.h> 48 #include <string.h> 49 50 #define COBJMACROS 51 #define NONAMELESSUNION 52 53 #include "windef.h" 54 #include "winbase.h" 55 #include "wingdi.h" 56 #include "winuser.h" 57 #include "winerror.h" 58 #include "ole2.h" 59 #include "compobj_private.h" 60 #include "wine/unicode.h" 61 #include "wine/list.h" 62 #include "wine/debug.h" 63 64 WINE_DEFAULT_DEBUG_CHANNEL(ole); 65 66 /**************************************************************************** 67 * PresentationDataHeader 68 * 69 * This structure represents the header of the \002OlePresXXX stream in 70 * the OLE object storage. 71 */ 72 typedef struct PresentationDataHeader 73 { 74 /* clipformat: 75 * - standard clipformat: 76 * DWORD length = 0xffffffff; 77 * DWORD cfFormat; 78 * - or custom clipformat: 79 * DWORD length; 80 * CHAR format_name[length]; (null-terminated) 81 */ 82 DWORD tdSize; /* This is actually a truncated DVTARGETDEVICE, if tdSize > sizeof(DWORD) 83 then there are tdSize - sizeof(DWORD) more bytes before dvAspect */ 84 DVASPECT dvAspect; 85 DWORD lindex; 86 DWORD advf; 87 DWORD unknown7; /* 0 */ 88 DWORD dwObjectExtentX; 89 DWORD dwObjectExtentY; 90 DWORD dwSize; 91 } PresentationDataHeader; 92 93 #define STREAM_NUMBER_NOT_SET -2 94 #define STREAM_NUMBER_CONTENTS -1 /* CONTENTS stream */ 95 96 typedef struct DataCacheEntry 97 { 98 struct list entry; 99 /* format of this entry */ 100 FORMATETC fmtetc; 101 /* cached data */ 102 STGMEDIUM stgmedium; 103 /* connection ID */ 104 DWORD id; 105 /* dirty flag */ 106 BOOL dirty; 107 /* stream number that the entry was loaded from. 108 This is used to defer loading until the data is actually needed. */ 109 int load_stream_num; 110 /* stream number that the entry will be saved to. 111 This may differ from above if cache entries have been Uncache()d for example. */ 112 int save_stream_num; 113 /* sink id set when object is running */ 114 DWORD sink_id; 115 /* Advise sink flags */ 116 DWORD advise_flags; 117 } DataCacheEntry; 118 119 /**************************************************************************** 120 * DataCache 121 */ 122 struct DataCache 123 { 124 /* 125 * List all interface here 126 */ 127 IUnknown IUnknown_inner; 128 IDataObject IDataObject_iface; 129 IPersistStorage IPersistStorage_iface; 130 IViewObject2 IViewObject2_iface; 131 IOleCache2 IOleCache2_iface; 132 IOleCacheControl IOleCacheControl_iface; 133 134 /* The sink that is connected to a remote object. 135 The other interfaces are not available by QI'ing the sink and vice-versa */ 136 IAdviseSink IAdviseSink_iface; 137 138 /* 139 * Reference count of this object 140 */ 141 LONG ref; 142 143 /* 144 * IUnknown implementation of the outer object. 145 */ 146 IUnknown *outer_unk; 147 148 /* 149 * The user of this object can setup ONE advise sink 150 * connection with the object. These parameters describe 151 * that connection. 152 */ 153 DWORD sinkAspects; 154 DWORD sinkAdviseFlag; 155 IAdviseSink *sinkInterface; 156 157 CLSID clsid; 158 /* Is the clsid one of the CLSID_Picture classes */ 159 BOOL clsid_static; 160 161 IStorage *presentationStorage; 162 163 /* list of cache entries */ 164 struct list cache_list; 165 /* last id assigned to an entry */ 166 DWORD last_cache_id; 167 /* dirty flag */ 168 BOOL dirty; 169 /* running object set by OnRun */ 170 IDataObject *running_object; 171 }; 172 173 typedef struct DataCache DataCache; 174 175 /* 176 * Here, I define utility macros to help with the casting of the 177 * "this" parameter. 178 * There is a version to accommodate all of the VTables implemented 179 * by this object. 180 */ 181 182 static inline DataCache *impl_from_IDataObject( IDataObject *iface ) 183 { 184 return CONTAINING_RECORD(iface, DataCache, IDataObject_iface); 185 } 186 187 static inline DataCache *impl_from_IUnknown( IUnknown *iface ) 188 { 189 return CONTAINING_RECORD(iface, DataCache, IUnknown_inner); 190 } 191 192 static inline DataCache *impl_from_IPersistStorage( IPersistStorage *iface ) 193 { 194 return CONTAINING_RECORD(iface, DataCache, IPersistStorage_iface); 195 } 196 197 static inline DataCache *impl_from_IViewObject2( IViewObject2 *iface ) 198 { 199 return CONTAINING_RECORD(iface, DataCache, IViewObject2_iface); 200 } 201 202 static inline DataCache *impl_from_IOleCache2( IOleCache2 *iface ) 203 { 204 return CONTAINING_RECORD(iface, DataCache, IOleCache2_iface); 205 } 206 207 static inline DataCache *impl_from_IOleCacheControl( IOleCacheControl *iface ) 208 { 209 return CONTAINING_RECORD(iface, DataCache, IOleCacheControl_iface); 210 } 211 212 static inline DataCache *impl_from_IAdviseSink( IAdviseSink *iface ) 213 { 214 return CONTAINING_RECORD(iface, DataCache, IAdviseSink_iface); 215 } 216 217 const char *debugstr_formatetc(const FORMATETC *formatetc) 218 { 219 return wine_dbg_sprintf("{ cfFormat = 0x%x, ptd = %p, dwAspect = %d, lindex = %d, tymed = %d }", 220 formatetc->cfFormat, formatetc->ptd, formatetc->dwAspect, 221 formatetc->lindex, formatetc->tymed); 222 } 223 224 /*********************************************************************** 225 * bitmap_info_size 226 * 227 * Return the size of the bitmap info structure including color table. 228 */ 229 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse ) 230 { 231 unsigned int colors, size, masks = 0; 232 233 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) 234 { 235 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info; 236 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0; 237 return sizeof(BITMAPCOREHEADER) + colors * 238 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD)); 239 } 240 else /* assume BITMAPINFOHEADER */ 241 { 242 colors = info->bmiHeader.biClrUsed; 243 if (colors > 256) /* buffer overflow otherwise */ 244 colors = 256; 245 if (!colors && (info->bmiHeader.biBitCount <= 8)) 246 colors = 1 << info->bmiHeader.biBitCount; 247 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3; 248 size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) ); 249 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD)); 250 } 251 } 252 253 static void DataCacheEntry_Destroy(DataCache *cache, DataCacheEntry *cache_entry) 254 { 255 list_remove(&cache_entry->entry); 256 CoTaskMemFree(cache_entry->fmtetc.ptd); 257 ReleaseStgMedium(&cache_entry->stgmedium); 258 if(cache_entry->sink_id) 259 IDataObject_DUnadvise(cache->running_object, cache_entry->sink_id); 260 261 HeapFree(GetProcessHeap(), 0, cache_entry); 262 } 263 264 static void DataCache_Destroy( 265 DataCache* ptrToDestroy) 266 { 267 DataCacheEntry *cache_entry, *next_cache_entry; 268 269 TRACE("()\n"); 270 271 if (ptrToDestroy->sinkInterface != NULL) 272 { 273 IAdviseSink_Release(ptrToDestroy->sinkInterface); 274 ptrToDestroy->sinkInterface = NULL; 275 } 276 277 LIST_FOR_EACH_ENTRY_SAFE(cache_entry, next_cache_entry, &ptrToDestroy->cache_list, DataCacheEntry, entry) 278 DataCacheEntry_Destroy(ptrToDestroy, cache_entry); 279 280 if (ptrToDestroy->presentationStorage != NULL) 281 { 282 IStorage_Release(ptrToDestroy->presentationStorage); 283 ptrToDestroy->presentationStorage = NULL; 284 } 285 286 /* 287 * Free the datacache pointer. 288 */ 289 HeapFree(GetProcessHeap(), 0, ptrToDestroy); 290 } 291 292 static DataCacheEntry *DataCache_GetEntryForFormatEtc(DataCache *This, const FORMATETC *formatetc) 293 { 294 DataCacheEntry *cache_entry; 295 FORMATETC fmt = *formatetc; 296 297 if (fmt.cfFormat == CF_BITMAP) 298 { 299 fmt.cfFormat = CF_DIB; 300 fmt.tymed = TYMED_HGLOBAL; 301 } 302 303 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 304 { 305 /* FIXME: also compare DVTARGETDEVICEs */ 306 if ((fmt.cfFormat == cache_entry->fmtetc.cfFormat) && 307 (fmt.dwAspect == cache_entry->fmtetc.dwAspect) && 308 (fmt.lindex == cache_entry->fmtetc.lindex) && 309 ((fmt.tymed == cache_entry->fmtetc.tymed) || !cache_entry->fmtetc.cfFormat)) /* tymed is ignored for view caching */ 310 return cache_entry; 311 } 312 return NULL; 313 } 314 315 /* Returns the cache entry associated with a static CLSID. 316 This will be first in the list with connection id == 1 */ 317 static HRESULT get_static_entry( DataCache *cache, DataCacheEntry **cache_entry ) 318 { 319 DataCacheEntry *entry; 320 struct list *head = list_head( &cache->cache_list ); 321 HRESULT hr = E_FAIL; 322 323 *cache_entry = NULL; 324 325 if (head) 326 { 327 entry = LIST_ENTRY( head, DataCacheEntry, entry ); 328 if (entry->id == 1) 329 { 330 *cache_entry = entry; 331 hr = S_OK; 332 } 333 } 334 335 return hr; 336 } 337 338 /* checks that the clipformat and tymed are valid and returns an error if they 339 * aren't and CACHE_S_NOTSUPPORTED if they are valid, but can't be rendered by 340 * DataCache_Draw */ 341 static HRESULT check_valid_formatetc( const FORMATETC *fmt ) 342 { 343 /* DVASPECT_ICON must be CF_METAFILEPICT */ 344 if (fmt->dwAspect == DVASPECT_ICON && fmt->cfFormat != CF_METAFILEPICT) 345 return DV_E_FORMATETC; 346 347 if (!fmt->cfFormat || 348 (fmt->cfFormat == CF_METAFILEPICT && fmt->tymed == TYMED_MFPICT) || 349 (fmt->cfFormat == CF_BITMAP && fmt->tymed == TYMED_GDI) || 350 (fmt->cfFormat == CF_DIB && fmt->tymed == TYMED_HGLOBAL) || 351 (fmt->cfFormat == CF_ENHMETAFILE && fmt->tymed == TYMED_ENHMF)) 352 return S_OK; 353 else if (fmt->tymed == TYMED_HGLOBAL) 354 return CACHE_S_FORMATETC_NOTSUPPORTED; 355 else 356 { 357 WARN("invalid clipformat/tymed combination: %d/%d\n", fmt->cfFormat, fmt->tymed); 358 return DV_E_TYMED; 359 } 360 } 361 362 static BOOL init_cache_entry(DataCacheEntry *entry, const FORMATETC *fmt, DWORD advf, 363 DWORD id) 364 { 365 HRESULT hr; 366 367 hr = copy_formatetc(&entry->fmtetc, fmt); 368 if (FAILED(hr)) return FALSE; 369 370 entry->stgmedium.tymed = TYMED_NULL; 371 entry->stgmedium.pUnkForRelease = NULL; 372 entry->id = id; 373 entry->dirty = TRUE; 374 entry->load_stream_num = STREAM_NUMBER_NOT_SET; 375 entry->save_stream_num = STREAM_NUMBER_NOT_SET; 376 entry->sink_id = 0; 377 entry->advise_flags = advf; 378 379 return TRUE; 380 } 381 382 static HRESULT DataCache_CreateEntry(DataCache *This, const FORMATETC *formatetc, DWORD advf, 383 BOOL automatic, DataCacheEntry **cache_entry) 384 { 385 HRESULT hr; 386 DWORD id = automatic ? 1 : This->last_cache_id; 387 DataCacheEntry *entry; 388 389 hr = check_valid_formatetc( formatetc ); 390 if (FAILED(hr)) 391 return hr; 392 if (hr == CACHE_S_FORMATETC_NOTSUPPORTED) 393 TRACE("creating unsupported format %d\n", formatetc->cfFormat); 394 395 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry)); 396 if (!entry) 397 return E_OUTOFMEMORY; 398 399 if (!init_cache_entry(entry, formatetc, advf, id)) 400 goto fail; 401 402 if (automatic) 403 list_add_head(&This->cache_list, &entry->entry); 404 else 405 { 406 list_add_tail(&This->cache_list, &entry->entry); 407 This->last_cache_id++; 408 } 409 410 if (cache_entry) *cache_entry = entry; 411 return hr; 412 413 fail: 414 HeapFree(GetProcessHeap(), 0, entry); 415 return E_OUTOFMEMORY; 416 } 417 418 /************************************************************************ 419 * DataCache_FireOnViewChange 420 * 421 * This method will fire an OnViewChange notification to the advise 422 * sink registered with the datacache. 423 * 424 * See IAdviseSink::OnViewChange for more details. 425 */ 426 static void DataCache_FireOnViewChange( 427 DataCache* this, 428 DWORD aspect, 429 LONG lindex) 430 { 431 TRACE("(%p, %x, %d)\n", this, aspect, lindex); 432 433 /* 434 * The sink supplies a filter when it registers 435 * we make sure we only send the notifications when that 436 * filter matches. 437 */ 438 if ((this->sinkAspects & aspect) != 0) 439 { 440 if (this->sinkInterface != NULL) 441 { 442 IAdviseSink_OnViewChange(this->sinkInterface, 443 aspect, 444 lindex); 445 446 /* 447 * Some sinks want to be unregistered automatically when 448 * the first notification goes out. 449 */ 450 if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0) 451 { 452 IAdviseSink_Release(this->sinkInterface); 453 454 this->sinkInterface = NULL; 455 this->sinkAspects = 0; 456 this->sinkAdviseFlag = 0; 457 } 458 } 459 } 460 } 461 462 static HRESULT read_clipformat(IStream *stream, CLIPFORMAT *clipformat) 463 { 464 DWORD length; 465 HRESULT hr; 466 ULONG read; 467 468 *clipformat = 0; 469 470 hr = IStream_Read(stream, &length, sizeof(length), &read); 471 if (hr != S_OK || read != sizeof(length)) 472 return DV_E_CLIPFORMAT; 473 if (!length) { 474 /* No clipboard format present */ 475 return S_OK; 476 } 477 if (length == -1) 478 { 479 DWORD cf; 480 hr = IStream_Read(stream, &cf, sizeof(cf), &read); 481 if (hr != S_OK || read != sizeof(cf)) 482 return DV_E_CLIPFORMAT; 483 *clipformat = cf; 484 } 485 else 486 { 487 char *format_name = HeapAlloc(GetProcessHeap(), 0, length); 488 if (!format_name) 489 return E_OUTOFMEMORY; 490 hr = IStream_Read(stream, format_name, length, &read); 491 if (hr != S_OK || read != length || format_name[length - 1] != '\0') 492 { 493 HeapFree(GetProcessHeap(), 0, format_name); 494 return DV_E_CLIPFORMAT; 495 } 496 *clipformat = RegisterClipboardFormatA(format_name); 497 HeapFree(GetProcessHeap(), 0, format_name); 498 } 499 return S_OK; 500 } 501 502 static HRESULT write_clipformat(IStream *stream, CLIPFORMAT clipformat) 503 { 504 DWORD length; 505 HRESULT hr; 506 char format_name[256]; 507 508 if (clipformat == 0) 509 length = 0; 510 else if (clipformat < 0xc000) 511 length = -1; 512 else 513 { 514 length = GetClipboardFormatNameA(clipformat, format_name, sizeof(format_name)); 515 /* If there is a clipboard format name, we need to include its terminating \0 */ 516 if (length) length++; 517 } 518 hr = IStream_Write(stream, &length, sizeof(length), NULL); 519 if (FAILED(hr) || clipformat == 0) 520 return hr; 521 522 if (clipformat < 0xc000) 523 { 524 DWORD cf = clipformat; 525 hr = IStream_Write(stream, &cf, sizeof(cf), NULL); 526 } 527 else 528 { 529 hr = IStream_Write(stream, format_name, length, NULL); 530 } 531 return hr; 532 } 533 534 static const WCHAR CONTENTS[] = {'C','O','N','T','E','N','T','S',0}; 535 536 static HRESULT open_pres_stream( IStorage *stg, int stream_number, IStream **stm ) 537 { 538 WCHAR pres[] = {2,'O','l','e','P','r','e','s', 539 '0' + (stream_number / 100) % 10, 540 '0' + (stream_number / 10) % 10, 541 '0' + stream_number % 10, 0}; 542 const WCHAR *name = pres; 543 544 if (stream_number == STREAM_NUMBER_NOT_SET) return E_FAIL; 545 if (stream_number == STREAM_NUMBER_CONTENTS) name = CONTENTS; 546 547 return IStorage_OpenStream( stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm ); 548 } 549 550 static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm ) 551 { 552 HRESULT hr; 553 STATSTG stat; 554 ULARGE_INTEGER current_pos; 555 void *bits; 556 METAFILEPICT *mfpict; 557 HGLOBAL hmfpict; 558 PresentationDataHeader header; 559 CLIPFORMAT clipformat; 560 static const LARGE_INTEGER offset_zero; 561 ULONG read; 562 563 if (cache_entry->load_stream_num == STREAM_NUMBER_CONTENTS) 564 { 565 FIXME( "Unimplemented for CONTENTS stream\n" ); 566 return E_FAIL; 567 } 568 569 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME ); 570 if (FAILED( hr )) return hr; 571 572 hr = read_clipformat( stm, &clipformat ); 573 if (FAILED( hr )) return hr; 574 575 hr = IStream_Read( stm, &header, sizeof(header), &read ); 576 if (hr != S_OK || read != sizeof(header)) return E_FAIL; 577 578 hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, ¤t_pos ); 579 if (FAILED( hr )) return hr; 580 581 stat.cbSize.QuadPart -= current_pos.QuadPart; 582 583 hmfpict = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) ); 584 if (!hmfpict) return E_OUTOFMEMORY; 585 mfpict = GlobalLock( hmfpict ); 586 587 bits = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart); 588 if (!bits) 589 { 590 GlobalFree( hmfpict ); 591 return E_OUTOFMEMORY; 592 } 593 594 hr = IStream_Read( stm, bits, stat.cbSize.u.LowPart, &read ); 595 if (hr != S_OK || read != stat.cbSize.u.LowPart) hr = E_FAIL; 596 597 if (SUCCEEDED( hr )) 598 { 599 /* FIXME: get this from the stream */ 600 mfpict->mm = MM_ANISOTROPIC; 601 mfpict->xExt = header.dwObjectExtentX; 602 mfpict->yExt = header.dwObjectExtentY; 603 mfpict->hMF = SetMetaFileBitsEx( stat.cbSize.u.LowPart, bits ); 604 if (!mfpict->hMF) 605 hr = E_FAIL; 606 } 607 608 GlobalUnlock( hmfpict ); 609 if (SUCCEEDED( hr )) 610 { 611 cache_entry->stgmedium.tymed = TYMED_MFPICT; 612 cache_entry->stgmedium.u.hMetaFilePict = hmfpict; 613 } 614 else 615 GlobalFree( hmfpict ); 616 617 HeapFree( GetProcessHeap(), 0, bits ); 618 619 return hr; 620 } 621 622 static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm ) 623 { 624 HRESULT hr; 625 STATSTG stat; 626 void *dib; 627 HGLOBAL hglobal; 628 ULONG read, info_size, bi_size; 629 BITMAPFILEHEADER file; 630 BITMAPINFOHEADER *info; 631 632 if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS) 633 { 634 FIXME( "Unimplemented for presentation stream\n" ); 635 return E_FAIL; 636 } 637 638 hr = IStream_Stat( stm, &stat, STATFLAG_NONAME ); 639 if (FAILED( hr )) return hr; 640 641 if (stat.cbSize.QuadPart < sizeof(file) + sizeof(DWORD)) return E_FAIL; 642 hr = IStream_Read( stm, &file, sizeof(file), &read ); 643 if (hr != S_OK || read != sizeof(file)) return E_FAIL; 644 stat.cbSize.QuadPart -= sizeof(file); 645 646 hglobal = GlobalAlloc( GMEM_MOVEABLE, stat.cbSize.u.LowPart ); 647 if (!hglobal) return E_OUTOFMEMORY; 648 dib = GlobalLock( hglobal ); 649 650 hr = IStream_Read( stm, dib, sizeof(DWORD), &read ); 651 if (hr != S_OK || read != sizeof(DWORD)) goto fail; 652 bi_size = *(DWORD *)dib; 653 if (stat.cbSize.QuadPart < bi_size) goto fail; 654 655 hr = IStream_Read( stm, (char *)dib + sizeof(DWORD), bi_size - sizeof(DWORD), &read ); 656 if (hr != S_OK || read != bi_size - sizeof(DWORD)) goto fail; 657 658 info_size = bitmap_info_size( dib, DIB_RGB_COLORS ); 659 if (stat.cbSize.QuadPart < info_size) goto fail; 660 if (info_size > bi_size) 661 { 662 hr = IStream_Read( stm, (char *)dib + bi_size, info_size - bi_size, &read ); 663 if (hr != S_OK || read != info_size - bi_size) goto fail; 664 } 665 stat.cbSize.QuadPart -= info_size; 666 667 if (file.bfOffBits) 668 { 669 LARGE_INTEGER skip; 670 671 skip.QuadPart = file.bfOffBits - sizeof(file) - info_size; 672 if (stat.cbSize.QuadPart < skip.QuadPart) goto fail; 673 hr = IStream_Seek( stm, skip, STREAM_SEEK_CUR, NULL ); 674 if (hr != S_OK) goto fail; 675 stat.cbSize.QuadPart -= skip.QuadPart; 676 } 677 678 hr = IStream_Read( stm, (char *)dib + info_size, stat.cbSize.u.LowPart, &read ); 679 if (hr != S_OK || read != stat.cbSize.QuadPart) goto fail; 680 681 if (bi_size >= sizeof(*info)) 682 { 683 info = (BITMAPINFOHEADER *)dib; 684 if (info->biXPelsPerMeter == 0 || info->biYPelsPerMeter == 0) 685 { 686 HDC hdc = GetDC( 0 ); 687 info->biXPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSX ), 10000, 254 ); 688 info->biYPelsPerMeter = MulDiv( GetDeviceCaps( hdc, LOGPIXELSY ), 10000, 254 ); 689 ReleaseDC( 0, hdc ); 690 } 691 } 692 693 GlobalUnlock( hglobal ); 694 695 cache_entry->stgmedium.tymed = TYMED_HGLOBAL; 696 cache_entry->stgmedium.u.hGlobal = hglobal; 697 698 return S_OK; 699 700 fail: 701 GlobalUnlock( hglobal ); 702 GlobalFree( hglobal ); 703 return E_FAIL; 704 705 } 706 707 /************************************************************************ 708 * DataCacheEntry_LoadData 709 * 710 * This method will read information for the requested presentation 711 * into the given structure. 712 * 713 * Param: 714 * This - The entry to load the data from. 715 * 716 * Returns: 717 * This method returns a metafile handle if it is successful. 718 * it will return 0 if not. 719 */ 720 static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry, IStorage *stg) 721 { 722 HRESULT hr; 723 IStream *stm; 724 725 if (!stg) return OLE_E_BLANK; 726 hr = open_pres_stream( stg, cache_entry->load_stream_num, &stm ); 727 if (FAILED(hr)) return hr; 728 729 switch (cache_entry->fmtetc.cfFormat) 730 { 731 case CF_METAFILEPICT: 732 hr = load_mf_pict( cache_entry, stm ); 733 break; 734 735 case CF_DIB: 736 hr = load_dib( cache_entry, stm ); 737 break; 738 739 default: 740 FIXME( "Unimplemented clip format %x\n", cache_entry->fmtetc.cfFormat ); 741 hr = E_NOTIMPL; 742 } 743 744 IStream_Release( stm ); 745 return hr; 746 } 747 748 static void init_stream_header(DataCacheEntry *entry, PresentationDataHeader *header) 749 { 750 if (entry->fmtetc.ptd) 751 FIXME("ptd not serialized\n"); 752 header->tdSize = sizeof(header->tdSize); 753 header->dvAspect = entry->fmtetc.dwAspect; 754 header->lindex = entry->fmtetc.lindex; 755 header->advf = entry->advise_flags; 756 header->unknown7 = 0; 757 header->dwObjectExtentX = 0; 758 header->dwObjectExtentY = 0; 759 header->dwSize = 0; 760 } 761 762 static HRESULT save_dib(DataCacheEntry *entry, BOOL contents, IStream *stream) 763 { 764 HRESULT hr = S_OK; 765 int data_size = 0; 766 BITMAPINFO *bmi = NULL; 767 768 if (entry->stgmedium.tymed != TYMED_NULL) 769 { 770 data_size = GlobalSize(entry->stgmedium.u.hGlobal); 771 bmi = GlobalLock(entry->stgmedium.u.hGlobal); 772 } 773 774 if (!contents) 775 { 776 PresentationDataHeader header; 777 778 init_stream_header(entry, &header); 779 hr = write_clipformat(stream, entry->fmtetc.cfFormat); 780 if (FAILED(hr)) goto end; 781 if (data_size) 782 { 783 header.dwSize = data_size; 784 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */ 785 if (bmi->bmiHeader.biXPelsPerMeter != 0 && bmi->bmiHeader.biYPelsPerMeter != 0) 786 { 787 header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 100000, bmi->bmiHeader.biXPelsPerMeter); 788 header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 100000, bmi->bmiHeader.biYPelsPerMeter); 789 } 790 else 791 { 792 HDC hdc = GetDC(0); 793 header.dwObjectExtentX = MulDiv(bmi->bmiHeader.biWidth, 2540, GetDeviceCaps(hdc, LOGPIXELSX)); 794 header.dwObjectExtentY = MulDiv(bmi->bmiHeader.biHeight, 2540, GetDeviceCaps(hdc, LOGPIXELSY)); 795 ReleaseDC(0, hdc); 796 } 797 } 798 hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL); 799 if (hr == S_OK && data_size) 800 hr = IStream_Write(stream, bmi, data_size, NULL); 801 } 802 else if(data_size) 803 { 804 BITMAPFILEHEADER bmp_fhdr; 805 806 bmp_fhdr.bfType = 0x4d42; 807 bmp_fhdr.bfSize = data_size + sizeof(BITMAPFILEHEADER); 808 bmp_fhdr.bfReserved1 = bmp_fhdr.bfReserved2 = 0; 809 bmp_fhdr.bfOffBits = bitmap_info_size(bmi, DIB_RGB_COLORS) + sizeof(BITMAPFILEHEADER); 810 hr = IStream_Write(stream, &bmp_fhdr, sizeof(BITMAPFILEHEADER), NULL); 811 if (hr == S_OK) 812 hr = IStream_Write(stream, bmi, data_size, NULL); 813 } 814 815 end: 816 if (bmi) GlobalUnlock(entry->stgmedium.u.hGlobal); 817 return hr; 818 } 819 820 #include <pshpack2.h> 821 struct meta_placeable 822 { 823 DWORD key; 824 WORD hwmf; 825 WORD bounding_box[4]; 826 WORD inch; 827 DWORD reserved; 828 WORD checksum; 829 }; 830 #include <poppack.h> 831 832 static HRESULT save_mfpict(DataCacheEntry *entry, BOOL contents, IStream *stream) 833 { 834 HRESULT hr = S_OK; 835 int data_size = 0; 836 void *data = NULL; 837 METAFILEPICT *mfpict = NULL; 838 839 if (!contents) 840 { 841 PresentationDataHeader header; 842 843 init_stream_header(entry, &header); 844 hr = write_clipformat(stream, entry->fmtetc.cfFormat); 845 if (FAILED(hr)) return hr; 846 if (entry->stgmedium.tymed != TYMED_NULL) 847 { 848 mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict); 849 if (!mfpict) 850 return DV_E_STGMEDIUM; 851 data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL); 852 header.dwObjectExtentX = mfpict->xExt; 853 header.dwObjectExtentY = mfpict->yExt; 854 header.dwSize = data_size; 855 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize); 856 if (!data) 857 { 858 GlobalUnlock(entry->stgmedium.u.hMetaFilePict); 859 return E_OUTOFMEMORY; 860 } 861 GetMetaFileBitsEx(mfpict->hMF, header.dwSize, data); 862 GlobalUnlock(entry->stgmedium.u.hMetaFilePict); 863 } 864 hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL); 865 if (hr == S_OK && data_size) 866 hr = IStream_Write(stream, data, data_size, NULL); 867 HeapFree(GetProcessHeap(), 0, data); 868 } 869 else if (entry->stgmedium.tymed != TYMED_NULL) 870 { 871 struct meta_placeable meta_place_rec; 872 WORD *check; 873 874 mfpict = GlobalLock(entry->stgmedium.u.hMetaFilePict); 875 if (!mfpict) 876 return DV_E_STGMEDIUM; 877 data_size = GetMetaFileBitsEx(mfpict->hMF, 0, NULL); 878 data = HeapAlloc(GetProcessHeap(), 0, data_size); 879 if (!data) 880 { 881 GlobalUnlock(entry->stgmedium.u.hMetaFilePict); 882 return E_OUTOFMEMORY; 883 } 884 GetMetaFileBitsEx(mfpict->hMF, data_size, data); 885 886 /* units are in 1/8th of a point (1 point is 1/72th of an inch) */ 887 meta_place_rec.key = 0x9ac6cdd7; 888 meta_place_rec.hwmf = 0; 889 meta_place_rec.inch = 576; 890 meta_place_rec.bounding_box[0] = 0; 891 meta_place_rec.bounding_box[1] = 0; 892 meta_place_rec.bounding_box[2] = 0; 893 meta_place_rec.bounding_box[3] = 0; 894 meta_place_rec.checksum = 0; 895 meta_place_rec.reserved = 0; 896 897 /* These values are rounded down so MulDiv won't do the right thing */ 898 meta_place_rec.bounding_box[2] = (LONGLONG)mfpict->xExt * meta_place_rec.inch / 2540; 899 meta_place_rec.bounding_box[3] = (LONGLONG)mfpict->yExt * meta_place_rec.inch / 2540; 900 GlobalUnlock(entry->stgmedium.u.hMetaFilePict); 901 902 for (check = (WORD *)&meta_place_rec; check != (WORD *)&meta_place_rec.checksum; check++) 903 meta_place_rec.checksum ^= *check; 904 hr = IStream_Write(stream, &meta_place_rec, sizeof(struct meta_placeable), NULL); 905 if (hr == S_OK && data_size) 906 hr = IStream_Write(stream, data, data_size, NULL); 907 HeapFree(GetProcessHeap(), 0, data); 908 } 909 910 return hr; 911 } 912 913 static HRESULT save_emf(DataCacheEntry *entry, BOOL contents, IStream *stream) 914 { 915 HRESULT hr = S_OK; 916 int data_size = 0; 917 BYTE *data; 918 919 if (!contents) 920 { 921 PresentationDataHeader header; 922 METAFILEPICT *mfpict; 923 HDC hdc = GetDC(0); 924 925 init_stream_header(entry, &header); 926 hr = write_clipformat(stream, entry->fmtetc.cfFormat); 927 if (FAILED(hr)) 928 { 929 ReleaseDC(0, hdc); 930 return hr; 931 } 932 data_size = GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL, MM_ANISOTROPIC, hdc); 933 header.dwSize = data_size; 934 data = HeapAlloc(GetProcessHeap(), 0, header.dwSize); 935 if (!data) 936 { 937 ReleaseDC(0, hdc); 938 return E_OUTOFMEMORY; 939 } 940 GetWinMetaFileBits(entry->stgmedium.u.hEnhMetaFile, header.dwSize, data, MM_ANISOTROPIC, hdc); 941 ReleaseDC(0, hdc); 942 mfpict = (METAFILEPICT *)data; 943 header.dwObjectExtentX = mfpict->xExt; 944 header.dwObjectExtentY = mfpict->yExt; 945 hr = IStream_Write(stream, &header, sizeof(PresentationDataHeader), NULL); 946 if (hr == S_OK && data_size) 947 hr = IStream_Write(stream, data, data_size, NULL); 948 HeapFree(GetProcessHeap(), 0, data); 949 } 950 else if (entry->stgmedium.tymed != TYMED_NULL) 951 { 952 data_size = GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, 0, NULL); 953 data = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) + sizeof(ENHMETAHEADER) + data_size); 954 if (!data) return E_OUTOFMEMORY; 955 *((DWORD *)data) = sizeof(ENHMETAHEADER); 956 GetEnhMetaFileBits(entry->stgmedium.u.hEnhMetaFile, data_size, data + sizeof(DWORD) + sizeof(ENHMETAHEADER)); 957 memcpy(data + sizeof(DWORD), data + sizeof(DWORD) + sizeof(ENHMETAHEADER), sizeof(ENHMETAHEADER)); 958 data_size += sizeof(DWORD) + sizeof(ENHMETAHEADER); 959 hr = IStream_Write(stream, data, data_size, NULL); 960 HeapFree(GetProcessHeap(), 0, data); 961 } 962 963 return hr; 964 } 965 966 static HRESULT save_view_cache(DataCacheEntry *entry, IStream *stream) 967 { 968 HRESULT hr; 969 PresentationDataHeader header; 970 971 init_stream_header(entry, &header); 972 hr = write_clipformat(stream, entry->fmtetc.cfFormat); 973 if (SUCCEEDED(hr)) 974 hr = IStream_Write(stream, &header, FIELD_OFFSET(PresentationDataHeader, unknown7), NULL); 975 976 return hr; 977 } 978 979 static HRESULT create_stream(DataCacheEntry *cache_entry, IStorage *storage, 980 BOOL contents, IStream **stream) 981 { 982 WCHAR pres[] = {2,'O','l','e','P','r','e','s', 983 '0' + (cache_entry->save_stream_num / 100) % 10, 984 '0' + (cache_entry->save_stream_num / 10) % 10, 985 '0' + cache_entry->save_stream_num % 10, 0}; 986 const WCHAR *name; 987 988 if (contents) 989 name = CONTENTS; 990 else 991 name = pres; 992 993 return IStorage_CreateStream(storage, name, 994 STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, 995 0, 0, stream); 996 } 997 998 static HRESULT DataCacheEntry_Save(DataCacheEntry *cache_entry, IStorage *storage, 999 BOOL same_as_load) 1000 { 1001 HRESULT hr; 1002 IStream *stream; 1003 BOOL contents = (cache_entry->id == 1); 1004 1005 TRACE("stream_number = %d, fmtetc = %s\n", cache_entry->save_stream_num, debugstr_formatetc(&cache_entry->fmtetc)); 1006 1007 hr = create_stream(cache_entry, storage, contents, &stream); 1008 if (FAILED(hr)) 1009 return hr; 1010 1011 switch (cache_entry->fmtetc.cfFormat) 1012 { 1013 case CF_DIB: 1014 hr = save_dib(cache_entry, contents, stream); 1015 break; 1016 case CF_METAFILEPICT: 1017 hr = save_mfpict(cache_entry, contents, stream); 1018 break; 1019 case CF_ENHMETAFILE: 1020 hr = save_emf(cache_entry, contents, stream); 1021 break; 1022 case 0: 1023 hr = save_view_cache(cache_entry, stream); 1024 break; 1025 default: 1026 FIXME("got unsupported clipboard format %x\n", cache_entry->fmtetc.cfFormat); 1027 } 1028 1029 IStream_Release(stream); 1030 return hr; 1031 } 1032 1033 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL. 1034 * does no checking of whether src_stgm has a supported tymed, so this should be 1035 * done in the caller */ 1036 static HRESULT copy_stg_medium(CLIPFORMAT cf, STGMEDIUM *dest_stgm, 1037 const STGMEDIUM *src_stgm) 1038 { 1039 if (src_stgm->tymed == TYMED_MFPICT) 1040 { 1041 const METAFILEPICT *src_mfpict = GlobalLock(src_stgm->u.hMetaFilePict); 1042 METAFILEPICT *dest_mfpict; 1043 1044 if (!src_mfpict) 1045 return DV_E_STGMEDIUM; 1046 dest_stgm->u.hMetaFilePict = GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT)); 1047 dest_mfpict = GlobalLock(dest_stgm->u.hMetaFilePict); 1048 if (!dest_mfpict) 1049 { 1050 GlobalUnlock(src_stgm->u.hMetaFilePict); 1051 return E_OUTOFMEMORY; 1052 } 1053 *dest_mfpict = *src_mfpict; 1054 dest_mfpict->hMF = CopyMetaFileW(src_mfpict->hMF, NULL); 1055 GlobalUnlock(src_stgm->u.hMetaFilePict); 1056 GlobalUnlock(dest_stgm->u.hMetaFilePict); 1057 } 1058 else if (src_stgm->tymed != TYMED_NULL) 1059 { 1060 dest_stgm->u.hGlobal = OleDuplicateData(src_stgm->u.hGlobal, cf, 1061 GMEM_MOVEABLE); 1062 if (!dest_stgm->u.hGlobal) 1063 return E_OUTOFMEMORY; 1064 } 1065 dest_stgm->tymed = src_stgm->tymed; 1066 dest_stgm->pUnkForRelease = src_stgm->pUnkForRelease; 1067 if (dest_stgm->pUnkForRelease) 1068 IUnknown_AddRef(dest_stgm->pUnkForRelease); 1069 return S_OK; 1070 } 1071 1072 static HRESULT synthesize_dib( HBITMAP bm, STGMEDIUM *med ) 1073 { 1074 HDC hdc = GetDC( 0 ); 1075 BITMAPINFOHEADER header; 1076 BITMAPINFO *bmi; 1077 HRESULT hr = E_FAIL; 1078 DWORD header_size; 1079 1080 memset( &header, 0, sizeof(header) ); 1081 header.biSize = sizeof(header); 1082 if (!GetDIBits( hdc, bm, 0, 0, NULL, (BITMAPINFO *)&header, DIB_RGB_COLORS )) goto done; 1083 1084 header_size = bitmap_info_size( (BITMAPINFO *)&header, DIB_RGB_COLORS ); 1085 if (!(med->u.hGlobal = GlobalAlloc( GMEM_MOVEABLE, header_size + header.biSizeImage ))) goto done; 1086 bmi = GlobalLock( med->u.hGlobal ); 1087 memset( bmi, 0, header_size ); 1088 memcpy( bmi, &header, header.biSize ); 1089 GetDIBits( hdc, bm, 0, abs(header.biHeight), (char *)bmi + header_size, bmi, DIB_RGB_COLORS ); 1090 GlobalUnlock( med->u.hGlobal ); 1091 med->tymed = TYMED_HGLOBAL; 1092 med->pUnkForRelease = NULL; 1093 hr = S_OK; 1094 1095 done: 1096 ReleaseDC( 0, hdc ); 1097 return hr; 1098 } 1099 1100 static HRESULT synthesize_bitmap( HGLOBAL dib, STGMEDIUM *med ) 1101 { 1102 HRESULT hr = E_FAIL; 1103 BITMAPINFO *bmi; 1104 HDC hdc = GetDC( 0 ); 1105 1106 if ((bmi = GlobalLock( dib ))) 1107 { 1108 /* FIXME: validate data size */ 1109 med->u.hBitmap = CreateDIBitmap( hdc, &bmi->bmiHeader, CBM_INIT, 1110 (char *)bmi + bitmap_info_size( bmi, DIB_RGB_COLORS ), 1111 bmi, DIB_RGB_COLORS ); 1112 GlobalUnlock( dib ); 1113 med->tymed = TYMED_GDI; 1114 med->pUnkForRelease = NULL; 1115 hr = S_OK; 1116 } 1117 ReleaseDC( 0, hdc ); 1118 return hr; 1119 } 1120 1121 static HRESULT synthesize_emf( HMETAFILEPICT data, STGMEDIUM *med ) 1122 { 1123 METAFILEPICT *pict; 1124 HRESULT hr = E_FAIL; 1125 UINT size; 1126 void *bits; 1127 1128 if (!(pict = GlobalLock( data ))) return hr; 1129 1130 size = GetMetaFileBitsEx( pict->hMF, 0, NULL ); 1131 if ((bits = HeapAlloc( GetProcessHeap(), 0, size ))) 1132 { 1133 GetMetaFileBitsEx( pict->hMF, size, bits ); 1134 med->u.hEnhMetaFile = SetWinMetaFileBits( size, bits, NULL, pict ); 1135 HeapFree( GetProcessHeap(), 0, bits ); 1136 med->tymed = TYMED_ENHMF; 1137 med->pUnkForRelease = NULL; 1138 hr = S_OK; 1139 } 1140 1141 GlobalUnlock( data ); 1142 return hr; 1143 } 1144 1145 static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry, 1146 const FORMATETC *formatetc, 1147 STGMEDIUM *stgmedium, 1148 BOOL fRelease) 1149 { 1150 STGMEDIUM copy; 1151 HRESULT hr; 1152 1153 if ((!cache_entry->fmtetc.cfFormat && !formatetc->cfFormat) || 1154 (cache_entry->fmtetc.tymed == TYMED_NULL && formatetc->tymed == TYMED_NULL) || 1155 stgmedium->tymed == TYMED_NULL) 1156 { 1157 WARN("invalid formatetc\n"); 1158 return DV_E_FORMATETC; 1159 } 1160 1161 cache_entry->dirty = TRUE; 1162 ReleaseStgMedium(&cache_entry->stgmedium); 1163 1164 if (formatetc->cfFormat == CF_BITMAP) 1165 { 1166 hr = synthesize_dib( stgmedium->u.hBitmap, © ); 1167 if (FAILED(hr)) return hr; 1168 if (fRelease) ReleaseStgMedium(stgmedium); 1169 stgmedium = © 1170 fRelease = TRUE; 1171 } 1172 else if (formatetc->cfFormat == CF_METAFILEPICT && cache_entry->fmtetc.cfFormat == CF_ENHMETAFILE) 1173 { 1174 hr = synthesize_emf( stgmedium->u.hMetaFilePict, © ); 1175 if (FAILED(hr)) return hr; 1176 if (fRelease) ReleaseStgMedium(stgmedium); 1177 stgmedium = © 1178 fRelease = TRUE; 1179 } 1180 1181 if (fRelease) 1182 { 1183 cache_entry->stgmedium = *stgmedium; 1184 return S_OK; 1185 } 1186 else 1187 return copy_stg_medium(cache_entry->fmtetc.cfFormat, &cache_entry->stgmedium, stgmedium); 1188 } 1189 1190 static HRESULT DataCacheEntry_GetData(DataCacheEntry *cache_entry, IStorage *stg, FORMATETC *fmt, STGMEDIUM *stgmedium) 1191 { 1192 if (cache_entry->stgmedium.tymed == TYMED_NULL && cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET) 1193 { 1194 HRESULT hr = DataCacheEntry_LoadData(cache_entry, stg); 1195 if (FAILED(hr)) 1196 return hr; 1197 } 1198 if (cache_entry->stgmedium.tymed == TYMED_NULL) 1199 return OLE_E_BLANK; 1200 1201 if (fmt->cfFormat == CF_BITMAP) 1202 return synthesize_bitmap( cache_entry->stgmedium.u.hGlobal, stgmedium ); 1203 1204 return copy_stg_medium(cache_entry->fmtetc.cfFormat, stgmedium, &cache_entry->stgmedium); 1205 } 1206 1207 static inline HRESULT DataCacheEntry_DiscardData(DataCacheEntry *cache_entry) 1208 { 1209 ReleaseStgMedium(&cache_entry->stgmedium); 1210 return S_OK; 1211 } 1212 1213 static inline DWORD tymed_from_cf( DWORD cf ) 1214 { 1215 switch( cf ) 1216 { 1217 case CF_BITMAP: return TYMED_GDI; 1218 case CF_METAFILEPICT: return TYMED_MFPICT; 1219 case CF_ENHMETAFILE: return TYMED_ENHMF; 1220 case CF_DIB: 1221 default: return TYMED_HGLOBAL; 1222 } 1223 } 1224 1225 /**************************************************************** 1226 * create_automatic_entry 1227 * 1228 * Creates an appropriate cache entry for one of the CLSID_Picture_ 1229 * classes. The connection id of the entry is one. Any pre-existing 1230 * automatic entry is re-assigned a new connection id, and moved to 1231 * the end of the list. 1232 */ 1233 static HRESULT create_automatic_entry(DataCache *cache, const CLSID *clsid) 1234 { 1235 static const struct data 1236 { 1237 const CLSID *clsid; 1238 FORMATETC fmt; 1239 } data[] = 1240 { 1241 { &CLSID_Picture_Dib, { CF_DIB, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL } }, 1242 { &CLSID_Picture_Metafile, { CF_METAFILEPICT, 0, DVASPECT_CONTENT, -1, TYMED_MFPICT } }, 1243 { &CLSID_Picture_EnhMetafile, { CF_ENHMETAFILE, 0, DVASPECT_CONTENT, -1, TYMED_ENHMF } }, 1244 { NULL } 1245 }; 1246 const struct data *ptr = data; 1247 struct list *head; 1248 DataCacheEntry *entry; 1249 1250 if (IsEqualCLSID( &cache->clsid, clsid )) return S_OK; 1251 1252 /* move and reassign any pre-existing automatic entry */ 1253 if ((head = list_head( &cache->cache_list ))) 1254 { 1255 entry = LIST_ENTRY( head, DataCacheEntry, entry ); 1256 if (entry->id == 1) 1257 { 1258 list_remove( &entry->entry ); 1259 entry->id = cache->last_cache_id++; 1260 list_add_tail( &cache->cache_list, &entry->entry ); 1261 } 1262 } 1263 1264 while (ptr->clsid) 1265 { 1266 if (IsEqualCLSID( clsid, ptr->clsid )) 1267 { 1268 cache->clsid_static = TRUE; 1269 return DataCache_CreateEntry( cache, &ptr->fmt, 0, TRUE, NULL ); 1270 } 1271 ptr++; 1272 } 1273 cache->clsid_static = FALSE; 1274 return S_OK; 1275 } 1276 1277 /********************************************************* 1278 * Method implementation for the non delegating IUnknown 1279 * part of the DataCache class. 1280 */ 1281 1282 /************************************************************************ 1283 * DataCache_NDIUnknown_QueryInterface (IUnknown) 1284 * 1285 * This version of QueryInterface will not delegate its implementation 1286 * to the outer unknown. 1287 */ 1288 static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface( 1289 IUnknown* iface, 1290 REFIID riid, 1291 void** ppvObject) 1292 { 1293 DataCache *this = impl_from_IUnknown(iface); 1294 1295 if ( ppvObject==0 ) 1296 return E_INVALIDARG; 1297 1298 *ppvObject = 0; 1299 1300 if (IsEqualIID(&IID_IUnknown, riid)) 1301 { 1302 if (this->outer_unk == iface) /* non-aggregated, return IUnknown from IOleCache2 */ 1303 *ppvObject = &this->IOleCache2_iface; 1304 else 1305 *ppvObject = iface; 1306 } 1307 else if (IsEqualIID(&IID_IDataObject, riid)) 1308 { 1309 *ppvObject = &this->IDataObject_iface; 1310 } 1311 else if ( IsEqualIID(&IID_IPersistStorage, riid) || 1312 IsEqualIID(&IID_IPersist, riid) ) 1313 { 1314 *ppvObject = &this->IPersistStorage_iface; 1315 } 1316 else if ( IsEqualIID(&IID_IViewObject, riid) || 1317 IsEqualIID(&IID_IViewObject2, riid) ) 1318 { 1319 *ppvObject = &this->IViewObject2_iface; 1320 } 1321 else if ( IsEqualIID(&IID_IOleCache, riid) || 1322 IsEqualIID(&IID_IOleCache2, riid) ) 1323 { 1324 *ppvObject = &this->IOleCache2_iface; 1325 } 1326 else if ( IsEqualIID(&IID_IOleCacheControl, riid) ) 1327 { 1328 *ppvObject = &this->IOleCacheControl_iface; 1329 } 1330 1331 if ((*ppvObject)==0) 1332 { 1333 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); 1334 return E_NOINTERFACE; 1335 } 1336 1337 IUnknown_AddRef((IUnknown*)*ppvObject); 1338 1339 return S_OK; 1340 } 1341 1342 /************************************************************************ 1343 * DataCache_NDIUnknown_AddRef (IUnknown) 1344 * 1345 * This version of QueryInterface will not delegate its implementation 1346 * to the outer unknown. 1347 */ 1348 static ULONG WINAPI DataCache_NDIUnknown_AddRef( 1349 IUnknown* iface) 1350 { 1351 DataCache *this = impl_from_IUnknown(iface); 1352 return InterlockedIncrement(&this->ref); 1353 } 1354 1355 /************************************************************************ 1356 * DataCache_NDIUnknown_Release (IUnknown) 1357 * 1358 * This version of QueryInterface will not delegate its implementation 1359 * to the outer unknown. 1360 */ 1361 static ULONG WINAPI DataCache_NDIUnknown_Release( 1362 IUnknown* iface) 1363 { 1364 DataCache *this = impl_from_IUnknown(iface); 1365 ULONG ref; 1366 1367 ref = InterlockedDecrement(&this->ref); 1368 1369 if (ref == 0) DataCache_Destroy(this); 1370 1371 return ref; 1372 } 1373 1374 /********************************************************* 1375 * Method implementation for the IDataObject 1376 * part of the DataCache class. 1377 */ 1378 1379 /************************************************************************ 1380 * DataCache_IDataObject_QueryInterface (IUnknown) 1381 */ 1382 static HRESULT WINAPI DataCache_IDataObject_QueryInterface( 1383 IDataObject* iface, 1384 REFIID riid, 1385 void** ppvObject) 1386 { 1387 DataCache *this = impl_from_IDataObject(iface); 1388 1389 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject); 1390 } 1391 1392 /************************************************************************ 1393 * DataCache_IDataObject_AddRef (IUnknown) 1394 */ 1395 static ULONG WINAPI DataCache_IDataObject_AddRef( 1396 IDataObject* iface) 1397 { 1398 DataCache *this = impl_from_IDataObject(iface); 1399 1400 return IUnknown_AddRef(this->outer_unk); 1401 } 1402 1403 /************************************************************************ 1404 * DataCache_IDataObject_Release (IUnknown) 1405 */ 1406 static ULONG WINAPI DataCache_IDataObject_Release( 1407 IDataObject* iface) 1408 { 1409 DataCache *this = impl_from_IDataObject(iface); 1410 1411 return IUnknown_Release(this->outer_unk); 1412 } 1413 1414 /************************************************************************ 1415 * DataCache_GetData 1416 * 1417 * Get Data from a source dataobject using format pformatetcIn->cfFormat 1418 */ 1419 static HRESULT WINAPI DataCache_GetData( 1420 IDataObject* iface, 1421 LPFORMATETC pformatetcIn, 1422 STGMEDIUM* pmedium) 1423 { 1424 DataCache *This = impl_from_IDataObject(iface); 1425 DataCacheEntry *cache_entry; 1426 1427 TRACE("(%p, %s, %p)\n", iface, debugstr_formatetc(pformatetcIn), pmedium); 1428 1429 memset(pmedium, 0, sizeof(*pmedium)); 1430 1431 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetcIn); 1432 if (!cache_entry) 1433 return OLE_E_BLANK; 1434 1435 return DataCacheEntry_GetData(cache_entry, This->presentationStorage, pformatetcIn, pmedium); 1436 } 1437 1438 static HRESULT WINAPI DataCache_GetDataHere( 1439 IDataObject* iface, 1440 LPFORMATETC pformatetc, 1441 STGMEDIUM* pmedium) 1442 { 1443 FIXME("stub\n"); 1444 return E_NOTIMPL; 1445 } 1446 1447 static HRESULT WINAPI DataCache_QueryGetData( IDataObject *iface, FORMATETC *fmt ) 1448 { 1449 DataCache *This = impl_from_IDataObject( iface ); 1450 DataCacheEntry *cache_entry; 1451 1452 TRACE( "(%p)->(%s)\n", iface, debugstr_formatetc( fmt ) ); 1453 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt ); 1454 1455 return cache_entry ? S_OK : S_FALSE; 1456 } 1457 1458 /************************************************************************ 1459 * DataCache_EnumFormatEtc (IDataObject) 1460 * 1461 * The data cache doesn't implement this method. 1462 */ 1463 static HRESULT WINAPI DataCache_GetCanonicalFormatEtc( 1464 IDataObject* iface, 1465 LPFORMATETC pformatectIn, 1466 LPFORMATETC pformatetcOut) 1467 { 1468 TRACE("()\n"); 1469 return E_NOTIMPL; 1470 } 1471 1472 /************************************************************************ 1473 * DataCache_IDataObject_SetData (IDataObject) 1474 * 1475 * This method is delegated to the IOleCache2 implementation. 1476 */ 1477 static HRESULT WINAPI DataCache_IDataObject_SetData( 1478 IDataObject* iface, 1479 LPFORMATETC pformatetc, 1480 STGMEDIUM* pmedium, 1481 BOOL fRelease) 1482 { 1483 IOleCache2* oleCache = NULL; 1484 HRESULT hres; 1485 1486 TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease); 1487 1488 hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache); 1489 1490 if (FAILED(hres)) 1491 return E_UNEXPECTED; 1492 1493 hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease); 1494 1495 IOleCache2_Release(oleCache); 1496 1497 return hres; 1498 } 1499 1500 /************************************************************************ 1501 * DataCache_EnumFormatEtc (IDataObject) 1502 * 1503 * The data cache doesn't implement this method. 1504 */ 1505 static HRESULT WINAPI DataCache_EnumFormatEtc( 1506 IDataObject* iface, 1507 DWORD dwDirection, 1508 IEnumFORMATETC** ppenumFormatEtc) 1509 { 1510 TRACE("()\n"); 1511 return E_NOTIMPL; 1512 } 1513 1514 /************************************************************************ 1515 * DataCache_DAdvise (IDataObject) 1516 * 1517 * The data cache doesn't support connections. 1518 */ 1519 static HRESULT WINAPI DataCache_DAdvise( 1520 IDataObject* iface, 1521 FORMATETC* pformatetc, 1522 DWORD advf, 1523 IAdviseSink* pAdvSink, 1524 DWORD* pdwConnection) 1525 { 1526 TRACE("()\n"); 1527 return OLE_E_ADVISENOTSUPPORTED; 1528 } 1529 1530 /************************************************************************ 1531 * DataCache_DUnadvise (IDataObject) 1532 * 1533 * The data cache doesn't support connections. 1534 */ 1535 static HRESULT WINAPI DataCache_DUnadvise( 1536 IDataObject* iface, 1537 DWORD dwConnection) 1538 { 1539 TRACE("()\n"); 1540 return OLE_E_NOCONNECTION; 1541 } 1542 1543 /************************************************************************ 1544 * DataCache_EnumDAdvise (IDataObject) 1545 * 1546 * The data cache doesn't support connections. 1547 */ 1548 static HRESULT WINAPI DataCache_EnumDAdvise( 1549 IDataObject* iface, 1550 IEnumSTATDATA** ppenumAdvise) 1551 { 1552 TRACE("()\n"); 1553 return OLE_E_ADVISENOTSUPPORTED; 1554 } 1555 1556 /********************************************************* 1557 * Method implementation for the IDataObject 1558 * part of the DataCache class. 1559 */ 1560 1561 /************************************************************************ 1562 * DataCache_IPersistStorage_QueryInterface (IUnknown) 1563 */ 1564 static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface( 1565 IPersistStorage* iface, 1566 REFIID riid, 1567 void** ppvObject) 1568 { 1569 DataCache *this = impl_from_IPersistStorage(iface); 1570 1571 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject); 1572 } 1573 1574 /************************************************************************ 1575 * DataCache_IPersistStorage_AddRef (IUnknown) 1576 */ 1577 static ULONG WINAPI DataCache_IPersistStorage_AddRef( 1578 IPersistStorage* iface) 1579 { 1580 DataCache *this = impl_from_IPersistStorage(iface); 1581 1582 return IUnknown_AddRef(this->outer_unk); 1583 } 1584 1585 /************************************************************************ 1586 * DataCache_IPersistStorage_Release (IUnknown) 1587 */ 1588 static ULONG WINAPI DataCache_IPersistStorage_Release( 1589 IPersistStorage* iface) 1590 { 1591 DataCache *this = impl_from_IPersistStorage(iface); 1592 1593 return IUnknown_Release(this->outer_unk); 1594 } 1595 1596 /************************************************************************ 1597 * DataCache_GetClassID (IPersistStorage) 1598 * 1599 */ 1600 static HRESULT WINAPI DataCache_GetClassID(IPersistStorage *iface, CLSID *clsid) 1601 { 1602 DataCache *This = impl_from_IPersistStorage( iface ); 1603 1604 TRACE( "(%p, %p) returning %s\n", iface, clsid, debugstr_guid(&This->clsid) ); 1605 *clsid = This->clsid; 1606 1607 return S_OK; 1608 } 1609 1610 /************************************************************************ 1611 * DataCache_IsDirty (IPersistStorage) 1612 */ 1613 static HRESULT WINAPI DataCache_IsDirty( 1614 IPersistStorage* iface) 1615 { 1616 DataCache *This = impl_from_IPersistStorage(iface); 1617 DataCacheEntry *cache_entry; 1618 1619 TRACE("(%p)\n", iface); 1620 1621 if (This->dirty) 1622 return S_OK; 1623 1624 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 1625 if (cache_entry->dirty) 1626 return S_OK; 1627 1628 return S_FALSE; 1629 } 1630 1631 /************************************************************************ 1632 * DataCache_InitNew (IPersistStorage) 1633 * 1634 * The data cache implementation of IPersistStorage_InitNew simply stores 1635 * the storage pointer. 1636 */ 1637 static HRESULT WINAPI DataCache_InitNew( 1638 IPersistStorage* iface, 1639 IStorage* pStg) 1640 { 1641 DataCache *This = impl_from_IPersistStorage(iface); 1642 CLSID clsid; 1643 HRESULT hr; 1644 1645 TRACE("(%p, %p)\n", iface, pStg); 1646 1647 if (This->presentationStorage != NULL) 1648 return CO_E_ALREADYINITIALIZED; 1649 1650 This->presentationStorage = pStg; 1651 1652 IStorage_AddRef(This->presentationStorage); 1653 This->dirty = TRUE; 1654 ReadClassStg( pStg, &clsid ); 1655 hr = create_automatic_entry( This, &clsid ); 1656 if (FAILED(hr)) 1657 { 1658 IStorage_Release( pStg ); 1659 This->presentationStorage = NULL; 1660 return hr; 1661 } 1662 This->clsid = clsid; 1663 1664 return S_OK; 1665 } 1666 1667 1668 static HRESULT add_cache_entry( DataCache *This, const FORMATETC *fmt, DWORD advf, int stream_number ) 1669 { 1670 DataCacheEntry *cache_entry; 1671 HRESULT hr = S_OK; 1672 1673 TRACE( "loading entry with formatetc: %s\n", debugstr_formatetc( fmt ) ); 1674 1675 cache_entry = DataCache_GetEntryForFormatEtc( This, fmt ); 1676 if (!cache_entry) 1677 hr = DataCache_CreateEntry( This, fmt, advf, FALSE, &cache_entry ); 1678 if (SUCCEEDED( hr )) 1679 { 1680 DataCacheEntry_DiscardData( cache_entry ); 1681 cache_entry->load_stream_num = stream_number; 1682 cache_entry->save_stream_num = stream_number; 1683 cache_entry->dirty = FALSE; 1684 } 1685 return hr; 1686 } 1687 1688 static HRESULT parse_pres_streams( DataCache *cache, IStorage *stg ) 1689 { 1690 HRESULT hr; 1691 IStream *stm; 1692 PresentationDataHeader header; 1693 ULONG actual_read; 1694 CLIPFORMAT clipformat; 1695 FORMATETC fmtetc; 1696 int stream_number = 0; 1697 1698 do 1699 { 1700 hr = open_pres_stream( stg, stream_number, &stm ); 1701 if (FAILED(hr)) break; 1702 1703 hr = read_clipformat( stm, &clipformat ); 1704 1705 if (hr == S_OK) hr = IStream_Read( stm, &header, sizeof(header), &actual_read ); 1706 1707 if (hr == S_OK && actual_read == sizeof(header)) 1708 { 1709 fmtetc.cfFormat = clipformat; 1710 fmtetc.ptd = NULL; /* FIXME */ 1711 fmtetc.dwAspect = header.dvAspect; 1712 fmtetc.lindex = header.lindex; 1713 fmtetc.tymed = tymed_from_cf( clipformat ); 1714 1715 add_cache_entry( cache, &fmtetc, header.advf, stream_number ); 1716 } 1717 IStream_Release( stm ); 1718 stream_number++; 1719 } while (hr == S_OK); 1720 1721 return S_OK; 1722 } 1723 1724 static HRESULT parse_contents_stream( DataCache *cache, IStorage *stg ) 1725 { 1726 HRESULT hr; 1727 IStream *stm; 1728 DataCacheEntry *cache_entry; 1729 1730 hr = open_pres_stream( stg, STREAM_NUMBER_CONTENTS, &stm ); 1731 if (FAILED( hr )) return hr; 1732 1733 hr = get_static_entry( cache, &cache_entry ); 1734 if (hr == S_OK) 1735 { 1736 cache_entry->load_stream_num = STREAM_NUMBER_CONTENTS; 1737 cache_entry->save_stream_num = STREAM_NUMBER_CONTENTS; 1738 cache_entry->dirty = FALSE; 1739 } 1740 1741 IStream_Release( stm ); 1742 return hr; 1743 } 1744 1745 /************************************************************************ 1746 * DataCache_Load (IPersistStorage) 1747 * 1748 * The data cache implementation of IPersistStorage_Load doesn't 1749 * actually load anything. Instead, it holds on to the storage pointer 1750 * and it will load the presentation information when the 1751 * IDataObject_GetData or IViewObject2_Draw methods are called. 1752 */ 1753 static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *stg ) 1754 { 1755 DataCache *This = impl_from_IPersistStorage(iface); 1756 HRESULT hr; 1757 CLSID clsid; 1758 DataCacheEntry *entry, *cursor2; 1759 1760 TRACE("(%p, %p)\n", iface, stg); 1761 1762 IPersistStorage_HandsOffStorage( iface ); 1763 1764 LIST_FOR_EACH_ENTRY_SAFE( entry, cursor2, &This->cache_list, DataCacheEntry, entry ) 1765 DataCacheEntry_Destroy( This, entry ); 1766 1767 ReadClassStg( stg, &clsid ); 1768 hr = create_automatic_entry( This, &clsid ); 1769 if (FAILED( hr )) return hr; 1770 1771 This->clsid = clsid; 1772 1773 if (This->clsid_static) 1774 { 1775 hr = parse_contents_stream( This, stg ); 1776 if (FAILED(hr)) hr = parse_pres_streams( This, stg ); 1777 } 1778 else 1779 hr = parse_pres_streams( This, stg ); 1780 1781 if (SUCCEEDED( hr )) 1782 { 1783 This->dirty = FALSE; 1784 This->presentationStorage = stg; 1785 IStorage_AddRef( This->presentationStorage ); 1786 } 1787 1788 return hr; 1789 } 1790 1791 /************************************************************************ 1792 * DataCache_Save (IPersistStorage) 1793 * 1794 * Until we actually connect to a running object and retrieve new 1795 * information to it, we never have to save anything. However, it is 1796 * our responsibility to copy the information when saving to a new 1797 * storage. 1798 */ 1799 static HRESULT WINAPI DataCache_Save(IPersistStorage* iface, IStorage *stg, BOOL same_as_load) 1800 { 1801 DataCache *This = impl_from_IPersistStorage(iface); 1802 DataCacheEntry *cache_entry; 1803 HRESULT hr = S_OK; 1804 int stream_number = 0; 1805 1806 TRACE("(%p, %p, %d)\n", iface, stg, same_as_load); 1807 1808 /* assign stream numbers to the cache entries */ 1809 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 1810 { 1811 if (cache_entry->save_stream_num != stream_number) 1812 { 1813 cache_entry->dirty = TRUE; /* needs to be written out again */ 1814 cache_entry->save_stream_num = stream_number; 1815 } 1816 stream_number++; 1817 } 1818 1819 /* write out the cache entries */ 1820 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 1821 { 1822 if (!same_as_load || cache_entry->dirty) 1823 { 1824 hr = DataCacheEntry_Save(cache_entry, stg, same_as_load); 1825 if (FAILED(hr)) 1826 break; 1827 1828 if (same_as_load) cache_entry->dirty = FALSE; 1829 } 1830 } 1831 1832 if (same_as_load) This->dirty = FALSE; 1833 return hr; 1834 } 1835 1836 /************************************************************************ 1837 * DataCache_SaveCompleted (IPersistStorage) 1838 * 1839 * This method is called to tell the cache to release the storage 1840 * pointer it's currently holding. 1841 */ 1842 static HRESULT WINAPI DataCache_SaveCompleted( 1843 IPersistStorage* iface, 1844 IStorage* pStgNew) 1845 { 1846 TRACE("(%p, %p)\n", iface, pStgNew); 1847 1848 if (pStgNew) 1849 { 1850 IPersistStorage_HandsOffStorage(iface); 1851 1852 DataCache_Load(iface, pStgNew); 1853 } 1854 1855 return S_OK; 1856 } 1857 1858 /************************************************************************ 1859 * DataCache_HandsOffStorage (IPersistStorage) 1860 * 1861 * This method is called to tell the cache to release the storage 1862 * pointer it's currently holding. 1863 */ 1864 static HRESULT WINAPI DataCache_HandsOffStorage( 1865 IPersistStorage* iface) 1866 { 1867 DataCache *this = impl_from_IPersistStorage(iface); 1868 1869 TRACE("(%p)\n", iface); 1870 1871 if (this->presentationStorage != NULL) 1872 { 1873 IStorage_Release(this->presentationStorage); 1874 this->presentationStorage = NULL; 1875 } 1876 1877 return S_OK; 1878 } 1879 1880 /********************************************************* 1881 * Method implementation for the IViewObject2 1882 * part of the DataCache class. 1883 */ 1884 1885 /************************************************************************ 1886 * DataCache_IViewObject2_QueryInterface (IUnknown) 1887 */ 1888 static HRESULT WINAPI DataCache_IViewObject2_QueryInterface( 1889 IViewObject2* iface, 1890 REFIID riid, 1891 void** ppvObject) 1892 { 1893 DataCache *this = impl_from_IViewObject2(iface); 1894 1895 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject); 1896 } 1897 1898 /************************************************************************ 1899 * DataCache_IViewObject2_AddRef (IUnknown) 1900 */ 1901 static ULONG WINAPI DataCache_IViewObject2_AddRef( 1902 IViewObject2* iface) 1903 { 1904 DataCache *this = impl_from_IViewObject2(iface); 1905 1906 return IUnknown_AddRef(this->outer_unk); 1907 } 1908 1909 /************************************************************************ 1910 * DataCache_IViewObject2_Release (IUnknown) 1911 */ 1912 static ULONG WINAPI DataCache_IViewObject2_Release( 1913 IViewObject2* iface) 1914 { 1915 DataCache *this = impl_from_IViewObject2(iface); 1916 1917 return IUnknown_Release(this->outer_unk); 1918 } 1919 1920 /************************************************************************ 1921 * DataCache_Draw (IViewObject2) 1922 * 1923 * This method will draw the cached representation of the object 1924 * to the given device context. 1925 */ 1926 static HRESULT WINAPI DataCache_Draw( 1927 IViewObject2* iface, 1928 DWORD dwDrawAspect, 1929 LONG lindex, 1930 void* pvAspect, 1931 DVTARGETDEVICE* ptd, 1932 HDC hdcTargetDev, 1933 HDC hdcDraw, 1934 LPCRECTL lprcBounds, 1935 LPCRECTL lprcWBounds, 1936 BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue), 1937 ULONG_PTR dwContinue) 1938 { 1939 DataCache *This = impl_from_IViewObject2(iface); 1940 HRESULT hres; 1941 DataCacheEntry *cache_entry; 1942 1943 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n", 1944 iface, 1945 dwDrawAspect, 1946 lindex, 1947 pvAspect, 1948 hdcTargetDev, 1949 hdcDraw, 1950 lprcBounds, 1951 lprcWBounds, 1952 pfnContinue, 1953 dwContinue); 1954 1955 if (lprcBounds==NULL) 1956 return E_INVALIDARG; 1957 1958 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 1959 { 1960 /* FIXME: compare ptd too */ 1961 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) || 1962 (cache_entry->fmtetc.lindex != lindex)) 1963 continue; 1964 1965 /* if the data hasn't been loaded yet, do it now */ 1966 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && (cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET)) 1967 { 1968 hres = DataCacheEntry_LoadData(cache_entry, This->presentationStorage); 1969 if (FAILED(hres)) 1970 continue; 1971 } 1972 1973 /* no data */ 1974 if (cache_entry->stgmedium.tymed == TYMED_NULL) 1975 continue; 1976 1977 if (pfnContinue && !pfnContinue(dwContinue)) return E_ABORT; 1978 1979 switch (cache_entry->fmtetc.cfFormat) 1980 { 1981 case CF_METAFILEPICT: 1982 { 1983 /* 1984 * We have to be careful not to modify the state of the 1985 * DC. 1986 */ 1987 INT prevMapMode; 1988 SIZE oldWindowExt; 1989 SIZE oldViewportExt; 1990 POINT oldViewportOrg; 1991 METAFILEPICT *mfpict; 1992 1993 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) || 1994 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict)))) 1995 continue; 1996 1997 prevMapMode = SetMapMode(hdcDraw, mfpict->mm); 1998 1999 SetWindowExtEx(hdcDraw, 2000 mfpict->xExt, 2001 mfpict->yExt, 2002 &oldWindowExt); 2003 2004 SetViewportExtEx(hdcDraw, 2005 lprcBounds->right - lprcBounds->left, 2006 lprcBounds->bottom - lprcBounds->top, 2007 &oldViewportExt); 2008 2009 SetViewportOrgEx(hdcDraw, 2010 lprcBounds->left, 2011 lprcBounds->top, 2012 &oldViewportOrg); 2013 2014 PlayMetaFile(hdcDraw, mfpict->hMF); 2015 2016 SetWindowExtEx(hdcDraw, 2017 oldWindowExt.cx, 2018 oldWindowExt.cy, 2019 NULL); 2020 2021 SetViewportExtEx(hdcDraw, 2022 oldViewportExt.cx, 2023 oldViewportExt.cy, 2024 NULL); 2025 2026 SetViewportOrgEx(hdcDraw, 2027 oldViewportOrg.x, 2028 oldViewportOrg.y, 2029 NULL); 2030 2031 SetMapMode(hdcDraw, prevMapMode); 2032 2033 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict); 2034 2035 return S_OK; 2036 } 2037 case CF_DIB: 2038 { 2039 BITMAPINFO *info; 2040 BYTE *bits; 2041 2042 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) || 2043 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal )))) 2044 continue; 2045 2046 bits = (BYTE *) info + bitmap_info_size( info, DIB_RGB_COLORS ); 2047 StretchDIBits( hdcDraw, lprcBounds->left, lprcBounds->top, 2048 lprcBounds->right - lprcBounds->left, lprcBounds->bottom - lprcBounds->top, 2049 0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight, 2050 bits, info, DIB_RGB_COLORS, SRCCOPY ); 2051 2052 GlobalUnlock( cache_entry->stgmedium.u.hGlobal ); 2053 return S_OK; 2054 } 2055 } 2056 } 2057 2058 WARN("no data could be found to be drawn\n"); 2059 2060 return OLE_E_BLANK; 2061 } 2062 2063 static HRESULT WINAPI DataCache_GetColorSet( 2064 IViewObject2* iface, 2065 DWORD dwDrawAspect, 2066 LONG lindex, 2067 void* pvAspect, 2068 DVTARGETDEVICE* ptd, 2069 HDC hicTargetDevice, 2070 LOGPALETTE** ppColorSet) 2071 { 2072 FIXME("stub\n"); 2073 return E_NOTIMPL; 2074 } 2075 2076 static HRESULT WINAPI DataCache_Freeze( 2077 IViewObject2* iface, 2078 DWORD dwDrawAspect, 2079 LONG lindex, 2080 void* pvAspect, 2081 DWORD* pdwFreeze) 2082 { 2083 FIXME("stub\n"); 2084 return E_NOTIMPL; 2085 } 2086 2087 static HRESULT WINAPI DataCache_Unfreeze( 2088 IViewObject2* iface, 2089 DWORD dwFreeze) 2090 { 2091 FIXME("stub\n"); 2092 return E_NOTIMPL; 2093 } 2094 2095 /************************************************************************ 2096 * DataCache_SetAdvise (IViewObject2) 2097 * 2098 * This sets-up an advisory sink with the data cache. When the object's 2099 * view changes, this sink is called. 2100 */ 2101 static HRESULT WINAPI DataCache_SetAdvise( 2102 IViewObject2* iface, 2103 DWORD aspects, 2104 DWORD advf, 2105 IAdviseSink* pAdvSink) 2106 { 2107 DataCache *this = impl_from_IViewObject2(iface); 2108 2109 TRACE("(%p, %x, %x, %p)\n", iface, aspects, advf, pAdvSink); 2110 2111 /* 2112 * A call to this function removes the previous sink 2113 */ 2114 if (this->sinkInterface != NULL) 2115 { 2116 IAdviseSink_Release(this->sinkInterface); 2117 this->sinkInterface = NULL; 2118 this->sinkAspects = 0; 2119 this->sinkAdviseFlag = 0; 2120 } 2121 2122 /* 2123 * Now, setup the new one. 2124 */ 2125 if (pAdvSink!=NULL) 2126 { 2127 this->sinkInterface = pAdvSink; 2128 this->sinkAspects = aspects; 2129 this->sinkAdviseFlag = advf; 2130 2131 IAdviseSink_AddRef(this->sinkInterface); 2132 } 2133 2134 /* 2135 * When the ADVF_PRIMEFIRST flag is set, we have to advise the 2136 * sink immediately. 2137 */ 2138 if (advf & ADVF_PRIMEFIRST) 2139 { 2140 DataCache_FireOnViewChange(this, aspects, -1); 2141 } 2142 2143 return S_OK; 2144 } 2145 2146 /************************************************************************ 2147 * DataCache_GetAdvise (IViewObject2) 2148 * 2149 * This method queries the current state of the advise sink 2150 * installed on the data cache. 2151 */ 2152 static HRESULT WINAPI DataCache_GetAdvise( 2153 IViewObject2* iface, 2154 DWORD* pAspects, 2155 DWORD* pAdvf, 2156 IAdviseSink** ppAdvSink) 2157 { 2158 DataCache *this = impl_from_IViewObject2(iface); 2159 2160 TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink); 2161 2162 /* 2163 * Just copy all the requested values. 2164 */ 2165 if (pAspects!=NULL) 2166 *pAspects = this->sinkAspects; 2167 2168 if (pAdvf!=NULL) 2169 *pAdvf = this->sinkAdviseFlag; 2170 2171 if (ppAdvSink!=NULL) 2172 { 2173 if (this->sinkInterface != NULL) 2174 IAdviseSink_QueryInterface(this->sinkInterface, 2175 &IID_IAdviseSink, 2176 (void**)ppAdvSink); 2177 else *ppAdvSink = NULL; 2178 } 2179 2180 return S_OK; 2181 } 2182 2183 /************************************************************************ 2184 * DataCache_GetExtent (IViewObject2) 2185 * 2186 * This method retrieves the "natural" size of this cached object. 2187 */ 2188 static HRESULT WINAPI DataCache_GetExtent( 2189 IViewObject2* iface, 2190 DWORD dwDrawAspect, 2191 LONG lindex, 2192 DVTARGETDEVICE* ptd, 2193 LPSIZEL lpsizel) 2194 { 2195 DataCache *This = impl_from_IViewObject2(iface); 2196 HRESULT hres = E_FAIL; 2197 DataCacheEntry *cache_entry; 2198 2199 TRACE("(%p, %x, %d, %p, %p)\n", 2200 iface, dwDrawAspect, lindex, ptd, lpsizel); 2201 2202 if (lpsizel==NULL) 2203 return E_POINTER; 2204 2205 lpsizel->cx = 0; 2206 lpsizel->cy = 0; 2207 2208 if (lindex!=-1) 2209 FIXME("Unimplemented flag lindex = %d\n", lindex); 2210 2211 /* 2212 * Right now, we support only the callback from 2213 * the default handler. 2214 */ 2215 if (ptd!=NULL) 2216 FIXME("Unimplemented ptd = %p\n", ptd); 2217 2218 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 2219 { 2220 /* FIXME: compare ptd too */ 2221 if ((cache_entry->fmtetc.dwAspect != dwDrawAspect) || 2222 (cache_entry->fmtetc.lindex != lindex)) 2223 continue; 2224 2225 /* if the data hasn't been loaded yet, do it now */ 2226 if ((cache_entry->stgmedium.tymed == TYMED_NULL) && (cache_entry->load_stream_num != STREAM_NUMBER_NOT_SET)) 2227 { 2228 hres = DataCacheEntry_LoadData(cache_entry, This->presentationStorage); 2229 if (FAILED(hres)) 2230 continue; 2231 } 2232 2233 /* no data */ 2234 if (cache_entry->stgmedium.tymed == TYMED_NULL) 2235 continue; 2236 2237 2238 switch (cache_entry->fmtetc.cfFormat) 2239 { 2240 case CF_METAFILEPICT: 2241 { 2242 METAFILEPICT *mfpict; 2243 2244 if ((cache_entry->stgmedium.tymed != TYMED_MFPICT) || 2245 !((mfpict = GlobalLock(cache_entry->stgmedium.u.hMetaFilePict)))) 2246 continue; 2247 2248 lpsizel->cx = mfpict->xExt; 2249 lpsizel->cy = mfpict->yExt; 2250 2251 GlobalUnlock(cache_entry->stgmedium.u.hMetaFilePict); 2252 2253 return S_OK; 2254 } 2255 case CF_DIB: 2256 { 2257 BITMAPINFOHEADER *info; 2258 LONG x_pels_m, y_pels_m; 2259 2260 2261 if ((cache_entry->stgmedium.tymed != TYMED_HGLOBAL) || 2262 !((info = GlobalLock( cache_entry->stgmedium.u.hGlobal )))) 2263 continue; 2264 2265 x_pels_m = info->biXPelsPerMeter; 2266 y_pels_m = info->biYPelsPerMeter; 2267 2268 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */ 2269 if (x_pels_m != 0 && y_pels_m != 0) 2270 { 2271 lpsizel->cx = info->biWidth * 100000 / x_pels_m; 2272 lpsizel->cy = info->biHeight * 100000 / y_pels_m; 2273 } 2274 else 2275 { 2276 HDC hdc = GetDC( 0 ); 2277 lpsizel->cx = info->biWidth * 2540 / GetDeviceCaps( hdc, LOGPIXELSX ); 2278 lpsizel->cy = info->biHeight * 2540 / GetDeviceCaps( hdc, LOGPIXELSY ); 2279 2280 ReleaseDC( 0, hdc ); 2281 } 2282 2283 GlobalUnlock( cache_entry->stgmedium.u.hGlobal ); 2284 2285 return S_OK; 2286 } 2287 } 2288 } 2289 2290 WARN("no data could be found to get the extents from\n"); 2291 2292 /* 2293 * This method returns OLE_E_BLANK when it fails. 2294 */ 2295 return OLE_E_BLANK; 2296 } 2297 2298 2299 /********************************************************* 2300 * Method implementation for the IOleCache2 2301 * part of the DataCache class. 2302 */ 2303 2304 /************************************************************************ 2305 * DataCache_IOleCache2_QueryInterface (IUnknown) 2306 */ 2307 static HRESULT WINAPI DataCache_IOleCache2_QueryInterface( 2308 IOleCache2* iface, 2309 REFIID riid, 2310 void** ppvObject) 2311 { 2312 DataCache *this = impl_from_IOleCache2(iface); 2313 2314 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject); 2315 } 2316 2317 /************************************************************************ 2318 * DataCache_IOleCache2_AddRef (IUnknown) 2319 */ 2320 static ULONG WINAPI DataCache_IOleCache2_AddRef( 2321 IOleCache2* iface) 2322 { 2323 DataCache *this = impl_from_IOleCache2(iface); 2324 2325 return IUnknown_AddRef(this->outer_unk); 2326 } 2327 2328 /************************************************************************ 2329 * DataCache_IOleCache2_Release (IUnknown) 2330 */ 2331 static ULONG WINAPI DataCache_IOleCache2_Release( 2332 IOleCache2* iface) 2333 { 2334 DataCache *this = impl_from_IOleCache2(iface); 2335 2336 return IUnknown_Release(this->outer_unk); 2337 } 2338 2339 /***************************************************************************** 2340 * setup_sink 2341 * 2342 * Set up the sink connection to the running object. 2343 */ 2344 static HRESULT setup_sink(DataCache *This, DataCacheEntry *cache_entry) 2345 { 2346 HRESULT hr = S_FALSE; 2347 DWORD flags; 2348 2349 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */ 2350 flags = cache_entry->advise_flags & ~(ADVFCACHE_NOHANDLER | ADVFCACHE_FORCEBUILTIN | ADVFCACHE_ONSAVE); 2351 2352 if(This->running_object) 2353 if(!(flags & ADVF_NODATA)) 2354 hr = IDataObject_DAdvise(This->running_object, &cache_entry->fmtetc, flags, 2355 &This->IAdviseSink_iface, &cache_entry->sink_id); 2356 return hr; 2357 } 2358 2359 static HRESULT WINAPI DataCache_Cache( 2360 IOleCache2* iface, 2361 FORMATETC* pformatetc, 2362 DWORD advf, 2363 DWORD* pdwConnection) 2364 { 2365 DataCache *This = impl_from_IOleCache2(iface); 2366 DataCacheEntry *cache_entry; 2367 HRESULT hr; 2368 FORMATETC fmt_cpy; 2369 2370 TRACE("(%p, 0x%x, %p)\n", pformatetc, advf, pdwConnection); 2371 2372 if (!pformatetc || !pdwConnection) 2373 return E_INVALIDARG; 2374 2375 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc)); 2376 2377 fmt_cpy = *pformatetc; /* No need for a deep copy */ 2378 if (fmt_cpy.cfFormat == CF_BITMAP && fmt_cpy.tymed == TYMED_GDI) 2379 { 2380 fmt_cpy.cfFormat = CF_DIB; 2381 fmt_cpy.tymed = TYMED_HGLOBAL; 2382 } 2383 2384 /* View caching DVASPECT_ICON gets converted to CF_METAFILEPICT */ 2385 if (fmt_cpy.dwAspect == DVASPECT_ICON && fmt_cpy.cfFormat == 0) 2386 { 2387 fmt_cpy.cfFormat = CF_METAFILEPICT; 2388 fmt_cpy.tymed = TYMED_MFPICT; 2389 } 2390 2391 *pdwConnection = 0; 2392 2393 cache_entry = DataCache_GetEntryForFormatEtc(This, &fmt_cpy); 2394 if (cache_entry) 2395 { 2396 TRACE("found an existing cache entry\n"); 2397 *pdwConnection = cache_entry->id; 2398 return CACHE_S_SAMECACHE; 2399 } 2400 2401 if (This->clsid_static && fmt_cpy.dwAspect != DVASPECT_ICON) return DV_E_FORMATETC; 2402 2403 hr = DataCache_CreateEntry(This, &fmt_cpy, advf, FALSE, &cache_entry); 2404 2405 if (SUCCEEDED(hr)) 2406 { 2407 *pdwConnection = cache_entry->id; 2408 setup_sink(This, cache_entry); 2409 } 2410 2411 return hr; 2412 } 2413 2414 static HRESULT WINAPI DataCache_Uncache( 2415 IOleCache2* iface, 2416 DWORD dwConnection) 2417 { 2418 DataCache *This = impl_from_IOleCache2(iface); 2419 DataCacheEntry *cache_entry; 2420 2421 TRACE("(%d)\n", dwConnection); 2422 2423 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 2424 if (cache_entry->id == dwConnection) 2425 { 2426 DataCacheEntry_Destroy(This, cache_entry); 2427 return S_OK; 2428 } 2429 2430 WARN("no connection found for %d\n", dwConnection); 2431 2432 return OLE_E_NOCONNECTION; 2433 } 2434 2435 static HRESULT WINAPI DataCache_EnumCache(IOleCache2 *iface, 2436 IEnumSTATDATA **enum_stat) 2437 { 2438 DataCache *This = impl_from_IOleCache2( iface ); 2439 DataCacheEntry *cache_entry; 2440 int i = 0, count = 0; 2441 STATDATA *data; 2442 HRESULT hr; 2443 2444 TRACE( "(%p, %p)\n", This, enum_stat ); 2445 2446 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry ) 2447 { 2448 count++; 2449 if (cache_entry->fmtetc.cfFormat == CF_DIB) 2450 count++; 2451 } 2452 2453 data = CoTaskMemAlloc( count * sizeof(*data) ); 2454 if (!data) return E_OUTOFMEMORY; 2455 2456 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry ) 2457 { 2458 if (i == count) goto fail; 2459 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc ); 2460 if (FAILED(hr)) goto fail; 2461 data[i].advf = cache_entry->advise_flags; 2462 data[i].pAdvSink = NULL; 2463 data[i].dwConnection = cache_entry->id; 2464 i++; 2465 2466 if (cache_entry->fmtetc.cfFormat == CF_DIB) 2467 { 2468 if (i == count) goto fail; 2469 hr = copy_formatetc( &data[i].formatetc, &cache_entry->fmtetc ); 2470 if (FAILED(hr)) goto fail; 2471 data[i].formatetc.cfFormat = CF_BITMAP; 2472 data[i].formatetc.tymed = TYMED_GDI; 2473 data[i].advf = cache_entry->advise_flags; 2474 data[i].pAdvSink = NULL; 2475 data[i].dwConnection = cache_entry->id; 2476 i++; 2477 } 2478 } 2479 2480 hr = EnumSTATDATA_Construct( NULL, 0, i, data, FALSE, enum_stat ); 2481 if (SUCCEEDED(hr)) return hr; 2482 2483 fail: 2484 while (i--) CoTaskMemFree( data[i].formatetc.ptd ); 2485 CoTaskMemFree( data ); 2486 return hr; 2487 } 2488 2489 static HRESULT WINAPI DataCache_InitCache( IOleCache2 *iface, IDataObject *data ) 2490 { 2491 TRACE( "(%p %p)\n", iface, data ); 2492 return IOleCache2_UpdateCache( iface, data, UPDFCACHE_ALLBUTNODATACACHE, NULL ); 2493 } 2494 2495 static HRESULT WINAPI DataCache_IOleCache2_SetData( 2496 IOleCache2* iface, 2497 FORMATETC* pformatetc, 2498 STGMEDIUM* pmedium, 2499 BOOL fRelease) 2500 { 2501 DataCache *This = impl_from_IOleCache2(iface); 2502 DataCacheEntry *cache_entry; 2503 HRESULT hr; 2504 2505 TRACE("(%p, %p, %s)\n", pformatetc, pmedium, fRelease ? "TRUE" : "FALSE"); 2506 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc)); 2507 2508 cache_entry = DataCache_GetEntryForFormatEtc(This, pformatetc); 2509 if (cache_entry) 2510 { 2511 hr = DataCacheEntry_SetData(cache_entry, pformatetc, pmedium, fRelease); 2512 2513 if (SUCCEEDED(hr)) 2514 DataCache_FireOnViewChange(This, cache_entry->fmtetc.dwAspect, 2515 cache_entry->fmtetc.lindex); 2516 2517 return hr; 2518 } 2519 WARN("cache entry not found\n"); 2520 2521 return OLE_E_BLANK; 2522 } 2523 2524 static BOOL entry_updatable( DataCacheEntry *entry, DWORD mode ) 2525 { 2526 BOOL is_blank = entry->stgmedium.tymed == TYMED_NULL; 2527 2528 if ((mode & UPDFCACHE_ONLYIFBLANK) && !is_blank) return FALSE; 2529 2530 if ((mode & UPDFCACHE_NODATACACHE) && (entry->advise_flags & ADVF_NODATA)) return TRUE; 2531 if ((mode & UPDFCACHE_ONSAVECACHE) && (entry->advise_flags & ADVFCACHE_ONSAVE)) return TRUE; 2532 if ((mode & UPDFCACHE_ONSTOPCACHE) && (entry->advise_flags & ADVF_DATAONSTOP)) return TRUE; 2533 if ((mode & UPDFCACHE_NORMALCACHE) && (entry->advise_flags == 0)) return TRUE; 2534 if ((mode & UPDFCACHE_IFBLANK) && (is_blank && !(entry->advise_flags & ADVF_NODATA))) return TRUE; 2535 2536 return FALSE; 2537 } 2538 2539 static HRESULT WINAPI DataCache_UpdateCache( IOleCache2 *iface, IDataObject *data, 2540 DWORD mode, void *reserved ) 2541 { 2542 DataCache *This = impl_from_IOleCache2(iface); 2543 DataCacheEntry *cache_entry; 2544 STGMEDIUM med; 2545 HRESULT hr = S_OK; 2546 CLIPFORMAT view_list[] = { CF_METAFILEPICT, CF_ENHMETAFILE, CF_DIB, CF_BITMAP }; 2547 FORMATETC fmt; 2548 int i, slots = 0; 2549 BOOL done_one = FALSE; 2550 2551 TRACE( "(%p %p %08x %p)\n", iface, data, mode, reserved ); 2552 2553 LIST_FOR_EACH_ENTRY( cache_entry, &This->cache_list, DataCacheEntry, entry ) 2554 { 2555 slots++; 2556 2557 if (!entry_updatable( cache_entry, mode )) 2558 { 2559 done_one = TRUE; 2560 continue; 2561 } 2562 2563 fmt = cache_entry->fmtetc; 2564 2565 if (fmt.cfFormat) 2566 { 2567 hr = IDataObject_GetData( data, &fmt, &med ); 2568 if (hr != S_OK && fmt.cfFormat == CF_DIB) 2569 { 2570 fmt.cfFormat = CF_BITMAP; 2571 fmt.tymed = TYMED_GDI; 2572 hr = IDataObject_GetData( data, &fmt, &med ); 2573 } 2574 if (hr != S_OK && fmt.cfFormat == CF_ENHMETAFILE) 2575 { 2576 fmt.cfFormat = CF_METAFILEPICT; 2577 fmt.tymed = TYMED_MFPICT; 2578 hr = IDataObject_GetData( data, &fmt, &med ); 2579 } 2580 if (hr == S_OK) 2581 { 2582 hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE ); 2583 if (hr != S_OK) ReleaseStgMedium( &med ); 2584 else done_one = TRUE; 2585 } 2586 } 2587 else 2588 { 2589 for (i = 0; i < sizeof(view_list) / sizeof(view_list[0]); i++) 2590 { 2591 fmt.cfFormat = view_list[i]; 2592 fmt.tymed = tymed_from_cf( fmt.cfFormat ); 2593 hr = IDataObject_QueryGetData( data, &fmt ); 2594 if (hr == S_OK) 2595 { 2596 hr = IDataObject_GetData( data, &fmt, &med ); 2597 if (hr == S_OK) 2598 { 2599 if (fmt.cfFormat == CF_BITMAP) 2600 { 2601 cache_entry->fmtetc.cfFormat = CF_DIB; 2602 cache_entry->fmtetc.tymed = TYMED_HGLOBAL; 2603 } 2604 else 2605 { 2606 cache_entry->fmtetc.cfFormat = fmt.cfFormat; 2607 cache_entry->fmtetc.tymed = fmt.tymed; 2608 } 2609 hr = DataCacheEntry_SetData( cache_entry, &fmt, &med, TRUE ); 2610 if (hr != S_OK) ReleaseStgMedium( &med ); 2611 else done_one = TRUE; 2612 break; 2613 } 2614 } 2615 } 2616 } 2617 } 2618 2619 return (!slots || done_one) ? S_OK : CACHE_E_NOCACHE_UPDATED; 2620 } 2621 2622 static HRESULT WINAPI DataCache_DiscardCache( 2623 IOleCache2* iface, 2624 DWORD dwDiscardOptions) 2625 { 2626 DataCache *This = impl_from_IOleCache2(iface); 2627 DataCacheEntry *cache_entry; 2628 HRESULT hr = S_OK; 2629 2630 TRACE("(%d)\n", dwDiscardOptions); 2631 2632 if (dwDiscardOptions == DISCARDCACHE_SAVEIFDIRTY) 2633 hr = DataCache_Save(&This->IPersistStorage_iface, This->presentationStorage, TRUE); 2634 2635 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 2636 { 2637 hr = DataCacheEntry_DiscardData(cache_entry); 2638 if (FAILED(hr)) 2639 break; 2640 } 2641 2642 return hr; 2643 } 2644 2645 2646 /********************************************************* 2647 * Method implementation for the IOleCacheControl 2648 * part of the DataCache class. 2649 */ 2650 2651 /************************************************************************ 2652 * DataCache_IOleCacheControl_QueryInterface (IUnknown) 2653 */ 2654 static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface( 2655 IOleCacheControl* iface, 2656 REFIID riid, 2657 void** ppvObject) 2658 { 2659 DataCache *this = impl_from_IOleCacheControl(iface); 2660 2661 return IUnknown_QueryInterface(this->outer_unk, riid, ppvObject); 2662 } 2663 2664 /************************************************************************ 2665 * DataCache_IOleCacheControl_AddRef (IUnknown) 2666 */ 2667 static ULONG WINAPI DataCache_IOleCacheControl_AddRef( 2668 IOleCacheControl* iface) 2669 { 2670 DataCache *this = impl_from_IOleCacheControl(iface); 2671 2672 return IUnknown_AddRef(this->outer_unk); 2673 } 2674 2675 /************************************************************************ 2676 * DataCache_IOleCacheControl_Release (IUnknown) 2677 */ 2678 static ULONG WINAPI DataCache_IOleCacheControl_Release( 2679 IOleCacheControl* iface) 2680 { 2681 DataCache *this = impl_from_IOleCacheControl(iface); 2682 2683 return IUnknown_Release(this->outer_unk); 2684 } 2685 2686 /************************************************************************ 2687 * DataCache_OnRun (IOleCacheControl) 2688 */ 2689 static HRESULT WINAPI DataCache_OnRun(IOleCacheControl* iface, IDataObject *data_obj) 2690 { 2691 DataCache *This = impl_from_IOleCacheControl(iface); 2692 DataCacheEntry *cache_entry; 2693 2694 TRACE("(%p)->(%p)\n", iface, data_obj); 2695 2696 if(This->running_object) return S_OK; 2697 2698 /* No reference is taken on the data object */ 2699 This->running_object = data_obj; 2700 2701 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 2702 { 2703 setup_sink(This, cache_entry); 2704 } 2705 2706 return S_OK; 2707 } 2708 2709 /************************************************************************ 2710 * DataCache_OnStop (IOleCacheControl) 2711 */ 2712 static HRESULT WINAPI DataCache_OnStop(IOleCacheControl* iface) 2713 { 2714 DataCache *This = impl_from_IOleCacheControl(iface); 2715 DataCacheEntry *cache_entry; 2716 2717 TRACE("(%p)\n", iface); 2718 2719 if(!This->running_object) return S_OK; 2720 2721 LIST_FOR_EACH_ENTRY(cache_entry, &This->cache_list, DataCacheEntry, entry) 2722 { 2723 if(cache_entry->sink_id) 2724 { 2725 IDataObject_DUnadvise(This->running_object, cache_entry->sink_id); 2726 cache_entry->sink_id = 0; 2727 } 2728 } 2729 2730 /* No ref taken in OnRun, so no Release call here */ 2731 This->running_object = NULL; 2732 return S_OK; 2733 } 2734 2735 /************************************************************************ 2736 * IAdviseSink methods. 2737 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't 2738 * give access to the cache's other interfaces. We don't maintain a ref count, 2739 * the object exists as long as the cache is around. 2740 */ 2741 static HRESULT WINAPI DataCache_IAdviseSink_QueryInterface(IAdviseSink *iface, REFIID iid, void **obj) 2742 { 2743 *obj = NULL; 2744 if (IsEqualIID(&IID_IUnknown, iid) || 2745 IsEqualIID(&IID_IAdviseSink, iid)) 2746 { 2747 *obj = iface; 2748 } 2749 2750 if(*obj) 2751 { 2752 IAdviseSink_AddRef(iface); 2753 return S_OK; 2754 } 2755 return E_NOINTERFACE; 2756 } 2757 2758 static ULONG WINAPI DataCache_IAdviseSink_AddRef(IAdviseSink *iface) 2759 { 2760 return 2; 2761 } 2762 2763 static ULONG WINAPI DataCache_IAdviseSink_Release(IAdviseSink *iface) 2764 { 2765 return 1; 2766 } 2767 2768 static void WINAPI DataCache_OnDataChange(IAdviseSink *iface, FORMATETC *fmt, STGMEDIUM *med) 2769 { 2770 DataCache *This = impl_from_IAdviseSink(iface); 2771 TRACE("(%p)->(%s, %p)\n", This, debugstr_formatetc(fmt), med); 2772 IOleCache2_SetData(&This->IOleCache2_iface, fmt, med, FALSE); 2773 } 2774 2775 static void WINAPI DataCache_OnViewChange(IAdviseSink *iface, DWORD aspect, LONG index) 2776 { 2777 FIXME("stub\n"); 2778 } 2779 2780 static void WINAPI DataCache_OnRename(IAdviseSink *iface, IMoniker *mk) 2781 { 2782 FIXME("stub\n"); 2783 } 2784 2785 static void WINAPI DataCache_OnSave(IAdviseSink *iface) 2786 { 2787 FIXME("stub\n"); 2788 } 2789 2790 static void WINAPI DataCache_OnClose(IAdviseSink *iface) 2791 { 2792 FIXME("stub\n"); 2793 } 2794 2795 /* 2796 * Virtual function tables for the DataCache class. 2797 */ 2798 static const IUnknownVtbl DataCache_NDIUnknown_VTable = 2799 { 2800 DataCache_NDIUnknown_QueryInterface, 2801 DataCache_NDIUnknown_AddRef, 2802 DataCache_NDIUnknown_Release 2803 }; 2804 2805 static const IDataObjectVtbl DataCache_IDataObject_VTable = 2806 { 2807 DataCache_IDataObject_QueryInterface, 2808 DataCache_IDataObject_AddRef, 2809 DataCache_IDataObject_Release, 2810 DataCache_GetData, 2811 DataCache_GetDataHere, 2812 DataCache_QueryGetData, 2813 DataCache_GetCanonicalFormatEtc, 2814 DataCache_IDataObject_SetData, 2815 DataCache_EnumFormatEtc, 2816 DataCache_DAdvise, 2817 DataCache_DUnadvise, 2818 DataCache_EnumDAdvise 2819 }; 2820 2821 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable = 2822 { 2823 DataCache_IPersistStorage_QueryInterface, 2824 DataCache_IPersistStorage_AddRef, 2825 DataCache_IPersistStorage_Release, 2826 DataCache_GetClassID, 2827 DataCache_IsDirty, 2828 DataCache_InitNew, 2829 DataCache_Load, 2830 DataCache_Save, 2831 DataCache_SaveCompleted, 2832 DataCache_HandsOffStorage 2833 }; 2834 2835 static const IViewObject2Vtbl DataCache_IViewObject2_VTable = 2836 { 2837 DataCache_IViewObject2_QueryInterface, 2838 DataCache_IViewObject2_AddRef, 2839 DataCache_IViewObject2_Release, 2840 DataCache_Draw, 2841 DataCache_GetColorSet, 2842 DataCache_Freeze, 2843 DataCache_Unfreeze, 2844 DataCache_SetAdvise, 2845 DataCache_GetAdvise, 2846 DataCache_GetExtent 2847 }; 2848 2849 static const IOleCache2Vtbl DataCache_IOleCache2_VTable = 2850 { 2851 DataCache_IOleCache2_QueryInterface, 2852 DataCache_IOleCache2_AddRef, 2853 DataCache_IOleCache2_Release, 2854 DataCache_Cache, 2855 DataCache_Uncache, 2856 DataCache_EnumCache, 2857 DataCache_InitCache, 2858 DataCache_IOleCache2_SetData, 2859 DataCache_UpdateCache, 2860 DataCache_DiscardCache 2861 }; 2862 2863 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable = 2864 { 2865 DataCache_IOleCacheControl_QueryInterface, 2866 DataCache_IOleCacheControl_AddRef, 2867 DataCache_IOleCacheControl_Release, 2868 DataCache_OnRun, 2869 DataCache_OnStop 2870 }; 2871 2872 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable = 2873 { 2874 DataCache_IAdviseSink_QueryInterface, 2875 DataCache_IAdviseSink_AddRef, 2876 DataCache_IAdviseSink_Release, 2877 DataCache_OnDataChange, 2878 DataCache_OnViewChange, 2879 DataCache_OnRename, 2880 DataCache_OnSave, 2881 DataCache_OnClose 2882 }; 2883 2884 /********************************************************* 2885 * Method implementation for DataCache class. 2886 */ 2887 static DataCache* DataCache_Construct( 2888 REFCLSID clsid, 2889 LPUNKNOWN pUnkOuter) 2890 { 2891 DataCache* newObject = 0; 2892 2893 /* 2894 * Allocate space for the object. 2895 */ 2896 newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache)); 2897 2898 if (newObject==0) 2899 return newObject; 2900 2901 /* 2902 * Initialize the virtual function table. 2903 */ 2904 newObject->IDataObject_iface.lpVtbl = &DataCache_IDataObject_VTable; 2905 newObject->IUnknown_inner.lpVtbl = &DataCache_NDIUnknown_VTable; 2906 newObject->IPersistStorage_iface.lpVtbl = &DataCache_IPersistStorage_VTable; 2907 newObject->IViewObject2_iface.lpVtbl = &DataCache_IViewObject2_VTable; 2908 newObject->IOleCache2_iface.lpVtbl = &DataCache_IOleCache2_VTable; 2909 newObject->IOleCacheControl_iface.lpVtbl = &DataCache_IOleCacheControl_VTable; 2910 newObject->IAdviseSink_iface.lpVtbl = &DataCache_IAdviseSink_VTable; 2911 newObject->outer_unk = pUnkOuter ? pUnkOuter : &newObject->IUnknown_inner; 2912 newObject->ref = 1; 2913 2914 /* 2915 * Initialize the other members of the structure. 2916 */ 2917 newObject->sinkAspects = 0; 2918 newObject->sinkAdviseFlag = 0; 2919 newObject->sinkInterface = 0; 2920 newObject->clsid = CLSID_NULL; 2921 newObject->clsid_static = FALSE; 2922 newObject->presentationStorage = NULL; 2923 list_init(&newObject->cache_list); 2924 newObject->last_cache_id = 2; 2925 newObject->dirty = FALSE; 2926 newObject->running_object = NULL; 2927 2928 create_automatic_entry( newObject, clsid ); 2929 newObject->clsid = *clsid; 2930 2931 return newObject; 2932 } 2933 2934 /****************************************************************************** 2935 * CreateDataCache [OLE32.@] 2936 * 2937 * Creates a data cache to allow an object to render one or more of its views, 2938 * whether running or not. 2939 * 2940 * PARAMS 2941 * pUnkOuter [I] Outer unknown for the object. 2942 * rclsid [I] 2943 * riid [I] IID of interface to return. 2944 * ppvObj [O] Address where the data cache object will be stored on return. 2945 * 2946 * RETURNS 2947 * Success: S_OK. 2948 * Failure: HRESULT code. 2949 * 2950 * NOTES 2951 * The following interfaces are supported by the returned data cache object: 2952 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject, 2953 * IViewObject and IViewObject2. 2954 */ 2955 HRESULT WINAPI CreateDataCache( 2956 LPUNKNOWN pUnkOuter, 2957 REFCLSID rclsid, 2958 REFIID riid, 2959 LPVOID* ppvObj) 2960 { 2961 DataCache* newCache = NULL; 2962 HRESULT hr = S_OK; 2963 2964 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj); 2965 2966 /* 2967 * Sanity check 2968 */ 2969 if (ppvObj==0) 2970 return E_POINTER; 2971 2972 *ppvObj = 0; 2973 2974 /* 2975 * If this cache is constructed for aggregation, make sure 2976 * the caller is requesting the IUnknown interface. 2977 * This is necessary because it's the only time the non-delegating 2978 * IUnknown pointer can be returned to the outside. 2979 */ 2980 if ( pUnkOuter && !IsEqualIID(&IID_IUnknown, riid) ) 2981 return E_INVALIDARG; 2982 2983 /* 2984 * Try to construct a new instance of the class. 2985 */ 2986 newCache = DataCache_Construct(rclsid, 2987 pUnkOuter); 2988 2989 if (newCache == 0) 2990 return E_OUTOFMEMORY; 2991 2992 hr = IUnknown_QueryInterface(&newCache->IUnknown_inner, riid, ppvObj); 2993 IUnknown_Release(&newCache->IUnknown_inner); 2994 2995 return hr; 2996 } 2997