4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 * Support PICTYPE_BITMAP and PICTYPE_ICON, altough only bitmaps very well..
26 * Lots of methods are just stubs.
29 * NOTES (or things that msdn doesn't tell you)
31 * The width and height properties are returned in HIMETRIC units (0.01mm)
32 * IPicture::Render also uses these to select a region of the src picture.
33 * A bitmap's size is converted into these units by using the screen resolution
34 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
39 #include "wine/port.h"
48 /* Must be before wine includes, the header has things conflicting with
52 #define NONAMELESSUNION
53 #define NONAMELESSSTRUCT
65 #include "wine/debug.h"
66 #include "wine/unicode.h"
68 #include "wine/wingdi16.h"
71 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
73 #define UINT8 JPEG_UINT8
74 #define UINT16 JPEG_UINT16
76 #define boolean jpeg_boolean
89 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
102 } CURSORICONFILEDIRENTRY
;
109 CURSORICONFILEDIRENTRY idEntries
[1];
114 /*************************************************************************
115 * Declaration of implementation class
118 typedef struct OLEPictureImpl
{
121 * IPicture handles IUnknown
124 const IPictureVtbl
*lpVtbl
;
125 const IDispatchVtbl
*lpvtblIDispatch
;
126 const IPersistStreamVtbl
*lpvtblIPersistStream
;
127 const IConnectionPointContainerVtbl
*lpvtblIConnectionPointContainer
;
129 /* Object reference count */
132 /* We own the object and must destroy it ourselves */
135 /* Picture description */
138 /* These are the pixel size of a bitmap */
142 /* And these are the size of the picture converted into HIMETRIC units */
143 OLE_XSIZE_HIMETRIC himetricWidth
;
144 OLE_YSIZE_HIMETRIC himetricHeight
;
146 IConnectionPoint
*pCP
;
151 /* Bitmap transparency mask */
159 BOOL bIsDirty
; /* Set to TRUE if picture has changed */
160 unsigned int loadtime_magic
; /* If a length header was found, saves value */
161 unsigned int loadtime_format
; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
165 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
168 static inline OLEPictureImpl
*impl_from_IDispatch( IDispatch
*iface
)
170 return (OLEPictureImpl
*)((char*)iface
- FIELD_OFFSET(OLEPictureImpl
, lpvtblIDispatch
));
173 static inline OLEPictureImpl
*impl_from_IPersistStream( IPersistStream
*iface
)
175 return (OLEPictureImpl
*)((char*)iface
- FIELD_OFFSET(OLEPictureImpl
, lpvtblIPersistStream
));
178 static inline OLEPictureImpl
*impl_from_IConnectionPointContainer( IConnectionPointContainer
*iface
)
180 return (OLEPictureImpl
*)((char*)iface
- FIELD_OFFSET(OLEPictureImpl
, lpvtblIConnectionPointContainer
));
184 * Predeclare VTables. They get initialized at the end.
186 static const IPictureVtbl OLEPictureImpl_VTable
;
187 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable
;
188 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable
;
189 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable
;
191 /***********************************************************************
192 * Implementation of the OLEPictureImpl class.
195 static void OLEPictureImpl_SetBitmap(OLEPictureImpl
*This
) {
199 TRACE("bitmap handle %p\n", This
->desc
.u
.bmp
.hbitmap
);
200 if(GetObjectA(This
->desc
.u
.bmp
.hbitmap
, sizeof(bm
), &bm
) != sizeof(bm
)) {
201 ERR("GetObject fails\n");
204 This
->origWidth
= bm
.bmWidth
;
205 This
->origHeight
= bm
.bmHeight
;
206 /* The width and height are stored in HIMETRIC units (0.01 mm),
207 so we take our pixel width divide by pixels per inch and
208 multiply by 25.4 * 100 */
209 /* Should we use GetBitmapDimension if available? */
210 hdcRef
= CreateCompatibleDC(0);
211 This
->himetricWidth
=(bm
.bmWidth
*2540)/GetDeviceCaps(hdcRef
, LOGPIXELSX
);
212 This
->himetricHeight
=(bm
.bmHeight
*2540)/GetDeviceCaps(hdcRef
, LOGPIXELSY
);
216 static void OLEPictureImpl_SetIcon(OLEPictureImpl
* This
)
220 TRACE("icon handle %p\n", This
->desc
.u
.icon
.hicon
);
221 if (GetIconInfo(This
->desc
.u
.icon
.hicon
, &infoIcon
)) {
225 TRACE("bitmap handle for icon is %p\n", infoIcon
.hbmColor
);
226 if(GetObjectA(infoIcon
.hbmColor
? infoIcon
.hbmColor
: infoIcon
.hbmMask
, sizeof(bm
), &bm
) != sizeof(bm
)) {
227 ERR("GetObject fails on icon bitmap\n");
231 This
->origWidth
= bm
.bmWidth
;
232 This
->origHeight
= infoIcon
.hbmColor
? bm
.bmHeight
: bm
.bmHeight
/ 2;
233 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
235 This
->himetricWidth
= (This
->origWidth
*2540)/GetDeviceCaps(hdcRef
, LOGPIXELSX
);
236 This
->himetricHeight
= (This
->origHeight
*2540)/GetDeviceCaps(hdcRef
, LOGPIXELSY
);
237 ReleaseDC(0, hdcRef
);
239 DeleteObject(infoIcon
.hbmMask
);
240 if (infoIcon
.hbmColor
) DeleteObject(infoIcon
.hbmColor
);
242 ERR("GetIconInfo() fails on icon %p\n", This
->desc
.u
.icon
.hicon
);
246 /************************************************************************
247 * OLEPictureImpl_Construct
249 * This method will construct a new instance of the OLEPictureImpl
252 * The caller of this method must release the object when it's
255 static OLEPictureImpl
* OLEPictureImpl_Construct(LPPICTDESC pictDesc
, BOOL fOwn
)
257 OLEPictureImpl
* newObject
= 0;
260 TRACE("(%p) type = %d\n", pictDesc
, pictDesc
->picType
);
263 * Allocate space for the object.
265 newObject
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(OLEPictureImpl
));
271 * Initialize the virtual function table.
273 newObject
->lpVtbl
= &OLEPictureImpl_VTable
;
274 newObject
->lpvtblIDispatch
= &OLEPictureImpl_IDispatch_VTable
;
275 newObject
->lpvtblIPersistStream
= &OLEPictureImpl_IPersistStream_VTable
;
276 newObject
->lpvtblIConnectionPointContainer
= &OLEPictureImpl_IConnectionPointContainer_VTable
;
278 newObject
->pCP
= NULL
;
279 CreateConnectionPoint((IUnknown
*)newObject
,&IID_IPropertyNotifySink
,&newObject
->pCP
);
282 HeapFree(GetProcessHeap(), 0, newObject
);
287 * Start with one reference count. The caller of this function
288 * must release the interface pointer when it is done.
291 newObject
->hDCCur
= 0;
293 newObject
->fOwn
= fOwn
;
295 /* dunno about original value */
296 newObject
->keepOrigFormat
= TRUE
;
298 newObject
->hbmMask
= NULL
;
299 newObject
->hbmXor
= NULL
;
300 newObject
->loadtime_magic
= 0xdeadbeef;
301 newObject
->loadtime_format
= 0;
302 newObject
->bIsDirty
= FALSE
;
305 memcpy(&newObject
->desc
, pictDesc
, sizeof(PICTDESC
));
307 switch(pictDesc
->picType
) {
309 OLEPictureImpl_SetBitmap(newObject
);
312 case PICTYPE_METAFILE
:
313 TRACE("metafile handle %p\n", pictDesc
->u
.wmf
.hmeta
);
314 newObject
->himetricWidth
= pictDesc
->u
.wmf
.xExt
;
315 newObject
->himetricHeight
= pictDesc
->u
.wmf
.yExt
;
319 /* not sure what to do here */
320 newObject
->himetricWidth
= newObject
->himetricHeight
= 0;
324 OLEPictureImpl_SetIcon(newObject
);
326 case PICTYPE_ENHMETAFILE
:
328 FIXME("Unsupported type %d\n", pictDesc
->picType
);
329 newObject
->himetricWidth
= newObject
->himetricHeight
= 0;
333 newObject
->desc
.picType
= PICTYPE_UNINITIALIZED
;
336 TRACE("returning %p\n", newObject
);
340 /************************************************************************
341 * OLEPictureImpl_Destroy
343 * This method is called by the Release method when the reference
344 * count goes down to 0. It will free all resources used by
346 static void OLEPictureImpl_Destroy(OLEPictureImpl
* Obj
)
348 TRACE("(%p)\n", Obj
);
351 IConnectionPoint_Release(Obj
->pCP
);
353 if(Obj
->fOwn
) { /* We need to destroy the picture */
354 switch(Obj
->desc
.picType
) {
356 DeleteObject(Obj
->desc
.u
.bmp
.hbitmap
);
357 if (Obj
->hbmMask
!= NULL
) DeleteObject(Obj
->hbmMask
);
358 if (Obj
->hbmXor
!= NULL
) DeleteObject(Obj
->hbmXor
);
360 case PICTYPE_METAFILE
:
361 DeleteMetaFile(Obj
->desc
.u
.wmf
.hmeta
);
364 DestroyIcon(Obj
->desc
.u
.icon
.hicon
);
366 case PICTYPE_ENHMETAFILE
:
367 DeleteEnhMetaFile(Obj
->desc
.u
.emf
.hemf
);
370 case PICTYPE_UNINITIALIZED
:
374 FIXME("Unsupported type %d - unable to delete\n", Obj
->desc
.picType
);
378 HeapFree(GetProcessHeap(), 0, Obj
->data
);
379 HeapFree(GetProcessHeap(), 0, Obj
);
383 /************************************************************************
384 * OLEPictureImpl_AddRef (IUnknown)
386 * See Windows documentation for more details on IUnknown methods.
388 static ULONG WINAPI
OLEPictureImpl_AddRef(
391 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
392 ULONG refCount
= InterlockedIncrement(&This
->ref
);
394 TRACE("(%p)->(ref before=%d)\n", This
, refCount
- 1);
399 /************************************************************************
400 * OLEPictureImpl_Release (IUnknown)
402 * See Windows documentation for more details on IUnknown methods.
404 static ULONG WINAPI
OLEPictureImpl_Release(
407 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
408 ULONG refCount
= InterlockedDecrement(&This
->ref
);
410 TRACE("(%p)->(ref before=%d)\n", This
, refCount
+ 1);
413 * If the reference count goes down to 0, perform suicide.
415 if (!refCount
) OLEPictureImpl_Destroy(This
);
420 /************************************************************************
421 * OLEPictureImpl_QueryInterface (IUnknown)
423 * See Windows documentation for more details on IUnknown methods.
425 static HRESULT WINAPI
OLEPictureImpl_QueryInterface(
430 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
431 TRACE("(%p)->(%s, %p)\n", This
, debugstr_guid(riid
), ppvObject
);
434 * Perform a sanity check on the parameters.
436 if ( (This
==0) || (ppvObject
==0) )
440 * Initialize the return parameter.
445 * Compare the riid with the interface IDs implemented by this object.
447 if (IsEqualIID(&IID_IUnknown
, riid
) || IsEqualIID(&IID_IPicture
, riid
))
448 *ppvObject
= (IPicture
*)This
;
449 else if (IsEqualIID(&IID_IDispatch
, riid
))
450 *ppvObject
= (IDispatch
*)&(This
->lpvtblIDispatch
);
451 else if (IsEqualIID(&IID_IPictureDisp
, riid
))
452 *ppvObject
= (IDispatch
*)&(This
->lpvtblIDispatch
);
453 else if (IsEqualIID(&IID_IPersist
, riid
) || IsEqualIID(&IID_IPersistStream
, riid
))
454 *ppvObject
= (IPersistStream
*)&(This
->lpvtblIPersistStream
);
455 else if (IsEqualIID(&IID_IConnectionPointContainer
, riid
))
456 *ppvObject
= (IConnectionPointContainer
*)&(This
->lpvtblIConnectionPointContainer
);
459 * Check that we obtained an interface.
463 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid
));
464 return E_NOINTERFACE
;
468 * Query Interface always increases the reference count by one when it is
471 OLEPictureImpl_AddRef((IPicture
*)This
);
476 /***********************************************************************
477 * OLEPicture_SendNotify (internal)
479 * Sends notification messages of changed properties to any interested
482 static void OLEPicture_SendNotify(OLEPictureImpl
* this, DISPID dispID
)
484 IEnumConnections
*pEnum
;
487 if (IConnectionPoint_EnumConnections(this->pCP
, &pEnum
))
489 while(IEnumConnections_Next(pEnum
, 1, &CD
, NULL
) == S_OK
) {
490 IPropertyNotifySink
*sink
;
492 IUnknown_QueryInterface(CD
.pUnk
, &IID_IPropertyNotifySink
, (LPVOID
)&sink
);
493 IPropertyNotifySink_OnChanged(sink
, dispID
);
494 IPropertyNotifySink_Release(sink
);
495 IUnknown_Release(CD
.pUnk
);
497 IEnumConnections_Release(pEnum
);
501 /************************************************************************
502 * OLEPictureImpl_get_Handle
504 static HRESULT WINAPI
OLEPictureImpl_get_Handle(IPicture
*iface
,
507 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
508 TRACE("(%p)->(%p)\n", This
, phandle
);
509 switch(This
->desc
.picType
) {
511 case PICTYPE_UNINITIALIZED
:
515 *phandle
= (OLE_HANDLE
)This
->desc
.u
.bmp
.hbitmap
;
517 case PICTYPE_METAFILE
:
518 *phandle
= (OLE_HANDLE
)This
->desc
.u
.wmf
.hmeta
;
521 *phandle
= (OLE_HANDLE
)This
->desc
.u
.icon
.hicon
;
523 case PICTYPE_ENHMETAFILE
:
524 *phandle
= (OLE_HANDLE
)This
->desc
.u
.emf
.hemf
;
527 FIXME("Unimplemented type %d\n", This
->desc
.picType
);
530 TRACE("returning handle %08x\n", *phandle
);
534 /************************************************************************
535 * OLEPictureImpl_get_hPal
537 static HRESULT WINAPI
OLEPictureImpl_get_hPal(IPicture
*iface
,
540 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
542 TRACE("(%p)->(%p)\n", This
, phandle
);
547 switch (This
->desc
.picType
) {
548 case (UINT
)PICTYPE_UNINITIALIZED
:
554 *phandle
= (OLE_HANDLE
)This
->desc
.u
.bmp
.hpal
;
558 case PICTYPE_METAFILE
:
559 case PICTYPE_ENHMETAFILE
:
561 FIXME("unimplemented for type %d. Returning 0 palette.\n",
567 TRACE("returning 0x%08x, palette handle %08x\n", hres
, *phandle
);
571 /************************************************************************
572 * OLEPictureImpl_get_Type
574 static HRESULT WINAPI
OLEPictureImpl_get_Type(IPicture
*iface
,
577 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
578 TRACE("(%p)->(%p): type is %d\n", This
, ptype
, This
->desc
.picType
);
579 *ptype
= This
->desc
.picType
;
583 /************************************************************************
584 * OLEPictureImpl_get_Width
586 static HRESULT WINAPI
OLEPictureImpl_get_Width(IPicture
*iface
,
587 OLE_XSIZE_HIMETRIC
*pwidth
)
589 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
590 TRACE("(%p)->(%p): width is %d\n", This
, pwidth
, This
->himetricWidth
);
591 *pwidth
= This
->himetricWidth
;
595 /************************************************************************
596 * OLEPictureImpl_get_Height
598 static HRESULT WINAPI
OLEPictureImpl_get_Height(IPicture
*iface
,
599 OLE_YSIZE_HIMETRIC
*pheight
)
601 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
602 TRACE("(%p)->(%p): height is %d\n", This
, pheight
, This
->himetricHeight
);
603 *pheight
= This
->himetricHeight
;
607 /************************************************************************
608 * OLEPictureImpl_Render
610 static HRESULT WINAPI
OLEPictureImpl_Render(IPicture
*iface
, HDC hdc
,
611 LONG x
, LONG y
, LONG cx
, LONG cy
,
612 OLE_XPOS_HIMETRIC xSrc
,
613 OLE_YPOS_HIMETRIC ySrc
,
614 OLE_XSIZE_HIMETRIC cxSrc
,
615 OLE_YSIZE_HIMETRIC cySrc
,
618 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
619 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
620 This
, hdc
, x
, y
, cx
, cy
, xSrc
, ySrc
, cxSrc
, cySrc
, prcWBounds
);
622 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds
->left
, prcWBounds
->top
,
623 prcWBounds
->right
, prcWBounds
->bottom
);
626 * While the documentation suggests this to be here (or after rendering?)
627 * it does cause an endless recursion in my sample app. -MM 20010804
628 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
631 switch(This
->desc
.picType
) {
637 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
638 NB y-axis gets flipped */
640 hdcBmp
= CreateCompatibleDC(0);
641 SetMapMode(hdcBmp
, MM_ANISOTROPIC
);
642 SetWindowOrgEx(hdcBmp
, 0, 0, NULL
);
643 SetWindowExtEx(hdcBmp
, This
->himetricWidth
, This
->himetricHeight
, NULL
);
644 SetViewportOrgEx(hdcBmp
, 0, This
->origHeight
, NULL
);
645 SetViewportExtEx(hdcBmp
, This
->origWidth
, -This
->origHeight
, NULL
);
648 HDC hdcMask
= CreateCompatibleDC(0);
649 HBITMAP hOldbm
= SelectObject(hdcMask
, This
->hbmMask
);
651 hbmpOld
= SelectObject(hdcBmp
, This
->hbmXor
);
653 SetMapMode(hdcMask
, MM_ANISOTROPIC
);
654 SetWindowOrgEx(hdcMask
, 0, 0, NULL
);
655 SetWindowExtEx(hdcMask
, This
->himetricWidth
, This
->himetricHeight
, NULL
);
656 SetViewportOrgEx(hdcMask
, 0, This
->origHeight
, NULL
);
657 SetViewportExtEx(hdcMask
, This
->origWidth
, -This
->origHeight
, NULL
);
659 SetBkColor(hdc
, RGB(255, 255, 255));
660 SetTextColor(hdc
, RGB(0, 0, 0));
661 StretchBlt(hdc
, x
, y
, cx
, cy
, hdcMask
, xSrc
, ySrc
, cxSrc
, cySrc
, SRCAND
);
662 StretchBlt(hdc
, x
, y
, cx
, cy
, hdcBmp
, xSrc
, ySrc
, cxSrc
, cySrc
, SRCPAINT
);
664 SelectObject(hdcMask
, hOldbm
);
667 hbmpOld
= SelectObject(hdcBmp
, This
->desc
.u
.bmp
.hbitmap
);
668 StretchBlt(hdc
, x
, y
, cx
, cy
, hdcBmp
, xSrc
, ySrc
, cxSrc
, cySrc
, SRCCOPY
);
671 SelectObject(hdcBmp
, hbmpOld
);
676 FIXME("Not quite correct implementation of rendering icons...\n");
677 DrawIcon(hdc
,x
,y
,This
->desc
.u
.icon
.hicon
);
680 case PICTYPE_METAFILE
:
681 PlayMetaFile(hdc
, This
->desc
.u
.wmf
.hmeta
);
684 case PICTYPE_ENHMETAFILE
:
686 RECT rc
= { x
, y
, x
+ cx
, y
+ cy
};
687 PlayEnhMetaFile(hdc
, This
->desc
.u
.emf
.hemf
, &rc
);
692 FIXME("type %d not implemented\n", This
->desc
.picType
);
698 /************************************************************************
699 * OLEPictureImpl_set_hPal
701 static HRESULT WINAPI
OLEPictureImpl_set_hPal(IPicture
*iface
,
704 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
705 FIXME("(%p)->(%08x): stub\n", This
, hpal
);
706 OLEPicture_SendNotify(This
,DISPID_PICT_HPAL
);
710 /************************************************************************
711 * OLEPictureImpl_get_CurDC
713 static HRESULT WINAPI
OLEPictureImpl_get_CurDC(IPicture
*iface
,
716 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
717 TRACE("(%p), returning %p\n", This
, This
->hDCCur
);
718 if (phdc
) *phdc
= This
->hDCCur
;
722 /************************************************************************
723 * OLEPictureImpl_SelectPicture
725 static HRESULT WINAPI
OLEPictureImpl_SelectPicture(IPicture
*iface
,
728 OLE_HANDLE
*phbmpOut
)
730 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
731 TRACE("(%p)->(%p, %p, %p)\n", This
, hdcIn
, phdcOut
, phbmpOut
);
732 if (This
->desc
.picType
== PICTYPE_BITMAP
) {
733 SelectObject(hdcIn
,This
->desc
.u
.bmp
.hbitmap
);
736 *phdcOut
= This
->hDCCur
;
737 This
->hDCCur
= hdcIn
;
739 *phbmpOut
= (OLE_HANDLE
)This
->desc
.u
.bmp
.hbitmap
;
742 FIXME("Don't know how to select picture type %d\n",This
->desc
.picType
);
747 /************************************************************************
748 * OLEPictureImpl_get_KeepOriginalFormat
750 static HRESULT WINAPI
OLEPictureImpl_get_KeepOriginalFormat(IPicture
*iface
,
753 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
754 TRACE("(%p)->(%p)\n", This
, pfKeep
);
757 *pfKeep
= This
->keepOrigFormat
;
761 /************************************************************************
762 * OLEPictureImpl_put_KeepOriginalFormat
764 static HRESULT WINAPI
OLEPictureImpl_put_KeepOriginalFormat(IPicture
*iface
,
767 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
768 TRACE("(%p)->(%d)\n", This
, keep
);
769 This
->keepOrigFormat
= keep
;
770 /* FIXME: what DISPID notification here? */
774 /************************************************************************
775 * OLEPictureImpl_PictureChanged
777 static HRESULT WINAPI
OLEPictureImpl_PictureChanged(IPicture
*iface
)
779 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
780 TRACE("(%p)->()\n", This
);
781 OLEPicture_SendNotify(This
,DISPID_PICT_HANDLE
);
782 This
->bIsDirty
= TRUE
;
786 /************************************************************************
787 * OLEPictureImpl_SaveAsFile
789 static HRESULT WINAPI
OLEPictureImpl_SaveAsFile(IPicture
*iface
,
794 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
795 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This
, pstream
, SaveMemCopy
, pcbSize
);
796 return IStream_Write(pstream
,This
->data
,This
->datalen
,(ULONG
*)pcbSize
);
799 /************************************************************************
800 * OLEPictureImpl_get_Attributes
802 static HRESULT WINAPI
OLEPictureImpl_get_Attributes(IPicture
*iface
,
805 OLEPictureImpl
*This
= (OLEPictureImpl
*)iface
;
806 TRACE("(%p)->(%p).\n", This
, pdwAttr
);
808 switch (This
->desc
.picType
) {
809 case PICTYPE_BITMAP
: if (This
->hbmMask
) *pdwAttr
= PICTURE_TRANSPARENT
; break; /* not 'truly' scalable, see MSDN. */
810 case PICTYPE_ICON
: *pdwAttr
= PICTURE_TRANSPARENT
;break;
811 case PICTYPE_ENHMETAFILE
: /* fall through */
812 case PICTYPE_METAFILE
: *pdwAttr
= PICTURE_TRANSPARENT
|PICTURE_SCALABLE
;break;
813 default:FIXME("Unknown pictype %d\n",This
->desc
.picType
);break;
819 /************************************************************************
820 * IConnectionPointContainer
822 static HRESULT WINAPI
OLEPictureImpl_IConnectionPointContainer_QueryInterface(
823 IConnectionPointContainer
* iface
,
827 OLEPictureImpl
*This
= impl_from_IConnectionPointContainer(iface
);
829 return IPicture_QueryInterface((IPicture
*)This
,riid
,ppvoid
);
832 static ULONG WINAPI
OLEPictureImpl_IConnectionPointContainer_AddRef(
833 IConnectionPointContainer
* iface
)
835 OLEPictureImpl
*This
= impl_from_IConnectionPointContainer(iface
);
837 return IPicture_AddRef((IPicture
*)This
);
840 static ULONG WINAPI
OLEPictureImpl_IConnectionPointContainer_Release(
841 IConnectionPointContainer
* iface
)
843 OLEPictureImpl
*This
= impl_from_IConnectionPointContainer(iface
);
845 return IPicture_Release((IPicture
*)This
);
848 static HRESULT WINAPI
OLEPictureImpl_EnumConnectionPoints(
849 IConnectionPointContainer
* iface
,
850 IEnumConnectionPoints
** ppEnum
)
852 OLEPictureImpl
*This
= impl_from_IConnectionPointContainer(iface
);
854 FIXME("(%p,%p), stub!\n",This
,ppEnum
);
858 static HRESULT WINAPI
OLEPictureImpl_FindConnectionPoint(
859 IConnectionPointContainer
* iface
,
861 IConnectionPoint
**ppCP
)
863 OLEPictureImpl
*This
= impl_from_IConnectionPointContainer(iface
);
864 TRACE("(%p,%s,%p)\n",This
,debugstr_guid(riid
),ppCP
);
868 if (IsEqualGUID(riid
,&IID_IPropertyNotifySink
))
869 return IConnectionPoint_QueryInterface(This
->pCP
,&IID_IConnectionPoint
,(LPVOID
)ppCP
);
870 FIXME("no connection point for %s\n",debugstr_guid(riid
));
871 return CONNECT_E_NOCONNECTION
;
875 /************************************************************************
879 /************************************************************************
880 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
882 * See Windows documentation for more details on IUnknown methods.
884 static HRESULT WINAPI
OLEPictureImpl_IPersistStream_QueryInterface(
885 IPersistStream
* iface
,
889 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
891 return IPicture_QueryInterface((IPicture
*)This
, riid
, ppvoid
);
894 /************************************************************************
895 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
897 * See Windows documentation for more details on IUnknown methods.
899 static ULONG WINAPI
OLEPictureImpl_IPersistStream_AddRef(
900 IPersistStream
* iface
)
902 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
904 return IPicture_AddRef((IPicture
*)This
);
907 /************************************************************************
908 * OLEPictureImpl_IPersistStream_Release (IUnknown)
910 * See Windows documentation for more details on IUnknown methods.
912 static ULONG WINAPI
OLEPictureImpl_IPersistStream_Release(
913 IPersistStream
* iface
)
915 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
917 return IPicture_Release((IPicture
*)This
);
920 /************************************************************************
921 * OLEPictureImpl_IPersistStream_GetClassID
923 static HRESULT WINAPI
OLEPictureImpl_GetClassID(
924 IPersistStream
* iface
,CLSID
* pClassID
)
926 TRACE("(%p)\n", pClassID
);
927 memcpy(pClassID
, &CLSID_StdPicture
, sizeof(*pClassID
));
931 /************************************************************************
932 * OLEPictureImpl_IPersistStream_IsDirty
934 static HRESULT WINAPI
OLEPictureImpl_IsDirty(
935 IPersistStream
* iface
)
937 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
938 FIXME("(%p),stub!\n",This
);
942 #ifdef SONAME_LIBJPEG
944 static void *libjpeg_handle
;
945 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
946 MAKE_FUNCPTR(jpeg_std_error
);
947 MAKE_FUNCPTR(jpeg_CreateDecompress
);
948 MAKE_FUNCPTR(jpeg_read_header
);
949 MAKE_FUNCPTR(jpeg_start_decompress
);
950 MAKE_FUNCPTR(jpeg_read_scanlines
);
951 MAKE_FUNCPTR(jpeg_finish_decompress
);
952 MAKE_FUNCPTR(jpeg_destroy_decompress
);
955 static void *load_libjpeg(void)
957 if((libjpeg_handle
= wine_dlopen(SONAME_LIBJPEG
, RTLD_NOW
, NULL
, 0)) != NULL
) {
959 #define LOAD_FUNCPTR(f) \
960 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
961 libjpeg_handle = NULL; \
965 LOAD_FUNCPTR(jpeg_std_error
);
966 LOAD_FUNCPTR(jpeg_CreateDecompress
);
967 LOAD_FUNCPTR(jpeg_read_header
);
968 LOAD_FUNCPTR(jpeg_start_decompress
);
969 LOAD_FUNCPTR(jpeg_read_scanlines
);
970 LOAD_FUNCPTR(jpeg_finish_decompress
);
971 LOAD_FUNCPTR(jpeg_destroy_decompress
);
974 return libjpeg_handle
;
977 /* for the jpeg decompressor source manager. */
978 static void _jpeg_init_source(j_decompress_ptr cinfo
) { }
980 static boolean
_jpeg_fill_input_buffer(j_decompress_ptr cinfo
) {
981 ERR("(), should not get here.\n");
985 static void _jpeg_skip_input_data(j_decompress_ptr cinfo
,long num_bytes
) {
986 TRACE("Skipping %ld bytes...\n", num_bytes
);
987 cinfo
->src
->next_input_byte
+= num_bytes
;
988 cinfo
->src
->bytes_in_buffer
-= num_bytes
;
991 static boolean
_jpeg_resync_to_restart(j_decompress_ptr cinfo
, int desired
) {
992 ERR("(desired=%d), should not get here.\n",desired
);
995 static void _jpeg_term_source(j_decompress_ptr cinfo
) { }
996 #endif /* SONAME_LIBJPEG */
1000 unsigned int curoff
;
1004 static int _gif_inputfunc(GifFileType
*gif
, GifByteType
*data
, int len
) {
1005 struct gifdata
*gd
= (struct gifdata
*)gif
->UserData
;
1007 if (len
+gd
->curoff
> gd
->len
) {
1008 FIXME("Trying to read %d bytes, but only %d available.\n",len
, gd
->len
-gd
->curoff
);
1009 len
= gd
->len
- gd
->curoff
;
1011 memcpy(data
, gd
->data
+gd
->curoff
, len
);
1017 static HRESULT
OLEPictureImpl_LoadGif(OLEPictureImpl
*This
, BYTE
*xbuf
, ULONG xread
)
1028 int transparent
= -1;
1035 gif
= DGifOpen((void*)&gd
, _gif_inputfunc
);
1036 ret
= DGifSlurp(gif
);
1037 if (ret
== GIF_ERROR
) {
1038 FIXME("Failed reading GIF using libgif.\n");
1041 TRACE("screen height %d, width %d\n", gif
->SWidth
, gif
->SHeight
);
1042 TRACE("color res %d, backgcolor %d\n", gif
->SColorResolution
, gif
->SBackGroundColor
);
1043 TRACE("imgcnt %d\n", gif
->ImageCount
);
1044 if (gif
->ImageCount
<1) {
1045 FIXME("GIF stream does not have images inside?\n");
1048 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1049 gif
->Image
.Width
, gif
->Image
.Height
,
1050 gif
->Image
.Left
, gif
->Image
.Top
,
1051 gif
->Image
.Interlace
1054 padding
= (gif
->SWidth
+3) & ~3;
1055 si
= gif
->SavedImages
+0;
1056 gid
= &(si
->ImageDesc
);
1058 if (!cm
) cm
= gif
->SColorMap
;
1059 bmi
= HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER
)+(cm
->ColorCount
)*sizeof(RGBQUAD
));
1060 bytes
= HeapAlloc(GetProcessHeap(),0,padding
*gif
->SHeight
);
1062 /* look for the transparent color extension */
1063 for (i
= 0; i
< si
->ExtensionBlockCount
; ++i
) {
1064 eb
= si
->ExtensionBlocks
+ i
;
1065 if (eb
->Function
== 0xF9 && eb
->ByteCount
== 4) {
1066 if ((eb
->Bytes
[0] & 1) == 1) {
1067 transparent
= (unsigned char)eb
->Bytes
[3];
1072 for (i
= 0; i
< cm
->ColorCount
; i
++) {
1073 bmi
->bmiColors
[i
].rgbRed
= cm
->Colors
[i
].Red
;
1074 bmi
->bmiColors
[i
].rgbGreen
= cm
->Colors
[i
].Green
;
1075 bmi
->bmiColors
[i
].rgbBlue
= cm
->Colors
[i
].Blue
;
1076 if (i
== transparent
) {
1077 This
->rgbTrans
= RGB(bmi
->bmiColors
[i
].rgbRed
,
1078 bmi
->bmiColors
[i
].rgbGreen
,
1079 bmi
->bmiColors
[i
].rgbBlue
);
1083 /* Map to in picture coordinates */
1084 for (i
= 0, j
= 0; i
< gid
->Height
; i
++) {
1085 if (gif
->Image
.Interlace
) {
1087 bytes
+ (gid
->Top
+ j
) * padding
+ gid
->Left
,
1088 si
->RasterBits
+ i
* gid
->Width
,
1091 /* Lower bits of interlaced counter encode current interlace */
1092 if (j
& 1) j
+= 2; /* Currently filling odd rows */
1093 else if (j
& 2) j
+= 4; /* Currently filling even rows not multiples of 4 */
1094 else j
+= 8; /* Currently filling every 8th row or 4th row in-between */
1096 if (j
>= gid
->Height
&& i
< gid
->Height
&& (j
& 1) == 0) {
1097 /* End of current interlace, go to next interlace */
1098 if (j
& 2) j
= 1; /* Next iteration fills odd rows */
1099 else if (j
& 4) j
= 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1100 else j
= 4; /* Next iteration fills rows in-between rows mod 6 */
1104 bytes
+ (gid
->Top
+ i
) * padding
+ gid
->Left
,
1105 si
->RasterBits
+ i
* gid
->Width
,
1110 bmi
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
1111 bmi
->bmiHeader
.biWidth
= gif
->SWidth
;
1112 bmi
->bmiHeader
.biHeight
= -gif
->SHeight
;
1113 bmi
->bmiHeader
.biPlanes
= 1;
1114 bmi
->bmiHeader
.biBitCount
= 8;
1115 bmi
->bmiHeader
.biCompression
= BI_RGB
;
1116 bmi
->bmiHeader
.biSizeImage
= padding
*gif
->SHeight
;
1117 bmi
->bmiHeader
.biXPelsPerMeter
= 0;
1118 bmi
->bmiHeader
.biYPelsPerMeter
= 0;
1119 bmi
->bmiHeader
.biClrUsed
= cm
->ColorCount
;
1120 bmi
->bmiHeader
.biClrImportant
= 0;
1123 This
->desc
.u
.bmp
.hbitmap
=CreateDIBitmap(
1132 if (transparent
> -1) {
1133 /* Create the Mask */
1134 HDC hdc
= CreateCompatibleDC(0);
1135 HDC hdcMask
= CreateCompatibleDC(0);
1137 HBITMAP hOldbitmapmask
;
1139 unsigned int monopadding
= (((unsigned)(gif
->SWidth
+ 31)) >> 5) << 2;
1142 This
->hbmXor
= CreateDIBitmap(
1151 bmi
->bmiColors
[0].rgbRed
= 0;
1152 bmi
->bmiColors
[0].rgbGreen
= 0;
1153 bmi
->bmiColors
[0].rgbBlue
= 0;
1154 bmi
->bmiColors
[1].rgbRed
= 255;
1155 bmi
->bmiColors
[1].rgbGreen
= 255;
1156 bmi
->bmiColors
[1].rgbBlue
= 255;
1158 bmi
->bmiHeader
.biBitCount
= 1;
1159 bmi
->bmiHeader
.biSizeImage
= monopadding
*gif
->SHeight
;
1160 bmi
->bmiHeader
.biClrUsed
= 2;
1162 for (i
= 0; i
< gif
->SHeight
; i
++) {
1163 unsigned char * colorPointer
= bytes
+ padding
* i
;
1164 unsigned char * monoPointer
= bytes
+ monopadding
* i
;
1165 for (j
= 0; j
< gif
->SWidth
; j
++) {
1166 unsigned char pixel
= colorPointer
[j
];
1167 if ((j
& 7) == 0) monoPointer
[j
>> 3] = 0;
1168 if (pixel
== (transparent
& 0x000000FFU
)) monoPointer
[j
>> 3] |= 1 << (7 - (j
& 7));
1172 hTempMask
= CreateDIBitmap(
1182 bmi
->bmiHeader
.biHeight
= -bmi
->bmiHeader
.biHeight
;
1183 This
->hbmMask
= CreateBitmap(bmi
->bmiHeader
.biWidth
, bmi
->bmiHeader
.biHeight
, 1, 1, NULL
);
1184 hOldbitmap
= SelectObject(hdc
, hTempMask
);
1185 hOldbitmapmask
= SelectObject(hdcMask
, This
->hbmMask
);
1187 SetBkColor(hdc
, RGB(255, 255, 255));
1188 BitBlt(hdcMask
, 0, 0, bmi
->bmiHeader
.biWidth
, bmi
->bmiHeader
.biHeight
, hdc
, 0, 0, SRCCOPY
);
1190 /* We no longer need the original bitmap, so we apply the first
1191 transformation with the mask to speed up the rendering */
1192 SelectObject(hdc
, This
->hbmXor
);
1193 SetBkColor(hdc
, RGB(0,0,0));
1194 SetTextColor(hdc
, RGB(255,255,255));
1195 BitBlt(hdc
, 0, 0, bmi
->bmiHeader
.biWidth
, bmi
->bmiHeader
.biHeight
,
1196 hdcMask
, 0, 0, SRCAND
);
1198 SelectObject(hdc
, hOldbitmap
);
1199 SelectObject(hdcMask
, hOldbitmapmask
);
1202 DeleteObject(hTempMask
);
1206 This
->desc
.picType
= PICTYPE_BITMAP
;
1207 OLEPictureImpl_SetBitmap(This
);
1209 HeapFree(GetProcessHeap(),0,bytes
);
1213 static HRESULT
OLEPictureImpl_LoadJpeg(OLEPictureImpl
*This
, BYTE
*xbuf
, ULONG xread
)
1215 #ifdef SONAME_LIBJPEG
1216 struct jpeg_decompress_struct jd
;
1217 struct jpeg_error_mgr jerr
;
1220 JSAMPROW samprow
,oldsamprow
;
1221 BITMAPINFOHEADER bmi
;
1224 struct jpeg_source_mgr xjsm
;
1228 if(!libjpeg_handle
) {
1229 if(!load_libjpeg()) {
1230 FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG
);
1235 /* This is basically so we can use in-memory data for jpeg decompression.
1236 * We need to have all the functions.
1238 xjsm
.next_input_byte
= xbuf
;
1239 xjsm
.bytes_in_buffer
= xread
;
1240 xjsm
.init_source
= _jpeg_init_source
;
1241 xjsm
.fill_input_buffer
= _jpeg_fill_input_buffer
;
1242 xjsm
.skip_input_data
= _jpeg_skip_input_data
;
1243 xjsm
.resync_to_restart
= _jpeg_resync_to_restart
;
1244 xjsm
.term_source
= _jpeg_term_source
;
1246 jd
.err
= pjpeg_std_error(&jerr
);
1247 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1248 * jpeg_create_decompress(&jd); */
1249 pjpeg_CreateDecompress(&jd
, JPEG_LIB_VERSION
, (size_t) sizeof(struct jpeg_decompress_struct
));
1251 ret
=pjpeg_read_header(&jd
,TRUE
);
1252 jd
.out_color_space
= JCS_RGB
;
1253 pjpeg_start_decompress(&jd
);
1254 if (ret
!= JPEG_HEADER_OK
) {
1255 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret
);
1256 HeapFree(GetProcessHeap(),0,xbuf
);
1260 bits
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,
1261 (jd
.output_height
+1) * ((jd
.output_width
*jd
.output_components
+ 3) & ~3) );
1262 samprow
=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,jd
.output_width
*jd
.output_components
);
1265 oldsamprow
= samprow
;
1266 while ( jd
.output_scanline
<jd
.output_height
) {
1267 x
= pjpeg_read_scanlines(&jd
,&samprow
,1);
1269 FIXME("failed to read current scanline?\n");
1272 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1273 for(i
=0;i
<jd
.output_width
;i
++,samprow
+=jd
.output_components
) {
1274 *(bits
++) = *(samprow
+2);
1275 *(bits
++) = *(samprow
+1);
1276 *(bits
++) = *(samprow
);
1278 bits
= (LPBYTE
)(((UINT_PTR
)bits
+ 3) & ~3);
1279 samprow
= oldsamprow
;
1283 bmi
.biSize
= sizeof(bmi
);
1284 bmi
.biWidth
= jd
.output_width
;
1285 bmi
.biHeight
= -jd
.output_height
;
1287 bmi
.biBitCount
= jd
.output_components
<<3;
1288 bmi
.biCompression
= BI_RGB
;
1289 bmi
.biSizeImage
= jd
.output_height
*jd
.output_width
*jd
.output_components
;
1290 bmi
.biXPelsPerMeter
= 0;
1291 bmi
.biYPelsPerMeter
= 0;
1293 bmi
.biClrImportant
= 0;
1295 HeapFree(GetProcessHeap(),0,samprow
);
1296 pjpeg_finish_decompress(&jd
);
1297 pjpeg_destroy_decompress(&jd
);
1299 This
->desc
.u
.bmp
.hbitmap
=CreateDIBitmap(
1308 This
->desc
.picType
= PICTYPE_BITMAP
;
1309 OLEPictureImpl_SetBitmap(This
);
1310 HeapFree(GetProcessHeap(),0,bits
);
1313 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1318 static HRESULT
OLEPictureImpl_LoadDIB(OLEPictureImpl
*This
, BYTE
*xbuf
, ULONG xread
)
1320 BITMAPFILEHEADER
*bfh
= (BITMAPFILEHEADER
*)xbuf
;
1321 BITMAPINFO
*bi
= (BITMAPINFO
*)(bfh
+1);
1324 /* Does not matter whether this is a coreheader or not, we only use
1325 * components which are in both
1328 This
->desc
.u
.bmp
.hbitmap
= CreateDIBitmap(
1332 xbuf
+bfh
->bfOffBits
,
1337 This
->desc
.picType
= PICTYPE_BITMAP
;
1338 OLEPictureImpl_SetBitmap(This
);
1342 /*****************************************************
1343 * start of PNG-specific code
1344 * currently only supports colortype PNG_COLOR_TYPE_RGB
1346 #ifdef SONAME_LIBPNG
1353 static void png_stream_read_data(png_structp png_ptr
, png_bytep data
,
1356 png_io
* io_ptr
= png_ptr
->io_ptr
;
1358 if(length
+ io_ptr
->position
> io_ptr
->size
){
1359 length
= io_ptr
->size
- io_ptr
->position
;
1362 memcpy(data
, io_ptr
->buff
+ io_ptr
->position
, length
);
1364 io_ptr
->position
+= length
;
1367 static void *libpng_handle
;
1368 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1369 MAKE_FUNCPTR(png_create_read_struct
);
1370 MAKE_FUNCPTR(png_create_info_struct
);
1371 MAKE_FUNCPTR(png_set_read_fn
);
1372 MAKE_FUNCPTR(png_read_info
);
1373 MAKE_FUNCPTR(png_read_image
);
1374 MAKE_FUNCPTR(png_get_rowbytes
);
1375 MAKE_FUNCPTR(png_set_bgr
);
1376 MAKE_FUNCPTR(png_destroy_read_struct
);
1377 MAKE_FUNCPTR(png_set_palette_to_rgb
);
1378 MAKE_FUNCPTR(png_read_update_info
);
1381 static void *load_libpng(void)
1383 if((libpng_handle
= wine_dlopen(SONAME_LIBPNG
, RTLD_NOW
, NULL
, 0)) != NULL
) {
1385 #define LOAD_FUNCPTR(f) \
1386 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1387 libpng_handle = NULL; \
1390 LOAD_FUNCPTR(png_create_read_struct
);
1391 LOAD_FUNCPTR(png_create_info_struct
);
1392 LOAD_FUNCPTR(png_set_read_fn
);
1393 LOAD_FUNCPTR(png_read_info
);
1394 LOAD_FUNCPTR(png_read_image
);
1395 LOAD_FUNCPTR(png_get_rowbytes
);
1396 LOAD_FUNCPTR(png_set_bgr
);
1397 LOAD_FUNCPTR(png_destroy_read_struct
);
1398 LOAD_FUNCPTR(png_set_palette_to_rgb
);
1399 LOAD_FUNCPTR(png_read_update_info
);
1403 return libpng_handle
;
1405 #endif /* SONAME_LIBPNG */
1407 static HRESULT
OLEPictureImpl_LoadPNG(OLEPictureImpl
*This
, BYTE
*xbuf
, ULONG xread
)
1409 #ifdef SONAME_LIBPNG
1411 png_structp png_ptr
= NULL
;
1412 png_infop info_ptr
= NULL
;
1413 INT row
, rowsize
, height
, width
;
1414 png_bytep
* row_pointers
= NULL
;
1415 png_bytep pngdata
= NULL
;
1416 BITMAPINFOHEADER bmi
;
1419 BOOL set_bgr
= FALSE
;
1421 if(!libpng_handle
) {
1422 if(!load_libpng()) {
1423 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG
);
1432 png_ptr
= ppng_create_read_struct(PNG_LIBPNG_VER_STRING
,
1435 if(setjmp(png_jmpbuf(png_ptr
))){
1436 TRACE("Error in libpng\n");
1441 info_ptr
= ppng_create_info_struct(png_ptr
);
1442 ppng_set_read_fn(png_ptr
, &io
, png_stream_read_data
);
1443 ppng_read_info(png_ptr
, info_ptr
);
1445 if(!(png_ptr
->color_type
== PNG_COLOR_TYPE_RGB
||
1446 png_ptr
->color_type
== PNG_COLOR_TYPE_PALETTE
||
1447 png_ptr
->color_type
== PNG_COLOR_TYPE_RGB_ALPHA
)){
1448 FIXME("Unsupported .PNG type: %d\n", png_ptr
->color_type
);
1453 if (png_ptr
->color_type
== PNG_COLOR_TYPE_PALETTE
){
1454 ppng_set_palette_to_rgb(png_ptr
);
1458 if (png_ptr
->color_type
== PNG_COLOR_TYPE_RGB
||
1459 png_ptr
->color_type
== PNG_COLOR_TYPE_RGB_ALPHA
||
1461 ppng_set_bgr(png_ptr
);
1464 ppng_read_update_info(png_ptr
, info_ptr
);
1466 rowsize
= ppng_get_rowbytes(png_ptr
, info_ptr
);
1467 /* align rowsize to 4-byte boundary */
1468 rowsize
= (rowsize
+ 3) & ~3;
1469 height
= info_ptr
->height
;
1470 width
= info_ptr
->width
;
1472 pngdata
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, height
* rowsize
);
1473 row_pointers
= HeapAlloc(GetProcessHeap(), 0, height
* (sizeof(VOID
*)));
1475 if(!pngdata
|| !row_pointers
){
1480 for (row
= 0; row
< height
; row
++){
1481 row_pointers
[row
] = pngdata
+ row
* rowsize
;
1484 ppng_read_image(png_ptr
, row_pointers
);
1486 bmi
.biSize
= sizeof(bmi
);
1487 bmi
.biWidth
= width
;
1488 bmi
.biHeight
= -height
;
1490 bmi
.biBitCount
= info_ptr
->channels
* 8;
1491 bmi
.biCompression
= BI_RGB
;
1492 bmi
.biSizeImage
= height
* rowsize
;
1493 bmi
.biXPelsPerMeter
= 0;
1494 bmi
.biYPelsPerMeter
= 0;
1496 bmi
.biClrImportant
= 0;
1499 This
->desc
.u
.bmp
.hbitmap
= CreateDIBitmap(
1507 ReleaseDC(0, hdcref
);
1508 This
->desc
.picType
= PICTYPE_BITMAP
;
1509 OLEPictureImpl_SetBitmap(This
);
1514 ppng_destroy_read_struct(&png_ptr
,
1515 (info_ptr
? &info_ptr
: (png_infopp
) NULL
),
1517 HeapFree(GetProcessHeap(), 0, row_pointers
);
1518 HeapFree(GetProcessHeap(), 0, pngdata
);
1520 #else /* SONAME_LIBPNG */
1521 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1526 /*****************************************************
1527 * start of Icon-specific code
1530 static HRESULT
OLEPictureImpl_LoadIcon(OLEPictureImpl
*This
, BYTE
*xbuf
, ULONG xread
)
1533 CURSORICONFILEDIR
*cifd
= (CURSORICONFILEDIR
*)xbuf
;
1538 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1539 FIXME("icon.idType=%d\n",cifd->idType);
1540 FIXME("icon.idCount=%d\n",cifd->idCount);
1542 for (i=0;i<cifd->idCount;i++) {
1543 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1544 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1545 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1546 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1547 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1548 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1549 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1550 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1554 /* If we have more than one icon, try to find the best.
1555 * this currently means '32 pixel wide'.
1557 if (cifd
->idCount
!=1) {
1558 for (i
=0;i
<cifd
->idCount
;i
++) {
1559 if (cifd
->idEntries
[i
].bWidth
== 32)
1562 if (i
==cifd
->idCount
) i
=0;
1565 hicon
= CreateIconFromResourceEx(
1566 xbuf
+cifd
->idEntries
[i
].dwDIBOffset
,
1567 cifd
->idEntries
[i
].dwDIBSize
,
1570 cifd
->idEntries
[i
].bWidth
,
1571 cifd
->idEntries
[i
].bHeight
,
1575 FIXME("CreateIcon failed.\n");
1578 This
->desc
.picType
= PICTYPE_ICON
;
1579 This
->desc
.u
.icon
.hicon
= hicon
;
1580 This
->origWidth
= cifd
->idEntries
[i
].bWidth
;
1581 This
->origHeight
= cifd
->idEntries
[i
].bHeight
;
1582 hdcRef
= CreateCompatibleDC(0);
1583 This
->himetricWidth
=(cifd
->idEntries
[i
].bWidth
*2540)/GetDeviceCaps(hdcRef
, LOGPIXELSX
);
1584 This
->himetricHeight
=(cifd
->idEntries
[i
].bHeight
*2540)/GetDeviceCaps(hdcRef
, LOGPIXELSY
);
1590 static HRESULT
OLEPictureImpl_LoadMetafile(OLEPictureImpl
*This
,
1591 const BYTE
*data
, ULONG size
)
1596 /* SetMetaFileBitsEx performs data check on its own */
1597 hmf
= SetMetaFileBitsEx(size
, data
);
1600 This
->desc
.picType
= PICTYPE_METAFILE
;
1601 This
->desc
.u
.wmf
.hmeta
= hmf
;
1602 This
->desc
.u
.wmf
.xExt
= 0;
1603 This
->desc
.u
.wmf
.yExt
= 0;
1605 This
->origWidth
= 0;
1606 This
->origHeight
= 0;
1607 This
->himetricWidth
= 0;
1608 This
->himetricHeight
= 0;
1613 hemf
= SetEnhMetaFileBits(size
, data
);
1614 if (!hemf
) return E_FAIL
;
1616 This
->desc
.picType
= PICTYPE_ENHMETAFILE
;
1617 This
->desc
.u
.emf
.hemf
= hemf
;
1619 This
->origWidth
= 0;
1620 This
->origHeight
= 0;
1621 This
->himetricWidth
= 0;
1622 This
->himetricHeight
= 0;
1627 /************************************************************************
1628 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1630 * Loads the binary data from the IStream. Starts at current position.
1631 * There appears to be an 2 DWORD header:
1635 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1637 static HRESULT WINAPI
OLEPictureImpl_Load(IPersistStream
* iface
,IStream
*pStm
) {
1638 HRESULT hr
= E_FAIL
;
1639 BOOL headerisdata
= FALSE
;
1640 BOOL statfailed
= FALSE
;
1641 ULONG xread
, toread
;
1647 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
1649 TRACE("(%p,%p)\n",This
,pStm
);
1651 /****************************************************************************************
1652 * Part 1: Load the data
1654 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1655 * out whether we do.
1657 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1658 * compound file. This may explain most, if not all, of the cases of "no
1659 * header", and the header validation should take this into account.
1660 * At least in Visual Basic 6, resource streams, valid headers are
1661 * header[0] == "lt\0\0",
1662 * header[1] == length_of_stream.
1664 * Also handle streams where we do not have a working "Stat" method by
1665 * reading all data until the end of the stream.
1667 hr
=IStream_Stat(pStm
,&statstg
,STATFLAG_NONAME
);
1669 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr
);
1671 /* we will read at least 8 byte ... just right below */
1672 statstg
.cbSize
.QuadPart
= 8;
1677 headerisdata
= FALSE
;
1679 hr
=IStream_Read(pStm
,header
,8,&xread
);
1680 if (hr
|| xread
!=8) {
1681 FIXME("Failure while reading picture header (hr is %x, nread is %d).\n",hr
,xread
);
1684 headerread
+= xread
;
1687 if (!memcmp(&(header
[0]),"lt\0\0", 4) && (statfailed
|| (header
[1] + headerread
<= statstg
.cbSize
.QuadPart
))) {
1688 if (toread
!= 0 && toread
!= header
[1])
1689 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1692 if (toread
== 0) break;
1694 if (!memcmp(&(header
[0]), "GIF8", 4) || /* GIF header */
1695 !memcmp(&(header
[0]), "BM", 2) || /* BMP header */
1696 !memcmp(&(header
[0]), "\xff\xd8", 2) || /* JPEG header */
1697 (header
[0] == EMR_HEADER
) || /* EMF header */
1698 (header
[1] > statstg
.cbSize
.QuadPart
)|| /* invalid size */
1700 ) {/* Found start of bitmap data */
1701 headerisdata
= TRUE
;
1703 toread
= statstg
.cbSize
.QuadPart
-8;
1707 FIXME("Unknown stream header magic: %08x\n", header
[0]);
1711 } while (!headerisdata
);
1713 if (statfailed
) { /* we don't know the size ... read all we get */
1715 int origsize
= sizeinc
;
1718 TRACE("Reading all data from stream.\n");
1719 xbuf
= HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY
, origsize
);
1721 memcpy (xbuf
, &header
, 8);
1723 while (xread
< origsize
) {
1724 hr
= IStream_Read(pStm
,xbuf
+xread
,origsize
-xread
,&nread
);
1729 if (!nread
|| hr
) /* done, or error */
1731 if (xread
== origsize
) {
1732 origsize
+= sizeinc
;
1733 sizeinc
= 2*sizeinc
; /* exponential increase */
1734 xbuf
= HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY
, xbuf
, origsize
);
1738 TRACE("hr in no-stat loader case is %08x\n", hr
);
1739 TRACE("loaded %d bytes.\n", xread
);
1740 This
->datalen
= xread
;
1743 This
->datalen
= toread
+(headerisdata
?8:0);
1744 xbuf
= This
->data
= HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->datalen
);
1747 memcpy (xbuf
, &header
, 8);
1749 while (xread
< This
->datalen
) {
1751 hr
= IStream_Read(pStm
,xbuf
+xread
,This
->datalen
-xread
,&nread
);
1756 if (xread
!= This
->datalen
)
1757 FIXME("Could only read %d of %d bytes out of stream?\n",xread
,This
->datalen
);
1759 if (This
->datalen
== 0) { /* Marks the "NONE" picture */
1760 This
->desc
.picType
= PICTYPE_NONE
;
1765 /****************************************************************************************
1766 * Part 2: Process the loaded data
1769 magic
= xbuf
[0] + (xbuf
[1]<<8);
1770 This
->loadtime_format
= magic
;
1773 case 0x4947: /* GIF */
1774 hr
= OLEPictureImpl_LoadGif(This
, xbuf
, xread
);
1776 case 0xd8ff: /* JPEG */
1777 hr
= OLEPictureImpl_LoadJpeg(This
, xbuf
, xread
);
1779 case 0x4d42: /* Bitmap */
1780 hr
= OLEPictureImpl_LoadDIB(This
, xbuf
, xread
);
1782 case 0x5089: /* PNG */
1783 hr
= OLEPictureImpl_LoadPNG(This
, xbuf
, xread
);
1785 case 0x0000: { /* ICON , first word is dwReserved */
1786 hr
= OLEPictureImpl_LoadIcon(This
, xbuf
, xread
);
1793 /* let's see if it's a metafile */
1794 hr
= OLEPictureImpl_LoadMetafile(This
, xbuf
, xread
);
1795 if (hr
== S_OK
) break;
1797 FIXME("Unknown magic %04x, %d read bytes:\n",magic
,xread
);
1799 for (i
=0;i
<xread
+8;i
++) {
1800 if (i
<8) MESSAGE("%02x ",((unsigned char*)&header
)[i
]);
1801 else MESSAGE("%02x ",xbuf
[i
-8]);
1802 if (i
% 10 == 9) MESSAGE("\n");
1808 This
->bIsDirty
= FALSE
;
1810 /* FIXME: this notify is not really documented */
1812 OLEPicture_SendNotify(This
,DISPID_PICT_TYPE
);
1816 static int serializeBMP(HBITMAP hBitmap
, void ** ppBuffer
, unsigned int * pLength
)
1820 BITMAPINFO
* pInfoBitmap
;
1821 int iNumPaletteEntries
;
1822 unsigned char * pPixelData
;
1823 BITMAPFILEHEADER
* pFileHeader
;
1824 BITMAPINFO
* pInfoHeader
;
1826 pInfoBitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
1827 sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1829 /* Find out bitmap size and padded length */
1831 pInfoBitmap
->bmiHeader
.biSize
= sizeof(pInfoBitmap
->bmiHeader
);
1832 GetDIBits(hDC
, hBitmap
, 0, 0, NULL
, pInfoBitmap
, DIB_RGB_COLORS
);
1834 /* Fetch bitmap palette & pixel data */
1836 pPixelData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, pInfoBitmap
->bmiHeader
.biSizeImage
);
1837 GetDIBits(hDC
, hBitmap
, 0, pInfoBitmap
->bmiHeader
.biHeight
, pPixelData
, pInfoBitmap
, DIB_RGB_COLORS
);
1839 /* Calculate the total length required for the BMP data */
1840 if (pInfoBitmap
->bmiHeader
.biClrUsed
!= 0) {
1841 iNumPaletteEntries
= pInfoBitmap
->bmiHeader
.biClrUsed
;
1842 if (iNumPaletteEntries
> 256) iNumPaletteEntries
= 256;
1844 if (pInfoBitmap
->bmiHeader
.biBitCount
<= 8)
1845 iNumPaletteEntries
= 1 << pInfoBitmap
->bmiHeader
.biBitCount
;
1847 iNumPaletteEntries
= 0;
1850 sizeof(BITMAPFILEHEADER
) +
1851 sizeof(BITMAPINFOHEADER
) +
1852 iNumPaletteEntries
* sizeof(RGBQUAD
) +
1853 pInfoBitmap
->bmiHeader
.biSizeImage
;
1854 *ppBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *pLength
);
1856 /* Fill the BITMAPFILEHEADER */
1857 pFileHeader
= (BITMAPFILEHEADER
*)(*ppBuffer
);
1858 pFileHeader
->bfType
= 0x4d42;
1859 pFileHeader
->bfSize
= *pLength
;
1860 pFileHeader
->bfOffBits
=
1861 sizeof(BITMAPFILEHEADER
) +
1862 sizeof(BITMAPINFOHEADER
) +
1863 iNumPaletteEntries
* sizeof(RGBQUAD
);
1865 /* Fill the BITMAPINFOHEADER and the palette data */
1866 pInfoHeader
= (BITMAPINFO
*)((unsigned char *)(*ppBuffer
) + sizeof(BITMAPFILEHEADER
));
1867 memcpy(pInfoHeader
, pInfoBitmap
, sizeof(BITMAPINFOHEADER
) + iNumPaletteEntries
* sizeof(RGBQUAD
));
1869 (unsigned char *)(*ppBuffer
) +
1870 sizeof(BITMAPFILEHEADER
) +
1871 sizeof(BITMAPINFOHEADER
) +
1872 iNumPaletteEntries
* sizeof(RGBQUAD
),
1873 pPixelData
, pInfoBitmap
->bmiHeader
.biSizeImage
);
1876 HeapFree(GetProcessHeap(), 0, pPixelData
);
1877 HeapFree(GetProcessHeap(), 0, pInfoBitmap
);
1881 static int serializeIcon(HICON hIcon
, void ** ppBuffer
, unsigned int * pLength
)
1886 *ppBuffer
= NULL
; *pLength
= 0;
1887 if (GetIconInfo(hIcon
, &infoIcon
)) {
1889 BITMAPINFO
* pInfoBitmap
;
1890 unsigned char * pIconData
= NULL
;
1891 unsigned int iDataSize
= 0;
1893 pInfoBitmap
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1895 /* Find out icon size */
1897 pInfoBitmap
->bmiHeader
.biSize
= sizeof(pInfoBitmap
->bmiHeader
);
1898 GetDIBits(hDC
, infoIcon
.hbmColor
, 0, 0, NULL
, pInfoBitmap
, DIB_RGB_COLORS
);
1900 /* Auxiliary pointers */
1901 CURSORICONFILEDIR
* pIconDir
;
1902 CURSORICONFILEDIRENTRY
* pIconEntry
;
1903 BITMAPINFOHEADER
* pIconBitmapHeader
;
1904 unsigned int iOffsetPalette
;
1905 unsigned int iOffsetColorData
;
1906 unsigned int iOffsetMaskData
;
1908 unsigned int iLengthScanLineColor
;
1909 unsigned int iLengthScanLineMask
;
1910 unsigned int iNumEntriesPalette
;
1912 iLengthScanLineMask
= ((pInfoBitmap
->bmiHeader
.biWidth
+ 31) >> 5) << 2;
1913 iLengthScanLineColor
= ((pInfoBitmap
->bmiHeader
.biWidth
* pInfoBitmap
->bmiHeader
.biBitCount
+ 31) >> 5) << 2;
1915 FIXME("DEBUG: bitmap size is %d x %d\n",
1916 pInfoBitmap->bmiHeader.biWidth,
1917 pInfoBitmap->bmiHeader.biHeight);
1918 FIXME("DEBUG: bitmap bpp is %d\n",
1919 pInfoBitmap->bmiHeader.biBitCount);
1920 FIXME("DEBUG: bitmap nplanes is %d\n",
1921 pInfoBitmap->bmiHeader.biPlanes);
1922 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1923 pInfoBitmap->bmiHeader.biSizeImage);
1925 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1926 iDataSize
+= 3 * sizeof(WORD
) + sizeof(CURSORICONFILEDIRENTRY
) + sizeof(BITMAPINFOHEADER
);
1927 pIconData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, iDataSize
);
1929 /* Fill out the CURSORICONFILEDIR */
1930 pIconDir
= (CURSORICONFILEDIR
*)pIconData
;
1931 pIconDir
->idType
= 1;
1932 pIconDir
->idCount
= 1;
1934 /* Fill out the CURSORICONFILEDIRENTRY */
1935 pIconEntry
= (CURSORICONFILEDIRENTRY
*)(pIconData
+ 3 * sizeof(WORD
));
1936 pIconEntry
->bWidth
= (unsigned char)pInfoBitmap
->bmiHeader
.biWidth
;
1937 pIconEntry
->bHeight
= (unsigned char)pInfoBitmap
->bmiHeader
.biHeight
;
1938 pIconEntry
->bColorCount
=
1939 (pInfoBitmap
->bmiHeader
.biBitCount
< 8)
1940 ? 1 << pInfoBitmap
->bmiHeader
.biBitCount
1942 pIconEntry
->xHotspot
= pInfoBitmap
->bmiHeader
.biPlanes
;
1943 pIconEntry
->yHotspot
= pInfoBitmap
->bmiHeader
.biBitCount
;
1944 pIconEntry
->dwDIBSize
= 0;
1945 pIconEntry
->dwDIBOffset
= 3 * sizeof(WORD
) + sizeof(CURSORICONFILEDIRENTRY
);
1947 /* Fill out the BITMAPINFOHEADER */
1948 pIconBitmapHeader
= (BITMAPINFOHEADER
*)(pIconData
+ 3 * sizeof(WORD
) + sizeof(CURSORICONFILEDIRENTRY
));
1949 memcpy(pIconBitmapHeader
, &pInfoBitmap
->bmiHeader
, sizeof(BITMAPINFOHEADER
));
1951 /* Find out whether a palette exists for the bitmap */
1952 if ( (pInfoBitmap
->bmiHeader
.biBitCount
== 16 && pInfoBitmap
->bmiHeader
.biCompression
== BI_RGB
)
1953 || (pInfoBitmap
->bmiHeader
.biBitCount
== 24)
1954 || (pInfoBitmap
->bmiHeader
.biBitCount
== 32 && pInfoBitmap
->bmiHeader
.biCompression
== BI_RGB
)) {
1955 iNumEntriesPalette
= pInfoBitmap
->bmiHeader
.biClrUsed
;
1956 if (iNumEntriesPalette
> 256) iNumEntriesPalette
= 256;
1957 } else if ((pInfoBitmap
->bmiHeader
.biBitCount
== 16 || pInfoBitmap
->bmiHeader
.biBitCount
== 32)
1958 && pInfoBitmap
->bmiHeader
.biCompression
== BI_BITFIELDS
) {
1959 iNumEntriesPalette
= 3;
1960 } else if (pInfoBitmap
->bmiHeader
.biBitCount
<= 8) {
1961 iNumEntriesPalette
= 1 << pInfoBitmap
->bmiHeader
.biBitCount
;
1963 iNumEntriesPalette
= 0;
1966 /* Add bitmap size and header size to icon data size. */
1967 iOffsetPalette
= iDataSize
;
1968 iDataSize
+= iNumEntriesPalette
* sizeof(DWORD
);
1969 iOffsetColorData
= iDataSize
;
1970 iDataSize
+= pIconBitmapHeader
->biSizeImage
;
1971 iOffsetMaskData
= iDataSize
;
1972 iDataSize
+= pIconBitmapHeader
->biHeight
* iLengthScanLineMask
;
1973 pIconBitmapHeader
->biSizeImage
+= pIconBitmapHeader
->biHeight
* iLengthScanLineMask
;
1974 pIconBitmapHeader
->biHeight
*= 2;
1975 pIconData
= HeapReAlloc(GetProcessHeap(), 0, pIconData
, iDataSize
);
1976 pIconEntry
= (CURSORICONFILEDIRENTRY
*)(pIconData
+ 3 * sizeof(WORD
));
1977 pIconBitmapHeader
= (BITMAPINFOHEADER
*)(pIconData
+ 3 * sizeof(WORD
) + sizeof(CURSORICONFILEDIRENTRY
));
1978 pIconEntry
->dwDIBSize
= iDataSize
- (3 * sizeof(WORD
) + sizeof(CURSORICONFILEDIRENTRY
));
1980 /* Get the actual bitmap data from the icon bitmap */
1981 GetDIBits(hDC
, infoIcon
.hbmColor
, 0, pInfoBitmap
->bmiHeader
.biHeight
,
1982 pIconData
+ iOffsetColorData
, pInfoBitmap
, DIB_RGB_COLORS
);
1983 if (iNumEntriesPalette
> 0) {
1984 memcpy(pIconData
+ iOffsetPalette
, pInfoBitmap
->bmiColors
,
1985 iNumEntriesPalette
* sizeof(RGBQUAD
));
1988 /* Reset all values so that GetDIBits call succeeds */
1989 memset(pIconData
+ iOffsetMaskData
, 0, iDataSize
- iOffsetMaskData
);
1990 memset(pInfoBitmap
, 0, sizeof(BITMAPINFOHEADER
) + 256 * sizeof(RGBQUAD
));
1991 pInfoBitmap
->bmiHeader
.biSize
= sizeof(pInfoBitmap
->bmiHeader
);
1993 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1994 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1995 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1997 printf("ERROR: unable to get bitmap mask (error %u)\n",
2002 GetDIBits(hDC
, infoIcon
.hbmMask
, 0, 0, NULL
, pInfoBitmap
, DIB_RGB_COLORS
);
2003 GetDIBits(hDC
, infoIcon
.hbmMask
, 0, pIconEntry
->bHeight
, pIconData
+ iOffsetMaskData
, pInfoBitmap
, DIB_RGB_COLORS
);
2005 /* Write out everything produced so far to the stream */
2006 *ppBuffer
= pIconData
; *pLength
= iDataSize
;
2010 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2015 Remarks (from MSDN entry on GetIconInfo):
2017 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2018 members of ICONINFO. The calling application must manage
2019 these bitmaps and delete them when they are no longer
2022 if (hDC
) ReleaseDC(0, hDC
);
2023 DeleteObject(infoIcon
.hbmMask
);
2024 if (infoIcon
.hbmColor
) DeleteObject(infoIcon
.hbmColor
);
2025 HeapFree(GetProcessHeap(), 0, pInfoBitmap
);
2027 printf("ERROR: Unable to get icon information (error %u)\n",
2033 static HRESULT WINAPI
OLEPictureImpl_Save(
2034 IPersistStream
* iface
,IStream
*pStm
,BOOL fClearDirty
)
2036 HRESULT hResult
= E_NOTIMPL
;
2038 unsigned int iDataSize
;
2040 int iSerializeResult
= 0;
2041 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
2043 TRACE("%p %p %d\n", This
, pStm
, fClearDirty
);
2045 switch (This
->desc
.picType
) {
2047 if (This
->bIsDirty
|| !This
->data
) {
2048 if (!serializeIcon(This
->desc
.u
.icon
.hicon
, &pIconData
, &iDataSize
)) {
2049 ERR("(%p,%p,%d), serializeIcon() failed\n", This
, pStm
, fClearDirty
);
2053 HeapFree(GetProcessHeap(), 0, This
->data
);
2054 This
->data
= pIconData
;
2055 This
->datalen
= iDataSize
;
2057 if (This
->loadtime_magic
!= 0xdeadbeef) {
2060 header
[0] = This
->loadtime_magic
;
2061 header
[1] = This
->datalen
;
2062 IStream_Write(pStm
, header
, 2 * sizeof(DWORD
), &dummy
);
2064 IStream_Write(pStm
, This
->data
, This
->datalen
, &dummy
);
2068 case PICTYPE_BITMAP
:
2069 if (This
->bIsDirty
) {
2070 switch (This
->keepOrigFormat
? This
->loadtime_format
: 0x4d42) {
2072 iSerializeResult
= serializeBMP(This
->desc
.u
.bmp
.hbitmap
, &pIconData
, &iDataSize
);
2075 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This
,pStm
,fClearDirty
);
2078 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This
,pStm
,fClearDirty
);
2081 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This
,pStm
,fClearDirty
);
2084 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This
,pStm
,fClearDirty
);
2087 if (iSerializeResult
) {
2089 if (This->loadtime_magic != 0xdeadbeef) {
2094 header
[0] = (This
->loadtime_magic
!= 0xdeadbeef) ? This
->loadtime_magic
: 0x0000746c;
2095 header
[1] = iDataSize
;
2096 IStream_Write(pStm
, header
, 2 * sizeof(DWORD
), &dummy
);
2098 IStream_Write(pStm
, pIconData
, iDataSize
, &dummy
);
2100 HeapFree(GetProcessHeap(), 0, This
->data
);
2101 This
->data
= pIconData
;
2102 This
->datalen
= iDataSize
;
2107 if (This->loadtime_magic != 0xdeadbeef) {
2112 header
[0] = (This
->loadtime_magic
!= 0xdeadbeef) ? This
->loadtime_magic
: 0x0000746c;
2113 header
[1] = This
->datalen
;
2114 IStream_Write(pStm
, header
, 2 * sizeof(DWORD
), &dummy
);
2116 IStream_Write(pStm
, This
->data
, This
->datalen
, &dummy
);
2120 case PICTYPE_METAFILE
:
2121 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This
,pStm
,fClearDirty
);
2123 case PICTYPE_ENHMETAFILE
:
2124 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This
,pStm
,fClearDirty
);
2127 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This
,pStm
,fClearDirty
);
2130 if (hResult
== S_OK
&& fClearDirty
) This
->bIsDirty
= FALSE
;
2134 static HRESULT WINAPI
OLEPictureImpl_GetSizeMax(
2135 IPersistStream
* iface
,ULARGE_INTEGER
*pcbSize
)
2137 OLEPictureImpl
*This
= impl_from_IPersistStream(iface
);
2138 FIXME("(%p,%p),stub!\n",This
,pcbSize
);
2143 /************************************************************************
2147 /************************************************************************
2148 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2150 * See Windows documentation for more details on IUnknown methods.
2152 static HRESULT WINAPI
OLEPictureImpl_IDispatch_QueryInterface(
2157 OLEPictureImpl
*This
= impl_from_IDispatch(iface
);
2159 return IPicture_QueryInterface((IPicture
*)This
, riid
, ppvoid
);
2162 /************************************************************************
2163 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2165 * See Windows documentation for more details on IUnknown methods.
2167 static ULONG WINAPI
OLEPictureImpl_IDispatch_AddRef(
2170 OLEPictureImpl
*This
= impl_from_IDispatch(iface
);
2172 return IPicture_AddRef((IPicture
*)This
);
2175 /************************************************************************
2176 * OLEPictureImpl_IDispatch_Release (IUnknown)
2178 * See Windows documentation for more details on IUnknown methods.
2180 static ULONG WINAPI
OLEPictureImpl_IDispatch_Release(
2183 OLEPictureImpl
*This
= impl_from_IDispatch(iface
);
2185 return IPicture_Release((IPicture
*)This
);
2188 /************************************************************************
2189 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2191 * See Windows documentation for more details on IDispatch methods.
2193 static HRESULT WINAPI
OLEPictureImpl_GetTypeInfoCount(
2195 unsigned int* pctinfo
)
2197 TRACE("(%p)\n", pctinfo
);
2204 /************************************************************************
2205 * OLEPictureImpl_GetTypeInfo (IDispatch)
2207 * See Windows documentation for more details on IDispatch methods.
2209 static HRESULT WINAPI
OLEPictureImpl_GetTypeInfo(
2213 ITypeInfo
** ppTInfo
)
2215 static const WCHAR stdole2tlb
[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2219 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo
, (int)lcid
, ppTInfo
);
2224 hres
= LoadTypeLib(stdole2tlb
, &tl
);
2227 ERR("Could not load stdole2.tlb\n");
2231 hres
= ITypeLib_GetTypeInfoOfGuid(tl
, &IID_IPictureDisp
, ppTInfo
);
2233 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres
);
2238 /************************************************************************
2239 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2241 * See Windows documentation for more details on IDispatch methods.
2243 static HRESULT WINAPI
OLEPictureImpl_GetIDsOfNames(
2246 LPOLESTR
* rgszNames
,
2256 /************************************************************************
2257 * OLEPictureImpl_Invoke (IDispatch)
2259 * See Windows documentation for more details on IDispatch methods.
2261 static HRESULT WINAPI
OLEPictureImpl_Invoke(
2263 DISPID dispIdMember
,
2267 DISPPARAMS
* pDispParams
,
2268 VARIANT
* pVarResult
,
2269 EXCEPINFO
* pExepInfo
,
2272 OLEPictureImpl
*This
= impl_from_IDispatch(iface
);
2274 /* validate parameters */
2276 if (!IsEqualIID(riid
, &IID_NULL
))
2278 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid
));
2279 return DISP_E_UNKNOWNNAME
;
2284 ERR("null pDispParams not allowed\n");
2285 return DISP_E_PARAMNOTOPTIONAL
;
2288 if (wFlags
& DISPATCH_PROPERTYGET
)
2290 if (pDispParams
->cArgs
!= 0)
2292 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams
->cArgs
);
2293 return DISP_E_BADPARAMCOUNT
;
2297 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2298 return DISP_E_PARAMNOTOPTIONAL
;
2301 else if (wFlags
& DISPATCH_PROPERTYPUT
)
2303 if (pDispParams
->cArgs
!= 1)
2305 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams
->cArgs
);
2306 return DISP_E_BADPARAMCOUNT
;
2310 switch (dispIdMember
)
2312 case DISPID_PICT_HANDLE
:
2313 if (wFlags
& DISPATCH_PROPERTYGET
)
2315 TRACE("DISPID_PICT_HANDLE\n");
2316 V_VT(pVarResult
) = VT_I4
;
2317 return IPicture_get_Handle((IPicture
*)&This
->lpVtbl
, &V_UINT(pVarResult
));
2320 case DISPID_PICT_HPAL
:
2321 if (wFlags
& DISPATCH_PROPERTYGET
)
2323 TRACE("DISPID_PICT_HPAL\n");
2324 V_VT(pVarResult
) = VT_I4
;
2325 return IPicture_get_hPal((IPicture
*)&This
->lpVtbl
, &V_UINT(pVarResult
));
2327 else if (wFlags
& DISPATCH_PROPERTYPUT
)
2331 TRACE("DISPID_PICT_HPAL\n");
2333 VariantInit(&vararg
);
2334 hr
= VariantChangeTypeEx(&vararg
, &pDispParams
->rgvarg
[0], lcid
, 0, VT_I4
);
2338 hr
= IPicture_set_hPal((IPicture
*)&This
->lpVtbl
, V_I4(&vararg
));
2340 VariantClear(&vararg
);
2344 case DISPID_PICT_TYPE
:
2345 if (wFlags
& DISPATCH_PROPERTYGET
)
2347 TRACE("DISPID_PICT_TYPE\n");
2348 V_VT(pVarResult
) = VT_I2
;
2349 return OLEPictureImpl_get_Type((IPicture
*)&This
->lpVtbl
, &V_I2(pVarResult
));
2352 case DISPID_PICT_WIDTH
:
2353 if (wFlags
& DISPATCH_PROPERTYGET
)
2355 TRACE("DISPID_PICT_WIDTH\n");
2356 V_VT(pVarResult
) = VT_I4
;
2357 return IPicture_get_Width((IPicture
*)&This
->lpVtbl
, &V_I4(pVarResult
));
2360 case DISPID_PICT_HEIGHT
:
2361 if (wFlags
& DISPATCH_PROPERTYGET
)
2363 TRACE("DISPID_PICT_HEIGHT\n");
2364 V_VT(pVarResult
) = VT_I4
;
2365 return IPicture_get_Height((IPicture
*)&This
->lpVtbl
, &V_I4(pVarResult
));
2370 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember
, wFlags
);
2371 return DISP_E_MEMBERNOTFOUND
;
2375 static const IPictureVtbl OLEPictureImpl_VTable
=
2377 OLEPictureImpl_QueryInterface
,
2378 OLEPictureImpl_AddRef
,
2379 OLEPictureImpl_Release
,
2380 OLEPictureImpl_get_Handle
,
2381 OLEPictureImpl_get_hPal
,
2382 OLEPictureImpl_get_Type
,
2383 OLEPictureImpl_get_Width
,
2384 OLEPictureImpl_get_Height
,
2385 OLEPictureImpl_Render
,
2386 OLEPictureImpl_set_hPal
,
2387 OLEPictureImpl_get_CurDC
,
2388 OLEPictureImpl_SelectPicture
,
2389 OLEPictureImpl_get_KeepOriginalFormat
,
2390 OLEPictureImpl_put_KeepOriginalFormat
,
2391 OLEPictureImpl_PictureChanged
,
2392 OLEPictureImpl_SaveAsFile
,
2393 OLEPictureImpl_get_Attributes
2396 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable
=
2398 OLEPictureImpl_IDispatch_QueryInterface
,
2399 OLEPictureImpl_IDispatch_AddRef
,
2400 OLEPictureImpl_IDispatch_Release
,
2401 OLEPictureImpl_GetTypeInfoCount
,
2402 OLEPictureImpl_GetTypeInfo
,
2403 OLEPictureImpl_GetIDsOfNames
,
2404 OLEPictureImpl_Invoke
2407 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable
=
2409 OLEPictureImpl_IPersistStream_QueryInterface
,
2410 OLEPictureImpl_IPersistStream_AddRef
,
2411 OLEPictureImpl_IPersistStream_Release
,
2412 OLEPictureImpl_GetClassID
,
2413 OLEPictureImpl_IsDirty
,
2414 OLEPictureImpl_Load
,
2415 OLEPictureImpl_Save
,
2416 OLEPictureImpl_GetSizeMax
2419 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable
=
2421 OLEPictureImpl_IConnectionPointContainer_QueryInterface
,
2422 OLEPictureImpl_IConnectionPointContainer_AddRef
,
2423 OLEPictureImpl_IConnectionPointContainer_Release
,
2424 OLEPictureImpl_EnumConnectionPoints
,
2425 OLEPictureImpl_FindConnectionPoint
2428 /***********************************************************************
2429 * OleCreatePictureIndirect (OLEAUT32.419)
2431 HRESULT WINAPI
OleCreatePictureIndirect(LPPICTDESC lpPictDesc
, REFIID riid
,
2432 BOOL fOwn
, LPVOID
*ppvObj
)
2434 OLEPictureImpl
* newPict
= NULL
;
2437 TRACE("(%p,%s,%d,%p)\n", lpPictDesc
, debugstr_guid(riid
), fOwn
, ppvObj
);
2448 * Try to construct a new instance of the class.
2450 newPict
= OLEPictureImpl_Construct(lpPictDesc
, fOwn
);
2452 if (newPict
== NULL
)
2453 return E_OUTOFMEMORY
;
2456 * Make sure it supports the interface required by the caller.
2458 hr
= IPicture_QueryInterface((IPicture
*)newPict
, riid
, ppvObj
);
2461 * Release the reference obtained in the constructor. If
2462 * the QueryInterface was unsuccessful, it will free the class.
2464 IPicture_Release((IPicture
*)newPict
);
2470 /***********************************************************************
2471 * OleLoadPicture (OLEAUT32.418)
2473 HRESULT WINAPI
OleLoadPicture( LPSTREAM lpstream
, LONG lSize
, BOOL fRunmode
,
2474 REFIID riid
, LPVOID
*ppvObj
)
2480 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2481 lpstream
, lSize
, fRunmode
, debugstr_guid(riid
), ppvObj
);
2483 hr
= OleCreatePictureIndirect(NULL
,riid
,!fRunmode
,(LPVOID
*)&newpic
);
2486 hr
= IPicture_QueryInterface(newpic
,&IID_IPersistStream
, (LPVOID
*)&ps
);
2488 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2489 IPicture_Release(newpic
);
2493 IPersistStream_Load(ps
,lpstream
);
2494 IPersistStream_Release(ps
);
2495 hr
= IPicture_QueryInterface(newpic
,riid
,ppvObj
);
2497 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid
));
2498 IPicture_Release(newpic
);
2502 /***********************************************************************
2503 * OleLoadPictureEx (OLEAUT32.401)
2505 HRESULT WINAPI
OleLoadPictureEx( LPSTREAM lpstream
, LONG lSize
, BOOL fRunmode
,
2506 REFIID riid
, DWORD xsiz
, DWORD ysiz
, DWORD flags
, LPVOID
*ppvObj
)
2512 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2513 lpstream
, lSize
, fRunmode
, debugstr_guid(riid
), xsiz
, ysiz
, flags
, ppvObj
);
2515 hr
= OleCreatePictureIndirect(NULL
,riid
,!fRunmode
,(LPVOID
*)&newpic
);
2518 hr
= IPicture_QueryInterface(newpic
,&IID_IPersistStream
, (LPVOID
*)&ps
);
2520 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2521 IPicture_Release(newpic
);
2525 IPersistStream_Load(ps
,lpstream
);
2526 IPersistStream_Release(ps
);
2527 hr
= IPicture_QueryInterface(newpic
,riid
,ppvObj
);
2529 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid
));
2530 IPicture_Release(newpic
);
2534 /***********************************************************************
2535 * OleLoadPicturePath (OLEAUT32.424)
2537 HRESULT WINAPI
OleLoadPicturePath( LPOLESTR szURLorPath
, LPUNKNOWN punkCaller
,
2538 DWORD dwReserved
, OLE_COLOR clrReserved
, REFIID riid
,
2541 static const WCHAR file
[] = { 'f','i','l','e',':','/','/',0 };
2545 HGLOBAL hGlobal
= NULL
;
2546 DWORD dwBytesRead
= 0;
2549 IPersistStream
*pStream
;
2552 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2553 debugstr_w(szURLorPath
), punkCaller
, dwReserved
, clrReserved
,
2554 debugstr_guid(riid
), ppvRet
);
2556 if (!ppvRet
) return E_POINTER
;
2558 if (strncmpW(szURLorPath
, file
, 7) == 0) {
2561 hFile
= CreateFileW(szURLorPath
, GENERIC_READ
, 0, NULL
, OPEN_EXISTING
,
2563 if (hFile
== INVALID_HANDLE_VALUE
)
2564 return E_UNEXPECTED
;
2566 dwFileSize
= GetFileSize(hFile
, NULL
);
2567 if (dwFileSize
!= INVALID_FILE_SIZE
)
2569 hGlobal
= GlobalAlloc(GMEM_FIXED
,dwFileSize
);
2572 bRead
= ReadFile(hFile
, hGlobal
, dwFileSize
, &dwBytesRead
, NULL
);
2575 GlobalFree(hGlobal
);
2583 return E_UNEXPECTED
;
2585 hRes
= CreateStreamOnHGlobal(hGlobal
, TRUE
, &stream
);
2588 GlobalFree(hGlobal
);
2595 hRes
= CreateBindCtx(0, &pbc
);
2596 if (SUCCEEDED(hRes
))
2598 hRes
= CreateURLMoniker(NULL
, szURLorPath
, &pmnk
);
2599 if (SUCCEEDED(hRes
))
2601 hRes
= IMoniker_BindToStorage(pmnk
, pbc
, NULL
, &IID_IStream
, (LPVOID
*)&stream
);
2602 IMoniker_Release(pmnk
);
2604 IBindCtx_Release(pbc
);
2610 hRes
= CoCreateInstance(&CLSID_StdPicture
, punkCaller
, CLSCTX_INPROC_SERVER
,
2611 &IID_IPicture
, (LPVOID
*)&ipicture
);
2613 IStream_Release(stream
);
2617 hRes
= IPicture_QueryInterface(ipicture
, &IID_IPersistStream
, (LPVOID
*)&pStream
);
2619 IStream_Release(stream
);
2620 IPicture_Release(ipicture
);
2624 hRes
= IPersistStream_Load(pStream
, stream
);
2625 IPersistStream_Release(pStream
);
2626 IStream_Release(stream
);
2629 IPicture_Release(ipicture
);
2633 hRes
= IPicture_QueryInterface(ipicture
,riid
,ppvRet
);
2635 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid
));
2637 IPicture_Release(ipicture
);
2641 /*******************************************************************************
2642 * StdPic ClassFactory
2646 /* IUnknown fields */
2647 const IClassFactoryVtbl
*lpVtbl
;
2649 } IClassFactoryImpl
;
2651 static HRESULT WINAPI
2652 SPCF_QueryInterface(LPCLASSFACTORY iface
,REFIID riid
,LPVOID
*ppobj
) {
2653 IClassFactoryImpl
*This
= (IClassFactoryImpl
*)iface
;
2655 FIXME("(%p)->(%s,%p),stub!\n",This
,debugstr_guid(riid
),ppobj
);
2656 return E_NOINTERFACE
;
2660 SPCF_AddRef(LPCLASSFACTORY iface
) {
2661 IClassFactoryImpl
*This
= (IClassFactoryImpl
*)iface
;
2662 return InterlockedIncrement(&This
->ref
);
2665 static ULONG WINAPI
SPCF_Release(LPCLASSFACTORY iface
) {
2666 IClassFactoryImpl
*This
= (IClassFactoryImpl
*)iface
;
2667 /* static class, won't be freed */
2668 return InterlockedDecrement(&This
->ref
);
2671 static HRESULT WINAPI
SPCF_CreateInstance(
2672 LPCLASSFACTORY iface
,LPUNKNOWN pOuter
,REFIID riid
,LPVOID
*ppobj
2674 /* Creates an uninitialized picture */
2675 return OleCreatePictureIndirect(NULL
,riid
,TRUE
,ppobj
);
2679 static HRESULT WINAPI
SPCF_LockServer(LPCLASSFACTORY iface
,BOOL dolock
) {
2680 IClassFactoryImpl
*This
= (IClassFactoryImpl
*)iface
;
2681 FIXME("(%p)->(%d),stub!\n",This
,dolock
);
2685 static const IClassFactoryVtbl SPCF_Vtbl
= {
2686 SPCF_QueryInterface
,
2689 SPCF_CreateInstance
,
2692 static IClassFactoryImpl STDPIC_CF
= {&SPCF_Vtbl
, 1 };
2694 void _get_STDPIC_CF(LPVOID
*ppv
) { *ppv
= (LPVOID
)&STDPIC_CF
; }