oleaut32: When marshalling VT_CARRAY, only marshall by reference for appropriate...
[wine/multimedia.git] / dlls / oleaut32 / olepicture.c
blob2195ba581529fd680edb99546e578cdc5c00a4f8
1 /*
2 * OLE Picture object
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
24 * BUGS
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).
39 #include "config.h"
40 #include "wine/port.h"
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <string.h>
49 #define COBJMACROS
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
53 #include "winerror.h"
54 #include "windef.h"
55 #include "winbase.h"
56 #include "wingdi.h"
57 #include "winuser.h"
58 #include "ole2.h"
59 #include "olectl.h"
60 #include "oleauto.h"
61 #include "connpt.h"
62 #include "urlmon.h"
63 #include "initguid.h"
64 #include "wincodec.h"
65 #include "wine/debug.h"
66 #include "wine/unicode.h"
67 #include "wine/library.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(ole);
71 #include "pshpack1.h"
73 /* Header for Aldus Placable Metafiles - a standard metafile follows */
74 typedef struct _APM_HEADER
76 DWORD key;
77 WORD handle;
78 SHORT left;
79 SHORT top;
80 SHORT right;
81 SHORT bottom;
82 WORD inch;
83 DWORD reserved;
84 WORD checksum;
85 } APM_HEADER;
87 typedef struct {
88 BYTE bWidth;
89 BYTE bHeight;
90 BYTE bColorCount;
91 BYTE bReserved;
92 WORD xHotspot;
93 WORD yHotspot;
94 DWORD dwDIBSize;
95 DWORD dwDIBOffset;
96 } CURSORICONFILEDIRENTRY;
98 typedef struct
100 WORD idReserved;
101 WORD idType;
102 WORD idCount;
103 CURSORICONFILEDIRENTRY idEntries[1];
104 } CURSORICONFILEDIR;
106 #include "poppack.h"
108 /*************************************************************************
109 * Declaration of implementation class
112 typedef struct OLEPictureImpl {
115 * IPicture handles IUnknown
118 IPicture IPicture_iface;
119 IDispatch IDispatch_iface;
120 IPersistStream IPersistStream_iface;
121 IConnectionPointContainer IConnectionPointContainer_iface;
123 /* Object reference count */
124 LONG ref;
126 /* We own the object and must destroy it ourselves */
127 BOOL fOwn;
129 /* Picture description */
130 PICTDESC desc;
132 /* These are the pixel size of a bitmap */
133 DWORD origWidth;
134 DWORD origHeight;
136 /* And these are the size of the picture converted into HIMETRIC units */
137 OLE_XSIZE_HIMETRIC himetricWidth;
138 OLE_YSIZE_HIMETRIC himetricHeight;
140 IConnectionPoint *pCP;
142 BOOL keepOrigFormat;
143 HDC hDCCur;
144 HBITMAP stock_bitmap;
146 /* Bitmap transparency mask */
147 HBITMAP hbmMask;
148 HBITMAP hbmXor;
149 COLORREF rgbTrans;
151 /* data */
152 void* data;
153 int datalen;
154 BOOL bIsDirty; /* Set to TRUE if picture has changed */
155 unsigned int loadtime_magic; /* If a length header was found, saves value */
156 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
157 } OLEPictureImpl;
159 static inline OLEPictureImpl *impl_from_IPicture(IPicture *iface)
161 return CONTAINING_RECORD(iface, OLEPictureImpl, IPicture_iface);
164 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
166 return CONTAINING_RECORD(iface, OLEPictureImpl, IDispatch_iface);
169 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
171 return CONTAINING_RECORD(iface, OLEPictureImpl, IPersistStream_iface);
174 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
176 return CONTAINING_RECORD(iface, OLEPictureImpl, IConnectionPointContainer_iface);
180 * Predeclare VTables. They get initialized at the end.
182 static const IPictureVtbl OLEPictureImpl_VTable;
183 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
184 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
185 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
187 /* pixels to HIMETRIC units conversion */
188 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
190 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
193 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
195 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
198 /***********************************************************************
199 * Implementation of the OLEPictureImpl class.
202 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
204 BITMAP bm;
205 HDC hdcRef;
207 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
208 if(GetObjectW(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
209 ERR("GetObject fails\n");
210 return;
212 This->origWidth = bm.bmWidth;
213 This->origHeight = bm.bmHeight;
215 /* The width and height are stored in HIMETRIC units (0.01 mm),
216 so we take our pixel width divide by pixels per inch and
217 multiply by 25.4 * 100 */
218 /* Should we use GetBitmapDimension if available? */
219 hdcRef = CreateCompatibleDC(0);
221 This->himetricWidth = xpixels_to_himetric(bm.bmWidth, hdcRef);
222 This->himetricHeight = ypixels_to_himetric(bm.bmHeight, hdcRef);
223 This->stock_bitmap = GetCurrentObject( hdcRef, OBJ_BITMAP );
225 DeleteDC(hdcRef);
228 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
230 ICONINFO infoIcon;
232 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
233 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
234 HDC hdcRef;
235 BITMAP bm;
237 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
238 if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
239 ERR("GetObject fails on icon bitmap\n");
240 return;
243 This->origWidth = bm.bmWidth;
244 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
245 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
246 hdcRef = GetDC(0);
248 This->himetricWidth = xpixels_to_himetric(This->origWidth, hdcRef);
249 This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
251 ReleaseDC(0, hdcRef);
253 DeleteObject(infoIcon.hbmMask);
254 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
255 } else {
256 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
260 /************************************************************************
261 * OLEPictureImpl_Construct
263 * This method will construct a new instance of the OLEPictureImpl
264 * class.
266 * The caller of this method must release the object when it's
267 * done with it.
269 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
271 OLEPictureImpl* newObject = 0;
273 if (pictDesc)
274 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
277 * Allocate space for the object.
279 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
281 if (newObject==0)
282 return newObject;
285 * Initialize the virtual function table.
287 newObject->IPicture_iface.lpVtbl = &OLEPictureImpl_VTable;
288 newObject->IDispatch_iface.lpVtbl = &OLEPictureImpl_IDispatch_VTable;
289 newObject->IPersistStream_iface.lpVtbl = &OLEPictureImpl_IPersistStream_VTable;
290 newObject->IConnectionPointContainer_iface.lpVtbl = &OLEPictureImpl_IConnectionPointContainer_VTable;
292 newObject->pCP = NULL;
293 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
294 if (!newObject->pCP)
296 HeapFree(GetProcessHeap(), 0, newObject);
297 return NULL;
301 * Start with one reference count. The caller of this function
302 * must release the interface pointer when it is done.
304 newObject->ref = 1;
305 newObject->hDCCur = 0;
307 newObject->fOwn = fOwn;
309 /* dunno about original value */
310 newObject->keepOrigFormat = TRUE;
312 newObject->hbmMask = NULL;
313 newObject->hbmXor = NULL;
314 newObject->loadtime_magic = 0xdeadbeef;
315 newObject->loadtime_format = 0;
316 newObject->bIsDirty = FALSE;
318 if (pictDesc) {
319 newObject->desc = *pictDesc;
321 switch(pictDesc->picType) {
322 case PICTYPE_BITMAP:
323 OLEPictureImpl_SetBitmap(newObject);
324 break;
326 case PICTYPE_METAFILE:
327 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
328 newObject->himetricWidth = pictDesc->u.wmf.xExt;
329 newObject->himetricHeight = pictDesc->u.wmf.yExt;
330 break;
332 case PICTYPE_NONE:
333 /* not sure what to do here */
334 newObject->himetricWidth = newObject->himetricHeight = 0;
335 break;
337 case PICTYPE_ICON:
338 OLEPictureImpl_SetIcon(newObject);
339 break;
340 case PICTYPE_ENHMETAFILE:
341 default:
342 FIXME("Unsupported type %d\n", pictDesc->picType);
343 newObject->himetricWidth = newObject->himetricHeight = 0;
344 break;
346 } else {
347 newObject->desc.picType = PICTYPE_UNINITIALIZED;
350 TRACE("returning %p\n", newObject);
351 return newObject;
354 /************************************************************************
355 * OLEPictureImpl_Destroy
357 * This method is called by the Release method when the reference
358 * count goes down to 0. It will free all resources used by
359 * this object. */
360 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
362 TRACE("(%p)\n", Obj);
364 if (Obj->pCP)
365 IConnectionPoint_Release(Obj->pCP);
367 if(Obj->fOwn) { /* We need to destroy the picture */
368 switch(Obj->desc.picType) {
369 case PICTYPE_BITMAP:
370 DeleteObject(Obj->desc.u.bmp.hbitmap);
371 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
372 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
373 break;
374 case PICTYPE_METAFILE:
375 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
376 break;
377 case PICTYPE_ICON:
378 DestroyIcon(Obj->desc.u.icon.hicon);
379 break;
380 case PICTYPE_ENHMETAFILE:
381 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
382 break;
383 case PICTYPE_NONE:
384 case PICTYPE_UNINITIALIZED:
385 /* Nothing to do */
386 break;
387 default:
388 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
389 break;
392 HeapFree(GetProcessHeap(), 0, Obj->data);
393 HeapFree(GetProcessHeap(), 0, Obj);
397 /************************************************************************
398 * OLEPictureImpl_AddRef (IUnknown)
400 * See Windows documentation for more details on IUnknown methods.
402 static ULONG WINAPI OLEPictureImpl_AddRef(
403 IPicture* iface)
405 OLEPictureImpl *This = impl_from_IPicture(iface);
406 ULONG refCount = InterlockedIncrement(&This->ref);
408 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
410 return refCount;
413 /************************************************************************
414 * OLEPictureImpl_Release (IUnknown)
416 * See Windows documentation for more details on IUnknown methods.
418 static ULONG WINAPI OLEPictureImpl_Release(
419 IPicture* iface)
421 OLEPictureImpl *This = impl_from_IPicture(iface);
422 ULONG refCount = InterlockedDecrement(&This->ref);
424 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
427 * If the reference count goes down to 0, perform suicide.
429 if (!refCount) OLEPictureImpl_Destroy(This);
431 return refCount;
434 /************************************************************************
435 * OLEPictureImpl_QueryInterface (IUnknown)
437 * See Windows documentation for more details on IUnknown methods.
439 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
440 IPicture* iface,
441 REFIID riid,
442 void** ppvObject)
444 OLEPictureImpl *This = impl_from_IPicture(iface);
446 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
448 if (!ppvObject)
449 return E_INVALIDARG;
451 *ppvObject = 0;
453 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
454 *ppvObject = This;
455 else if (IsEqualIID(&IID_IDispatch, riid))
456 *ppvObject = &This->IDispatch_iface;
457 else if (IsEqualIID(&IID_IPictureDisp, riid))
458 *ppvObject = &This->IDispatch_iface;
459 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
460 *ppvObject = &This->IPersistStream_iface;
461 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
462 *ppvObject = &This->IConnectionPointContainer_iface;
464 if (!*ppvObject)
466 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
467 return E_NOINTERFACE;
470 IPicture_AddRef(iface);
472 return S_OK;
475 /***********************************************************************
476 * OLEPicture_SendNotify (internal)
478 * Sends notification messages of changed properties to any interested
479 * connections.
481 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
483 IEnumConnections *pEnum;
484 CONNECTDATA CD;
486 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
487 return;
488 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
489 IPropertyNotifySink *sink;
491 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
492 IPropertyNotifySink_OnChanged(sink, dispID);
493 IPropertyNotifySink_Release(sink);
494 IUnknown_Release(CD.pUnk);
496 IEnumConnections_Release(pEnum);
499 /************************************************************************
500 * OLEPictureImpl_get_Handle
502 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
503 OLE_HANDLE *phandle)
505 OLEPictureImpl *This = impl_from_IPicture(iface);
506 TRACE("(%p)->(%p)\n", This, phandle);
508 if(!phandle)
509 return E_POINTER;
511 switch(This->desc.picType) {
512 case PICTYPE_NONE:
513 case PICTYPE_UNINITIALIZED:
514 *phandle = 0;
515 break;
516 case PICTYPE_BITMAP:
517 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
518 break;
519 case PICTYPE_METAFILE:
520 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
521 break;
522 case PICTYPE_ICON:
523 *phandle = HandleToUlong(This->desc.u.icon.hicon);
524 break;
525 case PICTYPE_ENHMETAFILE:
526 *phandle = HandleToUlong(This->desc.u.emf.hemf);
527 break;
528 default:
529 FIXME("Unimplemented type %d\n", This->desc.picType);
530 return E_NOTIMPL;
532 TRACE("returning handle %08x\n", *phandle);
533 return S_OK;
536 /************************************************************************
537 * OLEPictureImpl_get_hPal
539 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
540 OLE_HANDLE *phandle)
542 OLEPictureImpl *This = impl_from_IPicture(iface);
543 HRESULT hres;
544 TRACE("(%p)->(%p)\n", This, phandle);
546 if (!phandle)
547 return E_POINTER;
549 switch (This->desc.picType) {
550 case (UINT)PICTYPE_UNINITIALIZED:
551 case PICTYPE_NONE:
552 *phandle = 0;
553 hres = S_FALSE;
554 break;
555 case PICTYPE_BITMAP:
556 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
557 hres = S_OK;
558 break;
559 case PICTYPE_METAFILE:
560 hres = E_FAIL;
561 break;
562 case PICTYPE_ICON:
563 case PICTYPE_ENHMETAFILE:
564 default:
565 FIXME("unimplemented for type %d. Returning 0 palette.\n",
566 This->desc.picType);
567 *phandle = 0;
568 hres = S_OK;
571 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
572 return hres;
575 /************************************************************************
576 * OLEPictureImpl_get_Type
578 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
579 short *ptype)
581 OLEPictureImpl *This = impl_from_IPicture(iface);
582 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
584 if(!ptype)
585 return E_POINTER;
587 *ptype = This->desc.picType;
588 return S_OK;
591 /************************************************************************
592 * OLEPictureImpl_get_Width
594 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
595 OLE_XSIZE_HIMETRIC *pwidth)
597 OLEPictureImpl *This = impl_from_IPicture(iface);
598 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
599 *pwidth = This->himetricWidth;
600 return S_OK;
603 /************************************************************************
604 * OLEPictureImpl_get_Height
606 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
607 OLE_YSIZE_HIMETRIC *pheight)
609 OLEPictureImpl *This = impl_from_IPicture(iface);
610 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
611 *pheight = This->himetricHeight;
612 return S_OK;
615 /************************************************************************
616 * OLEPictureImpl_Render
618 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
619 LONG x, LONG y, LONG cx, LONG cy,
620 OLE_XPOS_HIMETRIC xSrc,
621 OLE_YPOS_HIMETRIC ySrc,
622 OLE_XSIZE_HIMETRIC cxSrc,
623 OLE_YSIZE_HIMETRIC cySrc,
624 LPCRECT prcWBounds)
626 OLEPictureImpl *This = impl_from_IPicture(iface);
627 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
628 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
629 if(prcWBounds)
630 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
631 prcWBounds->right, prcWBounds->bottom);
633 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
634 return CTL_E_INVALIDPROPERTYVALUE;
638 * While the documentation suggests this to be here (or after rendering?)
639 * it does cause an endless recursion in my sample app. -MM 20010804
640 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
643 switch(This->desc.picType) {
644 case PICTYPE_UNINITIALIZED:
645 case PICTYPE_NONE:
646 /* nothing to do */
647 return S_OK;
648 case PICTYPE_BITMAP:
650 HBITMAP hbmpOld;
651 HDC hdcBmp;
653 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
654 NB y-axis gets flipped */
656 hdcBmp = CreateCompatibleDC(0);
657 SetMapMode(hdcBmp, MM_ANISOTROPIC);
658 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
659 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
660 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
661 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
663 if (This->hbmMask) {
664 HDC hdcMask = CreateCompatibleDC(0);
665 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
667 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
669 SetMapMode(hdcMask, MM_ANISOTROPIC);
670 SetWindowOrgEx(hdcMask, 0, 0, NULL);
671 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
672 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
673 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
675 SetBkColor(hdc, RGB(255, 255, 255));
676 SetTextColor(hdc, RGB(0, 0, 0));
677 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
678 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
680 SelectObject(hdcMask, hOldbm);
681 DeleteDC(hdcMask);
682 } else {
683 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
684 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
687 SelectObject(hdcBmp, hbmpOld);
688 DeleteDC(hdcBmp);
690 break;
691 case PICTYPE_ICON:
692 FIXME("Not quite correct implementation of rendering icons...\n");
693 DrawIconEx(hdc, x, y, This->desc.u.icon.hicon, cx, cy, 0, NULL, DI_NORMAL);
694 break;
696 case PICTYPE_METAFILE:
698 POINT prevOrg, prevWndOrg;
699 SIZE prevExt, prevWndExt;
700 int oldmode;
702 /* Render the WMF to the appropriate location by setting the
703 appropriate ratio between "device units" and "logical units" */
704 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
705 /* For the "source rectangle" the y-axis must be inverted */
706 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
707 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
708 /* For the "destination rectangle" no inversion is necessary */
709 SetViewportOrgEx(hdc, x, y, &prevOrg);
710 SetViewportExtEx(hdc, cx, cy, &prevExt);
712 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
713 ERR("PlayMetaFile failed!\n");
715 /* We're done, restore the DC to the previous settings for converting
716 logical units to device units */
717 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
718 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
719 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
720 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
721 SetMapMode(hdc, oldmode);
722 break;
725 case PICTYPE_ENHMETAFILE:
727 RECT rc = { x, y, x + cx, y + cy };
728 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
729 break;
732 default:
733 FIXME("type %d not implemented\n", This->desc.picType);
734 return E_NOTIMPL;
736 return S_OK;
739 /************************************************************************
740 * OLEPictureImpl_set_hPal
742 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
743 OLE_HANDLE hpal)
745 OLEPictureImpl *This = impl_from_IPicture(iface);
746 FIXME("(%p)->(%08x): stub\n", This, hpal);
747 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
748 return E_NOTIMPL;
751 /************************************************************************
752 * OLEPictureImpl_get_CurDC
754 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
755 HDC *phdc)
757 OLEPictureImpl *This = impl_from_IPicture(iface);
758 TRACE("(%p), returning %p\n", This, This->hDCCur);
759 if (phdc) *phdc = This->hDCCur;
760 return S_OK;
763 /************************************************************************
764 * OLEPictureImpl_SelectPicture
766 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
767 HDC hdcIn,
768 HDC *phdcOut,
769 OLE_HANDLE *phbmpOut)
771 OLEPictureImpl *This = impl_from_IPicture(iface);
772 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
773 if (This->desc.picType == PICTYPE_BITMAP) {
774 if (phdcOut)
775 *phdcOut = This->hDCCur;
776 if (This->hDCCur) SelectObject(This->hDCCur,This->stock_bitmap);
777 if (hdcIn) SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
778 This->hDCCur = hdcIn;
779 if (phbmpOut)
780 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
781 return S_OK;
782 } else {
783 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
784 return E_FAIL;
788 /************************************************************************
789 * OLEPictureImpl_get_KeepOriginalFormat
791 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
792 BOOL *pfKeep)
794 OLEPictureImpl *This = impl_from_IPicture(iface);
795 TRACE("(%p)->(%p)\n", This, pfKeep);
796 if (!pfKeep)
797 return E_POINTER;
798 *pfKeep = This->keepOrigFormat;
799 return S_OK;
802 /************************************************************************
803 * OLEPictureImpl_put_KeepOriginalFormat
805 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
806 BOOL keep)
808 OLEPictureImpl *This = impl_from_IPicture(iface);
809 TRACE("(%p)->(%d)\n", This, keep);
810 This->keepOrigFormat = keep;
811 /* FIXME: what DISPID notification here? */
812 return S_OK;
815 /************************************************************************
816 * OLEPictureImpl_PictureChanged
818 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
820 OLEPictureImpl *This = impl_from_IPicture(iface);
821 TRACE("(%p)->()\n", This);
822 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
823 This->bIsDirty = TRUE;
824 return S_OK;
827 /************************************************************************
828 * OLEPictureImpl_SaveAsFile
830 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
831 IStream *pstream,
832 BOOL SaveMemCopy,
833 LONG *pcbSize)
835 OLEPictureImpl *This = impl_from_IPicture(iface);
836 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
837 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
840 /************************************************************************
841 * OLEPictureImpl_get_Attributes
843 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
844 DWORD *pdwAttr)
846 OLEPictureImpl *This = impl_from_IPicture(iface);
847 TRACE("(%p)->(%p).\n", This, pdwAttr);
849 if(!pdwAttr)
850 return E_POINTER;
852 *pdwAttr = 0;
853 switch (This->desc.picType) {
854 case PICTYPE_UNINITIALIZED:
855 case PICTYPE_NONE: break;
856 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
857 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
858 case PICTYPE_ENHMETAFILE: /* fall through */
859 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
860 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
862 return S_OK;
866 /************************************************************************
867 * IConnectionPointContainer
869 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
870 IConnectionPointContainer* iface,
871 REFIID riid,
872 VOID** ppvoid)
874 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
876 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
879 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
880 IConnectionPointContainer* iface)
882 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
884 return IPicture_AddRef(&This->IPicture_iface);
887 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
888 IConnectionPointContainer* iface)
890 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
892 return IPicture_Release(&This->IPicture_iface);
895 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
896 IConnectionPointContainer* iface,
897 IEnumConnectionPoints** ppEnum)
899 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
901 FIXME("(%p,%p), stub!\n",This,ppEnum);
902 return E_NOTIMPL;
905 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
906 IConnectionPointContainer* iface,
907 REFIID riid,
908 IConnectionPoint **ppCP)
910 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
911 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
912 if (!ppCP)
913 return E_POINTER;
914 *ppCP = NULL;
915 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
916 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
917 FIXME("no connection point for %s\n",debugstr_guid(riid));
918 return CONNECT_E_NOCONNECTION;
922 /************************************************************************
923 * IPersistStream
926 /************************************************************************
927 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
929 * See Windows documentation for more details on IUnknown methods.
931 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
932 IPersistStream* iface,
933 REFIID riid,
934 VOID** ppvoid)
936 OLEPictureImpl *This = impl_from_IPersistStream(iface);
938 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
941 /************************************************************************
942 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
944 * See Windows documentation for more details on IUnknown methods.
946 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
947 IPersistStream* iface)
949 OLEPictureImpl *This = impl_from_IPersistStream(iface);
951 return IPicture_AddRef(&This->IPicture_iface);
954 /************************************************************************
955 * OLEPictureImpl_IPersistStream_Release (IUnknown)
957 * See Windows documentation for more details on IUnknown methods.
959 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
960 IPersistStream* iface)
962 OLEPictureImpl *This = impl_from_IPersistStream(iface);
964 return IPicture_Release(&This->IPicture_iface);
967 /************************************************************************
968 * OLEPictureImpl_IPersistStream_GetClassID
970 static HRESULT WINAPI OLEPictureImpl_GetClassID(
971 IPersistStream* iface,CLSID* pClassID)
973 TRACE("(%p)\n", pClassID);
974 *pClassID = CLSID_StdPicture;
975 return S_OK;
978 /************************************************************************
979 * OLEPictureImpl_IPersistStream_IsDirty
981 static HRESULT WINAPI OLEPictureImpl_IsDirty(
982 IPersistStream* iface)
984 OLEPictureImpl *This = impl_from_IPersistStream(iface);
985 FIXME("(%p),stub!\n",This);
986 return E_NOTIMPL;
989 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
991 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
992 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
993 HDC hdcref;
995 /* Does not matter whether this is a coreheader or not, we only use
996 * components which are in both
998 hdcref = GetDC(0);
999 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1000 hdcref,
1001 &(bi->bmiHeader),
1002 CBM_INIT,
1003 xbuf+bfh->bfOffBits,
1005 DIB_RGB_COLORS
1007 ReleaseDC(0, hdcref);
1008 if (This->desc.u.bmp.hbitmap == 0)
1009 return E_FAIL;
1010 This->desc.picType = PICTYPE_BITMAP;
1011 OLEPictureImpl_SetBitmap(This);
1012 return S_OK;
1015 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1017 HRESULT hr;
1018 BITMAPINFOHEADER bih;
1019 HDC hdcref;
1020 UINT width, height;
1021 UINT stride, buffersize;
1022 LPBYTE bits=NULL;
1023 WICRect rc;
1024 IWICBitmapSource *real_source;
1025 UINT x, y;
1026 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1027 BOOL has_alpha=FALSE;
1029 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1030 if (FAILED(hr)) return hr;
1032 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1033 if (FAILED(hr)) goto end;
1035 bih.biSize = sizeof(bih);
1036 bih.biWidth = width;
1037 bih.biHeight = -height;
1038 bih.biPlanes = 1;
1039 bih.biBitCount = 32;
1040 bih.biCompression = BI_RGB;
1041 bih.biSizeImage = 0;
1042 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1043 bih.biYPelsPerMeter = 4085;
1044 bih.biClrUsed = 0;
1045 bih.biClrImportant = 0;
1047 stride = 4 * width;
1048 buffersize = stride * height;
1050 bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1051 if (!bits)
1053 hr = E_OUTOFMEMORY;
1054 goto end;
1057 rc.X = 0;
1058 rc.Y = 0;
1059 rc.Width = width;
1060 rc.Height = height;
1061 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1062 if (FAILED(hr))
1063 goto end;
1065 hdcref = GetDC(0);
1066 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1067 hdcref,
1068 &bih,
1069 CBM_INIT,
1070 bits,
1071 (BITMAPINFO*)&bih,
1072 DIB_RGB_COLORS);
1074 if (This->desc.u.bmp.hbitmap == 0)
1076 hr = E_FAIL;
1077 ReleaseDC(0, hdcref);
1078 goto end;
1081 This->desc.picType = PICTYPE_BITMAP;
1082 OLEPictureImpl_SetBitmap(This);
1084 /* set transparent pixels to black, all others to white */
1085 for(y = 0; y < height; y++){
1086 for(x = 0; x < width; x++){
1087 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1088 if((*pixel & 0x80000000) == 0)
1090 has_alpha = TRUE;
1091 *pixel = black;
1093 else
1094 *pixel = white;
1098 if (has_alpha)
1100 HDC hdcBmp, hdcXor, hdcMask;
1101 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1103 This->hbmXor = CreateDIBitmap(
1104 hdcref,
1105 &bih,
1106 CBM_INIT,
1107 bits,
1108 (BITMAPINFO*)&bih,
1109 DIB_RGB_COLORS
1112 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1113 hdcBmp = CreateCompatibleDC(NULL);
1114 hdcXor = CreateCompatibleDC(NULL);
1115 hdcMask = CreateCompatibleDC(NULL);
1117 hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1118 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1119 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1121 SetBkColor(hdcXor,black);
1122 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1123 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1125 SelectObject(hdcBmp,hbmoldBmp);
1126 SelectObject(hdcXor,hbmoldXor);
1127 SelectObject(hdcMask,hbmoldMask);
1129 DeleteDC(hdcBmp);
1130 DeleteDC(hdcXor);
1131 DeleteDC(hdcMask);
1134 ReleaseDC(0, hdcref);
1136 end:
1137 HeapFree(GetProcessHeap(), 0, bits);
1138 IWICBitmapSource_Release(real_source);
1139 return hr;
1142 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1144 HRESULT hr;
1145 IWICImagingFactory *factory;
1146 IWICBitmapDecoder *decoder;
1147 IWICBitmapFrameDecode *framedecode;
1148 HRESULT initresult;
1149 IWICStream *stream;
1151 initresult = CoInitialize(NULL);
1153 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1154 &IID_IWICImagingFactory, (void**)&factory);
1155 if (SUCCEEDED(hr)) /* created factory */
1157 hr = IWICImagingFactory_CreateStream(factory, &stream);
1158 IWICImagingFactory_Release(factory);
1161 if (SUCCEEDED(hr)) /* created stream */
1163 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1165 if (SUCCEEDED(hr)) /* initialized stream */
1167 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1168 &IID_IWICBitmapDecoder, (void**)&decoder);
1169 if (SUCCEEDED(hr)) /* created decoder */
1171 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1173 if (SUCCEEDED(hr)) /* initialized decoder */
1174 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1176 IWICBitmapDecoder_Release(decoder);
1180 IWICStream_Release(stream);
1183 if (SUCCEEDED(hr)) /* got framedecode */
1185 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1186 IWICBitmapFrameDecode_Release(framedecode);
1189 if (SUCCEEDED(initresult)) CoUninitialize();
1190 return hr;
1193 /*****************************************************
1194 * start of Icon-specific code
1197 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1199 HICON hicon;
1200 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1201 HDC hdcRef;
1202 int i;
1205 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1206 FIXME("icon.idType=%d\n",cifd->idType);
1207 FIXME("icon.idCount=%d\n",cifd->idCount);
1209 for (i=0;i<cifd->idCount;i++) {
1210 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1211 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1212 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1213 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1214 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1215 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1216 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1217 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1220 i=0;
1221 /* If we have more than one icon, try to find the best.
1222 * this currently means '32 pixel wide'.
1224 if (cifd->idCount!=1) {
1225 for (i=0;i<cifd->idCount;i++) {
1226 if (cifd->idEntries[i].bWidth == 32)
1227 break;
1229 if (i==cifd->idCount) i=0;
1232 hicon = CreateIconFromResourceEx(
1233 xbuf+cifd->idEntries[i].dwDIBOffset,
1234 cifd->idEntries[i].dwDIBSize,
1235 TRUE, /* is icon */
1236 0x00030000,
1237 cifd->idEntries[i].bWidth,
1238 cifd->idEntries[i].bHeight,
1241 if (!hicon) {
1242 ERR("CreateIcon failed.\n");
1243 return E_FAIL;
1244 } else {
1245 This->desc.picType = PICTYPE_ICON;
1246 This->desc.u.icon.hicon = hicon;
1247 This->origWidth = cifd->idEntries[i].bWidth;
1248 This->origHeight = cifd->idEntries[i].bHeight;
1249 hdcRef = CreateCompatibleDC(0);
1250 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1251 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1252 DeleteDC(hdcRef);
1253 return S_OK;
1257 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1258 const BYTE *data, ULONG size)
1260 HENHMETAFILE hemf;
1261 ENHMETAHEADER hdr;
1263 hemf = SetEnhMetaFileBits(size, data);
1264 if (!hemf) return E_FAIL;
1266 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1268 This->desc.picType = PICTYPE_ENHMETAFILE;
1269 This->desc.u.emf.hemf = hemf;
1271 This->origWidth = 0;
1272 This->origHeight = 0;
1273 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1274 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1276 return S_OK;
1279 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1280 const BYTE *data, ULONG size)
1282 const APM_HEADER *header = (const APM_HEADER *)data;
1283 HMETAFILE hmf;
1285 if (size < sizeof(APM_HEADER))
1286 return E_FAIL;
1287 if (header->key != 0x9ac6cdd7)
1288 return E_FAIL;
1290 /* SetMetaFileBitsEx performs data check on its own */
1291 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1292 if (!hmf) return E_FAIL;
1294 This->desc.picType = PICTYPE_METAFILE;
1295 This->desc.u.wmf.hmeta = hmf;
1296 This->desc.u.wmf.xExt = 0;
1297 This->desc.u.wmf.yExt = 0;
1299 This->origWidth = 0;
1300 This->origHeight = 0;
1301 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1302 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1303 return S_OK;
1306 /************************************************************************
1307 * BITMAP FORMAT FLAGS -
1308 * Flags that differentiate between different types of bitmaps.
1311 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1312 #define BITMAP_FORMAT_JPEG 0xd8ff
1313 #define BITMAP_FORMAT_GIF 0x4947
1314 #define BITMAP_FORMAT_PNG 0x5089
1315 #define BITMAP_FORMAT_APM 0xcdd7
1317 /************************************************************************
1318 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1320 * Loads the binary data from the IStream. Starts at current position.
1321 * There appears to be an 2 DWORD header:
1322 * DWORD magic;
1323 * DWORD len;
1325 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1327 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1328 HRESULT hr;
1329 BOOL headerisdata;
1330 BOOL statfailed = FALSE;
1331 ULONG xread, toread;
1332 ULONG headerread;
1333 BYTE *xbuf;
1334 DWORD header[2];
1335 WORD magic;
1336 STATSTG statstg;
1337 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1339 TRACE("(%p,%p)\n",This,pStm);
1341 /****************************************************************************************
1342 * Part 1: Load the data
1344 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1345 * out whether we do.
1347 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1348 * compound file. This may explain most, if not all, of the cases of "no
1349 * header", and the header validation should take this into account.
1350 * At least in Visual Basic 6, resource streams, valid headers are
1351 * header[0] == "lt\0\0",
1352 * header[1] == length_of_stream.
1354 * Also handle streams where we do not have a working "Stat" method by
1355 * reading all data until the end of the stream.
1357 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1358 if (hr != S_OK) {
1359 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1360 statfailed = TRUE;
1361 /* we will read at least 8 byte ... just right below */
1362 statstg.cbSize.QuadPart = 8;
1365 toread = 0;
1366 headerread = 0;
1367 headerisdata = FALSE;
1368 do {
1369 hr = IStream_Read(pStm, header, 8, &xread);
1370 if (hr != S_OK || xread!=8) {
1371 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1372 return (hr?hr:E_FAIL);
1374 headerread += xread;
1375 xread = 0;
1377 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1378 if (toread != 0 && toread != header[1])
1379 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1380 toread, header[1]);
1381 toread = header[1];
1382 if (toread == 0) break;
1383 } else {
1384 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1385 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1386 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1387 (header[0] == EMR_HEADER) || /* EMF header */
1388 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1389 (header[1]==0)
1390 ) {/* Found start of bitmap data */
1391 headerisdata = TRUE;
1392 if (toread == 0)
1393 toread = statstg.cbSize.QuadPart-8;
1394 else toread -= 8;
1395 xread = 8;
1396 } else {
1397 FIXME("Unknown stream header magic: %08x\n", header[0]);
1398 toread = header[1];
1401 } while (!headerisdata);
1403 if (statfailed) { /* we don't know the size ... read all we get */
1404 int sizeinc = 4096;
1405 int origsize = sizeinc;
1406 ULONG nread = 42;
1408 TRACE("Reading all data from stream.\n");
1409 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1410 if (headerisdata)
1411 memcpy (xbuf, header, 8);
1412 while (1) {
1413 while (xread < origsize) {
1414 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1415 xread += nread;
1416 if (hr != S_OK || !nread)
1417 break;
1419 if (!nread || hr != S_OK) /* done, or error */
1420 break;
1421 if (xread == origsize) {
1422 origsize += sizeinc;
1423 sizeinc = 2*sizeinc; /* exponential increase */
1424 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1427 if (hr != S_OK)
1428 TRACE("hr in no-stat loader case is %08x\n", hr);
1429 TRACE("loaded %d bytes.\n", xread);
1430 This->datalen = xread;
1431 This->data = xbuf;
1432 } else {
1433 This->datalen = toread+(headerisdata?8:0);
1434 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1435 if (!xbuf)
1436 return E_OUTOFMEMORY;
1438 if (headerisdata)
1439 memcpy (xbuf, header, 8);
1441 while (xread < This->datalen) {
1442 ULONG nread;
1443 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1444 xread += nread;
1445 if (hr != S_OK || !nread)
1446 break;
1448 if (xread != This->datalen)
1449 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1451 if (This->datalen == 0) { /* Marks the "NONE" picture */
1452 This->desc.picType = PICTYPE_NONE;
1453 return S_OK;
1457 /****************************************************************************************
1458 * Part 2: Process the loaded data
1461 magic = xbuf[0] + (xbuf[1]<<8);
1462 This->loadtime_format = magic;
1464 switch (magic) {
1465 case BITMAP_FORMAT_GIF: /* GIF */
1466 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1467 break;
1468 case BITMAP_FORMAT_JPEG: /* JPEG */
1469 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1470 break;
1471 case BITMAP_FORMAT_BMP: /* Bitmap */
1472 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1473 break;
1474 case BITMAP_FORMAT_PNG: /* PNG */
1475 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1476 break;
1477 case BITMAP_FORMAT_APM: /* APM */
1478 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1479 break;
1480 case 0x0000: { /* ICON , first word is dwReserved */
1481 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1482 break;
1484 default:
1486 unsigned int i;
1488 /* let's see if it's a EMF */
1489 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1490 if (hr == S_OK) break;
1492 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1493 hr=E_FAIL;
1494 for (i=0;i<xread+8;i++) {
1495 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1496 else MESSAGE("%02x ",xbuf[i-8]);
1497 if (i % 10 == 9) MESSAGE("\n");
1499 MESSAGE("\n");
1500 break;
1503 This->bIsDirty = FALSE;
1505 /* FIXME: this notify is not really documented */
1506 if (hr==S_OK)
1507 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1508 return hr;
1511 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1513 int iSuccess = 0;
1514 HDC hDC;
1515 BITMAPINFO * pInfoBitmap;
1516 int iNumPaletteEntries;
1517 unsigned char * pPixelData;
1518 BITMAPFILEHEADER * pFileHeader;
1519 BITMAPINFO * pInfoHeader;
1521 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1522 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1524 /* Find out bitmap size and padded length */
1525 hDC = GetDC(0);
1526 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1527 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1529 /* Fetch bitmap palette & pixel data */
1531 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1532 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1534 /* Calculate the total length required for the BMP data */
1535 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1536 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1537 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1538 } else {
1539 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1540 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1541 else
1542 iNumPaletteEntries = 0;
1544 *pLength =
1545 sizeof(BITMAPFILEHEADER) +
1546 sizeof(BITMAPINFOHEADER) +
1547 iNumPaletteEntries * sizeof(RGBQUAD) +
1548 pInfoBitmap->bmiHeader.biSizeImage;
1549 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1551 /* Fill the BITMAPFILEHEADER */
1552 pFileHeader = *ppBuffer;
1553 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1554 pFileHeader->bfSize = *pLength;
1555 pFileHeader->bfOffBits =
1556 sizeof(BITMAPFILEHEADER) +
1557 sizeof(BITMAPINFOHEADER) +
1558 iNumPaletteEntries * sizeof(RGBQUAD);
1560 /* Fill the BITMAPINFOHEADER and the palette data */
1561 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1562 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1563 memcpy(
1564 (unsigned char *)(*ppBuffer) +
1565 sizeof(BITMAPFILEHEADER) +
1566 sizeof(BITMAPINFOHEADER) +
1567 iNumPaletteEntries * sizeof(RGBQUAD),
1568 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1569 iSuccess = 1;
1571 HeapFree(GetProcessHeap(), 0, pPixelData);
1572 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1573 return iSuccess;
1576 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1578 ICONINFO infoIcon;
1579 int iSuccess = 0;
1581 *ppBuffer = NULL; *pLength = 0;
1582 if (GetIconInfo(hIcon, &infoIcon)) {
1583 HDC hDC;
1584 BITMAPINFO * pInfoBitmap;
1585 unsigned char * pIconData = NULL;
1586 unsigned int iDataSize = 0;
1588 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1590 /* Find out icon size */
1591 hDC = GetDC(0);
1592 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1593 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1594 if (1) {
1595 /* Auxiliary pointers */
1596 CURSORICONFILEDIR * pIconDir;
1597 CURSORICONFILEDIRENTRY * pIconEntry;
1598 BITMAPINFOHEADER * pIconBitmapHeader;
1599 unsigned int iOffsetPalette;
1600 unsigned int iOffsetColorData;
1601 unsigned int iOffsetMaskData;
1603 unsigned int iLengthScanLineMask;
1604 unsigned int iNumEntriesPalette;
1606 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1608 FIXME("DEBUG: bitmap size is %d x %d\n",
1609 pInfoBitmap->bmiHeader.biWidth,
1610 pInfoBitmap->bmiHeader.biHeight);
1611 FIXME("DEBUG: bitmap bpp is %d\n",
1612 pInfoBitmap->bmiHeader.biBitCount);
1613 FIXME("DEBUG: bitmap nplanes is %d\n",
1614 pInfoBitmap->bmiHeader.biPlanes);
1615 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1616 pInfoBitmap->bmiHeader.biSizeImage);
1618 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1619 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1620 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1622 /* Fill out the CURSORICONFILEDIR */
1623 pIconDir = (CURSORICONFILEDIR *)pIconData;
1624 pIconDir->idType = 1;
1625 pIconDir->idCount = 1;
1627 /* Fill out the CURSORICONFILEDIRENTRY */
1628 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1629 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1630 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1631 pIconEntry->bColorCount =
1632 (pInfoBitmap->bmiHeader.biBitCount < 8)
1633 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1634 : 0;
1635 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1636 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1637 pIconEntry->dwDIBSize = 0;
1638 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1640 /* Fill out the BITMAPINFOHEADER */
1641 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1642 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1644 /* Find out whether a palette exists for the bitmap */
1645 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1646 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1647 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1648 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1649 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1650 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1651 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1652 iNumEntriesPalette = 3;
1653 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1654 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1655 } else {
1656 iNumEntriesPalette = 0;
1659 /* Add bitmap size and header size to icon data size. */
1660 iOffsetPalette = iDataSize;
1661 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1662 iOffsetColorData = iDataSize;
1663 iDataSize += pIconBitmapHeader->biSizeImage;
1664 iOffsetMaskData = iDataSize;
1665 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1666 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1667 pIconBitmapHeader->biHeight *= 2;
1668 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1669 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1670 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1671 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1673 /* Get the actual bitmap data from the icon bitmap */
1674 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1675 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1676 if (iNumEntriesPalette > 0) {
1677 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1678 iNumEntriesPalette * sizeof(RGBQUAD));
1681 /* Reset all values so that GetDIBits call succeeds */
1682 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1683 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1684 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1686 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1687 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1688 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1690 printf("ERROR: unable to get bitmap mask (error %u)\n",
1691 GetLastError());
1695 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1696 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1698 /* Write out everything produced so far to the stream */
1699 *ppBuffer = pIconData; *pLength = iDataSize;
1700 iSuccess = 1;
1701 } else {
1703 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1704 GetLastError());
1708 Remarks (from MSDN entry on GetIconInfo):
1710 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1711 members of ICONINFO. The calling application must manage
1712 these bitmaps and delete them when they are no longer
1713 necessary.
1715 if (hDC) ReleaseDC(0, hDC);
1716 DeleteObject(infoIcon.hbmMask);
1717 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1718 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1719 } else {
1720 printf("ERROR: Unable to get icon information (error %u)\n",
1721 GetLastError());
1723 return iSuccess;
1726 static HRESULT WINAPI OLEPictureImpl_Save(
1727 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1729 HRESULT hResult = E_NOTIMPL;
1730 void * pIconData;
1731 unsigned int iDataSize;
1732 ULONG dummy;
1733 int iSerializeResult = 0;
1734 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1736 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1738 switch (This->desc.picType) {
1739 case PICTYPE_ICON:
1740 if (This->bIsDirty || !This->data) {
1741 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1742 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1743 hResult = E_FAIL;
1744 break;
1746 HeapFree(GetProcessHeap(), 0, This->data);
1747 This->data = pIconData;
1748 This->datalen = iDataSize;
1750 if (This->loadtime_magic != 0xdeadbeef) {
1751 DWORD header[2];
1753 header[0] = This->loadtime_magic;
1754 header[1] = This->datalen;
1755 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1757 IStream_Write(pStm, This->data, This->datalen, &dummy);
1759 hResult = S_OK;
1760 break;
1761 case PICTYPE_BITMAP:
1762 if (This->bIsDirty) {
1763 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1764 case BITMAP_FORMAT_BMP:
1765 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1766 break;
1767 case BITMAP_FORMAT_JPEG:
1768 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1769 break;
1770 case BITMAP_FORMAT_GIF:
1771 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1772 break;
1773 case BITMAP_FORMAT_PNG:
1774 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1775 break;
1776 default:
1777 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1778 break;
1780 if (iSerializeResult) {
1782 if (This->loadtime_magic != 0xdeadbeef) {
1784 if (1) {
1785 DWORD header[2];
1787 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1788 header[1] = iDataSize;
1789 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1791 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1793 HeapFree(GetProcessHeap(), 0, This->data);
1794 This->data = pIconData;
1795 This->datalen = iDataSize;
1796 hResult = S_OK;
1798 } else {
1800 if (This->loadtime_magic != 0xdeadbeef) {
1802 if (1) {
1803 DWORD header[2];
1805 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1806 header[1] = This->datalen;
1807 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1809 IStream_Write(pStm, This->data, This->datalen, &dummy);
1810 hResult = S_OK;
1812 break;
1813 case PICTYPE_METAFILE:
1814 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1815 break;
1816 case PICTYPE_ENHMETAFILE:
1817 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1818 break;
1819 default:
1820 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1821 break;
1823 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1824 return hResult;
1827 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1828 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1830 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1831 FIXME("(%p,%p),stub!\n",This,pcbSize);
1832 return E_NOTIMPL;
1836 /************************************************************************
1837 * IDispatch
1840 /************************************************************************
1841 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1843 * See Windows documentation for more details on IUnknown methods.
1845 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1846 IDispatch* iface,
1847 REFIID riid,
1848 VOID** ppvoid)
1850 OLEPictureImpl *This = impl_from_IDispatch(iface);
1852 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1855 /************************************************************************
1856 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1858 * See Windows documentation for more details on IUnknown methods.
1860 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1861 IDispatch* iface)
1863 OLEPictureImpl *This = impl_from_IDispatch(iface);
1865 return IPicture_AddRef(&This->IPicture_iface);
1868 /************************************************************************
1869 * OLEPictureImpl_IDispatch_Release (IUnknown)
1871 * See Windows documentation for more details on IUnknown methods.
1873 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1874 IDispatch* iface)
1876 OLEPictureImpl *This = impl_from_IDispatch(iface);
1878 return IPicture_Release(&This->IPicture_iface);
1881 /************************************************************************
1882 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1884 * See Windows documentation for more details on IDispatch methods.
1886 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1887 IDispatch* iface,
1888 unsigned int* pctinfo)
1890 TRACE("(%p)\n", pctinfo);
1892 *pctinfo = 1;
1894 return S_OK;
1897 /************************************************************************
1898 * OLEPictureImpl_GetTypeInfo (IDispatch)
1900 * See Windows documentation for more details on IDispatch methods.
1902 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1903 IDispatch* iface,
1904 UINT iTInfo,
1905 LCID lcid,
1906 ITypeInfo** ppTInfo)
1908 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1909 ITypeLib *tl;
1910 HRESULT hres;
1912 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1914 if (iTInfo != 0)
1915 return E_FAIL;
1917 hres = LoadTypeLib(stdole2tlb, &tl);
1918 if (FAILED(hres))
1920 ERR("Could not load stdole2.tlb\n");
1921 return hres;
1924 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1925 if (FAILED(hres))
1926 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1928 return hres;
1931 /************************************************************************
1932 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1934 * See Windows documentation for more details on IDispatch methods.
1936 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1937 IDispatch* iface,
1938 REFIID riid,
1939 LPOLESTR* rgszNames,
1940 UINT cNames,
1941 LCID lcid,
1942 DISPID* rgDispId)
1944 ITypeInfo * pTInfo;
1945 HRESULT hres;
1947 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1948 rgszNames, cNames, (int)lcid, rgDispId);
1950 if (cNames == 0)
1952 return E_INVALIDARG;
1954 else
1956 /* retrieve type information */
1957 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1959 if (FAILED(hres))
1961 ERR("GetTypeInfo failed.\n");
1962 return hres;
1965 /* convert names to DISPIDs */
1966 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1967 ITypeInfo_Release(pTInfo);
1969 return hres;
1973 /************************************************************************
1974 * OLEPictureImpl_Invoke (IDispatch)
1976 * See Windows documentation for more details on IDispatch methods.
1978 static HRESULT WINAPI OLEPictureImpl_Invoke(
1979 IDispatch* iface,
1980 DISPID dispIdMember,
1981 REFIID riid,
1982 LCID lcid,
1983 WORD wFlags,
1984 DISPPARAMS* pDispParams,
1985 VARIANT* pVarResult,
1986 EXCEPINFO* pExepInfo,
1987 UINT* puArgErr)
1989 OLEPictureImpl *This = impl_from_IDispatch(iface);
1991 /* validate parameters */
1993 if (!IsEqualIID(riid, &IID_NULL))
1995 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
1996 return DISP_E_UNKNOWNNAME;
1999 if (!pDispParams)
2001 ERR("null pDispParams not allowed\n");
2002 return DISP_E_PARAMNOTOPTIONAL;
2005 if (wFlags & DISPATCH_PROPERTYGET)
2007 if (pDispParams->cArgs != 0)
2009 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2010 return DISP_E_BADPARAMCOUNT;
2012 if (!pVarResult)
2014 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2015 return DISP_E_PARAMNOTOPTIONAL;
2018 else if (wFlags & DISPATCH_PROPERTYPUT)
2020 if (pDispParams->cArgs != 1)
2022 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2023 return DISP_E_BADPARAMCOUNT;
2027 switch (dispIdMember)
2029 case DISPID_PICT_HANDLE:
2030 if (wFlags & DISPATCH_PROPERTYGET)
2032 TRACE("DISPID_PICT_HANDLE\n");
2033 V_VT(pVarResult) = VT_I4;
2034 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2036 break;
2037 case DISPID_PICT_HPAL:
2038 if (wFlags & DISPATCH_PROPERTYGET)
2040 TRACE("DISPID_PICT_HPAL\n");
2041 V_VT(pVarResult) = VT_I4;
2042 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2044 else if (wFlags & DISPATCH_PROPERTYPUT)
2046 VARIANTARG vararg;
2047 HRESULT hr;
2048 TRACE("DISPID_PICT_HPAL\n");
2050 VariantInit(&vararg);
2051 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2052 if (FAILED(hr))
2053 return hr;
2055 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2057 VariantClear(&vararg);
2058 return hr;
2060 break;
2061 case DISPID_PICT_TYPE:
2062 if (wFlags & DISPATCH_PROPERTYGET)
2064 TRACE("DISPID_PICT_TYPE\n");
2065 V_VT(pVarResult) = VT_I2;
2066 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2068 break;
2069 case DISPID_PICT_WIDTH:
2070 if (wFlags & DISPATCH_PROPERTYGET)
2072 TRACE("DISPID_PICT_WIDTH\n");
2073 V_VT(pVarResult) = VT_I4;
2074 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2076 break;
2077 case DISPID_PICT_HEIGHT:
2078 if (wFlags & DISPATCH_PROPERTYGET)
2080 TRACE("DISPID_PICT_HEIGHT\n");
2081 V_VT(pVarResult) = VT_I4;
2082 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2084 break;
2087 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2088 return DISP_E_MEMBERNOTFOUND;
2092 static const IPictureVtbl OLEPictureImpl_VTable =
2094 OLEPictureImpl_QueryInterface,
2095 OLEPictureImpl_AddRef,
2096 OLEPictureImpl_Release,
2097 OLEPictureImpl_get_Handle,
2098 OLEPictureImpl_get_hPal,
2099 OLEPictureImpl_get_Type,
2100 OLEPictureImpl_get_Width,
2101 OLEPictureImpl_get_Height,
2102 OLEPictureImpl_Render,
2103 OLEPictureImpl_set_hPal,
2104 OLEPictureImpl_get_CurDC,
2105 OLEPictureImpl_SelectPicture,
2106 OLEPictureImpl_get_KeepOriginalFormat,
2107 OLEPictureImpl_put_KeepOriginalFormat,
2108 OLEPictureImpl_PictureChanged,
2109 OLEPictureImpl_SaveAsFile,
2110 OLEPictureImpl_get_Attributes
2113 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2115 OLEPictureImpl_IDispatch_QueryInterface,
2116 OLEPictureImpl_IDispatch_AddRef,
2117 OLEPictureImpl_IDispatch_Release,
2118 OLEPictureImpl_GetTypeInfoCount,
2119 OLEPictureImpl_GetTypeInfo,
2120 OLEPictureImpl_GetIDsOfNames,
2121 OLEPictureImpl_Invoke
2124 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2126 OLEPictureImpl_IPersistStream_QueryInterface,
2127 OLEPictureImpl_IPersistStream_AddRef,
2128 OLEPictureImpl_IPersistStream_Release,
2129 OLEPictureImpl_GetClassID,
2130 OLEPictureImpl_IsDirty,
2131 OLEPictureImpl_Load,
2132 OLEPictureImpl_Save,
2133 OLEPictureImpl_GetSizeMax
2136 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2138 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2139 OLEPictureImpl_IConnectionPointContainer_AddRef,
2140 OLEPictureImpl_IConnectionPointContainer_Release,
2141 OLEPictureImpl_EnumConnectionPoints,
2142 OLEPictureImpl_FindConnectionPoint
2145 /***********************************************************************
2146 * OleCreatePictureIndirect (OLEAUT32.419)
2148 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2149 BOOL Own, void **ppvObj )
2151 OLEPictureImpl* newPict;
2152 HRESULT hr;
2154 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2156 *ppvObj = NULL;
2158 newPict = OLEPictureImpl_Construct(lpPictDesc, Own);
2160 if (newPict == NULL)
2161 return E_OUTOFMEMORY;
2164 * Make sure it supports the interface required by the caller.
2166 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2169 * Release the reference obtained in the constructor. If
2170 * the QueryInterface was unsuccessful, it will free the class.
2172 IPicture_Release(&newPict->IPicture_iface);
2174 return hr;
2178 /***********************************************************************
2179 * OleLoadPicture (OLEAUT32.418)
2181 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2182 REFIID riid, LPVOID *ppvObj )
2184 LPPERSISTSTREAM ps;
2185 IPicture *newpic;
2186 HRESULT hr;
2188 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2189 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2191 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2192 if (hr != S_OK)
2193 return hr;
2194 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2195 if (hr != S_OK) {
2196 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2197 IPicture_Release(newpic);
2198 *ppvObj = NULL;
2199 return hr;
2201 hr = IPersistStream_Load(ps,lpstream);
2202 IPersistStream_Release(ps);
2203 if (FAILED(hr))
2205 ERR("IPersistStream_Load failed\n");
2206 IPicture_Release(newpic);
2207 *ppvObj = NULL;
2208 return hr;
2210 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2211 if (hr != S_OK)
2212 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2213 IPicture_Release(newpic);
2214 return hr;
2217 /***********************************************************************
2218 * OleLoadPictureEx (OLEAUT32.401)
2220 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2221 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2223 LPPERSISTSTREAM ps;
2224 IPicture *newpic;
2225 HRESULT hr;
2227 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2228 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2230 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2231 if (hr != S_OK)
2232 return hr;
2233 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2234 if (hr != S_OK) {
2235 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2236 IPicture_Release(newpic);
2237 *ppvObj = NULL;
2238 return hr;
2240 hr = IPersistStream_Load(ps,lpstream);
2241 IPersistStream_Release(ps);
2242 if (FAILED(hr))
2244 ERR("IPersistStream_Load failed\n");
2245 IPicture_Release(newpic);
2246 *ppvObj = NULL;
2247 return hr;
2249 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2250 if (hr != S_OK)
2251 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2252 IPicture_Release(newpic);
2253 return hr;
2256 /***********************************************************************
2257 * OleLoadPicturePath (OLEAUT32.424)
2259 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2260 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2261 LPVOID *ppvRet )
2263 static const WCHAR file[] = { 'f','i','l','e',':',0 };
2264 IPicture *ipicture;
2265 HANDLE hFile;
2266 DWORD dwFileSize;
2267 HGLOBAL hGlobal = NULL;
2268 DWORD dwBytesRead = 0;
2269 IStream *stream;
2270 BOOL bRead;
2271 IPersistStream *pStream;
2272 HRESULT hRes;
2273 HRESULT init_res;
2274 WCHAR *file_candidate;
2275 WCHAR path_buf[MAX_PATH];
2277 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2278 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2279 debugstr_guid(riid), ppvRet);
2281 if (!szURLorPath || !ppvRet)
2282 return E_INVALIDARG;
2284 *ppvRet = NULL;
2286 /* Convert file URLs to DOS paths. */
2287 if (strncmpW(szURLorPath, file, 5) == 0) {
2288 DWORD size;
2289 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2290 sizeof(path_buf)/sizeof(WCHAR), &size, 0);
2291 if (FAILED(hRes))
2292 return hRes;
2294 file_candidate = path_buf;
2296 else
2297 file_candidate = szURLorPath;
2299 /* Handle candidate DOS paths separately. */
2300 if (file_candidate[1] == ':') {
2301 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2302 0, NULL);
2303 if (hFile == INVALID_HANDLE_VALUE)
2304 return INET_E_RESOURCE_NOT_FOUND;
2306 dwFileSize = GetFileSize(hFile, NULL);
2307 if (dwFileSize != INVALID_FILE_SIZE )
2309 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2310 if ( hGlobal)
2312 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2313 if (!bRead)
2315 GlobalFree(hGlobal);
2316 hGlobal = 0;
2320 CloseHandle(hFile);
2322 if (!hGlobal)
2323 return INET_E_RESOURCE_NOT_FOUND;
2325 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2326 if (FAILED(hRes))
2328 GlobalFree(hGlobal);
2329 return hRes;
2331 } else {
2332 IMoniker *pmnk;
2333 IBindCtx *pbc;
2335 hRes = CreateBindCtx(0, &pbc);
2336 if (SUCCEEDED(hRes))
2338 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2339 if (SUCCEEDED(hRes))
2341 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2342 IMoniker_Release(pmnk);
2344 IBindCtx_Release(pbc);
2346 if (FAILED(hRes))
2347 return hRes;
2350 init_res = CoInitialize(NULL);
2352 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2353 &IID_IPicture, (LPVOID*)&ipicture);
2354 if (SUCCEEDED(hRes)) {
2355 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2357 if (SUCCEEDED(hRes)) {
2358 hRes = IPersistStream_Load(pStream, stream);
2360 if (SUCCEEDED(hRes)) {
2361 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2363 if (FAILED(hRes))
2364 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2366 IPersistStream_Release(pStream);
2368 IPicture_Release(ipicture);
2371 IStream_Release(stream);
2373 if (SUCCEEDED(init_res))
2374 CoUninitialize();
2376 return hRes;
2379 /*******************************************************************************
2380 * StdPic ClassFactory
2382 typedef struct
2384 /* IUnknown fields */
2385 IClassFactory IClassFactory_iface;
2386 LONG ref;
2387 } IClassFactoryImpl;
2389 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2391 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2394 static HRESULT WINAPI
2395 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2396 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2398 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2399 return E_NOINTERFACE;
2402 static ULONG WINAPI
2403 SPCF_AddRef(LPCLASSFACTORY iface) {
2404 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2405 return InterlockedIncrement(&This->ref);
2408 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2409 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2410 /* static class, won't be freed */
2411 return InterlockedDecrement(&This->ref);
2414 static HRESULT WINAPI SPCF_CreateInstance(
2415 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2417 /* Creates an uninitialized picture */
2418 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2422 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2423 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2424 FIXME("(%p)->(%d),stub!\n",This,dolock);
2425 return S_OK;
2428 static const IClassFactoryVtbl SPCF_Vtbl = {
2429 SPCF_QueryInterface,
2430 SPCF_AddRef,
2431 SPCF_Release,
2432 SPCF_CreateInstance,
2433 SPCF_LockServer
2435 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2437 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }