4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
8 * Copyright 2008 Kirill K. Smirnov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
27 * Lots of methods are just stubs.
30 * NOTES (or things that msdn doesn't tell you)
32 * The width and height properties are returned in HIMETRIC units (0.01mm)
33 * IPicture::Render also uses these to select a region of the src picture.
34 * A bitmap's size is converted into these units by using the screen resolution
35 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
44 #define NONAMELESSUNION
58 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(olepicture
);
62 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
63 #define BITMAP_FORMAT_JPEG 0xd8ff
64 #define BITMAP_FORMAT_GIF 0x4947
65 #define BITMAP_FORMAT_PNG 0x5089
66 #define BITMAP_FORMAT_APM 0xcdd7
70 /* Header for Aldus Placable Metafiles - a standard metafile follows */
71 typedef struct _APM_HEADER
93 } CURSORICONFILEDIRENTRY
;
100 CURSORICONFILEDIRENTRY idEntries
[1];
105 /*************************************************************************
106 * Declaration of implementation class
109 typedef struct OLEPictureImpl
{
112 * IPicture handles IUnknown
115 IPicture IPicture_iface
;
116 IDispatch IDispatch_iface
;
117 IPersistStream IPersistStream_iface
;
118 IConnectionPointContainer IConnectionPointContainer_iface
;
120 /* Object reference count */
123 /* We own the object and must destroy it ourselves */
126 /* Picture description */
129 /* These are the pixel size of a bitmap */
133 /* And these are the size of the picture converted into HIMETRIC units */
134 OLE_XSIZE_HIMETRIC himetricWidth
;
135 OLE_YSIZE_HIMETRIC himetricHeight
;
137 IConnectionPoint
*pCP
;
141 HBITMAP stock_bitmap
;
143 /* Bitmap transparency mask */
151 BOOL bIsDirty
; /* Set to TRUE if picture has changed */
152 unsigned int loadtime_magic
; /* If a length header was found, saves value */
153 unsigned int loadtime_format
; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
156 static inline OLEPictureImpl
*impl_from_IPicture(IPicture
*iface
)
158 return CONTAINING_RECORD(iface
, OLEPictureImpl
, IPicture_iface
);
161 static inline OLEPictureImpl
*impl_from_IDispatch( IDispatch
*iface
)
163 return CONTAINING_RECORD(iface
, OLEPictureImpl
, IDispatch_iface
);
166 static inline OLEPictureImpl
*impl_from_IPersistStream( IPersistStream
*iface
)
168 return CONTAINING_RECORD(iface
, OLEPictureImpl
, IPersistStream_iface
);
171 static inline OLEPictureImpl
*impl_from_IConnectionPointContainer( IConnectionPointContainer
*iface
)
173 return CONTAINING_RECORD(iface
, OLEPictureImpl
, IConnectionPointContainer_iface
);
177 * Predeclare VTables. They get initialized at the end.
179 static const IPictureVtbl OLEPictureImpl_VTable
;
180 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable
;
181 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable
;
182 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable
;
184 /* pixels to HIMETRIC units conversion */
185 static inline OLE_XSIZE_HIMETRIC
xpixels_to_himetric(INT pixels
, HDC hdc
)
187 return MulDiv(pixels
, 2540, GetDeviceCaps(hdc
, LOGPIXELSX
));
190 static inline OLE_YSIZE_HIMETRIC
ypixels_to_himetric(INT pixels
, HDC hdc
)
192 return MulDiv(pixels
, 2540, GetDeviceCaps(hdc
, LOGPIXELSY
));
195 /***********************************************************************
196 * Implementation of the OLEPictureImpl class.
199 static void OLEPictureImpl_SetBitmap(OLEPictureImpl
*This
)
204 TRACE("bitmap handle %p\n", This
->desc
.u
.bmp
.hbitmap
);
205 if(GetObjectW(This
->desc
.u
.bmp
.hbitmap
, sizeof(bm
), &bm
) != sizeof(bm
)) {
206 ERR("GetObject fails\n");
209 This
->origWidth
= bm
.bmWidth
;
210 This
->origHeight
= bm
.bmHeight
;
212 TRACE("width %d, height %d, bpp %d\n", bm
.bmWidth
, bm
.bmHeight
, bm
.bmBitsPixel
);
214 /* The width and height are stored in HIMETRIC units (0.01 mm),
215 so we take our pixel width divide by pixels per inch and
216 multiply by 25.4 * 100 */
217 /* Should we use GetBitmapDimension if available? */
218 hdcRef
= CreateCompatibleDC(0);
220 This
->himetricWidth
= xpixels_to_himetric(bm
.bmWidth
, hdcRef
);
221 This
->himetricHeight
= ypixels_to_himetric(bm
.bmHeight
, hdcRef
);
222 This
->stock_bitmap
= GetCurrentObject( hdcRef
, OBJ_BITMAP
);
224 This
->loadtime_format
= BITMAP_FORMAT_BMP
;
229 static void OLEPictureImpl_SetIcon(OLEPictureImpl
* This
)
233 TRACE("icon handle %p\n", This
->desc
.u
.icon
.hicon
);
234 if (GetIconInfo(This
->desc
.u
.icon
.hicon
, &infoIcon
)) {
238 TRACE("bitmap handle for icon is %p\n", infoIcon
.hbmColor
);
239 if(GetObjectW(infoIcon
.hbmColor
? infoIcon
.hbmColor
: infoIcon
.hbmMask
, sizeof(bm
), &bm
) != sizeof(bm
)) {
240 ERR("GetObject fails on icon bitmap\n");
244 This
->origWidth
= bm
.bmWidth
;
245 This
->origHeight
= infoIcon
.hbmColor
? bm
.bmHeight
: bm
.bmHeight
/ 2;
246 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
249 This
->himetricWidth
= xpixels_to_himetric(This
->origWidth
, hdcRef
);
250 This
->himetricHeight
= ypixels_to_himetric(This
->origHeight
, hdcRef
);
252 ReleaseDC(0, hdcRef
);
254 DeleteObject(infoIcon
.hbmMask
);
255 if (infoIcon
.hbmColor
) DeleteObject(infoIcon
.hbmColor
);
257 ERR("GetIconInfo() fails on icon %p\n", This
->desc
.u
.icon
.hicon
);
261 static void OLEPictureImpl_SetEMF(OLEPictureImpl
*This
)
265 GetEnhMetaFileHeader(This
->desc
.u
.emf
.hemf
, sizeof(emh
), &emh
);
268 This
->origHeight
= 0;
269 This
->himetricWidth
= emh
.rclFrame
.right
- emh
.rclFrame
.left
;
270 This
->himetricHeight
= emh
.rclFrame
.bottom
- emh
.rclFrame
.top
;
273 /************************************************************************
274 * OLEPictureImpl_Construct
276 * This method will construct a new instance of the OLEPictureImpl
279 * The caller of this method must release the object when it's
282 static HRESULT
OLEPictureImpl_Construct(LPPICTDESC pictDesc
, BOOL fOwn
, OLEPictureImpl
**pict
)
284 OLEPictureImpl
*newObject
;
288 TRACE("(%p) type = %d\n", pictDesc
, pictDesc
->picType
);
291 * Allocate space for the object.
293 newObject
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(OLEPictureImpl
));
295 return E_OUTOFMEMORY
;
298 * Initialize the virtual function table.
300 newObject
->IPicture_iface
.lpVtbl
= &OLEPictureImpl_VTable
;
301 newObject
->IDispatch_iface
.lpVtbl
= &OLEPictureImpl_IDispatch_VTable
;
302 newObject
->IPersistStream_iface
.lpVtbl
= &OLEPictureImpl_IPersistStream_VTable
;
303 newObject
->IConnectionPointContainer_iface
.lpVtbl
= &OLEPictureImpl_IConnectionPointContainer_VTable
;
305 newObject
->pCP
= NULL
;
306 hr
= CreateConnectionPoint((IUnknown
*)&newObject
->IPicture_iface
, &IID_IPropertyNotifySink
,
310 HeapFree(GetProcessHeap(), 0, newObject
);
315 * Start with one reference count. The caller of this function
316 * must release the interface pointer when it is done.
319 newObject
->hDCCur
= 0;
321 newObject
->fOwn
= fOwn
;
323 /* dunno about original value */
324 newObject
->keepOrigFormat
= TRUE
;
326 newObject
->hbmMask
= NULL
;
327 newObject
->hbmXor
= NULL
;
328 newObject
->loadtime_magic
= 0xdeadbeef;
329 newObject
->loadtime_format
= 0;
330 newObject
->bIsDirty
= FALSE
;
333 newObject
->desc
= *pictDesc
;
335 switch(pictDesc
->picType
) {
337 OLEPictureImpl_SetBitmap(newObject
);
340 case PICTYPE_METAFILE
:
341 TRACE("metafile handle %p\n", pictDesc
->u
.wmf
.hmeta
);
342 newObject
->himetricWidth
= pictDesc
->u
.wmf
.xExt
;
343 newObject
->himetricHeight
= pictDesc
->u
.wmf
.yExt
;
347 /* not sure what to do here */
348 newObject
->himetricWidth
= newObject
->himetricHeight
= 0;
352 OLEPictureImpl_SetIcon(newObject
);
355 case PICTYPE_ENHMETAFILE
:
356 OLEPictureImpl_SetEMF(newObject
);
360 WARN("Unsupported type %d\n", pictDesc
->picType
);
361 IPicture_Release(&newObject
->IPicture_iface
);
365 newObject
->desc
.picType
= PICTYPE_UNINITIALIZED
;
368 TRACE("returning %p\n", newObject
);
373 /************************************************************************
374 * OLEPictureImpl_Destroy
376 * This method is called by the Release method when the reference
377 * count goes down to 0. It will free all resources used by
379 static void OLEPictureImpl_Destroy(OLEPictureImpl
* Obj
)
381 TRACE("(%p)\n", Obj
);
384 IConnectionPoint_Release(Obj
->pCP
);
386 if(Obj
->fOwn
) { /* We need to destroy the picture */
387 switch(Obj
->desc
.picType
) {
389 DeleteObject(Obj
->desc
.u
.bmp
.hbitmap
);
390 if (Obj
->hbmMask
!= NULL
) DeleteObject(Obj
->hbmMask
);
391 if (Obj
->hbmXor
!= NULL
) DeleteObject(Obj
->hbmXor
);
393 case PICTYPE_METAFILE
:
394 DeleteMetaFile(Obj
->desc
.u
.wmf
.hmeta
);
397 DestroyIcon(Obj
->desc
.u
.icon
.hicon
);
399 case PICTYPE_ENHMETAFILE
:
400 DeleteEnhMetaFile(Obj
->desc
.u
.emf
.hemf
);
403 case PICTYPE_UNINITIALIZED
:
407 FIXME("Unsupported type %d - unable to delete\n", Obj
->desc
.picType
);
411 HeapFree(GetProcessHeap(), 0, Obj
->data
);
412 HeapFree(GetProcessHeap(), 0, Obj
);
416 /************************************************************************
417 * OLEPictureImpl_AddRef (IUnknown)
419 * See Windows documentation for more details on IUnknown methods.
421 static ULONG WINAPI
OLEPictureImpl_AddRef(
424 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
425 ULONG refCount
= InterlockedIncrement(&This
->ref
);
427 TRACE("(%p)->(ref before=%d)\n", This
, refCount
- 1);
432 /************************************************************************
433 * OLEPictureImpl_Release (IUnknown)
435 * See Windows documentation for more details on IUnknown methods.
437 static ULONG WINAPI
OLEPictureImpl_Release(
440 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
441 ULONG refCount
= InterlockedDecrement(&This
->ref
);
443 TRACE("(%p)->(ref before=%d)\n", This
, refCount
+ 1);
446 * If the reference count goes down to 0, perform suicide.
448 if (!refCount
) OLEPictureImpl_Destroy(This
);
453 /************************************************************************
454 * OLEPictureImpl_QueryInterface (IUnknown)
456 * See Windows documentation for more details on IUnknown methods.
458 static HRESULT WINAPI
OLEPictureImpl_QueryInterface(
463 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
465 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
472 if (IsEqualIID(&IID_IUnknown
, riid
) || IsEqualIID(&IID_IPicture
, riid
))
473 *ppvObject
= &This
->IPicture_iface
;
474 else if (IsEqualIID(&IID_IDispatch
, riid
))
475 *ppvObject
= &This
->IDispatch_iface
;
476 else if (IsEqualIID(&IID_IPictureDisp
, riid
))
477 *ppvObject
= &This
->IDispatch_iface
;
478 else if (IsEqualIID(&IID_IPersist
, riid
) || IsEqualIID(&IID_IPersistStream
, riid
))
479 *ppvObject
= &This
->IPersistStream_iface
;
480 else if (IsEqualIID(&IID_IConnectionPointContainer
, riid
))
481 *ppvObject
= &This
->IConnectionPointContainer_iface
;
485 FIXME("() : asking for unsupported interface %s\n",debugstr_guid(riid
));
486 return E_NOINTERFACE
;
489 IPicture_AddRef(iface
);
494 /***********************************************************************
495 * OLEPicture_SendNotify (internal)
497 * Sends notification messages of changed properties to any interested
500 static void OLEPicture_SendNotify(OLEPictureImpl
* this, DISPID dispID
)
502 IEnumConnections
*pEnum
;
505 if (IConnectionPoint_EnumConnections(this->pCP
, &pEnum
) != S_OK
)
507 while(IEnumConnections_Next(pEnum
, 1, &CD
, NULL
) == S_OK
) {
508 IPropertyNotifySink
*sink
;
510 IUnknown_QueryInterface(CD
.pUnk
, &IID_IPropertyNotifySink
, (LPVOID
)&sink
);
511 IPropertyNotifySink_OnChanged(sink
, dispID
);
512 IPropertyNotifySink_Release(sink
);
513 IUnknown_Release(CD
.pUnk
);
515 IEnumConnections_Release(pEnum
);
518 /************************************************************************
519 * OLEPictureImpl_get_Handle
521 static HRESULT WINAPI
OLEPictureImpl_get_Handle(IPicture
*iface
,
524 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
525 TRACE("(%p)->(%p)\n", This
, phandle
);
530 switch(This
->desc
.picType
) {
532 case PICTYPE_UNINITIALIZED
:
536 *phandle
= HandleToUlong(This
->desc
.u
.bmp
.hbitmap
);
538 case PICTYPE_METAFILE
:
539 *phandle
= HandleToUlong(This
->desc
.u
.wmf
.hmeta
);
542 *phandle
= HandleToUlong(This
->desc
.u
.icon
.hicon
);
544 case PICTYPE_ENHMETAFILE
:
545 *phandle
= HandleToUlong(This
->desc
.u
.emf
.hemf
);
548 FIXME("Unimplemented type %d\n", This
->desc
.picType
);
551 TRACE("returning handle %08x\n", *phandle
);
555 /************************************************************************
556 * OLEPictureImpl_get_hPal
558 static HRESULT WINAPI
OLEPictureImpl_get_hPal(IPicture
*iface
,
561 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
563 TRACE("(%p)->(%p)\n", This
, phandle
);
565 if (!phandle
) return E_POINTER
;
567 if (This
->desc
.picType
== PICTYPE_BITMAP
)
569 *phandle
= HandleToUlong(This
->desc
.u
.bmp
.hpal
);
576 /************************************************************************
577 * OLEPictureImpl_get_Type
579 static HRESULT WINAPI
OLEPictureImpl_get_Type(IPicture
*iface
,
582 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
583 TRACE("(%p)->(%p): type is %d\n", This
, ptype
, This
->desc
.picType
);
588 *ptype
= This
->desc
.picType
;
592 /************************************************************************
593 * OLEPictureImpl_get_Width
595 static HRESULT WINAPI
OLEPictureImpl_get_Width(IPicture
*iface
,
596 OLE_XSIZE_HIMETRIC
*pwidth
)
598 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
599 TRACE("(%p)->(%p): width is %d\n", This
, pwidth
, This
->himetricWidth
);
600 *pwidth
= This
->himetricWidth
;
604 /************************************************************************
605 * OLEPictureImpl_get_Height
607 static HRESULT WINAPI
OLEPictureImpl_get_Height(IPicture
*iface
,
608 OLE_YSIZE_HIMETRIC
*pheight
)
610 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
611 TRACE("(%p)->(%p): height is %d\n", This
, pheight
, This
->himetricHeight
);
612 *pheight
= This
->himetricHeight
;
616 static void render_masked_bitmap(OLEPictureImpl
*This
, HDC hdc
,
617 LONG x
, LONG y
, LONG cx
, LONG cy
, OLE_XPOS_HIMETRIC xSrc
, OLE_YPOS_HIMETRIC ySrc
,
618 OLE_XSIZE_HIMETRIC cxSrc
, OLE_YSIZE_HIMETRIC cySrc
, HBITMAP hbmMask
, HBITMAP hbmXor
)
622 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
623 * NB y-axis gets flipped
626 hdcBmp
= CreateCompatibleDC(0);
627 SetMapMode(hdcBmp
, MM_ANISOTROPIC
);
628 SetWindowOrgEx(hdcBmp
, 0, 0, NULL
);
629 SetWindowExtEx(hdcBmp
, This
->himetricWidth
, This
->himetricHeight
, NULL
);
630 SetViewportOrgEx(hdcBmp
, 0, This
->origHeight
, NULL
);
631 SetViewportExtEx(hdcBmp
, This
->origWidth
, -This
->origHeight
, NULL
);
635 SetBkColor(hdc
, RGB(255, 255, 255));
636 SetTextColor(hdc
, RGB(0, 0, 0));
638 SelectObject(hdcBmp
, hbmMask
);
639 StretchBlt(hdc
, x
, y
, cx
, cy
, hdcBmp
, xSrc
, ySrc
, cxSrc
, cySrc
, SRCAND
);
643 SelectObject(hdcBmp
, hbmXor
);
644 StretchBlt(hdc
, x
, y
, cx
, cy
, hdcBmp
, xSrc
, ySrc
, cxSrc
, cySrc
, SRCPAINT
);
646 else StretchBlt(hdc
, x
, y
, cx
, cy
, hdcBmp
, xSrc
, ySrc
- This
->himetricHeight
,
647 cxSrc
, cySrc
, SRCPAINT
);
651 SelectObject(hdcBmp
, hbmXor
);
652 StretchBlt(hdc
, x
, y
, cx
, cy
, hdcBmp
, xSrc
, ySrc
, cxSrc
, cySrc
, SRCCOPY
);
658 /************************************************************************
659 * OLEPictureImpl_Render
661 static HRESULT WINAPI
OLEPictureImpl_Render(IPicture
*iface
, HDC hdc
,
662 LONG x
, LONG y
, LONG cx
, LONG cy
,
663 OLE_XPOS_HIMETRIC xSrc
,
664 OLE_YPOS_HIMETRIC ySrc
,
665 OLE_XSIZE_HIMETRIC cxSrc
,
666 OLE_YSIZE_HIMETRIC cySrc
,
669 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
670 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
671 This
, hdc
, x
, y
, cx
, cy
, xSrc
, ySrc
, cxSrc
, cySrc
, prcWBounds
);
673 TRACE("prcWBounds %s\n", wine_dbgstr_rect(prcWBounds
));
675 if(cx
== 0 || cy
== 0 || cxSrc
== 0 || cySrc
== 0){
676 return CTL_E_INVALIDPROPERTYVALUE
;
680 * While the documentation suggests this to be here (or after rendering?)
681 * it does cause an endless recursion in my sample app. -MM 20010804
682 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
685 switch(This
->desc
.picType
) {
686 case PICTYPE_UNINITIALIZED
:
692 HBITMAP hbmMask
, hbmXor
;
696 hbmMask
= This
->hbmMask
;
697 hbmXor
= This
->hbmXor
;
702 hbmXor
= This
->desc
.u
.bmp
.hbitmap
;
705 render_masked_bitmap(This
, hdc
, x
, y
, cx
, cy
, xSrc
, ySrc
, cxSrc
, cySrc
, hbmMask
, hbmXor
);
713 if (!GetIconInfo(This
->desc
.u
.icon
.hicon
, &info
))
716 render_masked_bitmap(This
, hdc
, x
, y
, cx
, cy
, xSrc
, ySrc
, cxSrc
, cySrc
, info
.hbmMask
, info
.hbmColor
);
718 DeleteObject(info
.hbmMask
);
719 if (info
.hbmColor
) DeleteObject(info
.hbmColor
);
723 case PICTYPE_METAFILE
:
725 POINT prevOrg
, prevWndOrg
;
726 SIZE prevExt
, prevWndExt
;
729 /* Render the WMF to the appropriate location by setting the
730 appropriate ratio between "device units" and "logical units" */
731 oldmode
= SetMapMode(hdc
, MM_ANISOTROPIC
);
732 /* For the "source rectangle" the y-axis must be inverted */
733 SetWindowOrgEx(hdc
, xSrc
, This
->himetricHeight
-ySrc
, &prevWndOrg
);
734 SetWindowExtEx(hdc
, cxSrc
, -cySrc
, &prevWndExt
);
735 /* For the "destination rectangle" no inversion is necessary */
736 SetViewportOrgEx(hdc
, x
, y
, &prevOrg
);
737 SetViewportExtEx(hdc
, cx
, cy
, &prevExt
);
739 if (!PlayMetaFile(hdc
, This
->desc
.u
.wmf
.hmeta
))
740 ERR("PlayMetaFile failed!\n");
742 /* We're done, restore the DC to the previous settings for converting
743 logical units to device units */
744 SetWindowExtEx(hdc
, prevWndExt
.cx
, prevWndExt
.cy
, NULL
);
745 SetWindowOrgEx(hdc
, prevWndOrg
.x
, prevWndOrg
.y
, NULL
);
746 SetViewportExtEx(hdc
, prevExt
.cx
, prevExt
.cy
, NULL
);
747 SetViewportOrgEx(hdc
, prevOrg
.x
, prevOrg
.y
, NULL
);
748 SetMapMode(hdc
, oldmode
);
752 case PICTYPE_ENHMETAFILE
:
754 RECT rc
= { x
, y
, x
+ cx
, y
+ cy
};
755 PlayEnhMetaFile(hdc
, This
->desc
.u
.emf
.hemf
, &rc
);
760 FIXME("type %d not implemented\n", This
->desc
.picType
);
766 /************************************************************************
767 * OLEPictureImpl_set_hPal
769 static HRESULT WINAPI
OLEPictureImpl_set_hPal(IPicture
*iface
,
772 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
774 TRACE("(%p)->(%08x)\n", This
, hpal
);
776 if (This
->desc
.picType
== PICTYPE_BITMAP
)
778 This
->desc
.u
.bmp
.hpal
= ULongToHandle(hpal
);
779 OLEPicture_SendNotify(This
,DISPID_PICT_HPAL
);
786 /************************************************************************
787 * OLEPictureImpl_get_CurDC
789 static HRESULT WINAPI
OLEPictureImpl_get_CurDC(IPicture
*iface
,
792 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
793 TRACE("(%p), returning %p\n", This
, This
->hDCCur
);
794 if (phdc
) *phdc
= This
->hDCCur
;
798 /************************************************************************
799 * OLEPictureImpl_SelectPicture
801 static HRESULT WINAPI
OLEPictureImpl_SelectPicture(IPicture
*iface
,
804 OLE_HANDLE
*phbmpOut
)
806 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
807 TRACE("(%p)->(%p, %p, %p)\n", This
, hdcIn
, phdcOut
, phbmpOut
);
808 if (This
->desc
.picType
== PICTYPE_BITMAP
) {
810 *phdcOut
= This
->hDCCur
;
811 if (This
->hDCCur
) SelectObject(This
->hDCCur
,This
->stock_bitmap
);
812 if (hdcIn
) SelectObject(hdcIn
,This
->desc
.u
.bmp
.hbitmap
);
813 This
->hDCCur
= hdcIn
;
815 *phbmpOut
= HandleToUlong(This
->desc
.u
.bmp
.hbitmap
);
818 FIXME("Don't know how to select picture type %d\n",This
->desc
.picType
);
823 /************************************************************************
824 * OLEPictureImpl_get_KeepOriginalFormat
826 static HRESULT WINAPI
OLEPictureImpl_get_KeepOriginalFormat(IPicture
*iface
,
829 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
830 TRACE("(%p)->(%p)\n", This
, pfKeep
);
833 *pfKeep
= This
->keepOrigFormat
;
837 /************************************************************************
838 * OLEPictureImpl_put_KeepOriginalFormat
840 static HRESULT WINAPI
OLEPictureImpl_put_KeepOriginalFormat(IPicture
*iface
,
843 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
844 TRACE("(%p)->(%d)\n", This
, keep
);
845 This
->keepOrigFormat
= keep
;
846 /* FIXME: what DISPID notification here? */
850 /************************************************************************
851 * OLEPictureImpl_PictureChanged
853 static HRESULT WINAPI
OLEPictureImpl_PictureChanged(IPicture
*iface
)
855 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
856 TRACE("(%p)->()\n", This
);
857 OLEPicture_SendNotify(This
,DISPID_PICT_HANDLE
);
858 This
->bIsDirty
= TRUE
;
862 /************************************************************************
863 * OLEPictureImpl_get_Attributes
865 static HRESULT WINAPI
OLEPictureImpl_get_Attributes(IPicture
*iface
,
868 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
869 TRACE("(%p)->(%p).\n", This
, pdwAttr
);
875 switch (This
->desc
.picType
) {
876 case PICTYPE_UNINITIALIZED
:
877 case PICTYPE_NONE
: break;
878 case PICTYPE_BITMAP
: if (This
->hbmMask
) *pdwAttr
= PICTURE_TRANSPARENT
; break; /* not 'truly' scalable, see MSDN. */
879 case PICTYPE_ICON
: *pdwAttr
= PICTURE_TRANSPARENT
;break;
880 case PICTYPE_ENHMETAFILE
: /* fall through */
881 case PICTYPE_METAFILE
: *pdwAttr
= PICTURE_TRANSPARENT
|PICTURE_SCALABLE
;break;
882 default:FIXME("Unknown pictype %d\n",This
->desc
.picType
);break;
888 /************************************************************************
889 * IConnectionPointContainer
891 static HRESULT WINAPI
OLEPictureImpl_IConnectionPointContainer_QueryInterface(
892 IConnectionPointContainer
* iface
,
896 OLEPictureImpl
*This
= impl_from_IConnectionPointContainer(iface
);
898 return IPicture_QueryInterface(&This
->IPicture_iface
,riid
,ppvoid
);
901 static ULONG WINAPI
OLEPictureImpl_IConnectionPointContainer_AddRef(
902 IConnectionPointContainer
* iface
)
904 OLEPictureImpl
*This
= impl_from_IConnectionPointContainer(iface
);
906 return IPicture_AddRef(&This
->IPicture_iface
);
909 static ULONG WINAPI
OLEPictureImpl_IConnectionPointContainer_Release(
910 IConnectionPointContainer
* iface
)
912 OLEPictureImpl
*This
= impl_from_IConnectionPointContainer(iface
);
914 return IPicture_Release(&This
->IPicture_iface
);
917 static HRESULT WINAPI
OLEPictureImpl_EnumConnectionPoints(
918 IConnectionPointContainer
* iface
,
919 IEnumConnectionPoints
** ppEnum
)
921 OLEPictureImpl
*This
= impl_from_IConnectionPointContainer(iface
);
923 FIXME("(%p,%p), stub!\n",This
,ppEnum
);
927 static HRESULT WINAPI
OLEPictureImpl_FindConnectionPoint(
928 IConnectionPointContainer
* iface
,
930 IConnectionPoint
**ppCP
)
932 OLEPictureImpl
*This
= impl_from_IConnectionPointContainer(iface
);
933 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppCP
);
937 if (IsEqualGUID(riid
,&IID_IPropertyNotifySink
))
938 return IConnectionPoint_QueryInterface(This
->pCP
, &IID_IConnectionPoint
, (void**)ppCP
);
939 FIXME("no connection point for %s\n",debugstr_guid(riid
));
940 return CONNECT_E_NOCONNECTION
;
944 /************************************************************************
948 /************************************************************************
949 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
951 * See Windows documentation for more details on IUnknown methods.
953 static HRESULT WINAPI
OLEPictureImpl_IPersistStream_QueryInterface(
954 IPersistStream
* iface
,
958 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
960 return IPicture_QueryInterface(&This
->IPicture_iface
, riid
, ppvoid
);
963 /************************************************************************
964 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
966 * See Windows documentation for more details on IUnknown methods.
968 static ULONG WINAPI
OLEPictureImpl_IPersistStream_AddRef(
969 IPersistStream
* iface
)
971 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
973 return IPicture_AddRef(&This
->IPicture_iface
);
976 /************************************************************************
977 * OLEPictureImpl_IPersistStream_Release (IUnknown)
979 * See Windows documentation for more details on IUnknown methods.
981 static ULONG WINAPI
OLEPictureImpl_IPersistStream_Release(
982 IPersistStream
* iface
)
984 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
986 return IPicture_Release(&This
->IPicture_iface
);
989 /************************************************************************
990 * OLEPictureImpl_IPersistStream_GetClassID
992 static HRESULT WINAPI
OLEPictureImpl_GetClassID(
993 IPersistStream
* iface
,CLSID
* pClassID
)
995 TRACE("(%p)\n", pClassID
);
996 *pClassID
= CLSID_StdPicture
;
1000 /************************************************************************
1001 * OLEPictureImpl_IPersistStream_IsDirty
1003 static HRESULT WINAPI
OLEPictureImpl_IsDirty(
1004 IPersistStream
* iface
)
1006 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
1007 FIXME("(%p),stub!\n",This
);
1011 static HRESULT
OLEPictureImpl_LoadWICSource(OLEPictureImpl
*This
, IWICBitmapSource
*src
)
1014 BITMAPINFOHEADER bih
;
1016 UINT stride
, buffersize
;
1017 BYTE
*bits
, *mask
= NULL
;
1019 IWICBitmapSource
*real_source
;
1021 COLORREF white
= RGB(255, 255, 255), black
= RGB(0, 0, 0);
1022 BOOL has_alpha
=FALSE
;
1024 hr
= WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA
, src
, &real_source
);
1025 if (FAILED(hr
)) return hr
;
1027 hr
= IWICBitmapSource_GetSize(real_source
, &width
, &height
);
1028 if (FAILED(hr
)) goto end
;
1030 bih
.biSize
= sizeof(bih
);
1031 bih
.biWidth
= width
;
1032 bih
.biHeight
= -height
;
1034 bih
.biBitCount
= 32;
1035 bih
.biCompression
= BI_RGB
;
1036 bih
.biSizeImage
= 0;
1037 bih
.biXPelsPerMeter
= 4085; /* olepicture ignores the stored resolution */
1038 bih
.biYPelsPerMeter
= 4085;
1040 bih
.biClrImportant
= 0;
1043 buffersize
= stride
* height
;
1045 mask
= HeapAlloc(GetProcessHeap(), 0, buffersize
);
1052 This
->desc
.u
.bmp
.hbitmap
= CreateDIBSection(0, (BITMAPINFO
*)&bih
, DIB_RGB_COLORS
, (void **)&bits
, NULL
, 0);
1053 if (This
->desc
.u
.bmp
.hbitmap
== 0)
1063 hr
= IWICBitmapSource_CopyPixels(real_source
, &rc
, stride
, buffersize
, bits
);
1066 DeleteObject(This
->desc
.u
.bmp
.hbitmap
);
1070 This
->desc
.picType
= PICTYPE_BITMAP
;
1071 OLEPictureImpl_SetBitmap(This
);
1073 /* set transparent pixels to black, all others to white */
1074 for(y
= 0; y
< height
; y
++){
1075 for(x
= 0; x
< width
; x
++){
1076 DWORD
*pixel
= (DWORD
*)(bits
+ stride
*y
+ 4*x
);
1077 if((*pixel
& 0x80000000) == 0)
1080 *(DWORD
*)(mask
+ stride
* y
+ 4 * x
) = black
;
1083 *(DWORD
*)(mask
+ stride
* y
+ 4 * x
) = white
;
1089 HDC hdcref
, hdcBmp
, hdcXor
, hdcMask
;
1090 HBITMAP hbmoldBmp
, hbmoldXor
, hbmoldMask
;
1094 This
->hbmXor
= CreateDIBitmap(
1103 This
->hbmMask
= CreateBitmap(width
,-height
,1,1,NULL
);
1104 hdcBmp
= CreateCompatibleDC(NULL
);
1105 hdcXor
= CreateCompatibleDC(NULL
);
1106 hdcMask
= CreateCompatibleDC(NULL
);
1108 hbmoldBmp
= SelectObject(hdcBmp
,This
->desc
.u
.bmp
.hbitmap
);
1109 hbmoldXor
= SelectObject(hdcXor
,This
->hbmXor
);
1110 hbmoldMask
= SelectObject(hdcMask
,This
->hbmMask
);
1112 SetBkColor(hdcXor
,black
);
1113 BitBlt(hdcMask
,0,0,width
,height
,hdcXor
,0,0,SRCCOPY
);
1114 BitBlt(hdcXor
,0,0,width
,height
,hdcBmp
,0,0,SRCAND
);
1116 SelectObject(hdcBmp
,hbmoldBmp
);
1117 SelectObject(hdcXor
,hbmoldXor
);
1118 SelectObject(hdcMask
,hbmoldMask
);
1123 ReleaseDC(0, hdcref
);
1127 HeapFree(GetProcessHeap(), 0, mask
);
1128 IWICBitmapSource_Release(real_source
);
1132 static HRESULT
OLEPictureImpl_LoadWICDecoder(OLEPictureImpl
*This
, REFCLSID decoder_clsid
, BYTE
*xbuf
, ULONG xread
)
1135 IWICImagingFactory
*factory
;
1136 IWICBitmapDecoder
*decoder
;
1137 IWICBitmapFrameDecode
*framedecode
;
1141 initresult
= CoInitialize(NULL
);
1143 hr
= CoCreateInstance(&CLSID_WICImagingFactory
, NULL
, CLSCTX_INPROC_SERVER
,
1144 &IID_IWICImagingFactory
, (void**)&factory
);
1145 if (SUCCEEDED(hr
)) /* created factory */
1147 hr
= IWICImagingFactory_CreateStream(factory
, &stream
);
1148 IWICImagingFactory_Release(factory
);
1151 if (SUCCEEDED(hr
)) /* created stream */
1153 hr
= IWICStream_InitializeFromMemory(stream
, xbuf
, xread
);
1155 if (SUCCEEDED(hr
)) /* initialized stream */
1157 hr
= CoCreateInstance(decoder_clsid
, NULL
, CLSCTX_INPROC_SERVER
,
1158 &IID_IWICBitmapDecoder
, (void**)&decoder
);
1159 if (SUCCEEDED(hr
)) /* created decoder */
1161 hr
= IWICBitmapDecoder_Initialize(decoder
, (IStream
*)stream
, WICDecodeMetadataCacheOnLoad
);
1163 if (SUCCEEDED(hr
)) /* initialized decoder */
1164 hr
= IWICBitmapDecoder_GetFrame(decoder
, 0, &framedecode
);
1166 IWICBitmapDecoder_Release(decoder
);
1170 IWICStream_Release(stream
);
1173 if (SUCCEEDED(hr
)) /* got framedecode */
1175 hr
= OLEPictureImpl_LoadWICSource(This
, (IWICBitmapSource
*)framedecode
);
1176 IWICBitmapFrameDecode_Release(framedecode
);
1179 if (SUCCEEDED(initresult
)) CoUninitialize();
1183 /*****************************************************
1184 * start of Icon-specific code
1187 static HRESULT
OLEPictureImpl_LoadIcon(OLEPictureImpl
*This
, BYTE
*xbuf
, ULONG xread
)
1190 CURSORICONFILEDIR
*cifd
= (CURSORICONFILEDIR
*)xbuf
;
1194 TRACE("(this %p, xbuf %p, xread %u)\n", This
, xbuf
, xread
);
1197 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1198 FIXME("icon.idType=%d\n",cifd->idType);
1199 FIXME("icon.idCount=%d\n",cifd->idCount);
1201 for (i=0;i<cifd->idCount;i++) {
1202 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1203 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1204 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1205 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1206 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1207 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1208 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1209 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1213 /* Need at least one icon to do something. */
1216 ERR("Invalid icon count of zero.\n");
1220 /* If we have more than one icon, try to find the best.
1221 * this currently means '32 pixel wide'.
1223 if (cifd
->idCount
!=1) {
1224 for (i
=0;i
<cifd
->idCount
;i
++) {
1225 if (cifd
->idEntries
[i
].bWidth
== 32)
1228 if (i
==cifd
->idCount
) i
=0;
1230 if (xread
< cifd
->idEntries
[i
].dwDIBOffset
+ cifd
->idEntries
[i
].dwDIBSize
)
1232 ERR("Icon data address %u is over %u bytes available.\n",
1233 cifd
->idEntries
[i
].dwDIBOffset
+ cifd
->idEntries
[i
].dwDIBSize
, xread
);
1236 if (cifd
->idType
== 2)
1238 LPBYTE buf
= HeapAlloc(GetProcessHeap(), 0, cifd
->idEntries
[i
].dwDIBSize
+ 4);
1239 memcpy(buf
, &cifd
->idEntries
[i
].xHotspot
, 4);
1240 memcpy(buf
+ 4, xbuf
+cifd
->idEntries
[i
].dwDIBOffset
, cifd
->idEntries
[i
].dwDIBSize
);
1241 hicon
= CreateIconFromResourceEx(
1243 cifd
->idEntries
[i
].dwDIBSize
+ 4,
1244 FALSE
, /* is cursor */
1246 cifd
->idEntries
[i
].bWidth
,
1247 cifd
->idEntries
[i
].bHeight
,
1250 HeapFree(GetProcessHeap(), 0, buf
);
1254 hicon
= CreateIconFromResourceEx(
1255 xbuf
+cifd
->idEntries
[i
].dwDIBOffset
,
1256 cifd
->idEntries
[i
].dwDIBSize
,
1259 cifd
->idEntries
[i
].bWidth
,
1260 cifd
->idEntries
[i
].bHeight
,
1265 ERR("CreateIcon failed.\n");
1268 This
->desc
.picType
= PICTYPE_ICON
;
1269 This
->desc
.u
.icon
.hicon
= hicon
;
1270 This
->origWidth
= cifd
->idEntries
[i
].bWidth
;
1271 This
->origHeight
= cifd
->idEntries
[i
].bHeight
;
1272 hdcRef
= CreateCompatibleDC(0);
1273 This
->himetricWidth
= xpixels_to_himetric(cifd
->idEntries
[i
].bWidth
, hdcRef
);
1274 This
->himetricHeight
= ypixels_to_himetric(cifd
->idEntries
[i
].bHeight
, hdcRef
);
1280 static HRESULT
OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl
*This
,
1281 const BYTE
*data
, ULONG size
)
1286 hemf
= SetEnhMetaFileBits(size
, data
);
1287 if (!hemf
) return E_FAIL
;
1289 GetEnhMetaFileHeader(hemf
, sizeof(hdr
), &hdr
);
1291 This
->desc
.picType
= PICTYPE_ENHMETAFILE
;
1292 This
->desc
.u
.emf
.hemf
= hemf
;
1294 This
->origWidth
= 0;
1295 This
->origHeight
= 0;
1296 This
->himetricWidth
= hdr
.rclFrame
.right
- hdr
.rclFrame
.left
;
1297 This
->himetricHeight
= hdr
.rclFrame
.bottom
- hdr
.rclFrame
.top
;
1302 static HRESULT
OLEPictureImpl_LoadAPM(OLEPictureImpl
*This
,
1303 const BYTE
*data
, ULONG size
)
1305 const APM_HEADER
*header
= (const APM_HEADER
*)data
;
1308 if (size
< sizeof(APM_HEADER
))
1310 if (header
->key
!= 0x9ac6cdd7)
1313 /* SetMetaFileBitsEx performs data check on its own */
1314 hmf
= SetMetaFileBitsEx(size
- sizeof(*header
), data
+ sizeof(*header
));
1315 if (!hmf
) return E_FAIL
;
1317 This
->desc
.picType
= PICTYPE_METAFILE
;
1318 This
->desc
.u
.wmf
.hmeta
= hmf
;
1319 This
->desc
.u
.wmf
.xExt
= 0;
1320 This
->desc
.u
.wmf
.yExt
= 0;
1322 This
->origWidth
= 0;
1323 This
->origHeight
= 0;
1324 This
->himetricWidth
= MulDiv((INT
)header
->right
- header
->left
, 2540, header
->inch
);
1325 This
->himetricHeight
= MulDiv((INT
)header
->bottom
- header
->top
, 2540, header
->inch
);
1329 /************************************************************************
1330 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1332 * Loads the binary data from the IStream. Starts at current position.
1333 * There appears to be an 2 DWORD header:
1337 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1339 static HRESULT WINAPI
OLEPictureImpl_Load(IPersistStream
* iface
, IStream
*pStm
) {
1342 BOOL statfailed
= FALSE
;
1343 ULONG xread
, toread
;
1349 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
1351 TRACE("(%p,%p)\n",This
,pStm
);
1353 /****************************************************************************************
1354 * Part 1: Load the data
1356 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1357 * out whether we do.
1359 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1360 * compound file. This may explain most, if not all, of the cases of "no
1361 * header", and the header validation should take this into account.
1362 * At least in Visual Basic 6, resource streams, valid headers are
1363 * header[0] == "lt\0\0",
1364 * header[1] == length_of_stream.
1366 * Also handle streams where we do not have a working "Stat" method by
1367 * reading all data until the end of the stream.
1369 hr
= IStream_Stat(pStm
,&statstg
,STATFLAG_NONAME
);
1371 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr
);
1373 /* we will read at least 8 byte ... just right below */
1374 statstg
.cbSize
.QuadPart
= 8;
1379 headerisdata
= FALSE
;
1381 hr
= IStream_Read(pStm
, header
, 8, &xread
);
1382 if (hr
!= S_OK
|| xread
!=8) {
1383 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr
,xread
);
1384 return (hr
?hr
:E_FAIL
);
1386 headerread
+= xread
;
1389 if (!memcmp(&(header
[0]),"lt\0\0", 4) && (statfailed
|| (header
[1] + headerread
<= statstg
.cbSize
.QuadPart
))) {
1390 if (toread
!= 0 && toread
!= header
[1])
1391 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1396 statstg
.cbSize
.QuadPart
= header
[1] + 8;
1399 if (toread
== 0) break;
1401 if (!memcmp(&(header
[0]), "GIF8", 4) || /* GIF header */
1402 !memcmp(&(header
[0]), "BM", 2) || /* BMP header */
1403 !memcmp(&(header
[0]), "\xff\xd8", 2) || /* JPEG header */
1404 (header
[0] == EMR_HEADER
) || /* EMF header */
1405 (header
[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1406 (header
[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1407 (header
[1] > statstg
.cbSize
.QuadPart
)|| /* invalid size */
1409 ) {/* Found start of bitmap data */
1410 headerisdata
= TRUE
;
1412 toread
= statstg
.cbSize
.QuadPart
-8;
1416 FIXME("Unknown stream header magic: %08x\n", header
[0]);
1420 } while (!headerisdata
);
1422 if (statfailed
) { /* we don't know the size ... read all we get */
1423 unsigned int sizeinc
= 4096;
1424 unsigned int origsize
= sizeinc
;
1427 TRACE("Reading all data from stream.\n");
1428 xbuf
= HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY
, origsize
);
1430 memcpy (xbuf
, header
, 8);
1432 while (xread
< origsize
) {
1433 hr
= IStream_Read(pStm
,xbuf
+xread
,origsize
-xread
,&nread
);
1435 if (hr
!= S_OK
|| !nread
)
1438 if (!nread
|| hr
!= S_OK
) /* done, or error */
1440 if (xread
== origsize
) {
1441 origsize
+= sizeinc
;
1442 sizeinc
= 2*sizeinc
; /* exponential increase */
1443 xbuf
= HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY
, xbuf
, origsize
);
1447 TRACE("hr in no-stat loader case is %08x\n", hr
);
1448 TRACE("loaded %d bytes.\n", xread
);
1449 This
->datalen
= xread
;
1452 This
->datalen
= toread
+(headerisdata
?8:0);
1453 xbuf
= This
->data
= HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->datalen
);
1455 return E_OUTOFMEMORY
;
1458 memcpy (xbuf
, header
, 8);
1460 while (xread
< This
->datalen
) {
1462 hr
= IStream_Read(pStm
,xbuf
+xread
,This
->datalen
-xread
,&nread
);
1464 if (hr
!= S_OK
|| !nread
)
1467 if (xread
!= This
->datalen
)
1468 ERR("Could only read %d of %d bytes out of stream?\n",xread
,This
->datalen
);
1470 if (This
->datalen
== 0) { /* Marks the "NONE" picture */
1471 This
->desc
.picType
= PICTYPE_NONE
;
1476 /****************************************************************************************
1477 * Part 2: Process the loaded data
1480 magic
= xbuf
[0] + (xbuf
[1]<<8);
1481 This
->loadtime_format
= magic
;
1484 case BITMAP_FORMAT_GIF
: /* GIF */
1485 hr
= OLEPictureImpl_LoadWICDecoder(This
, &CLSID_WICGifDecoder
, xbuf
, xread
);
1487 case BITMAP_FORMAT_JPEG
: /* JPEG */
1488 hr
= OLEPictureImpl_LoadWICDecoder(This
, &CLSID_WICJpegDecoder
, xbuf
, xread
);
1490 case BITMAP_FORMAT_BMP
: /* Bitmap */
1491 hr
= OLEPictureImpl_LoadWICDecoder(This
, &CLSID_WICBmpDecoder
, xbuf
, xread
);
1493 case BITMAP_FORMAT_PNG
: /* PNG */
1494 hr
= OLEPictureImpl_LoadWICDecoder(This
, &CLSID_WICPngDecoder
, xbuf
, xread
);
1496 case BITMAP_FORMAT_APM
: /* APM */
1497 hr
= OLEPictureImpl_LoadAPM(This
, xbuf
, xread
);
1499 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1500 hr
= OLEPictureImpl_LoadIcon(This
, xbuf
, xread
);
1507 /* let's see if it's a EMF */
1508 hr
= OLEPictureImpl_LoadEnhMetafile(This
, xbuf
, xread
);
1509 if (hr
== S_OK
) break;
1511 FIXME("Unknown magic %04x, %d read bytes:\n",magic
,xread
);
1513 for (i
=0;i
<xread
+8;i
++) {
1514 if (i
<8) MESSAGE("%02x ",((unsigned char*)header
)[i
]);
1515 else MESSAGE("%02x ",xbuf
[i
-8]);
1516 if (i
% 10 == 9) MESSAGE("\n");
1522 This
->bIsDirty
= FALSE
;
1524 /* FIXME: this notify is not really documented */
1526 OLEPicture_SendNotify(This
,DISPID_PICT_TYPE
);
1530 static BOOL
serializeBMP(HBITMAP hBitmap
, void ** ppBuffer
, unsigned int * pLength
)
1532 BOOL success
= FALSE
;
1534 BITMAPINFO
* pInfoBitmap
;
1535 int iNumPaletteEntries
;
1536 unsigned char * pPixelData
;
1537 BITMAPFILEHEADER
* pFileHeader
;
1538 BITMAPINFO
* pInfoHeader
;
1540 pInfoBitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1541 sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1543 /* Find out bitmap size and padded length */
1545 pInfoBitmap
->bmiHeader
.biSize
= sizeof(pInfoBitmap
->bmiHeader
);
1546 GetDIBits(hDC
, hBitmap
, 0, 0, NULL
, pInfoBitmap
, DIB_RGB_COLORS
);
1548 /* Fetch bitmap palette & pixel data */
1550 pPixelData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, pInfoBitmap
->bmiHeader
.biSizeImage
);
1551 GetDIBits(hDC
, hBitmap
, 0, pInfoBitmap
->bmiHeader
.biHeight
, pPixelData
, pInfoBitmap
, DIB_RGB_COLORS
);
1553 /* Calculate the total length required for the BMP data */
1554 if (pInfoBitmap
->bmiHeader
.biClrUsed
!= 0) {
1555 iNumPaletteEntries
= pInfoBitmap
->bmiHeader
.biClrUsed
;
1556 if (iNumPaletteEntries
> 256) iNumPaletteEntries
= 256;
1558 if (pInfoBitmap
->bmiHeader
.biBitCount
<= 8)
1559 iNumPaletteEntries
= 1 << pInfoBitmap
->bmiHeader
.biBitCount
;
1561 iNumPaletteEntries
= 0;
1564 sizeof(BITMAPFILEHEADER
) +
1565 sizeof(BITMAPINFOHEADER
) +
1566 iNumPaletteEntries
* sizeof(RGBQUAD
) +
1567 pInfoBitmap
->bmiHeader
.biSizeImage
;
1568 *ppBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *pLength
);
1570 /* Fill the BITMAPFILEHEADER */
1571 pFileHeader
= *ppBuffer
;
1572 pFileHeader
->bfType
= BITMAP_FORMAT_BMP
;
1573 pFileHeader
->bfSize
= *pLength
;
1574 pFileHeader
->bfOffBits
=
1575 sizeof(BITMAPFILEHEADER
) +
1576 sizeof(BITMAPINFOHEADER
) +
1577 iNumPaletteEntries
* sizeof(RGBQUAD
);
1579 /* Fill the BITMAPINFOHEADER and the palette data */
1580 pInfoHeader
= (BITMAPINFO
*)((unsigned char *)(*ppBuffer
) + sizeof(BITMAPFILEHEADER
));
1581 memcpy(pInfoHeader
, pInfoBitmap
, sizeof(BITMAPINFOHEADER
) + iNumPaletteEntries
* sizeof(RGBQUAD
));
1583 (unsigned char *)(*ppBuffer
) +
1584 sizeof(BITMAPFILEHEADER
) +
1585 sizeof(BITMAPINFOHEADER
) +
1586 iNumPaletteEntries
* sizeof(RGBQUAD
),
1587 pPixelData
, pInfoBitmap
->bmiHeader
.biSizeImage
);
1590 HeapFree(GetProcessHeap(), 0, pPixelData
);
1591 HeapFree(GetProcessHeap(), 0, pInfoBitmap
);
1595 static BOOL
serializeIcon(HICON hIcon
, void ** ppBuffer
, unsigned int * pLength
)
1598 BOOL success
= FALSE
;
1600 *ppBuffer
= NULL
; *pLength
= 0;
1601 if (GetIconInfo(hIcon
, &infoIcon
)) {
1603 BITMAPINFO
* pInfoBitmap
;
1604 unsigned char * pIconData
= NULL
;
1605 unsigned int iDataSize
= 0;
1607 pInfoBitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1609 /* Find out icon size */
1611 pInfoBitmap
->bmiHeader
.biSize
= sizeof(pInfoBitmap
->bmiHeader
);
1612 GetDIBits(hDC
, infoIcon
.hbmColor
, 0, 0, NULL
, pInfoBitmap
, DIB_RGB_COLORS
);
1614 /* Auxiliary pointers */
1615 CURSORICONFILEDIR
* pIconDir
;
1616 CURSORICONFILEDIRENTRY
* pIconEntry
;
1617 BITMAPINFOHEADER
* pIconBitmapHeader
;
1618 unsigned int iOffsetPalette
;
1619 unsigned int iOffsetColorData
;
1620 unsigned int iOffsetMaskData
;
1622 unsigned int iLengthScanLineMask
;
1623 unsigned int iNumEntriesPalette
;
1625 iLengthScanLineMask
= ((pInfoBitmap
->bmiHeader
.biWidth
+ 31) >> 5) << 2;
1627 FIXME("DEBUG: bitmap size is %d x %d\n",
1628 pInfoBitmap->bmiHeader.biWidth,
1629 pInfoBitmap->bmiHeader.biHeight);
1630 FIXME("DEBUG: bitmap bpp is %d\n",
1631 pInfoBitmap->bmiHeader.biBitCount);
1632 FIXME("DEBUG: bitmap nplanes is %d\n",
1633 pInfoBitmap->bmiHeader.biPlanes);
1634 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1635 pInfoBitmap->bmiHeader.biSizeImage);
1637 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1638 iDataSize
+= 3 * sizeof(WORD
) + sizeof(CURSORICONFILEDIRENTRY
) + sizeof(BITMAPINFOHEADER
);
1639 pIconData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, iDataSize
);
1641 /* Fill out the CURSORICONFILEDIR */
1642 pIconDir
= (CURSORICONFILEDIR
*)pIconData
;
1643 pIconDir
->idType
= 1;
1644 pIconDir
->idCount
= 1;
1645 pIconDir
->idReserved
= 0;
1647 /* Fill out the CURSORICONFILEDIRENTRY */
1648 pIconEntry
= (CURSORICONFILEDIRENTRY
*)(pIconData
+ 3 * sizeof(WORD
));
1649 pIconEntry
->bWidth
= (unsigned char)pInfoBitmap
->bmiHeader
.biWidth
;
1650 pIconEntry
->bHeight
= (unsigned char)pInfoBitmap
->bmiHeader
.biHeight
;
1651 pIconEntry
->bColorCount
=
1652 (pInfoBitmap
->bmiHeader
.biBitCount
< 8)
1653 ? 1 << pInfoBitmap
->bmiHeader
.biBitCount
1655 pIconEntry
->xHotspot
= pInfoBitmap
->bmiHeader
.biPlanes
;
1656 pIconEntry
->yHotspot
= pInfoBitmap
->bmiHeader
.biBitCount
;
1657 pIconEntry
->dwDIBSize
= 0;
1658 pIconEntry
->dwDIBOffset
= 3 * sizeof(WORD
) + sizeof(CURSORICONFILEDIRENTRY
);
1660 /* Fill out the BITMAPINFOHEADER */
1661 pIconBitmapHeader
= (BITMAPINFOHEADER
*)(pIconData
+ 3 * sizeof(WORD
) + sizeof(CURSORICONFILEDIRENTRY
));
1662 *pIconBitmapHeader
= pInfoBitmap
->bmiHeader
;
1664 /* Find out whether a palette exists for the bitmap */
1665 if ( (pInfoBitmap
->bmiHeader
.biBitCount
== 16 && pInfoBitmap
->bmiHeader
.biCompression
== BI_RGB
)
1666 || (pInfoBitmap
->bmiHeader
.biBitCount
== 24)
1667 || (pInfoBitmap
->bmiHeader
.biBitCount
== 32 && pInfoBitmap
->bmiHeader
.biCompression
== BI_RGB
)) {
1668 iNumEntriesPalette
= pInfoBitmap
->bmiHeader
.biClrUsed
;
1669 if (iNumEntriesPalette
> 256) iNumEntriesPalette
= 256;
1670 } else if ((pInfoBitmap
->bmiHeader
.biBitCount
== 16 || pInfoBitmap
->bmiHeader
.biBitCount
== 32)
1671 && pInfoBitmap
->bmiHeader
.biCompression
== BI_BITFIELDS
) {
1672 iNumEntriesPalette
= 3;
1673 } else if (pInfoBitmap
->bmiHeader
.biBitCount
<= 8) {
1674 iNumEntriesPalette
= 1 << pInfoBitmap
->bmiHeader
.biBitCount
;
1676 iNumEntriesPalette
= 0;
1679 /* Add bitmap size and header size to icon data size. */
1680 iOffsetPalette
= iDataSize
;
1681 iDataSize
+= iNumEntriesPalette
* sizeof(DWORD
);
1682 iOffsetColorData
= iDataSize
;
1683 iDataSize
+= pIconBitmapHeader
->biSizeImage
;
1684 iOffsetMaskData
= iDataSize
;
1685 iDataSize
+= pIconBitmapHeader
->biHeight
* iLengthScanLineMask
;
1686 pIconBitmapHeader
->biSizeImage
+= pIconBitmapHeader
->biHeight
* iLengthScanLineMask
;
1687 pIconBitmapHeader
->biHeight
*= 2;
1688 pIconData
= HeapReAlloc(GetProcessHeap(), 0, pIconData
, iDataSize
);
1689 pIconEntry
= (CURSORICONFILEDIRENTRY
*)(pIconData
+ 3 * sizeof(WORD
));
1690 pIconBitmapHeader
= (BITMAPINFOHEADER
*)(pIconData
+ 3 * sizeof(WORD
) + sizeof(CURSORICONFILEDIRENTRY
));
1691 pIconEntry
->dwDIBSize
= iDataSize
- (3 * sizeof(WORD
) + sizeof(CURSORICONFILEDIRENTRY
));
1693 /* Get the actual bitmap data from the icon bitmap */
1694 GetDIBits(hDC
, infoIcon
.hbmColor
, 0, pInfoBitmap
->bmiHeader
.biHeight
,
1695 pIconData
+ iOffsetColorData
, pInfoBitmap
, DIB_RGB_COLORS
);
1696 if (iNumEntriesPalette
> 0) {
1697 memcpy(pIconData
+ iOffsetPalette
, pInfoBitmap
->bmiColors
,
1698 iNumEntriesPalette
* sizeof(RGBQUAD
));
1701 /* Reset all values so that GetDIBits call succeeds */
1702 memset(pIconData
+ iOffsetMaskData
, 0, iDataSize
- iOffsetMaskData
);
1703 memset(pInfoBitmap
, 0, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1704 pInfoBitmap
->bmiHeader
.biSize
= sizeof(pInfoBitmap
->bmiHeader
);
1706 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1707 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1708 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1710 printf("ERROR: unable to get bitmap mask (error %u)\n",
1715 GetDIBits(hDC
, infoIcon
.hbmMask
, 0, 0, NULL
, pInfoBitmap
, DIB_RGB_COLORS
);
1716 GetDIBits(hDC
, infoIcon
.hbmMask
, 0, pIconEntry
->bHeight
, pIconData
+ iOffsetMaskData
, pInfoBitmap
, DIB_RGB_COLORS
);
1718 /* Write out everything produced so far to the stream */
1719 *ppBuffer
= pIconData
; *pLength
= iDataSize
;
1723 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1728 Remarks (from MSDN entry on GetIconInfo):
1730 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1731 members of ICONINFO. The calling application must manage
1732 these bitmaps and delete them when they are no longer
1735 if (hDC
) ReleaseDC(0, hDC
);
1736 DeleteObject(infoIcon
.hbmMask
);
1737 if (infoIcon
.hbmColor
) DeleteObject(infoIcon
.hbmColor
);
1738 HeapFree(GetProcessHeap(), 0, pInfoBitmap
);
1740 printf("ERROR: Unable to get icon information (error %u)\n",
1746 static BOOL
serializeEMF(HENHMETAFILE hemf
, void **buf
, unsigned *size
)
1748 *size
= GetEnhMetaFileBits(hemf
, 0, NULL
);
1749 if (!*size
) return FALSE
;
1751 *buf
= HeapAlloc(GetProcessHeap(), 0, *size
);
1752 if (!*buf
) return FALSE
;
1754 return GetEnhMetaFileBits(hemf
, *size
, *buf
) != 0;
1757 static HRESULT WINAPI
OLEPictureImpl_Save(
1758 IPersistStream
* iface
,IStream
*pStm
,BOOL fClearDirty
)
1760 HRESULT hResult
= E_NOTIMPL
;
1762 unsigned int iDataSize
;
1765 BOOL serializeResult
= FALSE
;
1766 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
1768 TRACE("%p %p %d\n", This
, pStm
, fClearDirty
);
1770 switch (This
->desc
.picType
) {
1772 header
[0] = 0x0000746c;
1774 hResult
= IStream_Write(pStm
, header
, 2 * sizeof(DWORD
), &dummy
);
1778 if (This
->bIsDirty
|| !This
->data
) {
1779 if (!serializeIcon(This
->desc
.u
.icon
.hicon
, &pIconData
, &iDataSize
)) {
1780 ERR("(%p,%p,%d), serializeIcon() failed\n", This
, pStm
, fClearDirty
);
1784 HeapFree(GetProcessHeap(), 0, This
->data
);
1785 This
->data
= pIconData
;
1786 This
->datalen
= iDataSize
;
1789 header
[0] = (This
->loadtime_magic
!= 0xdeadbeef) ? This
->loadtime_magic
: 0x0000746c;
1790 header
[1] = This
->datalen
;
1791 IStream_Write(pStm
, header
, 2 * sizeof(DWORD
), &dummy
);
1792 IStream_Write(pStm
, This
->data
, This
->datalen
, &dummy
);
1795 case PICTYPE_BITMAP
:
1796 if (This
->bIsDirty
|| !This
->data
) {
1797 switch (This
->keepOrigFormat
? This
->loadtime_format
: BITMAP_FORMAT_BMP
) {
1798 case BITMAP_FORMAT_BMP
:
1799 serializeResult
= serializeBMP(This
->desc
.u
.bmp
.hbitmap
, &pIconData
, &iDataSize
);
1801 case BITMAP_FORMAT_JPEG
:
1802 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This
,pStm
,fClearDirty
);
1804 case BITMAP_FORMAT_GIF
:
1805 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This
,pStm
,fClearDirty
);
1807 case BITMAP_FORMAT_PNG
:
1808 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This
,pStm
,fClearDirty
);
1811 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This
,pStm
,fClearDirty
);
1815 if (!serializeResult
)
1821 HeapFree(GetProcessHeap(), 0, This
->data
);
1822 This
->data
= pIconData
;
1823 This
->datalen
= iDataSize
;
1826 header
[0] = (This
->loadtime_magic
!= 0xdeadbeef) ? This
->loadtime_magic
: 0x0000746c;
1827 header
[1] = This
->datalen
;
1828 IStream_Write(pStm
, header
, 2 * sizeof(DWORD
), &dummy
);
1829 IStream_Write(pStm
, This
->data
, This
->datalen
, &dummy
);
1833 case PICTYPE_ENHMETAFILE
:
1834 if (This
->bIsDirty
|| !This
->data
)
1836 serializeResult
= serializeEMF(This
->desc
.u
.emf
.hemf
, &pIconData
, &iDataSize
);
1837 if (!serializeResult
)
1843 HeapFree(GetProcessHeap(), 0, This
->data
);
1844 This
->data
= pIconData
;
1845 This
->datalen
= iDataSize
;
1847 header
[0] = 0x0000746c;
1848 header
[1] = This
->datalen
;
1849 IStream_Write(pStm
, header
, 2 * sizeof(DWORD
), &dummy
);
1850 IStream_Write(pStm
, This
->data
, This
->datalen
, &dummy
);
1854 case PICTYPE_METAFILE
:
1855 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This
,pStm
,fClearDirty
);
1858 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This
,pStm
,fClearDirty
);
1861 if (hResult
== S_OK
&& fClearDirty
) This
->bIsDirty
= FALSE
;
1865 static HRESULT WINAPI
OLEPictureImpl_GetSizeMax(
1866 IPersistStream
* iface
,ULARGE_INTEGER
*pcbSize
)
1868 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
1869 FIXME("(%p,%p),stub!\n",This
,pcbSize
);
1873 /************************************************************************
1874 * OLEPictureImpl_SaveAsFile
1876 static HRESULT WINAPI
OLEPictureImpl_SaveAsFile(IPicture
*iface
,
1877 IStream
*stream
, BOOL mem_copy
, LONG
*size
)
1879 OLEPictureImpl
*This
= impl_from_IPicture(iface
);
1885 FIXME("(%p)->(%p,%d,%p): semi-stub\n", This
, stream
, mem_copy
, size
);
1887 switch (This
->desc
.picType
)
1893 if (!mem_copy
) return E_FAIL
;
1895 if (This
->bIsDirty
|| !This
->data
)
1897 if (!serializeIcon(This
->desc
.u
.icon
.hicon
, &data
, &data_size
))
1899 HeapFree(GetProcessHeap(), 0, This
->data
);
1901 This
->datalen
= data_size
;
1903 hr
= IStream_Write(stream
, This
->data
, This
->datalen
, &written
);
1904 if (hr
== S_OK
&& size
) *size
= written
;
1907 case PICTYPE_BITMAP
:
1908 if (!mem_copy
) return E_FAIL
;
1910 if (This
->bIsDirty
|| !This
->data
)
1912 switch (This
->keepOrigFormat
? This
->loadtime_format
: BITMAP_FORMAT_BMP
)
1914 case BITMAP_FORMAT_BMP
:
1915 if (!serializeBMP(This
->desc
.u
.bmp
.hbitmap
, &data
, &data_size
))
1918 case BITMAP_FORMAT_JPEG
:
1919 FIXME("BITMAP_FORMAT_JPEG is not implemented\n");
1921 case BITMAP_FORMAT_GIF
:
1922 FIXME("BITMAP_FORMAT_GIF is not implemented\n");
1924 case BITMAP_FORMAT_PNG
:
1925 FIXME("BITMAP_FORMAT_PNG is not implemented\n");
1928 FIXME("PICTYPE_BITMAP/%#x is not implemented\n", This
->loadtime_format
);
1932 HeapFree(GetProcessHeap(), 0, This
->data
);
1934 This
->datalen
= data_size
;
1936 hr
= IStream_Write(stream
, This
->data
, This
->datalen
, &written
);
1937 if (hr
== S_OK
&& size
) *size
= written
;
1940 case PICTYPE_METAFILE
:
1941 FIXME("PICTYPE_METAFILE is not implemented\n");
1944 case PICTYPE_ENHMETAFILE
:
1945 if (!mem_copy
) return E_FAIL
;
1947 if (This
->bIsDirty
|| !This
->data
)
1949 if (!serializeEMF(This
->desc
.u
.emf
.hemf
, &data
, &data_size
))
1951 HeapFree(GetProcessHeap(), 0, This
->data
);
1953 This
->datalen
= data_size
;
1955 hr
= IStream_Write(stream
, This
->data
, This
->datalen
, &written
);
1956 if (hr
== S_OK
&& size
) *size
= written
;
1960 FIXME("%#x is not implemented\n", This
->desc
.picType
);
1966 /************************************************************************
1970 /************************************************************************
1971 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1973 * See Windows documentation for more details on IUnknown methods.
1975 static HRESULT WINAPI
OLEPictureImpl_IDispatch_QueryInterface(
1980 OLEPictureImpl
*This
= impl_from_IDispatch(iface
);
1982 return IPicture_QueryInterface(&This
->IPicture_iface
, riid
, ppvoid
);
1985 /************************************************************************
1986 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1988 * See Windows documentation for more details on IUnknown methods.
1990 static ULONG WINAPI
OLEPictureImpl_IDispatch_AddRef(
1993 OLEPictureImpl
*This
= impl_from_IDispatch(iface
);
1995 return IPicture_AddRef(&This
->IPicture_iface
);
1998 /************************************************************************
1999 * OLEPictureImpl_IDispatch_Release (IUnknown)
2001 * See Windows documentation for more details on IUnknown methods.
2003 static ULONG WINAPI
OLEPictureImpl_IDispatch_Release(
2006 OLEPictureImpl
*This
= impl_from_IDispatch(iface
);
2008 return IPicture_Release(&This
->IPicture_iface
);
2011 /************************************************************************
2012 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2014 * See Windows documentation for more details on IDispatch methods.
2016 static HRESULT WINAPI
OLEPictureImpl_GetTypeInfoCount(
2018 unsigned int* pctinfo
)
2020 TRACE("(%p)\n", pctinfo
);
2027 /************************************************************************
2028 * OLEPictureImpl_GetTypeInfo (IDispatch)
2030 * See Windows documentation for more details on IDispatch methods.
2032 static HRESULT WINAPI
OLEPictureImpl_GetTypeInfo(
2036 ITypeInfo
** ppTInfo
)
2038 static const WCHAR stdole2tlb
[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2042 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo
, (int)lcid
, ppTInfo
);
2047 hres
= LoadTypeLib(stdole2tlb
, &tl
);
2050 ERR("Could not load stdole2.tlb\n");
2054 hres
= ITypeLib_GetTypeInfoOfGuid(tl
, &IID_IPictureDisp
, ppTInfo
);
2056 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres
);
2061 /************************************************************************
2062 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2064 * See Windows documentation for more details on IDispatch methods.
2066 static HRESULT WINAPI
OLEPictureImpl_GetIDsOfNames(
2069 LPOLESTR
* rgszNames
,
2077 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface
, debugstr_guid(riid
),
2078 rgszNames
, cNames
, (int)lcid
, rgDispId
);
2082 return E_INVALIDARG
;
2086 /* retrieve type information */
2087 hres
= OLEPictureImpl_GetTypeInfo(iface
, 0, lcid
, &pTInfo
);
2091 ERR("GetTypeInfo failed.\n");
2095 /* convert names to DISPIDs */
2096 hres
= DispGetIDsOfNames (pTInfo
, rgszNames
, cNames
, rgDispId
);
2097 ITypeInfo_Release(pTInfo
);
2103 /************************************************************************
2104 * OLEPictureImpl_Invoke (IDispatch)
2106 * See Windows documentation for more details on IDispatch methods.
2108 static HRESULT WINAPI
OLEPictureImpl_Invoke(
2110 DISPID dispIdMember
,
2114 DISPPARAMS
* pDispParams
,
2115 VARIANT
* pVarResult
,
2116 EXCEPINFO
* pExepInfo
,
2119 OLEPictureImpl
*This
= impl_from_IDispatch(iface
);
2122 /* validate parameters */
2124 if (!IsEqualIID(riid
, &IID_NULL
))
2126 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid
));
2127 return DISP_E_UNKNOWNNAME
;
2132 ERR("null pDispParams not allowed\n");
2133 return DISP_E_PARAMNOTOPTIONAL
;
2136 if (wFlags
& DISPATCH_PROPERTYGET
)
2138 if (pDispParams
->cArgs
!= 0)
2140 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams
->cArgs
);
2141 return DISP_E_BADPARAMCOUNT
;
2145 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2146 return DISP_E_PARAMNOTOPTIONAL
;
2149 else if (wFlags
& DISPATCH_PROPERTYPUT
)
2151 if (pDispParams
->cArgs
!= 1)
2153 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams
->cArgs
);
2154 return DISP_E_BADPARAMCOUNT
;
2158 switch (dispIdMember
)
2160 case DISPID_PICT_HANDLE
:
2161 if (wFlags
& DISPATCH_PROPERTYGET
)
2163 TRACE("DISPID_PICT_HANDLE\n");
2164 V_VT(pVarResult
) = VT_I4
;
2165 return IPicture_get_Handle(&This
->IPicture_iface
, &V_UINT(pVarResult
));
2168 case DISPID_PICT_HPAL
:
2169 if (wFlags
& DISPATCH_PROPERTYGET
)
2171 TRACE("DISPID_PICT_HPAL\n");
2172 V_VT(pVarResult
) = VT_I4
;
2173 return IPicture_get_hPal(&This
->IPicture_iface
, &V_UINT(pVarResult
));
2175 else if (wFlags
& DISPATCH_PROPERTYPUT
)
2179 TRACE("DISPID_PICT_HPAL\n");
2181 VariantInit(&vararg
);
2182 hr
= VariantChangeTypeEx(&vararg
, &pDispParams
->rgvarg
[0], lcid
, 0, VT_I4
);
2186 hr
= IPicture_set_hPal(&This
->IPicture_iface
, V_I4(&vararg
));
2188 VariantClear(&vararg
);
2192 case DISPID_PICT_TYPE
:
2193 if (wFlags
& DISPATCH_PROPERTYGET
)
2195 TRACE("DISPID_PICT_TYPE\n");
2196 V_VT(pVarResult
) = VT_I2
;
2197 return OLEPictureImpl_get_Type(&This
->IPicture_iface
, &V_I2(pVarResult
));
2200 case DISPID_PICT_WIDTH
:
2201 if (wFlags
& DISPATCH_PROPERTYGET
)
2203 TRACE("DISPID_PICT_WIDTH\n");
2204 V_VT(pVarResult
) = VT_I4
;
2205 return IPicture_get_Width(&This
->IPicture_iface
, &V_I4(pVarResult
));
2208 case DISPID_PICT_HEIGHT
:
2209 if (wFlags
& DISPATCH_PROPERTYGET
)
2211 TRACE("DISPID_PICT_HEIGHT\n");
2212 V_VT(pVarResult
) = VT_I4
;
2213 return IPicture_get_Height(&This
->IPicture_iface
, &V_I4(pVarResult
));
2216 case DISPID_PICT_RENDER
:
2217 if (wFlags
& DISPATCH_METHOD
)
2219 VARIANTARG
*args
= pDispParams
->rgvarg
;
2222 TRACE("DISPID_PICT_RENDER\n");
2224 if (pDispParams
->cArgs
!= 10)
2225 return DISP_E_BADPARAMCOUNT
;
2227 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2228 for (i
= 0; i
< pDispParams
->cArgs
; i
++)
2229 if (V_VT(&args
[i
]) != VT_I4
)
2231 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i
, V_VT(&args
[i
]));
2232 return DISP_E_TYPEMISMATCH
;
2235 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2236 currently Render() doesn't use it at all so for now NULL is passed. */
2237 return IPicture_Render(&This
->IPicture_iface
,
2238 LongToHandle(V_I4(&args
[9])),
2252 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember
, wFlags
);
2253 return DISP_E_MEMBERNOTFOUND
;
2257 static const IPictureVtbl OLEPictureImpl_VTable
=
2259 OLEPictureImpl_QueryInterface
,
2260 OLEPictureImpl_AddRef
,
2261 OLEPictureImpl_Release
,
2262 OLEPictureImpl_get_Handle
,
2263 OLEPictureImpl_get_hPal
,
2264 OLEPictureImpl_get_Type
,
2265 OLEPictureImpl_get_Width
,
2266 OLEPictureImpl_get_Height
,
2267 OLEPictureImpl_Render
,
2268 OLEPictureImpl_set_hPal
,
2269 OLEPictureImpl_get_CurDC
,
2270 OLEPictureImpl_SelectPicture
,
2271 OLEPictureImpl_get_KeepOriginalFormat
,
2272 OLEPictureImpl_put_KeepOriginalFormat
,
2273 OLEPictureImpl_PictureChanged
,
2274 OLEPictureImpl_SaveAsFile
,
2275 OLEPictureImpl_get_Attributes
2278 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable
=
2280 OLEPictureImpl_IDispatch_QueryInterface
,
2281 OLEPictureImpl_IDispatch_AddRef
,
2282 OLEPictureImpl_IDispatch_Release
,
2283 OLEPictureImpl_GetTypeInfoCount
,
2284 OLEPictureImpl_GetTypeInfo
,
2285 OLEPictureImpl_GetIDsOfNames
,
2286 OLEPictureImpl_Invoke
2289 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable
=
2291 OLEPictureImpl_IPersistStream_QueryInterface
,
2292 OLEPictureImpl_IPersistStream_AddRef
,
2293 OLEPictureImpl_IPersistStream_Release
,
2294 OLEPictureImpl_GetClassID
,
2295 OLEPictureImpl_IsDirty
,
2296 OLEPictureImpl_Load
,
2297 OLEPictureImpl_Save
,
2298 OLEPictureImpl_GetSizeMax
2301 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable
=
2303 OLEPictureImpl_IConnectionPointContainer_QueryInterface
,
2304 OLEPictureImpl_IConnectionPointContainer_AddRef
,
2305 OLEPictureImpl_IConnectionPointContainer_Release
,
2306 OLEPictureImpl_EnumConnectionPoints
,
2307 OLEPictureImpl_FindConnectionPoint
2310 /***********************************************************************
2311 * OleCreatePictureIndirect (OLEAUT32.419)
2313 HRESULT WINAPI
OleCreatePictureIndirect(LPPICTDESC lpPictDesc
, REFIID riid
,
2314 BOOL Own
, void **ppvObj
)
2316 OLEPictureImpl
* newPict
;
2319 TRACE("(%p,%s,%d,%p)\n", lpPictDesc
, debugstr_guid(riid
), Own
, ppvObj
);
2323 hr
= OLEPictureImpl_Construct(lpPictDesc
, Own
, &newPict
);
2324 if (hr
!= S_OK
) return hr
;
2327 * Make sure it supports the interface required by the caller.
2329 hr
= IPicture_QueryInterface(&newPict
->IPicture_iface
, riid
, ppvObj
);
2332 * Release the reference obtained in the constructor. If
2333 * the QueryInterface was unsuccessful, it will free the class.
2335 IPicture_Release(&newPict
->IPicture_iface
);
2341 /***********************************************************************
2342 * OleLoadPicture (OLEAUT32.418)
2344 HRESULT WINAPI
OleLoadPicture( LPSTREAM lpstream
, LONG lSize
, BOOL fRunmode
,
2345 REFIID riid
, LPVOID
*ppvObj
)
2351 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2352 lpstream
, lSize
, fRunmode
, debugstr_guid(riid
), ppvObj
);
2354 hr
= OleCreatePictureIndirect(NULL
,riid
,!fRunmode
,(LPVOID
*)&newpic
);
2357 hr
= IPicture_QueryInterface(newpic
,&IID_IPersistStream
, (LPVOID
*)&ps
);
2359 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2360 IPicture_Release(newpic
);
2364 hr
= IPersistStream_Load(ps
,lpstream
);
2365 IPersistStream_Release(ps
);
2368 ERR("IPersistStream_Load failed\n");
2369 IPicture_Release(newpic
);
2373 hr
= IPicture_QueryInterface(newpic
,riid
,ppvObj
);
2375 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid
));
2376 IPicture_Release(newpic
);
2380 /***********************************************************************
2381 * OleLoadPictureEx (OLEAUT32.401)
2383 HRESULT WINAPI
OleLoadPictureEx( LPSTREAM lpstream
, LONG lSize
, BOOL fRunmode
,
2384 REFIID riid
, DWORD xsiz
, DWORD ysiz
, DWORD flags
, LPVOID
*ppvObj
)
2390 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2391 lpstream
, lSize
, fRunmode
, debugstr_guid(riid
), xsiz
, ysiz
, flags
, ppvObj
);
2393 hr
= OleCreatePictureIndirect(NULL
,riid
,!fRunmode
,(LPVOID
*)&newpic
);
2396 hr
= IPicture_QueryInterface(newpic
,&IID_IPersistStream
, (LPVOID
*)&ps
);
2398 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2399 IPicture_Release(newpic
);
2403 hr
= IPersistStream_Load(ps
,lpstream
);
2404 IPersistStream_Release(ps
);
2407 ERR("IPersistStream_Load failed\n");
2408 IPicture_Release(newpic
);
2412 hr
= IPicture_QueryInterface(newpic
,riid
,ppvObj
);
2414 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid
));
2415 IPicture_Release(newpic
);
2419 static HRESULT
create_stream(const WCHAR
*filename
, IStream
**stream
)
2423 HGLOBAL hGlobal
= NULL
;
2427 hFile
= CreateFileW(filename
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
, 0, NULL
);
2428 if (hFile
== INVALID_HANDLE_VALUE
)
2429 return HRESULT_FROM_WIN32(GetLastError());
2431 dwFileSize
= GetFileSize(hFile
, NULL
);
2432 if (dwFileSize
!= INVALID_FILE_SIZE
)
2434 hGlobal
= GlobalAlloc(GMEM_FIXED
, dwFileSize
);
2439 if (!ReadFile(hFile
, hGlobal
, dwFileSize
, &dwBytesRead
, NULL
))
2441 GlobalFree(hGlobal
);
2442 hr
= HRESULT_FROM_WIN32(GetLastError());
2449 if (FAILED(hr
)) return hr
;
2451 hr
= CreateStreamOnHGlobal(hGlobal
, TRUE
, stream
);
2453 GlobalFree(hGlobal
);
2458 /***********************************************************************
2459 * OleLoadPictureFile (OLEAUT32.422)
2461 HRESULT WINAPI
OleLoadPictureFile(VARIANT filename
, IDispatch
**picture
)
2466 TRACE("(%s,%p)\n", wine_dbgstr_variant(&filename
), picture
);
2468 if (V_VT(&filename
) != VT_BSTR
)
2469 return CTL_E_FILENOTFOUND
;
2471 hr
= create_stream(V_BSTR(&filename
), &stream
);
2474 if (hr
== HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND
))
2475 return CTL_E_FILENOTFOUND
;
2477 return CTL_E_PATHFILEACCESSERROR
;
2480 hr
= OleLoadPicture(stream
, 0, FALSE
, &IID_IDispatch
, (void **)picture
);
2481 IStream_Release(stream
);
2485 /***********************************************************************
2486 * OleSavePictureFile (OLEAUT32.423)
2488 HRESULT WINAPI
OleSavePictureFile(IDispatch
*picture
, BSTR filename
)
2490 FIXME("(%p %s): stub\n", picture
, debugstr_w(filename
));
2491 return CTL_E_FILENOTFOUND
;
2494 /***********************************************************************
2495 * OleLoadPicturePath (OLEAUT32.424)
2497 HRESULT WINAPI
OleLoadPicturePath( LPOLESTR szURLorPath
, LPUNKNOWN punkCaller
,
2498 DWORD dwReserved
, OLE_COLOR clrReserved
, REFIID riid
,
2501 static const WCHAR file
[] = { 'f','i','l','e',':',0 };
2504 WCHAR
*file_candidate
;
2505 WCHAR path_buf
[MAX_PATH
];
2507 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2508 debugstr_w(szURLorPath
), punkCaller
, dwReserved
, clrReserved
,
2509 debugstr_guid(riid
), ppvRet
);
2511 if (!szURLorPath
|| !ppvRet
)
2512 return E_INVALIDARG
;
2516 /* Convert file URLs to DOS paths. */
2517 if (wcsncmp(szURLorPath
, file
, 5) == 0) {
2519 hRes
= CoInternetParseUrl(szURLorPath
, PARSE_PATH_FROM_URL
, 0, path_buf
,
2520 ARRAY_SIZE(path_buf
), &size
, 0);
2524 file_candidate
= path_buf
;
2527 file_candidate
= szURLorPath
;
2529 /* Handle candidate DOS paths separately. */
2530 if (file_candidate
[1] == ':') {
2531 hRes
= create_stream(file_candidate
, &stream
);
2533 return INET_E_RESOURCE_NOT_FOUND
;
2538 hRes
= CreateBindCtx(0, &pbc
);
2539 if (SUCCEEDED(hRes
))
2541 hRes
= CreateURLMoniker(NULL
, szURLorPath
, &pmnk
);
2542 if (SUCCEEDED(hRes
))
2544 hRes
= IMoniker_BindToStorage(pmnk
, pbc
, NULL
, &IID_IStream
, (LPVOID
*)&stream
);
2545 IMoniker_Release(pmnk
);
2547 IBindCtx_Release(pbc
);
2553 hRes
= OleLoadPicture(stream
, 0, FALSE
, riid
, ppvRet
);
2555 IStream_Release(stream
);
2560 /*******************************************************************************
2561 * StdPic ClassFactory
2565 /* IUnknown fields */
2566 IClassFactory IClassFactory_iface
;
2568 } IClassFactoryImpl
;
2570 static inline IClassFactoryImpl
*impl_from_IClassFactory(IClassFactory
*iface
)
2572 return CONTAINING_RECORD(iface
, IClassFactoryImpl
, IClassFactory_iface
);
2575 static HRESULT WINAPI
2576 SPCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
2577 IClassFactoryImpl
*This
= impl_from_IClassFactory(iface
);
2579 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
2580 return E_NOINTERFACE
;
2584 SPCF_AddRef(LPCLASSFACTORY iface
) {
2585 IClassFactoryImpl
*This
= impl_from_IClassFactory(iface
);
2586 return InterlockedIncrement(&This
->ref
);
2589 static ULONG WINAPI
SPCF_Release(LPCLASSFACTORY iface
) {
2590 IClassFactoryImpl
*This
= impl_from_IClassFactory(iface
);
2591 /* static class, won't be freed */
2592 return InterlockedDecrement(&This
->ref
);
2595 static HRESULT WINAPI
SPCF_CreateInstance(
2596 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2598 /* Creates an uninitialized picture */
2599 return OleCreatePictureIndirect(NULL
,riid
,TRUE
,ppobj
);
2603 static HRESULT WINAPI
SPCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
2604 IClassFactoryImpl
*This
= impl_from_IClassFactory(iface
);
2605 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
2609 static const IClassFactoryVtbl SPCF_Vtbl
= {
2610 SPCF_QueryInterface
,
2613 SPCF_CreateInstance
,
2616 static IClassFactoryImpl STDPIC_CF
= {{&SPCF_Vtbl
}, 1 };
2618 void _get_STDPIC_CF(LPVOID
*ppv
) { *ppv
= &STDPIC_CF
; }