4 * Copyright 1999 Francis Beaudet
5 * Copyright 2000 Abey George
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.
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.
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
22 * The OLE2 data cache supports a whole whack of
23 * interfaces including:
24 * IDataObject, IPersistStorage, IViewObject2,
25 * IOleCache2 and IOleCacheControl.
27 * Most of the implementation details are taken from: Inside OLE
28 * second edition by Kraig Brockschmidt,
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.
51 #define NONAMELESSUNION
59 #include "compobj_private.h"
60 #include "wine/unicode.h"
61 #include "wine/list.h"
62 #include "wine/debug.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
66 /****************************************************************************
67 * PresentationDataHeader
69 * This structure represents the header of the \002OlePresXXX stream in
70 * the OLE object storage.
72 typedef struct PresentationDataHeader
75 * - standard clipformat:
76 * DWORD length = 0xffffffff;
78 * - or custom clipformat:
80 * CHAR format_name[length]; (null-terminated)
82 DWORD tdSize
; /* This is actually a truncated DVTARGETDEVICE, if tdSize > sizeof(DWORD)
83 then there are tdSize - sizeof(DWORD) more bytes before dvAspect */
87 DWORD unknown7
; /* 0 */
88 DWORD dwObjectExtentX
;
89 DWORD dwObjectExtentY
;
91 } PresentationDataHeader
;
93 #define STREAM_NUMBER_NOT_SET -2
94 #define STREAM_NUMBER_CONTENTS -1 /* CONTENTS stream */
96 typedef struct DataCacheEntry
99 /* format of this entry */
107 /* stream number that the entry was loaded from.
108 This is used to defer loading until the data is actually needed. */
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. */
113 /* sink id set when object is running */
115 /* Advise sink flags */
119 /****************************************************************************
125 * List all interface here
127 IUnknown IUnknown_inner
;
128 IDataObject IDataObject_iface
;
129 IPersistStorage IPersistStorage_iface
;
130 IViewObject2 IViewObject2_iface
;
131 IOleCache2 IOleCache2_iface
;
132 IOleCacheControl IOleCacheControl_iface
;
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
;
139 * Reference count of this object
144 * IUnknown implementation of the outer object.
149 * The user of this object can setup ONE advise sink
150 * connection with the object. These parameters describe
154 DWORD sinkAdviseFlag
;
155 IAdviseSink
*sinkInterface
;
158 /* Is the clsid one of the CLSID_Picture classes */
161 IStorage
*presentationStorage
;
163 /* list of cache entries */
164 struct list cache_list
;
165 /* last id assigned to an entry */
169 /* running object set by OnRun */
170 IDataObject
*running_object
;
173 typedef struct DataCache DataCache
;
176 * Here, I define utility macros to help with the casting of the
178 * There is a version to accommodate all of the VTables implemented
182 static inline DataCache
*impl_from_IDataObject( IDataObject
*iface
)
184 return CONTAINING_RECORD(iface
, DataCache
, IDataObject_iface
);
187 static inline DataCache
*impl_from_IUnknown( IUnknown
*iface
)
189 return CONTAINING_RECORD(iface
, DataCache
, IUnknown_inner
);
192 static inline DataCache
*impl_from_IPersistStorage( IPersistStorage
*iface
)
194 return CONTAINING_RECORD(iface
, DataCache
, IPersistStorage_iface
);
197 static inline DataCache
*impl_from_IViewObject2( IViewObject2
*iface
)
199 return CONTAINING_RECORD(iface
, DataCache
, IViewObject2_iface
);
202 static inline DataCache
*impl_from_IOleCache2( IOleCache2
*iface
)
204 return CONTAINING_RECORD(iface
, DataCache
, IOleCache2_iface
);
207 static inline DataCache
*impl_from_IOleCacheControl( IOleCacheControl
*iface
)
209 return CONTAINING_RECORD(iface
, DataCache
, IOleCacheControl_iface
);
212 static inline DataCache
*impl_from_IAdviseSink( IAdviseSink
*iface
)
214 return CONTAINING_RECORD(iface
, DataCache
, IAdviseSink_iface
);
217 const char *debugstr_formatetc(const FORMATETC
*formatetc
)
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
);
224 /***********************************************************************
227 * Return the size of the bitmap info structure including color table.
229 static int bitmap_info_size( const BITMAPINFO
* info
, WORD coloruse
)
231 unsigned int colors
, size
, masks
= 0;
233 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
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
));
240 else /* assume BITMAPINFOHEADER */
242 colors
= info
->bmiHeader
.biClrUsed
;
243 if (colors
> 256) /* buffer overflow otherwise */
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
));
253 static void DataCacheEntry_Destroy(DataCache
*cache
, DataCacheEntry
*cache_entry
)
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
);
261 HeapFree(GetProcessHeap(), 0, cache_entry
);
264 static void DataCache_Destroy(
265 DataCache
* ptrToDestroy
)
267 DataCacheEntry
*cache_entry
, *next_cache_entry
;
271 if (ptrToDestroy
->sinkInterface
!= NULL
)
273 IAdviseSink_Release(ptrToDestroy
->sinkInterface
);
274 ptrToDestroy
->sinkInterface
= NULL
;
277 LIST_FOR_EACH_ENTRY_SAFE(cache_entry
, next_cache_entry
, &ptrToDestroy
->cache_list
, DataCacheEntry
, entry
)
278 DataCacheEntry_Destroy(ptrToDestroy
, cache_entry
);
280 if (ptrToDestroy
->presentationStorage
!= NULL
)
282 IStorage_Release(ptrToDestroy
->presentationStorage
);
283 ptrToDestroy
->presentationStorage
= NULL
;
287 * Free the datacache pointer.
289 HeapFree(GetProcessHeap(), 0, ptrToDestroy
);
292 static DataCacheEntry
*DataCache_GetEntryForFormatEtc(DataCache
*This
, const FORMATETC
*formatetc
)
294 DataCacheEntry
*cache_entry
;
295 FORMATETC fmt
= *formatetc
;
297 if (fmt
.cfFormat
== CF_BITMAP
)
299 fmt
.cfFormat
= CF_DIB
;
300 fmt
.tymed
= TYMED_HGLOBAL
;
303 LIST_FOR_EACH_ENTRY(cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
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 */
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
)
319 DataCacheEntry
*entry
;
320 struct list
*head
= list_head( &cache
->cache_list
);
327 entry
= LIST_ENTRY( head
, DataCacheEntry
, entry
);
330 *cache_entry
= entry
;
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
341 static HRESULT
check_valid_formatetc( const FORMATETC
*fmt
)
343 /* DVASPECT_ICON must be CF_METAFILEPICT */
344 if (fmt
->dwAspect
== DVASPECT_ICON
&& fmt
->cfFormat
!= CF_METAFILEPICT
)
345 return DV_E_FORMATETC
;
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
))
353 else if (fmt
->tymed
== TYMED_HGLOBAL
)
354 return CACHE_S_FORMATETC_NOTSUPPORTED
;
357 WARN("invalid clipformat/tymed combination: %d/%d\n", fmt
->cfFormat
, fmt
->tymed
);
362 static BOOL
init_cache_entry(DataCacheEntry
*entry
, const FORMATETC
*fmt
, DWORD advf
,
367 hr
= copy_formatetc(&entry
->fmtetc
, fmt
);
368 if (FAILED(hr
)) return FALSE
;
370 entry
->stgmedium
.tymed
= TYMED_NULL
;
371 entry
->stgmedium
.pUnkForRelease
= NULL
;
374 entry
->load_stream_num
= STREAM_NUMBER_NOT_SET
;
375 entry
->save_stream_num
= STREAM_NUMBER_NOT_SET
;
377 entry
->advise_flags
= advf
;
382 static HRESULT
DataCache_CreateEntry(DataCache
*This
, const FORMATETC
*formatetc
, DWORD advf
,
383 BOOL automatic
, DataCacheEntry
**cache_entry
)
386 DWORD id
= automatic
? 1 : This
->last_cache_id
;
387 DataCacheEntry
*entry
;
389 hr
= check_valid_formatetc( formatetc
);
392 if (hr
== CACHE_S_FORMATETC_NOTSUPPORTED
)
393 TRACE("creating unsupported format %d\n", formatetc
->cfFormat
);
395 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(*entry
));
397 return E_OUTOFMEMORY
;
399 if (!init_cache_entry(entry
, formatetc
, advf
, id
))
403 list_add_head(&This
->cache_list
, &entry
->entry
);
406 list_add_tail(&This
->cache_list
, &entry
->entry
);
407 This
->last_cache_id
++;
410 if (cache_entry
) *cache_entry
= entry
;
414 HeapFree(GetProcessHeap(), 0, entry
);
415 return E_OUTOFMEMORY
;
418 /************************************************************************
419 * DataCache_FireOnViewChange
421 * This method will fire an OnViewChange notification to the advise
422 * sink registered with the datacache.
424 * See IAdviseSink::OnViewChange for more details.
426 static void DataCache_FireOnViewChange(
431 TRACE("(%p, %x, %d)\n", this, aspect
, lindex
);
434 * The sink supplies a filter when it registers
435 * we make sure we only send the notifications when that
438 if ((this->sinkAspects
& aspect
) != 0)
440 if (this->sinkInterface
!= NULL
)
442 IAdviseSink_OnViewChange(this->sinkInterface
,
447 * Some sinks want to be unregistered automatically when
448 * the first notification goes out.
450 if ( (this->sinkAdviseFlag
& ADVF_ONLYONCE
) != 0)
452 IAdviseSink_Release(this->sinkInterface
);
454 this->sinkInterface
= NULL
;
455 this->sinkAspects
= 0;
456 this->sinkAdviseFlag
= 0;
462 static HRESULT
read_clipformat(IStream
*stream
, CLIPFORMAT
*clipformat
)
470 hr
= IStream_Read(stream
, &length
, sizeof(length
), &read
);
471 if (hr
!= S_OK
|| read
!= sizeof(length
))
472 return DV_E_CLIPFORMAT
;
474 /* No clipboard format present */
480 hr
= IStream_Read(stream
, &cf
, sizeof(cf
), &read
);
481 if (hr
!= S_OK
|| read
!= sizeof(cf
))
482 return DV_E_CLIPFORMAT
;
487 char *format_name
= HeapAlloc(GetProcessHeap(), 0, length
);
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')
493 HeapFree(GetProcessHeap(), 0, format_name
);
494 return DV_E_CLIPFORMAT
;
496 *clipformat
= RegisterClipboardFormatA(format_name
);
497 HeapFree(GetProcessHeap(), 0, format_name
);
502 static HRESULT
write_clipformat(IStream
*stream
, CLIPFORMAT clipformat
)
506 char format_name
[256];
510 else if (clipformat
< 0xc000)
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
++;
518 hr
= IStream_Write(stream
, &length
, sizeof(length
), NULL
);
519 if (FAILED(hr
) || clipformat
== 0)
522 if (clipformat
< 0xc000)
524 DWORD cf
= clipformat
;
525 hr
= IStream_Write(stream
, &cf
, sizeof(cf
), NULL
);
529 hr
= IStream_Write(stream
, format_name
, length
, NULL
);
534 static const WCHAR CONTENTS
[] = {'C','O','N','T','E','N','T','S',0};
536 static HRESULT
open_pres_stream( IStorage
*stg
, int stream_number
, IStream
**stm
)
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
;
544 if (stream_number
== STREAM_NUMBER_NOT_SET
) return E_FAIL
;
545 if (stream_number
== STREAM_NUMBER_CONTENTS
) name
= CONTENTS
;
547 return IStorage_OpenStream( stg
, name
, NULL
, STGM_READ
| STGM_SHARE_EXCLUSIVE
, 0, stm
);
550 static HRESULT
synthesize_emf( HMETAFILEPICT data
, STGMEDIUM
*med
)
557 if (!(pict
= GlobalLock( data
))) return hr
;
559 size
= GetMetaFileBitsEx( pict
->hMF
, 0, NULL
);
560 if ((bits
= HeapAlloc( GetProcessHeap(), 0, size
)))
562 GetMetaFileBitsEx( pict
->hMF
, size
, bits
);
563 med
->u
.hEnhMetaFile
= SetWinMetaFileBits( size
, bits
, NULL
, pict
);
564 HeapFree( GetProcessHeap(), 0, bits
);
565 med
->tymed
= TYMED_ENHMF
;
566 med
->pUnkForRelease
= NULL
;
570 GlobalUnlock( data
);
573 #include <pshpack2.h>
574 struct meta_placeable
578 WORD bounding_box
[4];
585 static HRESULT
load_mf_pict( DataCacheEntry
*cache_entry
, IStream
*stm
)
589 ULARGE_INTEGER current_pos
;
591 METAFILEPICT
*mfpict
;
593 PresentationDataHeader header
;
594 CLIPFORMAT clipformat
;
595 static const LARGE_INTEGER offset_zero
;
597 struct meta_placeable mf_place
;
599 hr
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
600 if (FAILED( hr
)) return hr
;
602 if (cache_entry
->load_stream_num
!= STREAM_NUMBER_CONTENTS
)
604 hr
= read_clipformat( stm
, &clipformat
);
605 if (hr
!= S_OK
) return hr
;
606 hr
= IStream_Read( stm
, &header
, sizeof(header
), &read
);
607 if (hr
!= S_OK
) return hr
;
611 hr
= IStream_Read( stm
, &mf_place
, sizeof(mf_place
), &read
);
612 if (hr
!= S_OK
) return hr
;
615 hr
= IStream_Seek( stm
, offset_zero
, STREAM_SEEK_CUR
, ¤t_pos
);
616 if (FAILED( hr
)) return hr
;
617 stat
.cbSize
.QuadPart
-= current_pos
.QuadPart
;
619 hmfpict
= GlobalAlloc( GMEM_MOVEABLE
, sizeof(METAFILEPICT
) );
620 if (!hmfpict
) return E_OUTOFMEMORY
;
621 mfpict
= GlobalLock( hmfpict
);
623 bits
= HeapAlloc( GetProcessHeap(), 0, stat
.cbSize
.u
.LowPart
);
626 GlobalFree( hmfpict
);
627 return E_OUTOFMEMORY
;
630 hr
= IStream_Read( stm
, bits
, stat
.cbSize
.u
.LowPart
, &read
);
634 mfpict
->mm
= MM_ANISOTROPIC
;
635 /* FIXME: get this from the stream */
636 if (cache_entry
->load_stream_num
!= STREAM_NUMBER_CONTENTS
)
638 mfpict
->xExt
= header
.dwObjectExtentX
;
639 mfpict
->yExt
= header
.dwObjectExtentY
;
643 mfpict
->xExt
= ((mf_place
.bounding_box
[2] - mf_place
.bounding_box
[0])
644 * 2540) / mf_place
.inch
;
645 mfpict
->yExt
= ((mf_place
.bounding_box
[3] - mf_place
.bounding_box
[1])
646 * 2540) / mf_place
.inch
;
648 mfpict
->hMF
= SetMetaFileBitsEx( stat
.cbSize
.u
.LowPart
, bits
);
653 GlobalUnlock( hmfpict
);
656 cache_entry
->stgmedium
.tymed
= TYMED_MFPICT
;
657 cache_entry
->stgmedium
.u
.hMetaFilePict
= hmfpict
;
660 GlobalFree( hmfpict
);
662 HeapFree( GetProcessHeap(), 0, bits
);
667 static HRESULT
load_dib( DataCacheEntry
*cache_entry
, IStream
*stm
)
673 ULONG read
, info_size
, bi_size
;
674 BITMAPFILEHEADER file
;
675 BITMAPINFOHEADER
*info
;
677 PresentationDataHeader pres
;
678 ULARGE_INTEGER current_pos
;
679 static const LARGE_INTEGER offset_zero
;
681 hr
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
682 if (FAILED( hr
)) return hr
;
684 if (cache_entry
->load_stream_num
!= STREAM_NUMBER_CONTENTS
)
686 hr
= read_clipformat( stm
, &cf
);
687 if (hr
!= S_OK
) return hr
;
688 hr
= IStream_Read( stm
, &pres
, sizeof(pres
), &read
);
689 if (hr
!= S_OK
) return hr
;
693 hr
= IStream_Read( stm
, &file
, sizeof(BITMAPFILEHEADER
), &read
);
694 if (hr
!= S_OK
) return hr
;
697 hr
= IStream_Seek( stm
, offset_zero
, STREAM_SEEK_CUR
, ¤t_pos
);
698 if (FAILED( hr
)) return hr
;
699 stat
.cbSize
.QuadPart
-= current_pos
.QuadPart
;
701 hglobal
= GlobalAlloc( GMEM_MOVEABLE
, stat
.cbSize
.u
.LowPart
);
702 if (!hglobal
) return E_OUTOFMEMORY
;
703 dib
= GlobalLock( hglobal
);
705 /* read first DWORD of BITMAPINFOHEADER */
706 hr
= IStream_Read( stm
, dib
, sizeof(DWORD
), &read
);
707 if (hr
!= S_OK
) goto fail
;
708 bi_size
= *(DWORD
*)dib
;
709 if (stat
.cbSize
.QuadPart
< bi_size
) goto fail
;
711 /* read rest of BITMAPINFOHEADER */
712 hr
= IStream_Read( stm
, dib
+ sizeof(DWORD
), bi_size
- sizeof(DWORD
), &read
);
713 if (hr
!= S_OK
) goto fail
;
715 info_size
= bitmap_info_size( (BITMAPINFO
*)dib
, DIB_RGB_COLORS
);
716 if (stat
.cbSize
.QuadPart
< info_size
) goto fail
;
717 if (info_size
> bi_size
)
719 hr
= IStream_Read( stm
, dib
+ bi_size
, info_size
- bi_size
, &read
);
720 if (hr
!= S_OK
) goto fail
;
722 stat
.cbSize
.QuadPart
-= info_size
;
724 /* set Stream pointer to beginning of bitmap bits */
725 if (cache_entry
->load_stream_num
== STREAM_NUMBER_CONTENTS
&& file
.bfOffBits
)
729 skip
.QuadPart
= file
.bfOffBits
- sizeof(file
) - info_size
;
730 if (stat
.cbSize
.QuadPart
< skip
.QuadPart
) goto fail
;
731 hr
= IStream_Seek( stm
, skip
, STREAM_SEEK_CUR
, NULL
);
732 if (hr
!= S_OK
) goto fail
;
733 stat
.cbSize
.QuadPart
-= skip
.QuadPart
;
736 hr
= IStream_Read( stm
, dib
+ info_size
, stat
.cbSize
.u
.LowPart
, &read
);
737 if (hr
!= S_OK
) goto fail
;
739 if (bi_size
>= sizeof(*info
))
741 info
= (BITMAPINFOHEADER
*)dib
;
742 if (info
->biXPelsPerMeter
== 0 || info
->biYPelsPerMeter
== 0)
744 HDC hdc
= GetDC( 0 );
745 info
->biXPelsPerMeter
= MulDiv( GetDeviceCaps( hdc
, LOGPIXELSX
), 10000, 254 );
746 info
->biYPelsPerMeter
= MulDiv( GetDeviceCaps( hdc
, LOGPIXELSY
), 10000, 254 );
751 GlobalUnlock( hglobal
);
753 cache_entry
->stgmedium
.tymed
= TYMED_HGLOBAL
;
754 cache_entry
->stgmedium
.u
.hGlobal
= hglobal
;
759 GlobalUnlock( hglobal
);
760 GlobalFree( hglobal
);
765 static HRESULT
load_emf( DataCacheEntry
*cache_entry
, IStream
*stm
)
769 if (cache_entry
->load_stream_num
!= STREAM_NUMBER_CONTENTS
)
773 hr
= load_mf_pict( cache_entry
, stm
);
776 hr
= synthesize_emf( cache_entry
->stgmedium
.u
.hMetaFilePict
, &stgmed
);
777 ReleaseStgMedium( &cache_entry
->stgmedium
);
780 cache_entry
->stgmedium
= stgmed
;
786 ULONG read
, size_bits
;
788 hr
= IStream_Stat( stm
, &stat
, STATFLAG_NONAME
);
792 data
= HeapAlloc( GetProcessHeap(), 0, stat
.cbSize
.u
.LowPart
);
793 if (!data
) return E_OUTOFMEMORY
;
795 hr
= IStream_Read( stm
, data
, stat
.cbSize
.u
.LowPart
, &read
);
798 HeapFree( GetProcessHeap(), 0, data
);
802 if (read
<= sizeof(DWORD
) + sizeof(ENHMETAHEADER
))
804 HeapFree( GetProcessHeap(), 0, data
);
807 size_bits
= read
- sizeof(DWORD
) - sizeof(ENHMETAHEADER
);
808 cache_entry
->stgmedium
.u
.hEnhMetaFile
= SetEnhMetaFileBits( size_bits
, data
+ (read
- size_bits
) );
809 cache_entry
->stgmedium
.tymed
= TYMED_ENHMF
;
810 cache_entry
->stgmedium
.pUnkForRelease
= NULL
;
812 HeapFree( GetProcessHeap(), 0, data
);
819 /************************************************************************
820 * DataCacheEntry_LoadData
822 * This method will read information for the requested presentation
823 * into the given structure.
826 * This - The entry to load the data from.
829 * This method returns a metafile handle if it is successful.
830 * it will return 0 if not.
832 static HRESULT
DataCacheEntry_LoadData(DataCacheEntry
*cache_entry
, IStorage
*stg
)
837 if (!stg
) return OLE_E_BLANK
;
838 hr
= open_pres_stream( stg
, cache_entry
->load_stream_num
, &stm
);
839 if (FAILED(hr
)) return hr
;
841 switch (cache_entry
->fmtetc
.cfFormat
)
843 case CF_METAFILEPICT
:
844 hr
= load_mf_pict( cache_entry
, stm
);
848 hr
= load_dib( cache_entry
, stm
);
852 hr
= load_emf( cache_entry
, stm
);
856 FIXME( "Unimplemented clip format %x\n", cache_entry
->fmtetc
.cfFormat
);
860 IStream_Release( stm
);
864 static void init_stream_header(DataCacheEntry
*entry
, PresentationDataHeader
*header
)
866 if (entry
->fmtetc
.ptd
)
867 FIXME("ptd not serialized\n");
868 header
->tdSize
= sizeof(header
->tdSize
);
869 header
->dvAspect
= entry
->fmtetc
.dwAspect
;
870 header
->lindex
= entry
->fmtetc
.lindex
;
871 header
->advf
= entry
->advise_flags
;
872 header
->unknown7
= 0;
873 header
->dwObjectExtentX
= 0;
874 header
->dwObjectExtentY
= 0;
878 static HRESULT
save_dib(DataCacheEntry
*entry
, BOOL contents
, IStream
*stream
)
882 BITMAPINFO
*bmi
= NULL
;
884 if (entry
->stgmedium
.tymed
!= TYMED_NULL
)
886 data_size
= GlobalSize(entry
->stgmedium
.u
.hGlobal
);
887 bmi
= GlobalLock(entry
->stgmedium
.u
.hGlobal
);
892 PresentationDataHeader header
;
894 init_stream_header(entry
, &header
);
895 hr
= write_clipformat(stream
, entry
->fmtetc
.cfFormat
);
896 if (FAILED(hr
)) goto end
;
899 header
.dwSize
= data_size
;
900 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
901 if (bmi
->bmiHeader
.biXPelsPerMeter
!= 0 && bmi
->bmiHeader
.biYPelsPerMeter
!= 0)
903 header
.dwObjectExtentX
= MulDiv(bmi
->bmiHeader
.biWidth
, 100000, bmi
->bmiHeader
.biXPelsPerMeter
);
904 header
.dwObjectExtentY
= MulDiv(bmi
->bmiHeader
.biHeight
, 100000, bmi
->bmiHeader
.biYPelsPerMeter
);
909 header
.dwObjectExtentX
= MulDiv(bmi
->bmiHeader
.biWidth
, 2540, GetDeviceCaps(hdc
, LOGPIXELSX
));
910 header
.dwObjectExtentY
= MulDiv(bmi
->bmiHeader
.biHeight
, 2540, GetDeviceCaps(hdc
, LOGPIXELSY
));
914 hr
= IStream_Write(stream
, &header
, sizeof(PresentationDataHeader
), NULL
);
915 if (hr
== S_OK
&& data_size
)
916 hr
= IStream_Write(stream
, bmi
, data_size
, NULL
);
920 BITMAPFILEHEADER bmp_fhdr
;
922 bmp_fhdr
.bfType
= 0x4d42;
923 bmp_fhdr
.bfSize
= data_size
+ sizeof(BITMAPFILEHEADER
);
924 bmp_fhdr
.bfReserved1
= bmp_fhdr
.bfReserved2
= 0;
925 bmp_fhdr
.bfOffBits
= bitmap_info_size(bmi
, DIB_RGB_COLORS
) + sizeof(BITMAPFILEHEADER
);
926 hr
= IStream_Write(stream
, &bmp_fhdr
, sizeof(BITMAPFILEHEADER
), NULL
);
928 hr
= IStream_Write(stream
, bmi
, data_size
, NULL
);
932 if (bmi
) GlobalUnlock(entry
->stgmedium
.u
.hGlobal
);
936 static HRESULT
save_mfpict(DataCacheEntry
*entry
, BOOL contents
, IStream
*stream
)
941 METAFILEPICT
*mfpict
= NULL
;
945 PresentationDataHeader header
;
947 init_stream_header(entry
, &header
);
948 hr
= write_clipformat(stream
, entry
->fmtetc
.cfFormat
);
949 if (FAILED(hr
)) return hr
;
950 if (entry
->stgmedium
.tymed
!= TYMED_NULL
)
952 mfpict
= GlobalLock(entry
->stgmedium
.u
.hMetaFilePict
);
954 return DV_E_STGMEDIUM
;
955 data_size
= GetMetaFileBitsEx(mfpict
->hMF
, 0, NULL
);
956 header
.dwObjectExtentX
= mfpict
->xExt
;
957 header
.dwObjectExtentY
= mfpict
->yExt
;
958 header
.dwSize
= data_size
;
959 data
= HeapAlloc(GetProcessHeap(), 0, header
.dwSize
);
962 GlobalUnlock(entry
->stgmedium
.u
.hMetaFilePict
);
963 return E_OUTOFMEMORY
;
965 GetMetaFileBitsEx(mfpict
->hMF
, header
.dwSize
, data
);
966 GlobalUnlock(entry
->stgmedium
.u
.hMetaFilePict
);
968 hr
= IStream_Write(stream
, &header
, sizeof(PresentationDataHeader
), NULL
);
969 if (hr
== S_OK
&& data_size
)
970 hr
= IStream_Write(stream
, data
, data_size
, NULL
);
971 HeapFree(GetProcessHeap(), 0, data
);
973 else if (entry
->stgmedium
.tymed
!= TYMED_NULL
)
975 struct meta_placeable meta_place_rec
;
978 mfpict
= GlobalLock(entry
->stgmedium
.u
.hMetaFilePict
);
980 return DV_E_STGMEDIUM
;
981 data_size
= GetMetaFileBitsEx(mfpict
->hMF
, 0, NULL
);
982 data
= HeapAlloc(GetProcessHeap(), 0, data_size
);
985 GlobalUnlock(entry
->stgmedium
.u
.hMetaFilePict
);
986 return E_OUTOFMEMORY
;
988 GetMetaFileBitsEx(mfpict
->hMF
, data_size
, data
);
990 /* units are in 1/8th of a point (1 point is 1/72th of an inch) */
991 meta_place_rec
.key
= 0x9ac6cdd7;
992 meta_place_rec
.hwmf
= 0;
993 meta_place_rec
.inch
= 576;
994 meta_place_rec
.bounding_box
[0] = 0;
995 meta_place_rec
.bounding_box
[1] = 0;
996 meta_place_rec
.bounding_box
[2] = 0;
997 meta_place_rec
.bounding_box
[3] = 0;
998 meta_place_rec
.checksum
= 0;
999 meta_place_rec
.reserved
= 0;
1001 /* These values are rounded down so MulDiv won't do the right thing */
1002 meta_place_rec
.bounding_box
[2] = (LONGLONG
)mfpict
->xExt
* meta_place_rec
.inch
/ 2540;
1003 meta_place_rec
.bounding_box
[3] = (LONGLONG
)mfpict
->yExt
* meta_place_rec
.inch
/ 2540;
1004 GlobalUnlock(entry
->stgmedium
.u
.hMetaFilePict
);
1006 for (check
= (WORD
*)&meta_place_rec
; check
!= (WORD
*)&meta_place_rec
.checksum
; check
++)
1007 meta_place_rec
.checksum
^= *check
;
1008 hr
= IStream_Write(stream
, &meta_place_rec
, sizeof(struct meta_placeable
), NULL
);
1009 if (hr
== S_OK
&& data_size
)
1010 hr
= IStream_Write(stream
, data
, data_size
, NULL
);
1011 HeapFree(GetProcessHeap(), 0, data
);
1017 static HRESULT
save_emf(DataCacheEntry
*entry
, BOOL contents
, IStream
*stream
)
1025 PresentationDataHeader header
;
1026 METAFILEPICT
*mfpict
;
1029 init_stream_header(entry
, &header
);
1030 hr
= write_clipformat(stream
, entry
->fmtetc
.cfFormat
);
1036 data_size
= GetWinMetaFileBits(entry
->stgmedium
.u
.hEnhMetaFile
, 0, NULL
, MM_ANISOTROPIC
, hdc
);
1037 header
.dwSize
= data_size
;
1038 data
= HeapAlloc(GetProcessHeap(), 0, header
.dwSize
);
1042 return E_OUTOFMEMORY
;
1044 GetWinMetaFileBits(entry
->stgmedium
.u
.hEnhMetaFile
, header
.dwSize
, data
, MM_ANISOTROPIC
, hdc
);
1046 mfpict
= (METAFILEPICT
*)data
;
1047 header
.dwObjectExtentX
= mfpict
->xExt
;
1048 header
.dwObjectExtentY
= mfpict
->yExt
;
1049 hr
= IStream_Write(stream
, &header
, sizeof(PresentationDataHeader
), NULL
);
1050 if (hr
== S_OK
&& data_size
)
1051 hr
= IStream_Write(stream
, data
, data_size
, NULL
);
1052 HeapFree(GetProcessHeap(), 0, data
);
1054 else if (entry
->stgmedium
.tymed
!= TYMED_NULL
)
1056 data_size
= GetEnhMetaFileBits(entry
->stgmedium
.u
.hEnhMetaFile
, 0, NULL
);
1057 data
= HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD
) + sizeof(ENHMETAHEADER
) + data_size
);
1058 if (!data
) return E_OUTOFMEMORY
;
1059 *((DWORD
*)data
) = sizeof(ENHMETAHEADER
);
1060 GetEnhMetaFileBits(entry
->stgmedium
.u
.hEnhMetaFile
, data_size
, data
+ sizeof(DWORD
) + sizeof(ENHMETAHEADER
));
1061 memcpy(data
+ sizeof(DWORD
), data
+ sizeof(DWORD
) + sizeof(ENHMETAHEADER
), sizeof(ENHMETAHEADER
));
1062 data_size
+= sizeof(DWORD
) + sizeof(ENHMETAHEADER
);
1063 hr
= IStream_Write(stream
, data
, data_size
, NULL
);
1064 HeapFree(GetProcessHeap(), 0, data
);
1070 static HRESULT
save_view_cache(DataCacheEntry
*entry
, IStream
*stream
)
1073 PresentationDataHeader header
;
1075 init_stream_header(entry
, &header
);
1076 hr
= write_clipformat(stream
, entry
->fmtetc
.cfFormat
);
1078 hr
= IStream_Write(stream
, &header
, FIELD_OFFSET(PresentationDataHeader
, unknown7
), NULL
);
1083 static HRESULT
create_stream(DataCacheEntry
*cache_entry
, IStorage
*storage
,
1084 BOOL contents
, IStream
**stream
)
1086 WCHAR pres
[] = {2,'O','l','e','P','r','e','s',
1087 '0' + (cache_entry
->save_stream_num
/ 100) % 10,
1088 '0' + (cache_entry
->save_stream_num
/ 10) % 10,
1089 '0' + cache_entry
->save_stream_num
% 10, 0};
1097 return IStorage_CreateStream(storage
, name
,
1098 STGM_READWRITE
| STGM_SHARE_EXCLUSIVE
| STGM_CREATE
,
1102 static HRESULT
DataCacheEntry_Save(DataCacheEntry
*cache_entry
, IStorage
*storage
,
1107 BOOL contents
= (cache_entry
->id
== 1);
1109 TRACE("stream_number = %d, fmtetc = %s\n", cache_entry
->save_stream_num
, debugstr_formatetc(&cache_entry
->fmtetc
));
1111 hr
= create_stream(cache_entry
, storage
, contents
, &stream
);
1115 switch (cache_entry
->fmtetc
.cfFormat
)
1118 hr
= save_dib(cache_entry
, contents
, stream
);
1120 case CF_METAFILEPICT
:
1121 hr
= save_mfpict(cache_entry
, contents
, stream
);
1123 case CF_ENHMETAFILE
:
1124 hr
= save_emf(cache_entry
, contents
, stream
);
1127 hr
= save_view_cache(cache_entry
, stream
);
1130 FIXME("got unsupported clipboard format %x\n", cache_entry
->fmtetc
.cfFormat
);
1133 IStream_Release(stream
);
1137 /* helper for copying STGMEDIUM of type bitmap, MF, EMF or HGLOBAL.
1138 * does no checking of whether src_stgm has a supported tymed, so this should be
1139 * done in the caller */
1140 static HRESULT
copy_stg_medium(CLIPFORMAT cf
, STGMEDIUM
*dest_stgm
,
1141 const STGMEDIUM
*src_stgm
)
1143 if (src_stgm
->tymed
== TYMED_MFPICT
)
1145 const METAFILEPICT
*src_mfpict
= GlobalLock(src_stgm
->u
.hMetaFilePict
);
1146 METAFILEPICT
*dest_mfpict
;
1149 return DV_E_STGMEDIUM
;
1150 dest_stgm
->u
.hMetaFilePict
= GlobalAlloc(GMEM_MOVEABLE
, sizeof(METAFILEPICT
));
1151 dest_mfpict
= GlobalLock(dest_stgm
->u
.hMetaFilePict
);
1154 GlobalUnlock(src_stgm
->u
.hMetaFilePict
);
1155 return E_OUTOFMEMORY
;
1157 *dest_mfpict
= *src_mfpict
;
1158 dest_mfpict
->hMF
= CopyMetaFileW(src_mfpict
->hMF
, NULL
);
1159 GlobalUnlock(src_stgm
->u
.hMetaFilePict
);
1160 GlobalUnlock(dest_stgm
->u
.hMetaFilePict
);
1162 else if (src_stgm
->tymed
!= TYMED_NULL
)
1164 dest_stgm
->u
.hGlobal
= OleDuplicateData(src_stgm
->u
.hGlobal
, cf
,
1166 if (!dest_stgm
->u
.hGlobal
)
1167 return E_OUTOFMEMORY
;
1169 dest_stgm
->tymed
= src_stgm
->tymed
;
1170 dest_stgm
->pUnkForRelease
= src_stgm
->pUnkForRelease
;
1171 if (dest_stgm
->pUnkForRelease
)
1172 IUnknown_AddRef(dest_stgm
->pUnkForRelease
);
1176 static HRESULT
synthesize_dib( HBITMAP bm
, STGMEDIUM
*med
)
1178 HDC hdc
= GetDC( 0 );
1179 BITMAPINFOHEADER header
;
1181 HRESULT hr
= E_FAIL
;
1184 memset( &header
, 0, sizeof(header
) );
1185 header
.biSize
= sizeof(header
);
1186 if (!GetDIBits( hdc
, bm
, 0, 0, NULL
, (BITMAPINFO
*)&header
, DIB_RGB_COLORS
)) goto done
;
1188 header_size
= bitmap_info_size( (BITMAPINFO
*)&header
, DIB_RGB_COLORS
);
1189 if (!(med
->u
.hGlobal
= GlobalAlloc( GMEM_MOVEABLE
, header_size
+ header
.biSizeImage
))) goto done
;
1190 bmi
= GlobalLock( med
->u
.hGlobal
);
1191 memset( bmi
, 0, header_size
);
1192 memcpy( bmi
, &header
, header
.biSize
);
1193 GetDIBits( hdc
, bm
, 0, abs(header
.biHeight
), (char *)bmi
+ header_size
, bmi
, DIB_RGB_COLORS
);
1194 GlobalUnlock( med
->u
.hGlobal
);
1195 med
->tymed
= TYMED_HGLOBAL
;
1196 med
->pUnkForRelease
= NULL
;
1200 ReleaseDC( 0, hdc
);
1204 static HRESULT
synthesize_bitmap( HGLOBAL dib
, STGMEDIUM
*med
)
1206 HRESULT hr
= E_FAIL
;
1208 HDC hdc
= GetDC( 0 );
1210 if ((bmi
= GlobalLock( dib
)))
1212 /* FIXME: validate data size */
1213 med
->u
.hBitmap
= CreateDIBitmap( hdc
, &bmi
->bmiHeader
, CBM_INIT
,
1214 (char *)bmi
+ bitmap_info_size( bmi
, DIB_RGB_COLORS
),
1215 bmi
, DIB_RGB_COLORS
);
1216 GlobalUnlock( dib
);
1217 med
->tymed
= TYMED_GDI
;
1218 med
->pUnkForRelease
= NULL
;
1221 ReleaseDC( 0, hdc
);
1225 static HRESULT
DataCacheEntry_SetData(DataCacheEntry
*cache_entry
,
1226 const FORMATETC
*formatetc
,
1227 STGMEDIUM
*stgmedium
,
1233 if ((!cache_entry
->fmtetc
.cfFormat
&& !formatetc
->cfFormat
) ||
1234 (cache_entry
->fmtetc
.tymed
== TYMED_NULL
&& formatetc
->tymed
== TYMED_NULL
) ||
1235 stgmedium
->tymed
== TYMED_NULL
)
1237 WARN("invalid formatetc\n");
1238 return DV_E_FORMATETC
;
1241 cache_entry
->dirty
= TRUE
;
1242 ReleaseStgMedium(&cache_entry
->stgmedium
);
1244 if (formatetc
->cfFormat
== CF_BITMAP
)
1246 hr
= synthesize_dib( stgmedium
->u
.hBitmap
, ©
);
1247 if (FAILED(hr
)) return hr
;
1248 if (fRelease
) ReleaseStgMedium(stgmedium
);
1252 else if (formatetc
->cfFormat
== CF_METAFILEPICT
&& cache_entry
->fmtetc
.cfFormat
== CF_ENHMETAFILE
)
1254 hr
= synthesize_emf( stgmedium
->u
.hMetaFilePict
, ©
);
1255 if (FAILED(hr
)) return hr
;
1256 if (fRelease
) ReleaseStgMedium(stgmedium
);
1263 cache_entry
->stgmedium
= *stgmedium
;
1267 return copy_stg_medium(cache_entry
->fmtetc
.cfFormat
, &cache_entry
->stgmedium
, stgmedium
);
1270 static HRESULT
DataCacheEntry_GetData(DataCacheEntry
*cache_entry
, IStorage
*stg
, FORMATETC
*fmt
, STGMEDIUM
*stgmedium
)
1272 if (cache_entry
->stgmedium
.tymed
== TYMED_NULL
&& cache_entry
->load_stream_num
!= STREAM_NUMBER_NOT_SET
)
1274 HRESULT hr
= DataCacheEntry_LoadData(cache_entry
, stg
);
1278 if (cache_entry
->stgmedium
.tymed
== TYMED_NULL
)
1281 if (fmt
->cfFormat
== CF_BITMAP
)
1282 return synthesize_bitmap( cache_entry
->stgmedium
.u
.hGlobal
, stgmedium
);
1284 return copy_stg_medium(cache_entry
->fmtetc
.cfFormat
, stgmedium
, &cache_entry
->stgmedium
);
1287 static inline HRESULT
DataCacheEntry_DiscardData(DataCacheEntry
*cache_entry
)
1289 ReleaseStgMedium(&cache_entry
->stgmedium
);
1293 static inline DWORD
tymed_from_cf( DWORD cf
)
1297 case CF_BITMAP
: return TYMED_GDI
;
1298 case CF_METAFILEPICT
: return TYMED_MFPICT
;
1299 case CF_ENHMETAFILE
: return TYMED_ENHMF
;
1301 default: return TYMED_HGLOBAL
;
1305 /****************************************************************
1306 * create_automatic_entry
1308 * Creates an appropriate cache entry for one of the CLSID_Picture_
1309 * classes. The connection id of the entry is one. Any pre-existing
1310 * automatic entry is re-assigned a new connection id, and moved to
1311 * the end of the list.
1313 static HRESULT
create_automatic_entry(DataCache
*cache
, const CLSID
*clsid
)
1315 static const struct data
1321 { &CLSID_Picture_Dib
, { CF_DIB
, 0, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
} },
1322 { &CLSID_Picture_Metafile
, { CF_METAFILEPICT
, 0, DVASPECT_CONTENT
, -1, TYMED_MFPICT
} },
1323 { &CLSID_Picture_EnhMetafile
, { CF_ENHMETAFILE
, 0, DVASPECT_CONTENT
, -1, TYMED_ENHMF
} },
1326 const struct data
*ptr
= data
;
1328 DataCacheEntry
*entry
;
1330 if (IsEqualCLSID( &cache
->clsid
, clsid
)) return S_OK
;
1332 /* move and reassign any pre-existing automatic entry */
1333 if ((head
= list_head( &cache
->cache_list
)))
1335 entry
= LIST_ENTRY( head
, DataCacheEntry
, entry
);
1338 list_remove( &entry
->entry
);
1339 entry
->id
= cache
->last_cache_id
++;
1340 list_add_tail( &cache
->cache_list
, &entry
->entry
);
1346 if (IsEqualCLSID( clsid
, ptr
->clsid
))
1348 cache
->clsid_static
= TRUE
;
1349 return DataCache_CreateEntry( cache
, &ptr
->fmt
, 0, TRUE
, NULL
);
1353 cache
->clsid_static
= FALSE
;
1357 /*********************************************************
1358 * Method implementation for the non delegating IUnknown
1359 * part of the DataCache class.
1362 /************************************************************************
1363 * DataCache_NDIUnknown_QueryInterface (IUnknown)
1365 * This version of QueryInterface will not delegate its implementation
1366 * to the outer unknown.
1368 static HRESULT WINAPI
DataCache_NDIUnknown_QueryInterface(
1373 DataCache
*this = impl_from_IUnknown(iface
);
1376 return E_INVALIDARG
;
1380 if (IsEqualIID(&IID_IUnknown
, riid
))
1382 if (this->outer_unk
== iface
) /* non-aggregated, return IUnknown from IOleCache2 */
1383 *ppvObject
= &this->IOleCache2_iface
;
1387 else if (IsEqualIID(&IID_IDataObject
, riid
))
1389 *ppvObject
= &this->IDataObject_iface
;
1391 else if ( IsEqualIID(&IID_IPersistStorage
, riid
) ||
1392 IsEqualIID(&IID_IPersist
, riid
) )
1394 *ppvObject
= &this->IPersistStorage_iface
;
1396 else if ( IsEqualIID(&IID_IViewObject
, riid
) ||
1397 IsEqualIID(&IID_IViewObject2
, riid
) )
1399 *ppvObject
= &this->IViewObject2_iface
;
1401 else if ( IsEqualIID(&IID_IOleCache
, riid
) ||
1402 IsEqualIID(&IID_IOleCache2
, riid
) )
1404 *ppvObject
= &this->IOleCache2_iface
;
1406 else if ( IsEqualIID(&IID_IOleCacheControl
, riid
) )
1408 *ppvObject
= &this->IOleCacheControl_iface
;
1411 if ((*ppvObject
)==0)
1413 WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid
));
1414 return E_NOINTERFACE
;
1417 IUnknown_AddRef((IUnknown
*)*ppvObject
);
1422 /************************************************************************
1423 * DataCache_NDIUnknown_AddRef (IUnknown)
1425 * This version of QueryInterface will not delegate its implementation
1426 * to the outer unknown.
1428 static ULONG WINAPI
DataCache_NDIUnknown_AddRef(
1431 DataCache
*this = impl_from_IUnknown(iface
);
1432 return InterlockedIncrement(&this->ref
);
1435 /************************************************************************
1436 * DataCache_NDIUnknown_Release (IUnknown)
1438 * This version of QueryInterface will not delegate its implementation
1439 * to the outer unknown.
1441 static ULONG WINAPI
DataCache_NDIUnknown_Release(
1444 DataCache
*this = impl_from_IUnknown(iface
);
1447 ref
= InterlockedDecrement(&this->ref
);
1449 if (ref
== 0) DataCache_Destroy(this);
1454 /*********************************************************
1455 * Method implementation for the IDataObject
1456 * part of the DataCache class.
1459 /************************************************************************
1460 * DataCache_IDataObject_QueryInterface (IUnknown)
1462 static HRESULT WINAPI
DataCache_IDataObject_QueryInterface(
1467 DataCache
*this = impl_from_IDataObject(iface
);
1469 return IUnknown_QueryInterface(this->outer_unk
, riid
, ppvObject
);
1472 /************************************************************************
1473 * DataCache_IDataObject_AddRef (IUnknown)
1475 static ULONG WINAPI
DataCache_IDataObject_AddRef(
1478 DataCache
*this = impl_from_IDataObject(iface
);
1480 return IUnknown_AddRef(this->outer_unk
);
1483 /************************************************************************
1484 * DataCache_IDataObject_Release (IUnknown)
1486 static ULONG WINAPI
DataCache_IDataObject_Release(
1489 DataCache
*this = impl_from_IDataObject(iface
);
1491 return IUnknown_Release(this->outer_unk
);
1494 /************************************************************************
1497 * Get Data from a source dataobject using format pformatetcIn->cfFormat
1499 static HRESULT WINAPI
DataCache_GetData(
1501 LPFORMATETC pformatetcIn
,
1504 DataCache
*This
= impl_from_IDataObject(iface
);
1505 DataCacheEntry
*cache_entry
;
1507 TRACE("(%p, %s, %p)\n", iface
, debugstr_formatetc(pformatetcIn
), pmedium
);
1509 memset(pmedium
, 0, sizeof(*pmedium
));
1511 cache_entry
= DataCache_GetEntryForFormatEtc(This
, pformatetcIn
);
1515 return DataCacheEntry_GetData(cache_entry
, This
->presentationStorage
, pformatetcIn
, pmedium
);
1518 static HRESULT WINAPI
DataCache_GetDataHere(
1520 LPFORMATETC pformatetc
,
1527 static HRESULT WINAPI
DataCache_QueryGetData( IDataObject
*iface
, FORMATETC
*fmt
)
1529 DataCache
*This
= impl_from_IDataObject( iface
);
1530 DataCacheEntry
*cache_entry
;
1532 TRACE( "(%p)->(%s)\n", iface
, debugstr_formatetc( fmt
) );
1533 cache_entry
= DataCache_GetEntryForFormatEtc( This
, fmt
);
1535 return cache_entry
? S_OK
: S_FALSE
;
1538 /************************************************************************
1539 * DataCache_EnumFormatEtc (IDataObject)
1541 * The data cache doesn't implement this method.
1543 static HRESULT WINAPI
DataCache_GetCanonicalFormatEtc(
1545 LPFORMATETC pformatectIn
,
1546 LPFORMATETC pformatetcOut
)
1552 /************************************************************************
1553 * DataCache_IDataObject_SetData (IDataObject)
1555 * This method is delegated to the IOleCache2 implementation.
1557 static HRESULT WINAPI
DataCache_IDataObject_SetData(
1559 LPFORMATETC pformatetc
,
1563 IOleCache2
* oleCache
= NULL
;
1566 TRACE("(%p, %p, %p, %d)\n", iface
, pformatetc
, pmedium
, fRelease
);
1568 hres
= IDataObject_QueryInterface(iface
, &IID_IOleCache2
, (void**)&oleCache
);
1571 return E_UNEXPECTED
;
1573 hres
= IOleCache2_SetData(oleCache
, pformatetc
, pmedium
, fRelease
);
1575 IOleCache2_Release(oleCache
);
1580 /************************************************************************
1581 * DataCache_EnumFormatEtc (IDataObject)
1583 * The data cache doesn't implement this method.
1585 static HRESULT WINAPI
DataCache_EnumFormatEtc(
1588 IEnumFORMATETC
** ppenumFormatEtc
)
1594 /************************************************************************
1595 * DataCache_DAdvise (IDataObject)
1597 * The data cache doesn't support connections.
1599 static HRESULT WINAPI
DataCache_DAdvise(
1601 FORMATETC
* pformatetc
,
1603 IAdviseSink
* pAdvSink
,
1604 DWORD
* pdwConnection
)
1607 return OLE_E_ADVISENOTSUPPORTED
;
1610 /************************************************************************
1611 * DataCache_DUnadvise (IDataObject)
1613 * The data cache doesn't support connections.
1615 static HRESULT WINAPI
DataCache_DUnadvise(
1620 return OLE_E_NOCONNECTION
;
1623 /************************************************************************
1624 * DataCache_EnumDAdvise (IDataObject)
1626 * The data cache doesn't support connections.
1628 static HRESULT WINAPI
DataCache_EnumDAdvise(
1630 IEnumSTATDATA
** ppenumAdvise
)
1633 return OLE_E_ADVISENOTSUPPORTED
;
1636 /*********************************************************
1637 * Method implementation for the IDataObject
1638 * part of the DataCache class.
1641 /************************************************************************
1642 * DataCache_IPersistStorage_QueryInterface (IUnknown)
1644 static HRESULT WINAPI
DataCache_IPersistStorage_QueryInterface(
1645 IPersistStorage
* iface
,
1649 DataCache
*this = impl_from_IPersistStorage(iface
);
1651 return IUnknown_QueryInterface(this->outer_unk
, riid
, ppvObject
);
1654 /************************************************************************
1655 * DataCache_IPersistStorage_AddRef (IUnknown)
1657 static ULONG WINAPI
DataCache_IPersistStorage_AddRef(
1658 IPersistStorage
* iface
)
1660 DataCache
*this = impl_from_IPersistStorage(iface
);
1662 return IUnknown_AddRef(this->outer_unk
);
1665 /************************************************************************
1666 * DataCache_IPersistStorage_Release (IUnknown)
1668 static ULONG WINAPI
DataCache_IPersistStorage_Release(
1669 IPersistStorage
* iface
)
1671 DataCache
*this = impl_from_IPersistStorage(iface
);
1673 return IUnknown_Release(this->outer_unk
);
1676 /************************************************************************
1677 * DataCache_GetClassID (IPersistStorage)
1680 static HRESULT WINAPI
DataCache_GetClassID(IPersistStorage
*iface
, CLSID
*clsid
)
1682 DataCache
*This
= impl_from_IPersistStorage( iface
);
1684 TRACE( "(%p, %p) returning %s\n", iface
, clsid
, debugstr_guid(&This
->clsid
) );
1685 *clsid
= This
->clsid
;
1690 /************************************************************************
1691 * DataCache_IsDirty (IPersistStorage)
1693 static HRESULT WINAPI
DataCache_IsDirty(
1694 IPersistStorage
* iface
)
1696 DataCache
*This
= impl_from_IPersistStorage(iface
);
1697 DataCacheEntry
*cache_entry
;
1699 TRACE("(%p)\n", iface
);
1704 LIST_FOR_EACH_ENTRY(cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
1705 if (cache_entry
->dirty
)
1711 /************************************************************************
1712 * DataCache_InitNew (IPersistStorage)
1714 * The data cache implementation of IPersistStorage_InitNew simply stores
1715 * the storage pointer.
1717 static HRESULT WINAPI
DataCache_InitNew(
1718 IPersistStorage
* iface
,
1721 DataCache
*This
= impl_from_IPersistStorage(iface
);
1725 TRACE("(%p, %p)\n", iface
, pStg
);
1727 if (This
->presentationStorage
!= NULL
)
1728 return CO_E_ALREADYINITIALIZED
;
1730 This
->presentationStorage
= pStg
;
1732 IStorage_AddRef(This
->presentationStorage
);
1734 ReadClassStg( pStg
, &clsid
);
1735 hr
= create_automatic_entry( This
, &clsid
);
1738 IStorage_Release( pStg
);
1739 This
->presentationStorage
= NULL
;
1742 This
->clsid
= clsid
;
1748 static HRESULT
add_cache_entry( DataCache
*This
, const FORMATETC
*fmt
, DWORD advf
, int stream_number
)
1750 DataCacheEntry
*cache_entry
;
1753 TRACE( "loading entry with formatetc: %s\n", debugstr_formatetc( fmt
) );
1755 cache_entry
= DataCache_GetEntryForFormatEtc( This
, fmt
);
1757 hr
= DataCache_CreateEntry( This
, fmt
, advf
, FALSE
, &cache_entry
);
1758 if (SUCCEEDED( hr
))
1760 DataCacheEntry_DiscardData( cache_entry
);
1761 cache_entry
->load_stream_num
= stream_number
;
1762 cache_entry
->save_stream_num
= stream_number
;
1763 cache_entry
->dirty
= FALSE
;
1768 static HRESULT
parse_pres_streams( DataCache
*cache
, IStorage
*stg
)
1772 PresentationDataHeader header
;
1774 CLIPFORMAT clipformat
;
1776 int stream_number
= 0;
1780 hr
= open_pres_stream( stg
, stream_number
, &stm
);
1781 if (FAILED(hr
)) break;
1783 hr
= read_clipformat( stm
, &clipformat
);
1785 if (hr
== S_OK
) hr
= IStream_Read( stm
, &header
, sizeof(header
), &actual_read
);
1787 if (hr
== S_OK
&& actual_read
== sizeof(header
))
1789 fmtetc
.cfFormat
= clipformat
;
1790 fmtetc
.ptd
= NULL
; /* FIXME */
1791 fmtetc
.dwAspect
= header
.dvAspect
;
1792 fmtetc
.lindex
= header
.lindex
;
1793 fmtetc
.tymed
= tymed_from_cf( clipformat
);
1795 add_cache_entry( cache
, &fmtetc
, header
.advf
, stream_number
);
1797 IStream_Release( stm
);
1799 } while (hr
== S_OK
);
1804 static HRESULT
parse_contents_stream( DataCache
*cache
, IStorage
*stg
)
1808 DataCacheEntry
*cache_entry
;
1810 hr
= open_pres_stream( stg
, STREAM_NUMBER_CONTENTS
, &stm
);
1811 if (FAILED( hr
)) return hr
;
1813 hr
= get_static_entry( cache
, &cache_entry
);
1816 cache_entry
->load_stream_num
= STREAM_NUMBER_CONTENTS
;
1817 cache_entry
->save_stream_num
= STREAM_NUMBER_CONTENTS
;
1818 cache_entry
->dirty
= FALSE
;
1821 IStream_Release( stm
);
1825 /************************************************************************
1826 * DataCache_Load (IPersistStorage)
1828 * The data cache implementation of IPersistStorage_Load doesn't
1829 * actually load anything. Instead, it holds on to the storage pointer
1830 * and it will load the presentation information when the
1831 * IDataObject_GetData or IViewObject2_Draw methods are called.
1833 static HRESULT WINAPI
DataCache_Load( IPersistStorage
*iface
, IStorage
*stg
)
1835 DataCache
*This
= impl_from_IPersistStorage(iface
);
1838 DataCacheEntry
*entry
, *cursor2
;
1840 TRACE("(%p, %p)\n", iface
, stg
);
1842 IPersistStorage_HandsOffStorage( iface
);
1844 LIST_FOR_EACH_ENTRY_SAFE( entry
, cursor2
, &This
->cache_list
, DataCacheEntry
, entry
)
1845 DataCacheEntry_Destroy( This
, entry
);
1846 This
->clsid
= CLSID_NULL
;
1848 ReadClassStg( stg
, &clsid
);
1849 hr
= create_automatic_entry( This
, &clsid
);
1850 if (FAILED( hr
)) return hr
;
1852 This
->clsid
= clsid
;
1854 if (This
->clsid_static
)
1856 hr
= parse_contents_stream( This
, stg
);
1857 if (FAILED(hr
)) hr
= parse_pres_streams( This
, stg
);
1860 hr
= parse_pres_streams( This
, stg
);
1862 if (SUCCEEDED( hr
))
1864 This
->dirty
= FALSE
;
1865 This
->presentationStorage
= stg
;
1866 IStorage_AddRef( This
->presentationStorage
);
1872 /************************************************************************
1873 * DataCache_Save (IPersistStorage)
1875 * Until we actually connect to a running object and retrieve new
1876 * information to it, we never have to save anything. However, it is
1877 * our responsibility to copy the information when saving to a new
1880 static HRESULT WINAPI
DataCache_Save(IPersistStorage
* iface
, IStorage
*stg
, BOOL same_as_load
)
1882 DataCache
*This
= impl_from_IPersistStorage(iface
);
1883 DataCacheEntry
*cache_entry
;
1885 int stream_number
= 0;
1887 TRACE("(%p, %p, %d)\n", iface
, stg
, same_as_load
);
1889 /* assign stream numbers to the cache entries */
1890 LIST_FOR_EACH_ENTRY(cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
1892 if (cache_entry
->save_stream_num
!= stream_number
)
1894 cache_entry
->dirty
= TRUE
; /* needs to be written out again */
1895 cache_entry
->save_stream_num
= stream_number
;
1900 /* write out the cache entries */
1901 LIST_FOR_EACH_ENTRY(cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
1903 if (!same_as_load
|| cache_entry
->dirty
)
1905 hr
= DataCacheEntry_Save(cache_entry
, stg
, same_as_load
);
1909 if (same_as_load
) cache_entry
->dirty
= FALSE
;
1913 if (same_as_load
) This
->dirty
= FALSE
;
1917 /************************************************************************
1918 * DataCache_SaveCompleted (IPersistStorage)
1920 * This method is called to tell the cache to release the storage
1921 * pointer it's currently holding.
1923 static HRESULT WINAPI
DataCache_SaveCompleted(
1924 IPersistStorage
* iface
,
1927 TRACE("(%p, %p)\n", iface
, pStgNew
);
1931 IPersistStorage_HandsOffStorage(iface
);
1933 DataCache_Load(iface
, pStgNew
);
1939 /************************************************************************
1940 * DataCache_HandsOffStorage (IPersistStorage)
1942 * This method is called to tell the cache to release the storage
1943 * pointer it's currently holding.
1945 static HRESULT WINAPI
DataCache_HandsOffStorage(
1946 IPersistStorage
* iface
)
1948 DataCache
*this = impl_from_IPersistStorage(iface
);
1950 TRACE("(%p)\n", iface
);
1952 if (this->presentationStorage
!= NULL
)
1954 IStorage_Release(this->presentationStorage
);
1955 this->presentationStorage
= NULL
;
1961 /*********************************************************
1962 * Method implementation for the IViewObject2
1963 * part of the DataCache class.
1966 /************************************************************************
1967 * DataCache_IViewObject2_QueryInterface (IUnknown)
1969 static HRESULT WINAPI
DataCache_IViewObject2_QueryInterface(
1970 IViewObject2
* iface
,
1974 DataCache
*this = impl_from_IViewObject2(iface
);
1976 return IUnknown_QueryInterface(this->outer_unk
, riid
, ppvObject
);
1979 /************************************************************************
1980 * DataCache_IViewObject2_AddRef (IUnknown)
1982 static ULONG WINAPI
DataCache_IViewObject2_AddRef(
1983 IViewObject2
* iface
)
1985 DataCache
*this = impl_from_IViewObject2(iface
);
1987 return IUnknown_AddRef(this->outer_unk
);
1990 /************************************************************************
1991 * DataCache_IViewObject2_Release (IUnknown)
1993 static ULONG WINAPI
DataCache_IViewObject2_Release(
1994 IViewObject2
* iface
)
1996 DataCache
*this = impl_from_IViewObject2(iface
);
1998 return IUnknown_Release(this->outer_unk
);
2001 /************************************************************************
2002 * DataCache_Draw (IViewObject2)
2004 * This method will draw the cached representation of the object
2005 * to the given device context.
2007 static HRESULT WINAPI
DataCache_Draw(
2008 IViewObject2
* iface
,
2012 DVTARGETDEVICE
* ptd
,
2015 LPCRECTL lprcBounds
,
2016 LPCRECTL lprcWBounds
,
2017 BOOL (CALLBACK
*pfnContinue
)(ULONG_PTR dwContinue
),
2018 ULONG_PTR dwContinue
)
2020 DataCache
*This
= impl_from_IViewObject2(iface
);
2022 DataCacheEntry
*cache_entry
;
2024 TRACE("(%p, %x, %d, %p, %p, %p, %p, %p, %p, %lx)\n",
2036 if (lprcBounds
==NULL
)
2037 return E_INVALIDARG
;
2039 LIST_FOR_EACH_ENTRY(cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
2041 /* FIXME: compare ptd too */
2042 if ((cache_entry
->fmtetc
.dwAspect
!= dwDrawAspect
) ||
2043 (cache_entry
->fmtetc
.lindex
!= lindex
))
2046 /* if the data hasn't been loaded yet, do it now */
2047 if ((cache_entry
->stgmedium
.tymed
== TYMED_NULL
) && (cache_entry
->load_stream_num
!= STREAM_NUMBER_NOT_SET
))
2049 hres
= DataCacheEntry_LoadData(cache_entry
, This
->presentationStorage
);
2055 if (cache_entry
->stgmedium
.tymed
== TYMED_NULL
)
2058 if (pfnContinue
&& !pfnContinue(dwContinue
)) return E_ABORT
;
2060 switch (cache_entry
->fmtetc
.cfFormat
)
2062 case CF_METAFILEPICT
:
2065 * We have to be careful not to modify the state of the
2070 SIZE oldViewportExt
;
2071 POINT oldViewportOrg
;
2072 METAFILEPICT
*mfpict
;
2074 if ((cache_entry
->stgmedium
.tymed
!= TYMED_MFPICT
) ||
2075 !((mfpict
= GlobalLock(cache_entry
->stgmedium
.u
.hMetaFilePict
))))
2078 prevMapMode
= SetMapMode(hdcDraw
, mfpict
->mm
);
2080 SetWindowExtEx(hdcDraw
,
2085 SetViewportExtEx(hdcDraw
,
2086 lprcBounds
->right
- lprcBounds
->left
,
2087 lprcBounds
->bottom
- lprcBounds
->top
,
2090 SetViewportOrgEx(hdcDraw
,
2095 PlayMetaFile(hdcDraw
, mfpict
->hMF
);
2097 SetWindowExtEx(hdcDraw
,
2102 SetViewportExtEx(hdcDraw
,
2107 SetViewportOrgEx(hdcDraw
,
2112 SetMapMode(hdcDraw
, prevMapMode
);
2114 GlobalUnlock(cache_entry
->stgmedium
.u
.hMetaFilePict
);
2123 if ((cache_entry
->stgmedium
.tymed
!= TYMED_HGLOBAL
) ||
2124 !((info
= GlobalLock( cache_entry
->stgmedium
.u
.hGlobal
))))
2127 bits
= (BYTE
*) info
+ bitmap_info_size( info
, DIB_RGB_COLORS
);
2128 StretchDIBits( hdcDraw
, lprcBounds
->left
, lprcBounds
->top
,
2129 lprcBounds
->right
- lprcBounds
->left
, lprcBounds
->bottom
- lprcBounds
->top
,
2130 0, 0, info
->bmiHeader
.biWidth
, info
->bmiHeader
.biHeight
,
2131 bits
, info
, DIB_RGB_COLORS
, SRCCOPY
);
2133 GlobalUnlock( cache_entry
->stgmedium
.u
.hGlobal
);
2139 WARN("no data could be found to be drawn\n");
2144 static HRESULT WINAPI
DataCache_GetColorSet(
2145 IViewObject2
* iface
,
2149 DVTARGETDEVICE
* ptd
,
2150 HDC hicTargetDevice
,
2151 LOGPALETTE
** ppColorSet
)
2157 static HRESULT WINAPI
DataCache_Freeze(
2158 IViewObject2
* iface
,
2168 static HRESULT WINAPI
DataCache_Unfreeze(
2169 IViewObject2
* iface
,
2176 /************************************************************************
2177 * DataCache_SetAdvise (IViewObject2)
2179 * This sets-up an advisory sink with the data cache. When the object's
2180 * view changes, this sink is called.
2182 static HRESULT WINAPI
DataCache_SetAdvise(
2183 IViewObject2
* iface
,
2186 IAdviseSink
* pAdvSink
)
2188 DataCache
*this = impl_from_IViewObject2(iface
);
2190 TRACE("(%p, %x, %x, %p)\n", iface
, aspects
, advf
, pAdvSink
);
2193 * A call to this function removes the previous sink
2195 if (this->sinkInterface
!= NULL
)
2197 IAdviseSink_Release(this->sinkInterface
);
2198 this->sinkInterface
= NULL
;
2199 this->sinkAspects
= 0;
2200 this->sinkAdviseFlag
= 0;
2204 * Now, setup the new one.
2208 this->sinkInterface
= pAdvSink
;
2209 this->sinkAspects
= aspects
;
2210 this->sinkAdviseFlag
= advf
;
2212 IAdviseSink_AddRef(this->sinkInterface
);
2216 * When the ADVF_PRIMEFIRST flag is set, we have to advise the
2219 if (advf
& ADVF_PRIMEFIRST
)
2221 DataCache_FireOnViewChange(this, aspects
, -1);
2227 /************************************************************************
2228 * DataCache_GetAdvise (IViewObject2)
2230 * This method queries the current state of the advise sink
2231 * installed on the data cache.
2233 static HRESULT WINAPI
DataCache_GetAdvise(
2234 IViewObject2
* iface
,
2237 IAdviseSink
** ppAdvSink
)
2239 DataCache
*this = impl_from_IViewObject2(iface
);
2241 TRACE("(%p, %p, %p, %p)\n", iface
, pAspects
, pAdvf
, ppAdvSink
);
2244 * Just copy all the requested values.
2247 *pAspects
= this->sinkAspects
;
2250 *pAdvf
= this->sinkAdviseFlag
;
2252 if (ppAdvSink
!=NULL
)
2254 if (this->sinkInterface
!= NULL
)
2255 IAdviseSink_QueryInterface(this->sinkInterface
,
2258 else *ppAdvSink
= NULL
;
2264 /************************************************************************
2265 * DataCache_GetExtent (IViewObject2)
2267 * This method retrieves the "natural" size of this cached object.
2269 static HRESULT WINAPI
DataCache_GetExtent(
2270 IViewObject2
* iface
,
2273 DVTARGETDEVICE
* ptd
,
2276 DataCache
*This
= impl_from_IViewObject2(iface
);
2277 HRESULT hres
= E_FAIL
;
2278 DataCacheEntry
*cache_entry
;
2280 TRACE("(%p, %x, %d, %p, %p)\n",
2281 iface
, dwDrawAspect
, lindex
, ptd
, lpsizel
);
2290 FIXME("Unimplemented flag lindex = %d\n", lindex
);
2293 * Right now, we support only the callback from
2294 * the default handler.
2297 FIXME("Unimplemented ptd = %p\n", ptd
);
2299 LIST_FOR_EACH_ENTRY(cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
2301 /* FIXME: compare ptd too */
2302 if ((cache_entry
->fmtetc
.dwAspect
!= dwDrawAspect
) ||
2303 (cache_entry
->fmtetc
.lindex
!= lindex
))
2306 /* if the data hasn't been loaded yet, do it now */
2307 if ((cache_entry
->stgmedium
.tymed
== TYMED_NULL
) && (cache_entry
->load_stream_num
!= STREAM_NUMBER_NOT_SET
))
2309 hres
= DataCacheEntry_LoadData(cache_entry
, This
->presentationStorage
);
2315 if (cache_entry
->stgmedium
.tymed
== TYMED_NULL
)
2319 switch (cache_entry
->fmtetc
.cfFormat
)
2321 case CF_METAFILEPICT
:
2323 METAFILEPICT
*mfpict
;
2325 if ((cache_entry
->stgmedium
.tymed
!= TYMED_MFPICT
) ||
2326 !((mfpict
= GlobalLock(cache_entry
->stgmedium
.u
.hMetaFilePict
))))
2329 lpsizel
->cx
= mfpict
->xExt
;
2330 lpsizel
->cy
= mfpict
->yExt
;
2332 GlobalUnlock(cache_entry
->stgmedium
.u
.hMetaFilePict
);
2338 BITMAPINFOHEADER
*info
;
2339 LONG x_pels_m
, y_pels_m
;
2342 if ((cache_entry
->stgmedium
.tymed
!= TYMED_HGLOBAL
) ||
2343 !((info
= GlobalLock( cache_entry
->stgmedium
.u
.hGlobal
))))
2346 x_pels_m
= info
->biXPelsPerMeter
;
2347 y_pels_m
= info
->biYPelsPerMeter
;
2349 /* Size in units of 0.01mm (ie. MM_HIMETRIC) */
2350 if (x_pels_m
!= 0 && y_pels_m
!= 0)
2352 lpsizel
->cx
= info
->biWidth
* 100000 / x_pels_m
;
2353 lpsizel
->cy
= info
->biHeight
* 100000 / y_pels_m
;
2357 HDC hdc
= GetDC( 0 );
2358 lpsizel
->cx
= info
->biWidth
* 2540 / GetDeviceCaps( hdc
, LOGPIXELSX
);
2359 lpsizel
->cy
= info
->biHeight
* 2540 / GetDeviceCaps( hdc
, LOGPIXELSY
);
2361 ReleaseDC( 0, hdc
);
2364 GlobalUnlock( cache_entry
->stgmedium
.u
.hGlobal
);
2371 WARN("no data could be found to get the extents from\n");
2374 * This method returns OLE_E_BLANK when it fails.
2380 /*********************************************************
2381 * Method implementation for the IOleCache2
2382 * part of the DataCache class.
2385 /************************************************************************
2386 * DataCache_IOleCache2_QueryInterface (IUnknown)
2388 static HRESULT WINAPI
DataCache_IOleCache2_QueryInterface(
2393 DataCache
*this = impl_from_IOleCache2(iface
);
2395 return IUnknown_QueryInterface(this->outer_unk
, riid
, ppvObject
);
2398 /************************************************************************
2399 * DataCache_IOleCache2_AddRef (IUnknown)
2401 static ULONG WINAPI
DataCache_IOleCache2_AddRef(
2404 DataCache
*this = impl_from_IOleCache2(iface
);
2406 return IUnknown_AddRef(this->outer_unk
);
2409 /************************************************************************
2410 * DataCache_IOleCache2_Release (IUnknown)
2412 static ULONG WINAPI
DataCache_IOleCache2_Release(
2415 DataCache
*this = impl_from_IOleCache2(iface
);
2417 return IUnknown_Release(this->outer_unk
);
2420 /*****************************************************************************
2423 * Set up the sink connection to the running object.
2425 static HRESULT
setup_sink(DataCache
*This
, DataCacheEntry
*cache_entry
)
2427 HRESULT hr
= S_FALSE
;
2430 /* Clear the ADVFCACHE_* bits. Native also sets the two highest bits for some reason. */
2431 flags
= cache_entry
->advise_flags
& ~(ADVFCACHE_NOHANDLER
| ADVFCACHE_FORCEBUILTIN
| ADVFCACHE_ONSAVE
);
2433 if(This
->running_object
)
2434 if(!(flags
& ADVF_NODATA
))
2435 hr
= IDataObject_DAdvise(This
->running_object
, &cache_entry
->fmtetc
, flags
,
2436 &This
->IAdviseSink_iface
, &cache_entry
->sink_id
);
2440 static HRESULT WINAPI
DataCache_Cache(
2442 FORMATETC
* pformatetc
,
2444 DWORD
* pdwConnection
)
2446 DataCache
*This
= impl_from_IOleCache2(iface
);
2447 DataCacheEntry
*cache_entry
;
2451 TRACE("(%p, 0x%x, %p)\n", pformatetc
, advf
, pdwConnection
);
2453 if (!pformatetc
|| !pdwConnection
)
2454 return E_INVALIDARG
;
2456 TRACE("pformatetc = %s\n", debugstr_formatetc(pformatetc
));
2458 fmt_cpy
= *pformatetc
; /* No need for a deep copy */
2459 if (fmt_cpy
.cfFormat
== CF_BITMAP
&& fmt_cpy
.tymed
== TYMED_GDI
)
2461 fmt_cpy
.cfFormat
= CF_DIB
;
2462 fmt_cpy
.tymed
= TYMED_HGLOBAL
;
2465 /* View caching DVASPECT_ICON gets converted to CF_METAFILEPICT */
2466 if (fmt_cpy
.dwAspect
== DVASPECT_ICON
&& fmt_cpy
.cfFormat
== 0)
2468 fmt_cpy
.cfFormat
= CF_METAFILEPICT
;
2469 fmt_cpy
.tymed
= TYMED_MFPICT
;
2474 cache_entry
= DataCache_GetEntryForFormatEtc(This
, &fmt_cpy
);
2477 TRACE("found an existing cache entry\n");
2478 *pdwConnection
= cache_entry
->id
;
2479 return CACHE_S_SAMECACHE
;
2482 if (This
->clsid_static
&& fmt_cpy
.dwAspect
!= DVASPECT_ICON
) return DV_E_FORMATETC
;
2484 hr
= DataCache_CreateEntry(This
, &fmt_cpy
, advf
, FALSE
, &cache_entry
);
2488 *pdwConnection
= cache_entry
->id
;
2489 setup_sink(This
, cache_entry
);
2495 static HRESULT WINAPI
DataCache_Uncache(
2499 DataCache
*This
= impl_from_IOleCache2(iface
);
2500 DataCacheEntry
*cache_entry
;
2502 TRACE("(%d)\n", dwConnection
);
2504 LIST_FOR_EACH_ENTRY(cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
2505 if (cache_entry
->id
== dwConnection
)
2507 DataCacheEntry_Destroy(This
, cache_entry
);
2511 WARN("no connection found for %d\n", dwConnection
);
2513 return OLE_E_NOCONNECTION
;
2516 static HRESULT WINAPI
DataCache_EnumCache(IOleCache2
*iface
,
2517 IEnumSTATDATA
**enum_stat
)
2519 DataCache
*This
= impl_from_IOleCache2( iface
);
2520 DataCacheEntry
*cache_entry
;
2521 int i
= 0, count
= 0;
2525 TRACE( "(%p, %p)\n", This
, enum_stat
);
2527 LIST_FOR_EACH_ENTRY( cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
2530 if (cache_entry
->fmtetc
.cfFormat
== CF_DIB
)
2534 data
= CoTaskMemAlloc( count
* sizeof(*data
) );
2535 if (!data
) return E_OUTOFMEMORY
;
2537 LIST_FOR_EACH_ENTRY( cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
2539 if (i
== count
) goto fail
;
2540 hr
= copy_formatetc( &data
[i
].formatetc
, &cache_entry
->fmtetc
);
2541 if (FAILED(hr
)) goto fail
;
2542 data
[i
].advf
= cache_entry
->advise_flags
;
2543 data
[i
].pAdvSink
= NULL
;
2544 data
[i
].dwConnection
= cache_entry
->id
;
2547 if (cache_entry
->fmtetc
.cfFormat
== CF_DIB
)
2549 if (i
== count
) goto fail
;
2550 hr
= copy_formatetc( &data
[i
].formatetc
, &cache_entry
->fmtetc
);
2551 if (FAILED(hr
)) goto fail
;
2552 data
[i
].formatetc
.cfFormat
= CF_BITMAP
;
2553 data
[i
].formatetc
.tymed
= TYMED_GDI
;
2554 data
[i
].advf
= cache_entry
->advise_flags
;
2555 data
[i
].pAdvSink
= NULL
;
2556 data
[i
].dwConnection
= cache_entry
->id
;
2561 hr
= EnumSTATDATA_Construct( NULL
, 0, i
, data
, FALSE
, enum_stat
);
2562 if (SUCCEEDED(hr
)) return hr
;
2565 while (i
--) CoTaskMemFree( data
[i
].formatetc
.ptd
);
2566 CoTaskMemFree( data
);
2570 static HRESULT WINAPI
DataCache_InitCache( IOleCache2
*iface
, IDataObject
*data
)
2572 TRACE( "(%p %p)\n", iface
, data
);
2573 return IOleCache2_UpdateCache( iface
, data
, UPDFCACHE_ALLBUTNODATACACHE
, NULL
);
2576 static HRESULT WINAPI
DataCache_IOleCache2_SetData(
2578 FORMATETC
* pformatetc
,
2582 DataCache
*This
= impl_from_IOleCache2(iface
);
2583 DataCacheEntry
*cache_entry
;
2586 TRACE("(%p, %p, %s)\n", pformatetc
, pmedium
, fRelease
? "TRUE" : "FALSE");
2587 TRACE("formatetc = %s\n", debugstr_formatetc(pformatetc
));
2589 cache_entry
= DataCache_GetEntryForFormatEtc(This
, pformatetc
);
2592 hr
= DataCacheEntry_SetData(cache_entry
, pformatetc
, pmedium
, fRelease
);
2595 DataCache_FireOnViewChange(This
, cache_entry
->fmtetc
.dwAspect
,
2596 cache_entry
->fmtetc
.lindex
);
2600 WARN("cache entry not found\n");
2605 static BOOL
entry_updatable( DataCacheEntry
*entry
, DWORD mode
)
2607 BOOL is_blank
= entry
->stgmedium
.tymed
== TYMED_NULL
;
2609 if ((mode
& UPDFCACHE_ONLYIFBLANK
) && !is_blank
) return FALSE
;
2611 if ((mode
& UPDFCACHE_NODATACACHE
) && (entry
->advise_flags
& ADVF_NODATA
)) return TRUE
;
2612 if ((mode
& UPDFCACHE_ONSAVECACHE
) && (entry
->advise_flags
& ADVFCACHE_ONSAVE
)) return TRUE
;
2613 if ((mode
& UPDFCACHE_ONSTOPCACHE
) && (entry
->advise_flags
& ADVF_DATAONSTOP
)) return TRUE
;
2614 if ((mode
& UPDFCACHE_NORMALCACHE
) && (entry
->advise_flags
== 0)) return TRUE
;
2615 if ((mode
& UPDFCACHE_IFBLANK
) && (is_blank
&& !(entry
->advise_flags
& ADVF_NODATA
))) return TRUE
;
2620 static HRESULT WINAPI
DataCache_UpdateCache( IOleCache2
*iface
, IDataObject
*data
,
2621 DWORD mode
, void *reserved
)
2623 DataCache
*This
= impl_from_IOleCache2(iface
);
2624 DataCacheEntry
*cache_entry
;
2627 CLIPFORMAT view_list
[] = { CF_METAFILEPICT
, CF_ENHMETAFILE
, CF_DIB
, CF_BITMAP
};
2630 BOOL done_one
= FALSE
;
2632 TRACE( "(%p %p %08x %p)\n", iface
, data
, mode
, reserved
);
2634 LIST_FOR_EACH_ENTRY( cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
2638 if (!entry_updatable( cache_entry
, mode
))
2644 fmt
= cache_entry
->fmtetc
;
2648 hr
= IDataObject_GetData( data
, &fmt
, &med
);
2649 if (hr
!= S_OK
&& fmt
.cfFormat
== CF_DIB
)
2651 fmt
.cfFormat
= CF_BITMAP
;
2652 fmt
.tymed
= TYMED_GDI
;
2653 hr
= IDataObject_GetData( data
, &fmt
, &med
);
2655 if (hr
!= S_OK
&& fmt
.cfFormat
== CF_ENHMETAFILE
)
2657 fmt
.cfFormat
= CF_METAFILEPICT
;
2658 fmt
.tymed
= TYMED_MFPICT
;
2659 hr
= IDataObject_GetData( data
, &fmt
, &med
);
2663 hr
= DataCacheEntry_SetData( cache_entry
, &fmt
, &med
, TRUE
);
2664 if (hr
!= S_OK
) ReleaseStgMedium( &med
);
2665 else done_one
= TRUE
;
2670 for (i
= 0; i
< ARRAY_SIZE(view_list
); i
++)
2672 fmt
.cfFormat
= view_list
[i
];
2673 fmt
.tymed
= tymed_from_cf( fmt
.cfFormat
);
2674 hr
= IDataObject_QueryGetData( data
, &fmt
);
2677 hr
= IDataObject_GetData( data
, &fmt
, &med
);
2680 if (fmt
.cfFormat
== CF_BITMAP
)
2682 cache_entry
->fmtetc
.cfFormat
= CF_DIB
;
2683 cache_entry
->fmtetc
.tymed
= TYMED_HGLOBAL
;
2687 cache_entry
->fmtetc
.cfFormat
= fmt
.cfFormat
;
2688 cache_entry
->fmtetc
.tymed
= fmt
.tymed
;
2690 hr
= DataCacheEntry_SetData( cache_entry
, &fmt
, &med
, TRUE
);
2691 if (hr
!= S_OK
) ReleaseStgMedium( &med
);
2692 else done_one
= TRUE
;
2700 return (!slots
|| done_one
) ? S_OK
: CACHE_E_NOCACHE_UPDATED
;
2703 static HRESULT WINAPI
DataCache_DiscardCache(
2705 DWORD dwDiscardOptions
)
2707 DataCache
*This
= impl_from_IOleCache2(iface
);
2708 DataCacheEntry
*cache_entry
;
2711 TRACE("(%d)\n", dwDiscardOptions
);
2713 if (dwDiscardOptions
== DISCARDCACHE_SAVEIFDIRTY
)
2714 hr
= DataCache_Save(&This
->IPersistStorage_iface
, This
->presentationStorage
, TRUE
);
2716 LIST_FOR_EACH_ENTRY(cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
2718 hr
= DataCacheEntry_DiscardData(cache_entry
);
2727 /*********************************************************
2728 * Method implementation for the IOleCacheControl
2729 * part of the DataCache class.
2732 /************************************************************************
2733 * DataCache_IOleCacheControl_QueryInterface (IUnknown)
2735 static HRESULT WINAPI
DataCache_IOleCacheControl_QueryInterface(
2736 IOleCacheControl
* iface
,
2740 DataCache
*this = impl_from_IOleCacheControl(iface
);
2742 return IUnknown_QueryInterface(this->outer_unk
, riid
, ppvObject
);
2745 /************************************************************************
2746 * DataCache_IOleCacheControl_AddRef (IUnknown)
2748 static ULONG WINAPI
DataCache_IOleCacheControl_AddRef(
2749 IOleCacheControl
* iface
)
2751 DataCache
*this = impl_from_IOleCacheControl(iface
);
2753 return IUnknown_AddRef(this->outer_unk
);
2756 /************************************************************************
2757 * DataCache_IOleCacheControl_Release (IUnknown)
2759 static ULONG WINAPI
DataCache_IOleCacheControl_Release(
2760 IOleCacheControl
* iface
)
2762 DataCache
*this = impl_from_IOleCacheControl(iface
);
2764 return IUnknown_Release(this->outer_unk
);
2767 /************************************************************************
2768 * DataCache_OnRun (IOleCacheControl)
2770 static HRESULT WINAPI
DataCache_OnRun(IOleCacheControl
* iface
, IDataObject
*data_obj
)
2772 DataCache
*This
= impl_from_IOleCacheControl(iface
);
2773 DataCacheEntry
*cache_entry
;
2775 TRACE("(%p)->(%p)\n", iface
, data_obj
);
2777 if(This
->running_object
) return S_OK
;
2779 /* No reference is taken on the data object */
2780 This
->running_object
= data_obj
;
2782 LIST_FOR_EACH_ENTRY(cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
2784 setup_sink(This
, cache_entry
);
2790 /************************************************************************
2791 * DataCache_OnStop (IOleCacheControl)
2793 static HRESULT WINAPI
DataCache_OnStop(IOleCacheControl
* iface
)
2795 DataCache
*This
= impl_from_IOleCacheControl(iface
);
2796 DataCacheEntry
*cache_entry
;
2798 TRACE("(%p)\n", iface
);
2800 if(!This
->running_object
) return S_OK
;
2802 LIST_FOR_EACH_ENTRY(cache_entry
, &This
->cache_list
, DataCacheEntry
, entry
)
2804 if(cache_entry
->sink_id
)
2806 IDataObject_DUnadvise(This
->running_object
, cache_entry
->sink_id
);
2807 cache_entry
->sink_id
= 0;
2811 /* No ref taken in OnRun, so no Release call here */
2812 This
->running_object
= NULL
;
2816 /************************************************************************
2817 * IAdviseSink methods.
2818 * This behaves as an internal object to the data cache. QI'ing its ptr doesn't
2819 * give access to the cache's other interfaces. We don't maintain a ref count,
2820 * the object exists as long as the cache is around.
2822 static HRESULT WINAPI
DataCache_IAdviseSink_QueryInterface(IAdviseSink
*iface
, REFIID iid
, void **obj
)
2825 if (IsEqualIID(&IID_IUnknown
, iid
) ||
2826 IsEqualIID(&IID_IAdviseSink
, iid
))
2833 IAdviseSink_AddRef(iface
);
2836 return E_NOINTERFACE
;
2839 static ULONG WINAPI
DataCache_IAdviseSink_AddRef(IAdviseSink
*iface
)
2844 static ULONG WINAPI
DataCache_IAdviseSink_Release(IAdviseSink
*iface
)
2849 static void WINAPI
DataCache_OnDataChange(IAdviseSink
*iface
, FORMATETC
*fmt
, STGMEDIUM
*med
)
2851 DataCache
*This
= impl_from_IAdviseSink(iface
);
2852 TRACE("(%p)->(%s, %p)\n", This
, debugstr_formatetc(fmt
), med
);
2853 IOleCache2_SetData(&This
->IOleCache2_iface
, fmt
, med
, FALSE
);
2856 static void WINAPI
DataCache_OnViewChange(IAdviseSink
*iface
, DWORD aspect
, LONG index
)
2861 static void WINAPI
DataCache_OnRename(IAdviseSink
*iface
, IMoniker
*mk
)
2866 static void WINAPI
DataCache_OnSave(IAdviseSink
*iface
)
2871 static void WINAPI
DataCache_OnClose(IAdviseSink
*iface
)
2877 * Virtual function tables for the DataCache class.
2879 static const IUnknownVtbl DataCache_NDIUnknown_VTable
=
2881 DataCache_NDIUnknown_QueryInterface
,
2882 DataCache_NDIUnknown_AddRef
,
2883 DataCache_NDIUnknown_Release
2886 static const IDataObjectVtbl DataCache_IDataObject_VTable
=
2888 DataCache_IDataObject_QueryInterface
,
2889 DataCache_IDataObject_AddRef
,
2890 DataCache_IDataObject_Release
,
2892 DataCache_GetDataHere
,
2893 DataCache_QueryGetData
,
2894 DataCache_GetCanonicalFormatEtc
,
2895 DataCache_IDataObject_SetData
,
2896 DataCache_EnumFormatEtc
,
2898 DataCache_DUnadvise
,
2899 DataCache_EnumDAdvise
2902 static const IPersistStorageVtbl DataCache_IPersistStorage_VTable
=
2904 DataCache_IPersistStorage_QueryInterface
,
2905 DataCache_IPersistStorage_AddRef
,
2906 DataCache_IPersistStorage_Release
,
2907 DataCache_GetClassID
,
2912 DataCache_SaveCompleted
,
2913 DataCache_HandsOffStorage
2916 static const IViewObject2Vtbl DataCache_IViewObject2_VTable
=
2918 DataCache_IViewObject2_QueryInterface
,
2919 DataCache_IViewObject2_AddRef
,
2920 DataCache_IViewObject2_Release
,
2922 DataCache_GetColorSet
,
2925 DataCache_SetAdvise
,
2926 DataCache_GetAdvise
,
2930 static const IOleCache2Vtbl DataCache_IOleCache2_VTable
=
2932 DataCache_IOleCache2_QueryInterface
,
2933 DataCache_IOleCache2_AddRef
,
2934 DataCache_IOleCache2_Release
,
2937 DataCache_EnumCache
,
2938 DataCache_InitCache
,
2939 DataCache_IOleCache2_SetData
,
2940 DataCache_UpdateCache
,
2941 DataCache_DiscardCache
2944 static const IOleCacheControlVtbl DataCache_IOleCacheControl_VTable
=
2946 DataCache_IOleCacheControl_QueryInterface
,
2947 DataCache_IOleCacheControl_AddRef
,
2948 DataCache_IOleCacheControl_Release
,
2953 static const IAdviseSinkVtbl DataCache_IAdviseSink_VTable
=
2955 DataCache_IAdviseSink_QueryInterface
,
2956 DataCache_IAdviseSink_AddRef
,
2957 DataCache_IAdviseSink_Release
,
2958 DataCache_OnDataChange
,
2959 DataCache_OnViewChange
,
2965 /*********************************************************
2966 * Method implementation for DataCache class.
2968 static DataCache
* DataCache_Construct(
2970 LPUNKNOWN pUnkOuter
)
2972 DataCache
* newObject
= 0;
2975 * Allocate space for the object.
2977 newObject
= HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache
));
2983 * Initialize the virtual function table.
2985 newObject
->IDataObject_iface
.lpVtbl
= &DataCache_IDataObject_VTable
;
2986 newObject
->IUnknown_inner
.lpVtbl
= &DataCache_NDIUnknown_VTable
;
2987 newObject
->IPersistStorage_iface
.lpVtbl
= &DataCache_IPersistStorage_VTable
;
2988 newObject
->IViewObject2_iface
.lpVtbl
= &DataCache_IViewObject2_VTable
;
2989 newObject
->IOleCache2_iface
.lpVtbl
= &DataCache_IOleCache2_VTable
;
2990 newObject
->IOleCacheControl_iface
.lpVtbl
= &DataCache_IOleCacheControl_VTable
;
2991 newObject
->IAdviseSink_iface
.lpVtbl
= &DataCache_IAdviseSink_VTable
;
2992 newObject
->outer_unk
= pUnkOuter
? pUnkOuter
: &newObject
->IUnknown_inner
;
2996 * Initialize the other members of the structure.
2998 newObject
->sinkAspects
= 0;
2999 newObject
->sinkAdviseFlag
= 0;
3000 newObject
->sinkInterface
= 0;
3001 newObject
->clsid
= CLSID_NULL
;
3002 newObject
->clsid_static
= FALSE
;
3003 newObject
->presentationStorage
= NULL
;
3004 list_init(&newObject
->cache_list
);
3005 newObject
->last_cache_id
= 2;
3006 newObject
->dirty
= FALSE
;
3007 newObject
->running_object
= NULL
;
3009 create_automatic_entry( newObject
, clsid
);
3010 newObject
->clsid
= *clsid
;
3015 /******************************************************************************
3016 * CreateDataCache [OLE32.@]
3018 * Creates a data cache to allow an object to render one or more of its views,
3019 * whether running or not.
3022 * pUnkOuter [I] Outer unknown for the object.
3024 * riid [I] IID of interface to return.
3025 * ppvObj [O] Address where the data cache object will be stored on return.
3029 * Failure: HRESULT code.
3032 * The following interfaces are supported by the returned data cache object:
3033 * IOleCache, IOleCache2, IOleCacheControl, IPersistStorage, IDataObject,
3034 * IViewObject and IViewObject2.
3036 HRESULT WINAPI
CreateDataCache(
3037 LPUNKNOWN pUnkOuter
,
3042 DataCache
* newCache
= NULL
;
3045 TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid
), pUnkOuter
, debugstr_guid(riid
), ppvObj
);
3056 * If this cache is constructed for aggregation, make sure
3057 * the caller is requesting the IUnknown interface.
3058 * This is necessary because it's the only time the non-delegating
3059 * IUnknown pointer can be returned to the outside.
3061 if ( pUnkOuter
&& !IsEqualIID(&IID_IUnknown
, riid
) )
3062 return E_INVALIDARG
;
3065 * Try to construct a new instance of the class.
3067 newCache
= DataCache_Construct(rclsid
,
3071 return E_OUTOFMEMORY
;
3073 hr
= IUnknown_QueryInterface(&newCache
->IUnknown_inner
, riid
, ppvObj
);
3074 IUnknown_Release(&newCache
->IUnknown_inner
);