ieframe: Store ShellBrowser in DocHost instead of creating it on every QueryService...
[wine] / dlls / oleaut32 / olepicture.c
1 /*
2  * OLE Picture object
3  *
4  * Implementation of OLE IPicture and related interfaces
5  *
6  * Copyright 2000 Huw D M Davies for CodeWeavers.
7  * Copyright 2001 Marcus Meissner
8  * Copyright 2008 Kirill K. Smirnov
9  *
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.
14  *
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.
19  *
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
23  *
24  * BUGS
25  *
26  * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
27  * Lots of methods are just stubs.
28  *
29  *
30  * NOTES (or things that msdn doesn't tell you)
31  *
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).
36  *
37  */
38
39 #include "config.h"
40 #include "wine/port.h"
41
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <string.h>
48
49 #define COBJMACROS
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
52
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"
68
69 WINE_DEFAULT_DEBUG_CHANNEL(ole);
70
71 #include "pshpack1.h"
72
73 /* Header for Aldus Placable Metafiles - a standard metafile follows */
74 typedef struct _APM_HEADER
75 {
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;
86
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;
97
98 typedef struct
99 {
100     WORD                idReserved;
101     WORD                idType;
102     WORD                idCount;
103     CURSORICONFILEDIRENTRY  idEntries[1];
104 } CURSORICONFILEDIR;
105
106 #include "poppack.h"
107
108 /*************************************************************************
109  *  Declaration of implementation class
110  */
111
112 typedef struct OLEPictureImpl {
113
114   /*
115    * IPicture handles IUnknown
116    */
117
118     IPicture                  IPicture_iface;
119     IDispatch                 IDispatch_iface;
120     IPersistStream            IPersistStream_iface;
121     IConnectionPointContainer IConnectionPointContainer_iface;
122
123   /* Object reference count */
124     LONG ref;
125
126   /* We own the object and must destroy it ourselves */
127     BOOL fOwn;
128
129   /* Picture description */
130     PICTDESC desc;
131
132   /* These are the pixel size of a bitmap */
133     DWORD origWidth;
134     DWORD origHeight;
135
136   /* And these are the size of the picture converted into HIMETRIC units */
137     OLE_XSIZE_HIMETRIC himetricWidth;
138     OLE_YSIZE_HIMETRIC himetricHeight;
139
140     IConnectionPoint *pCP;
141
142     BOOL keepOrigFormat;
143     HDC hDCCur;
144
145   /* Bitmap transparency mask */
146     HBITMAP hbmMask;
147     HBITMAP hbmXor;
148     COLORREF rgbTrans;
149
150   /* data */
151     void* data;
152     int datalen;
153     BOOL bIsDirty;                  /* Set to TRUE if picture has changed */
154     unsigned int loadtime_magic;    /* If a length header was found, saves value */
155     unsigned int loadtime_format;   /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
156 } OLEPictureImpl;
157
158 static inline OLEPictureImpl *impl_from_IPicture(IPicture *iface)
159 {
160     return CONTAINING_RECORD(iface, OLEPictureImpl, IPicture_iface);
161 }
162
163 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
164 {
165     return CONTAINING_RECORD(iface, OLEPictureImpl, IDispatch_iface);
166 }
167
168 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
169 {
170     return CONTAINING_RECORD(iface, OLEPictureImpl, IPersistStream_iface);
171 }
172
173 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
174 {
175     return CONTAINING_RECORD(iface, OLEPictureImpl, IConnectionPointContainer_iface);
176 }
177
178 /*
179  * Predeclare VTables.  They get initialized at the end.
180  */
181 static const IPictureVtbl OLEPictureImpl_VTable;
182 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
183 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
184 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
185
186 /* pixels to HIMETRIC units conversion */
187 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
188 {
189     return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
190 }
191
192 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
193 {
194     return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
195 }
196
197 /***********************************************************************
198  * Implementation of the OLEPictureImpl class.
199  */
200
201 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
202 {
203   BITMAP bm;
204   HDC hdcRef;
205
206   TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
207   if(GetObjectW(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
208     ERR("GetObject fails\n");
209     return;
210   }
211   This->origWidth = bm.bmWidth;
212   This->origHeight = bm.bmHeight;
213
214   /* The width and height are stored in HIMETRIC units (0.01 mm),
215      so we take our pixel width divide by pixels per inch and
216      multiply by 25.4 * 100 */
217   /* Should we use GetBitmapDimension if available? */
218   hdcRef = CreateCompatibleDC(0);
219
220   This->himetricWidth  = xpixels_to_himetric(bm.bmWidth, hdcRef);
221   This->himetricHeight = ypixels_to_himetric(bm.bmHeight, hdcRef);
222
223   DeleteDC(hdcRef);
224 }
225
226 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
227 {
228     ICONINFO infoIcon;
229
230     TRACE("icon handle %p\n", This->desc.u.icon.hicon);
231     if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
232         HDC hdcRef;
233         BITMAP bm;
234
235         TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
236         if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
237             ERR("GetObject fails on icon bitmap\n");
238             return;
239         }
240
241         This->origWidth = bm.bmWidth;
242         This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
243         /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
244         hdcRef = GetDC(0);
245
246         This->himetricWidth  = xpixels_to_himetric(This->origWidth, hdcRef);
247         This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
248
249         ReleaseDC(0, hdcRef);
250
251         DeleteObject(infoIcon.hbmMask);
252         if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
253     } else {
254         ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
255     }
256 }
257
258 /************************************************************************
259  * OLEPictureImpl_Construct
260  *
261  * This method will construct a new instance of the OLEPictureImpl
262  * class.
263  *
264  * The caller of this method must release the object when it's
265  * done with it.
266  */
267 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
268 {
269   OLEPictureImpl* newObject = 0;
270
271   if (pictDesc)
272       TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
273
274   /*
275    * Allocate space for the object.
276    */
277   newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
278
279   if (newObject==0)
280     return newObject;
281
282   /*
283    * Initialize the virtual function table.
284    */
285   newObject->IPicture_iface.lpVtbl = &OLEPictureImpl_VTable;
286   newObject->IDispatch_iface.lpVtbl = &OLEPictureImpl_IDispatch_VTable;
287   newObject->IPersistStream_iface.lpVtbl = &OLEPictureImpl_IPersistStream_VTable;
288   newObject->IConnectionPointContainer_iface.lpVtbl = &OLEPictureImpl_IConnectionPointContainer_VTable;
289
290   newObject->pCP = NULL;
291   CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
292   if (!newObject->pCP)
293   {
294     HeapFree(GetProcessHeap(), 0, newObject);
295     return NULL;
296   }
297
298   /*
299    * Start with one reference count. The caller of this function
300    * must release the interface pointer when it is done.
301    */
302   newObject->ref        = 1;
303   newObject->hDCCur     = 0;
304
305   newObject->fOwn       = fOwn;
306
307   /* dunno about original value */
308   newObject->keepOrigFormat = TRUE;
309
310   newObject->hbmMask = NULL;
311   newObject->hbmXor = NULL;
312   newObject->loadtime_magic = 0xdeadbeef;
313   newObject->loadtime_format = 0;
314   newObject->bIsDirty = FALSE;
315
316   if (pictDesc) {
317       newObject->desc = *pictDesc;
318
319       switch(pictDesc->picType) {
320       case PICTYPE_BITMAP:
321         OLEPictureImpl_SetBitmap(newObject);
322         break;
323
324       case PICTYPE_METAFILE:
325         TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
326         newObject->himetricWidth = pictDesc->u.wmf.xExt;
327         newObject->himetricHeight = pictDesc->u.wmf.yExt;
328         break;
329
330       case PICTYPE_NONE:
331         /* not sure what to do here */
332         newObject->himetricWidth = newObject->himetricHeight = 0;
333         break;
334
335       case PICTYPE_ICON:
336         OLEPictureImpl_SetIcon(newObject);
337         break;
338       case PICTYPE_ENHMETAFILE:
339       default:
340         FIXME("Unsupported type %d\n", pictDesc->picType);
341         newObject->himetricWidth = newObject->himetricHeight = 0;
342         break;
343       }
344   } else {
345       newObject->desc.picType = PICTYPE_UNINITIALIZED;
346   }
347
348   TRACE("returning %p\n", newObject);
349   return newObject;
350 }
351
352 /************************************************************************
353  * OLEPictureImpl_Destroy
354  *
355  * This method is called by the Release method when the reference
356  * count goes down to 0. It will free all resources used by
357  * this object.  */
358 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
359 {
360   TRACE("(%p)\n", Obj);
361
362   if (Obj->pCP)
363     IConnectionPoint_Release(Obj->pCP);
364
365   if(Obj->fOwn) { /* We need to destroy the picture */
366     switch(Obj->desc.picType) {
367     case PICTYPE_BITMAP:
368       DeleteObject(Obj->desc.u.bmp.hbitmap);
369       if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
370       if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
371       break;
372     case PICTYPE_METAFILE:
373       DeleteMetaFile(Obj->desc.u.wmf.hmeta);
374       break;
375     case PICTYPE_ICON:
376       DestroyIcon(Obj->desc.u.icon.hicon);
377       break;
378     case PICTYPE_ENHMETAFILE:
379       DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
380       break;
381     case PICTYPE_NONE:
382     case PICTYPE_UNINITIALIZED:
383       /* Nothing to do */
384       break;
385     default:
386       FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
387       break;
388     }
389   }
390   HeapFree(GetProcessHeap(), 0, Obj->data);
391   HeapFree(GetProcessHeap(), 0, Obj);
392 }
393
394
395 /************************************************************************
396  * OLEPictureImpl_AddRef (IUnknown)
397  *
398  * See Windows documentation for more details on IUnknown methods.
399  */
400 static ULONG WINAPI OLEPictureImpl_AddRef(
401   IPicture* iface)
402 {
403   OLEPictureImpl *This = impl_from_IPicture(iface);
404   ULONG refCount = InterlockedIncrement(&This->ref);
405
406   TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
407
408   return refCount;
409 }
410
411 /************************************************************************
412  * OLEPictureImpl_Release (IUnknown)
413  *
414  * See Windows documentation for more details on IUnknown methods.
415  */
416 static ULONG WINAPI OLEPictureImpl_Release(
417       IPicture* iface)
418 {
419   OLEPictureImpl *This = impl_from_IPicture(iface);
420   ULONG refCount = InterlockedDecrement(&This->ref);
421
422   TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
423
424   /*
425    * If the reference count goes down to 0, perform suicide.
426    */
427   if (!refCount) OLEPictureImpl_Destroy(This);
428
429   return refCount;
430 }
431
432 /************************************************************************
433  * OLEPictureImpl_QueryInterface (IUnknown)
434  *
435  * See Windows documentation for more details on IUnknown methods.
436  */
437 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
438   IPicture*  iface,
439   REFIID  riid,
440   void**  ppvObject)
441 {
442   OLEPictureImpl *This = impl_from_IPicture(iface);
443
444   TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
445
446   if (!ppvObject)
447     return E_INVALIDARG;
448
449   *ppvObject = 0;
450
451   if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
452     *ppvObject = This;
453   else if (IsEqualIID(&IID_IDispatch, riid))
454     *ppvObject = &This->IDispatch_iface;
455   else if (IsEqualIID(&IID_IPictureDisp, riid))
456     *ppvObject = &This->IDispatch_iface;
457   else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
458     *ppvObject = &This->IPersistStream_iface;
459   else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
460     *ppvObject = &This->IConnectionPointContainer_iface;
461
462   if (!*ppvObject)
463   {
464     FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
465     return E_NOINTERFACE;
466   }
467
468   IPicture_AddRef(iface);
469
470   return S_OK;
471 }
472
473 /***********************************************************************
474  *    OLEPicture_SendNotify (internal)
475  *
476  * Sends notification messages of changed properties to any interested
477  * connections.
478  */
479 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
480 {
481   IEnumConnections *pEnum;
482   CONNECTDATA CD;
483
484   if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
485       return;
486   while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
487     IPropertyNotifySink *sink;
488
489     IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
490     IPropertyNotifySink_OnChanged(sink, dispID);
491     IPropertyNotifySink_Release(sink);
492     IUnknown_Release(CD.pUnk);
493   }
494   IEnumConnections_Release(pEnum);
495 }
496
497 /************************************************************************
498  * OLEPictureImpl_get_Handle
499  */
500 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
501                                                 OLE_HANDLE *phandle)
502 {
503   OLEPictureImpl *This = impl_from_IPicture(iface);
504   TRACE("(%p)->(%p)\n", This, phandle);
505
506   if(!phandle)
507     return E_POINTER;
508
509   switch(This->desc.picType) {
510   case PICTYPE_NONE:
511   case PICTYPE_UNINITIALIZED:
512     *phandle = 0;
513     break;
514   case PICTYPE_BITMAP:
515     *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
516     break;
517   case PICTYPE_METAFILE:
518     *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
519     break;
520   case PICTYPE_ICON:
521     *phandle = HandleToUlong(This->desc.u.icon.hicon);
522     break;
523   case PICTYPE_ENHMETAFILE:
524     *phandle = HandleToUlong(This->desc.u.emf.hemf);
525     break;
526   default:
527     FIXME("Unimplemented type %d\n", This->desc.picType);
528     return E_NOTIMPL;
529   }
530   TRACE("returning handle %08x\n", *phandle);
531   return S_OK;
532 }
533
534 /************************************************************************
535  * OLEPictureImpl_get_hPal
536  */
537 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
538                                               OLE_HANDLE *phandle)
539 {
540   OLEPictureImpl *This = impl_from_IPicture(iface);
541   HRESULT hres;
542   TRACE("(%p)->(%p)\n", This, phandle);
543
544   if (!phandle)
545     return E_POINTER;
546
547   switch (This->desc.picType) {
548     case (UINT)PICTYPE_UNINITIALIZED:
549     case PICTYPE_NONE:
550       *phandle = 0;
551       hres = S_FALSE;
552       break;
553     case PICTYPE_BITMAP:
554       *phandle = HandleToUlong(This->desc.u.bmp.hpal);
555       hres = S_OK;
556       break;
557     case PICTYPE_METAFILE:
558       hres = E_FAIL;
559       break;
560     case PICTYPE_ICON:
561     case PICTYPE_ENHMETAFILE:
562     default:
563       FIXME("unimplemented for type %d. Returning 0 palette.\n",
564            This->desc.picType);
565       *phandle = 0;
566       hres = S_OK;
567   }
568
569   TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
570   return hres;
571 }
572
573 /************************************************************************
574  * OLEPictureImpl_get_Type
575  */
576 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
577                                               short *ptype)
578 {
579   OLEPictureImpl *This = impl_from_IPicture(iface);
580   TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
581
582   if(!ptype)
583     return E_POINTER;
584
585   *ptype = This->desc.picType;
586   return S_OK;
587 }
588
589 /************************************************************************
590  * OLEPictureImpl_get_Width
591  */
592 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
593                                                OLE_XSIZE_HIMETRIC *pwidth)
594 {
595   OLEPictureImpl *This = impl_from_IPicture(iface);
596   TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
597   *pwidth = This->himetricWidth;
598   return S_OK;
599 }
600
601 /************************************************************************
602  * OLEPictureImpl_get_Height
603  */
604 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
605                                                 OLE_YSIZE_HIMETRIC *pheight)
606 {
607   OLEPictureImpl *This = impl_from_IPicture(iface);
608   TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
609   *pheight = This->himetricHeight;
610   return S_OK;
611 }
612
613 /************************************************************************
614  * OLEPictureImpl_Render
615  */
616 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
617                                             LONG x, LONG y, LONG cx, LONG cy,
618                                             OLE_XPOS_HIMETRIC xSrc,
619                                             OLE_YPOS_HIMETRIC ySrc,
620                                             OLE_XSIZE_HIMETRIC cxSrc,
621                                             OLE_YSIZE_HIMETRIC cySrc,
622                                             LPCRECT prcWBounds)
623 {
624   OLEPictureImpl *This = impl_from_IPicture(iface);
625   TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
626         This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
627   if(prcWBounds)
628     TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
629           prcWBounds->right, prcWBounds->bottom);
630
631   if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
632     return CTL_E_INVALIDPROPERTYVALUE;
633   }
634
635   /*
636    * While the documentation suggests this to be here (or after rendering?)
637    * it does cause an endless recursion in my sample app. -MM 20010804
638   OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
639    */
640
641   switch(This->desc.picType) {
642   case PICTYPE_UNINITIALIZED:
643   case PICTYPE_NONE:
644     /* nothing to do */
645     return S_OK;
646   case PICTYPE_BITMAP:
647     {
648       HBITMAP hbmpOld;
649       HDC hdcBmp;
650
651       /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
652          NB y-axis gets flipped */
653
654       hdcBmp = CreateCompatibleDC(0);
655       SetMapMode(hdcBmp, MM_ANISOTROPIC);
656       SetWindowOrgEx(hdcBmp, 0, 0, NULL);
657       SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
658       SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
659       SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
660
661       if (This->hbmMask) {
662           HDC hdcMask = CreateCompatibleDC(0);
663           HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
664
665           hbmpOld = SelectObject(hdcBmp, This->hbmXor);
666
667           SetMapMode(hdcMask, MM_ANISOTROPIC);
668           SetWindowOrgEx(hdcMask, 0, 0, NULL);
669           SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
670           SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
671           SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
672           
673           SetBkColor(hdc, RGB(255, 255, 255));    
674           SetTextColor(hdc, RGB(0, 0, 0));        
675           StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND); 
676           StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
677
678           SelectObject(hdcMask, hOldbm);
679           DeleteDC(hdcMask);
680       } else {
681           hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
682           StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
683       }
684
685       SelectObject(hdcBmp, hbmpOld);
686       DeleteDC(hdcBmp);
687     }
688     break;
689   case PICTYPE_ICON:
690     FIXME("Not quite correct implementation of rendering icons...\n");
691     DrawIconEx(hdc, x, y, This->desc.u.icon.hicon, cx, cy, 0, NULL, DI_NORMAL);
692     break;
693
694   case PICTYPE_METAFILE:
695   {
696     POINT prevOrg, prevWndOrg;
697     SIZE prevExt, prevWndExt;
698     int oldmode;
699
700     /* Render the WMF to the appropriate location by setting the
701        appropriate ratio between "device units" and "logical units" */
702     oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
703     /* For the "source rectangle" the y-axis must be inverted */
704     SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
705     SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
706     /* For the "destination rectangle" no inversion is necessary */
707     SetViewportOrgEx(hdc, x, y, &prevOrg);
708     SetViewportExtEx(hdc, cx, cy, &prevExt);
709
710     if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
711         ERR("PlayMetaFile failed!\n");
712
713     /* We're done, restore the DC to the previous settings for converting
714        logical units to device units */
715     SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
716     SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
717     SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
718     SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
719     SetMapMode(hdc, oldmode);
720     break;
721   }
722
723   case PICTYPE_ENHMETAFILE:
724   {
725     RECT rc = { x, y, x + cx, y + cy };
726     PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
727     break;
728   }
729
730   default:
731     FIXME("type %d not implemented\n", This->desc.picType);
732     return E_NOTIMPL;
733   }
734   return S_OK;
735 }
736
737 /************************************************************************
738  * OLEPictureImpl_set_hPal
739  */
740 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
741                                               OLE_HANDLE hpal)
742 {
743   OLEPictureImpl *This = impl_from_IPicture(iface);
744   FIXME("(%p)->(%08x): stub\n", This, hpal);
745   OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
746   return E_NOTIMPL;
747 }
748
749 /************************************************************************
750  * OLEPictureImpl_get_CurDC
751  */
752 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
753                                                HDC *phdc)
754 {
755   OLEPictureImpl *This = impl_from_IPicture(iface);
756   TRACE("(%p), returning %p\n", This, This->hDCCur);
757   if (phdc) *phdc = This->hDCCur;
758   return S_OK;
759 }
760
761 /************************************************************************
762  * OLEPictureImpl_SelectPicture
763  */
764 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
765                                                    HDC hdcIn,
766                                                    HDC *phdcOut,
767                                                    OLE_HANDLE *phbmpOut)
768 {
769   OLEPictureImpl *This = impl_from_IPicture(iface);
770   TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
771   if (This->desc.picType == PICTYPE_BITMAP) {
772       SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
773
774       if (phdcOut)
775           *phdcOut = This->hDCCur;
776       This->hDCCur = hdcIn;
777       if (phbmpOut)
778           *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
779       return S_OK;
780   } else {
781       FIXME("Don't know how to select picture type %d\n",This->desc.picType);
782       return E_FAIL;
783   }
784 }
785
786 /************************************************************************
787  * OLEPictureImpl_get_KeepOriginalFormat
788  */
789 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
790                                                             BOOL *pfKeep)
791 {
792   OLEPictureImpl *This = impl_from_IPicture(iface);
793   TRACE("(%p)->(%p)\n", This, pfKeep);
794   if (!pfKeep)
795       return E_POINTER;
796   *pfKeep = This->keepOrigFormat;
797   return S_OK;
798 }
799
800 /************************************************************************
801  * OLEPictureImpl_put_KeepOriginalFormat
802  */
803 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
804                                                             BOOL keep)
805 {
806   OLEPictureImpl *This = impl_from_IPicture(iface);
807   TRACE("(%p)->(%d)\n", This, keep);
808   This->keepOrigFormat = keep;
809   /* FIXME: what DISPID notification here? */
810   return S_OK;
811 }
812
813 /************************************************************************
814  * OLEPictureImpl_PictureChanged
815  */
816 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
817 {
818   OLEPictureImpl *This = impl_from_IPicture(iface);
819   TRACE("(%p)->()\n", This);
820   OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
821   This->bIsDirty = TRUE;
822   return S_OK;
823 }
824
825 /************************************************************************
826  * OLEPictureImpl_SaveAsFile
827  */
828 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
829                                                 IStream *pstream,
830                                                 BOOL SaveMemCopy,
831                                                 LONG *pcbSize)
832 {
833   OLEPictureImpl *This = impl_from_IPicture(iface);
834   FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
835   return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
836 }
837
838 /************************************************************************
839  * OLEPictureImpl_get_Attributes
840  */
841 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
842                                                     DWORD *pdwAttr)
843 {
844   OLEPictureImpl *This = impl_from_IPicture(iface);
845   TRACE("(%p)->(%p).\n", This, pdwAttr);
846
847   if(!pdwAttr)
848     return E_POINTER;
849
850   *pdwAttr = 0;
851   switch (This->desc.picType) {
852   case PICTYPE_UNINITIALIZED:
853   case PICTYPE_NONE: break;
854   case PICTYPE_BITMAP:  if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break;       /* not 'truly' scalable, see MSDN. */
855   case PICTYPE_ICON: *pdwAttr     = PICTURE_TRANSPARENT;break;
856   case PICTYPE_ENHMETAFILE: /* fall through */
857   case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
858   default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
859   }
860   return S_OK;
861 }
862
863
864 /************************************************************************
865  *    IConnectionPointContainer
866  */
867 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
868   IConnectionPointContainer* iface,
869   REFIID riid,
870   VOID** ppvoid)
871 {
872   OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
873
874   return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
875 }
876
877 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
878   IConnectionPointContainer* iface)
879 {
880   OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
881
882   return IPicture_AddRef(&This->IPicture_iface);
883 }
884
885 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
886   IConnectionPointContainer* iface)
887 {
888   OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
889
890   return IPicture_Release(&This->IPicture_iface);
891 }
892
893 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
894   IConnectionPointContainer* iface,
895   IEnumConnectionPoints** ppEnum)
896 {
897   OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
898
899   FIXME("(%p,%p), stub!\n",This,ppEnum);
900   return E_NOTIMPL;
901 }
902
903 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
904   IConnectionPointContainer* iface,
905   REFIID riid,
906   IConnectionPoint **ppCP)
907 {
908   OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
909   TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
910   if (!ppCP)
911       return E_POINTER;
912   *ppCP = NULL;
913   if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
914       return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
915   FIXME("no connection point for %s\n",debugstr_guid(riid));
916   return CONNECT_E_NOCONNECTION;
917 }
918
919
920 /************************************************************************
921  *    IPersistStream
922  */
923
924 /************************************************************************
925  * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
926  *
927  * See Windows documentation for more details on IUnknown methods.
928  */
929 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
930   IPersistStream* iface,
931   REFIID     riid,
932   VOID**     ppvoid)
933 {
934   OLEPictureImpl *This = impl_from_IPersistStream(iface);
935
936   return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
937 }
938
939 /************************************************************************
940  * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
941  *
942  * See Windows documentation for more details on IUnknown methods.
943  */
944 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
945   IPersistStream* iface)
946 {
947   OLEPictureImpl *This = impl_from_IPersistStream(iface);
948
949   return IPicture_AddRef(&This->IPicture_iface);
950 }
951
952 /************************************************************************
953  * OLEPictureImpl_IPersistStream_Release (IUnknown)
954  *
955  * See Windows documentation for more details on IUnknown methods.
956  */
957 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
958   IPersistStream* iface)
959 {
960   OLEPictureImpl *This = impl_from_IPersistStream(iface);
961
962   return IPicture_Release(&This->IPicture_iface);
963 }
964
965 /************************************************************************
966  * OLEPictureImpl_IPersistStream_GetClassID
967  */
968 static HRESULT WINAPI OLEPictureImpl_GetClassID(
969   IPersistStream* iface,CLSID* pClassID)
970 {
971   TRACE("(%p)\n", pClassID);
972   *pClassID = CLSID_StdPicture;
973   return S_OK;
974 }
975
976 /************************************************************************
977  * OLEPictureImpl_IPersistStream_IsDirty
978  */
979 static HRESULT WINAPI OLEPictureImpl_IsDirty(
980   IPersistStream* iface)
981 {
982   OLEPictureImpl *This = impl_from_IPersistStream(iface);
983   FIXME("(%p),stub!\n",This);
984   return E_NOTIMPL;
985 }
986
987 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
988 {
989     BITMAPFILEHEADER    *bfh = (BITMAPFILEHEADER*)xbuf;
990     BITMAPINFO          *bi = (BITMAPINFO*)(bfh+1);
991     HDC                 hdcref;
992
993     /* Does not matter whether this is a coreheader or not, we only use
994      * components which are in both
995      */
996     hdcref = GetDC(0);
997     This->desc.u.bmp.hbitmap = CreateDIBitmap(
998         hdcref,
999         &(bi->bmiHeader),
1000         CBM_INIT,
1001         xbuf+bfh->bfOffBits,
1002         bi,
1003        DIB_RGB_COLORS
1004     );
1005     ReleaseDC(0, hdcref);
1006     if (This->desc.u.bmp.hbitmap == 0)
1007         return E_FAIL;
1008     This->desc.picType = PICTYPE_BITMAP;
1009     OLEPictureImpl_SetBitmap(This);
1010     return S_OK;
1011 }
1012
1013 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1014 {
1015     HRESULT hr;
1016     BITMAPINFOHEADER bih;
1017     HDC hdcref;
1018     UINT width, height;
1019     UINT stride, buffersize;
1020     LPBYTE bits=NULL;
1021     WICRect rc;
1022     IWICBitmapSource *real_source;
1023     UINT x, y;
1024     COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1025     BOOL has_alpha=FALSE;
1026
1027     hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1028     if (FAILED(hr)) return hr;
1029
1030     hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1031     if (FAILED(hr)) goto end;
1032
1033     bih.biSize = sizeof(bih);
1034     bih.biWidth = width;
1035     bih.biHeight = -height;
1036     bih.biPlanes = 1;
1037     bih.biBitCount = 32;
1038     bih.biCompression = BI_RGB;
1039     bih.biSizeImage = 0;
1040     bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1041     bih.biYPelsPerMeter = 4085;
1042     bih.biClrUsed = 0;
1043     bih.biClrImportant = 0;
1044
1045     stride = 4 * width;
1046     buffersize = stride * height;
1047
1048     bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1049     if (!bits)
1050     {
1051         hr = E_OUTOFMEMORY;
1052         goto end;
1053     }
1054
1055     rc.X = 0;
1056     rc.Y = 0;
1057     rc.Width = width;
1058     rc.Height = height;
1059     hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1060     if (FAILED(hr))
1061         goto end;
1062
1063     hdcref = GetDC(0);
1064     This->desc.u.bmp.hbitmap = CreateDIBitmap(
1065         hdcref,
1066         &bih,
1067         CBM_INIT,
1068         bits,
1069         (BITMAPINFO*)&bih,
1070         DIB_RGB_COLORS);
1071
1072     if (This->desc.u.bmp.hbitmap == 0)
1073     {
1074         hr = E_FAIL;
1075         ReleaseDC(0, hdcref);
1076         goto end;
1077     }
1078
1079     This->desc.picType = PICTYPE_BITMAP;
1080     OLEPictureImpl_SetBitmap(This);
1081
1082     /* set transparent pixels to black, all others to white */
1083     for(y = 0; y < height; y++){
1084         for(x = 0; x < width; x++){
1085             DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1086             if((*pixel & 0x80000000) == 0)
1087             {
1088                 has_alpha = TRUE;
1089                 *pixel = black;
1090             }
1091             else
1092                 *pixel = white;
1093         }
1094     }
1095
1096     if (has_alpha)
1097     {
1098         HDC hdcBmp, hdcXor, hdcMask;
1099         HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1100
1101         This->hbmXor = CreateDIBitmap(
1102             hdcref,
1103             &bih,
1104             CBM_INIT,
1105             bits,
1106             (BITMAPINFO*)&bih,
1107             DIB_RGB_COLORS
1108         );
1109
1110         This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1111         hdcBmp = CreateCompatibleDC(NULL);
1112         hdcXor = CreateCompatibleDC(NULL);
1113         hdcMask = CreateCompatibleDC(NULL);
1114
1115         hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1116         hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1117         hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1118
1119         SetBkColor(hdcXor,black);
1120         BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1121         BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1122
1123         SelectObject(hdcBmp,hbmoldBmp);
1124         SelectObject(hdcXor,hbmoldXor);
1125         SelectObject(hdcMask,hbmoldMask);
1126
1127         DeleteDC(hdcBmp);
1128         DeleteDC(hdcXor);
1129         DeleteDC(hdcMask);
1130     }
1131
1132     ReleaseDC(0, hdcref);
1133
1134 end:
1135     HeapFree(GetProcessHeap(), 0, bits);
1136     IWICBitmapSource_Release(real_source);
1137     return hr;
1138 }
1139
1140 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1141 {
1142     HRESULT hr;
1143     IWICImagingFactory *factory;
1144     IWICBitmapDecoder *decoder;
1145     IWICBitmapFrameDecode *framedecode;
1146     HRESULT initresult;
1147     IWICStream *stream;
1148
1149     initresult = CoInitialize(NULL);
1150
1151     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1152         &IID_IWICImagingFactory, (void**)&factory);
1153     if (SUCCEEDED(hr)) /* created factory */
1154     {
1155         hr = IWICImagingFactory_CreateStream(factory, &stream);
1156         IWICImagingFactory_Release(factory);
1157     }
1158
1159     if (SUCCEEDED(hr)) /* created stream */
1160     {
1161         hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1162
1163         if (SUCCEEDED(hr)) /* initialized stream */
1164         {
1165             hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1166                 &IID_IWICBitmapDecoder, (void**)&decoder);
1167             if (SUCCEEDED(hr)) /* created decoder */
1168             {
1169                 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1170
1171                 if (SUCCEEDED(hr)) /* initialized decoder */
1172                     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1173
1174                 IWICBitmapDecoder_Release(decoder);
1175             }
1176         }
1177
1178         IWICStream_Release(stream);
1179     }
1180
1181     if (SUCCEEDED(hr)) /* got framedecode */
1182     {
1183         hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1184         IWICBitmapFrameDecode_Release(framedecode);
1185     }
1186
1187     if (SUCCEEDED(initresult)) CoUninitialize();
1188     return hr;
1189 }
1190
1191 /*****************************************************
1192 *   start of Icon-specific code
1193 */
1194
1195 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1196 {
1197     HICON hicon;
1198     CURSORICONFILEDIR   *cifd = (CURSORICONFILEDIR*)xbuf;
1199     HDC hdcRef;
1200     int i;
1201
1202     /*
1203     FIXME("icon.idReserved=%d\n",cifd->idReserved);
1204     FIXME("icon.idType=%d\n",cifd->idType);
1205     FIXME("icon.idCount=%d\n",cifd->idCount);
1206
1207     for (i=0;i<cifd->idCount;i++) {
1208         FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1209         FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1210         FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1211         FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1212         FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1213         FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1214         FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1215         FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1216     }
1217     */
1218     i=0;
1219     /* If we have more than one icon, try to find the best.
1220      * this currently means '32 pixel wide'.
1221      */
1222     if (cifd->idCount!=1) {
1223         for (i=0;i<cifd->idCount;i++) {
1224             if (cifd->idEntries[i].bWidth == 32)
1225                 break;
1226         }
1227         if (i==cifd->idCount) i=0;
1228     }
1229
1230     hicon = CreateIconFromResourceEx(
1231                 xbuf+cifd->idEntries[i].dwDIBOffset,
1232                 cifd->idEntries[i].dwDIBSize,
1233                 TRUE, /* is icon */
1234                 0x00030000,
1235                 cifd->idEntries[i].bWidth,
1236                 cifd->idEntries[i].bHeight,
1237                 0
1238     );
1239     if (!hicon) {
1240         ERR("CreateIcon failed.\n");
1241         return E_FAIL;
1242     } else {
1243         This->desc.picType = PICTYPE_ICON;
1244         This->desc.u.icon.hicon = hicon;
1245         This->origWidth = cifd->idEntries[i].bWidth;
1246         This->origHeight = cifd->idEntries[i].bHeight;
1247         hdcRef = CreateCompatibleDC(0);
1248         This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1249         This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1250         DeleteDC(hdcRef);
1251         return S_OK;
1252     }
1253 }
1254
1255 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1256                                               const BYTE *data, ULONG size)
1257 {
1258     HENHMETAFILE hemf;
1259     ENHMETAHEADER hdr;
1260
1261     hemf = SetEnhMetaFileBits(size, data);
1262     if (!hemf) return E_FAIL;
1263
1264     GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1265
1266     This->desc.picType = PICTYPE_ENHMETAFILE;
1267     This->desc.u.emf.hemf = hemf;
1268
1269     This->origWidth = 0;
1270     This->origHeight = 0;
1271     This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1272     This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1273
1274     return S_OK;
1275 }
1276
1277 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1278                                       const BYTE *data, ULONG size)
1279 {
1280     const APM_HEADER *header = (const APM_HEADER *)data;
1281     HMETAFILE hmf;
1282
1283     if (size < sizeof(APM_HEADER))
1284         return E_FAIL;
1285     if (header->key != 0x9ac6cdd7)
1286         return E_FAIL;
1287
1288     /* SetMetaFileBitsEx performs data check on its own */
1289     hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1290     if (!hmf) return E_FAIL;
1291
1292     This->desc.picType = PICTYPE_METAFILE;
1293     This->desc.u.wmf.hmeta = hmf;
1294     This->desc.u.wmf.xExt = 0;
1295     This->desc.u.wmf.yExt = 0;
1296
1297     This->origWidth = 0;
1298     This->origHeight = 0;
1299     This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1300     This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1301     return S_OK;
1302 }
1303
1304 /************************************************************************
1305  * BITMAP FORMAT FLAGS -
1306  *   Flags that differentiate between different types of bitmaps.
1307  */
1308
1309 #define BITMAP_FORMAT_BMP   0x4d42 /* "BM" */
1310 #define BITMAP_FORMAT_JPEG  0xd8ff
1311 #define BITMAP_FORMAT_GIF   0x4947
1312 #define BITMAP_FORMAT_PNG   0x5089
1313 #define BITMAP_FORMAT_APM   0xcdd7
1314
1315 /************************************************************************
1316  * OLEPictureImpl_IPersistStream_Load (IUnknown)
1317  *
1318  * Loads the binary data from the IStream. Starts at current position.
1319  * There appears to be an 2 DWORD header:
1320  *      DWORD magic;
1321  *      DWORD len;
1322  *
1323  * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1324  */
1325 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1326   HRESULT       hr;
1327   BOOL          headerisdata;
1328   BOOL          statfailed = FALSE;
1329   ULONG         xread, toread;
1330   ULONG         headerread;
1331   BYTE          *xbuf;
1332   DWORD         header[2];
1333   WORD          magic;
1334   STATSTG       statstg;
1335   OLEPictureImpl *This = impl_from_IPersistStream(iface);
1336   
1337   TRACE("(%p,%p)\n",This,pStm);
1338
1339   /****************************************************************************************
1340    * Part 1: Load the data
1341    */
1342   /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1343    * out whether we do.
1344    *
1345    * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1346    * compound file. This may explain most, if not all, of the cases of "no
1347    * header", and the header validation should take this into account.
1348    * At least in Visual Basic 6, resource streams, valid headers are
1349    *    header[0] == "lt\0\0",
1350    *    header[1] == length_of_stream.
1351    *
1352    * Also handle streams where we do not have a working "Stat" method by
1353    * reading all data until the end of the stream.
1354    */
1355   hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1356   if (hr != S_OK) {
1357       TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1358       statfailed = TRUE;
1359       /* we will read at least 8 byte ... just right below */
1360       statstg.cbSize.QuadPart = 8;
1361   }
1362
1363   toread = 0;
1364   headerread = 0;
1365   headerisdata = FALSE;
1366   do {
1367       hr = IStream_Read(pStm, header, 8, &xread);
1368       if (hr != S_OK || xread!=8) {
1369           ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1370           return (hr?hr:E_FAIL);
1371       }
1372       headerread += xread;
1373       xread = 0;
1374       
1375       if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1376           if (toread != 0 && toread != header[1]) 
1377               FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1378                   toread, header[1]);
1379           toread = header[1];
1380           if (toread == 0) break;
1381       } else {
1382           if (!memcmp(&(header[0]), "GIF8",     4) ||   /* GIF header */
1383               !memcmp(&(header[0]), "BM",       2) ||   /* BMP header */
1384               !memcmp(&(header[0]), "\xff\xd8", 2) ||   /* JPEG header */
1385               (header[0] == EMR_HEADER)            ||   /* EMF header */
1386               (header[1] > statstg.cbSize.QuadPart)||   /* invalid size */
1387               (header[1]==0)
1388           ) {/* Found start of bitmap data */
1389               headerisdata = TRUE;
1390               if (toread == 0) 
1391                   toread = statstg.cbSize.QuadPart-8;
1392               else toread -= 8;
1393               xread = 8;
1394           } else {
1395               FIXME("Unknown stream header magic: %08x\n", header[0]);
1396               toread = header[1];
1397           }
1398       }
1399   } while (!headerisdata);
1400
1401   if (statfailed) { /* we don't know the size ... read all we get */
1402       int sizeinc = 4096;
1403       int origsize = sizeinc;
1404       ULONG nread = 42;
1405
1406       TRACE("Reading all data from stream.\n");
1407       xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1408       if (headerisdata)
1409           memcpy (xbuf, header, 8);
1410       while (1) {
1411           while (xread < origsize) {
1412               hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1413               xread += nread;
1414               if (hr != S_OK || !nread)
1415                   break;
1416           }
1417           if (!nread || hr != S_OK) /* done, or error */
1418               break;
1419           if (xread == origsize) {
1420               origsize += sizeinc;
1421               sizeinc = 2*sizeinc; /* exponential increase */
1422               xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1423           }
1424       }
1425       if (hr != S_OK)
1426           TRACE("hr in no-stat loader case is %08x\n", hr);
1427       TRACE("loaded %d bytes.\n", xread);
1428       This->datalen = xread;
1429       This->data    = xbuf;
1430   } else {
1431       This->datalen = toread+(headerisdata?8:0);
1432       xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1433       if (!xbuf)
1434           return E_OUTOFMEMORY;
1435
1436       if (headerisdata)
1437           memcpy (xbuf, header, 8);
1438
1439       while (xread < This->datalen) {
1440           ULONG nread;
1441           hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1442           xread += nread;
1443           if (hr != S_OK || !nread)
1444               break;
1445       }
1446       if (xread != This->datalen)
1447           ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1448   }
1449   if (This->datalen == 0) { /* Marks the "NONE" picture */
1450       This->desc.picType = PICTYPE_NONE;
1451       return S_OK;
1452   }
1453
1454
1455   /****************************************************************************************
1456    * Part 2: Process the loaded data
1457    */
1458
1459   magic = xbuf[0] + (xbuf[1]<<8);
1460   This->loadtime_format = magic;
1461
1462   switch (magic) {
1463   case BITMAP_FORMAT_GIF: /* GIF */
1464     hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1465     break;
1466   case BITMAP_FORMAT_JPEG: /* JPEG */
1467     hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1468     break;
1469   case BITMAP_FORMAT_BMP: /* Bitmap */
1470     hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1471     break;
1472   case BITMAP_FORMAT_PNG: /* PNG */
1473     hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1474     break;
1475   case BITMAP_FORMAT_APM: /* APM */
1476     hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1477     break;
1478   case 0x0000: { /* ICON , first word is dwReserved */
1479     hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1480     break;
1481   }
1482   default:
1483   {
1484     unsigned int i;
1485
1486     /* let's see if it's a EMF */
1487     hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1488     if (hr == S_OK) break;
1489
1490     FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1491     hr=E_FAIL;
1492     for (i=0;i<xread+8;i++) {
1493         if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1494         else MESSAGE("%02x ",xbuf[i-8]);
1495         if (i % 10 == 9) MESSAGE("\n");
1496     }
1497     MESSAGE("\n");
1498     break;
1499   }
1500   }
1501   This->bIsDirty = FALSE;
1502
1503   /* FIXME: this notify is not really documented */
1504   if (hr==S_OK)
1505       OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1506   return hr;
1507 }
1508
1509 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1510 {
1511     int iSuccess = 0;
1512     HDC hDC;
1513     BITMAPINFO * pInfoBitmap;
1514     int iNumPaletteEntries;
1515     unsigned char * pPixelData;
1516     BITMAPFILEHEADER * pFileHeader;
1517     BITMAPINFO * pInfoHeader;
1518
1519     pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1520         sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1521
1522     /* Find out bitmap size and padded length */
1523     hDC = GetDC(0);
1524     pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1525     GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1526
1527     /* Fetch bitmap palette & pixel data */
1528
1529     pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1530     GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1531
1532     /* Calculate the total length required for the BMP data */
1533     if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1534         iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1535         if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1536     } else {
1537         if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1538             iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1539         else
1540             iNumPaletteEntries = 0;
1541     }
1542     *pLength =
1543         sizeof(BITMAPFILEHEADER) +
1544         sizeof(BITMAPINFOHEADER) +
1545         iNumPaletteEntries * sizeof(RGBQUAD) +
1546         pInfoBitmap->bmiHeader.biSizeImage;
1547     *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1548
1549     /* Fill the BITMAPFILEHEADER */
1550     pFileHeader = *ppBuffer;
1551     pFileHeader->bfType = BITMAP_FORMAT_BMP;
1552     pFileHeader->bfSize = *pLength;
1553     pFileHeader->bfOffBits =
1554         sizeof(BITMAPFILEHEADER) +
1555         sizeof(BITMAPINFOHEADER) +
1556         iNumPaletteEntries * sizeof(RGBQUAD);
1557
1558     /* Fill the BITMAPINFOHEADER and the palette data */
1559     pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1560     memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1561     memcpy(
1562         (unsigned char *)(*ppBuffer) +
1563             sizeof(BITMAPFILEHEADER) +
1564             sizeof(BITMAPINFOHEADER) +
1565             iNumPaletteEntries * sizeof(RGBQUAD),
1566         pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1567     iSuccess = 1;
1568
1569     HeapFree(GetProcessHeap(), 0, pPixelData);
1570     HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1571     return iSuccess;
1572 }
1573
1574 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1575 {
1576         ICONINFO infoIcon;
1577         int iSuccess = 0;
1578
1579         *ppBuffer = NULL; *pLength = 0;
1580         if (GetIconInfo(hIcon, &infoIcon)) {
1581                 HDC hDC;
1582                 BITMAPINFO * pInfoBitmap;
1583                 unsigned char * pIconData = NULL;
1584                 unsigned int iDataSize = 0;
1585
1586         pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1587
1588                 /* Find out icon size */
1589                 hDC = GetDC(0);
1590                 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1591                 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1592                 if (1) {
1593                         /* Auxiliary pointers */
1594                         CURSORICONFILEDIR * pIconDir;
1595                         CURSORICONFILEDIRENTRY * pIconEntry;
1596                         BITMAPINFOHEADER * pIconBitmapHeader;
1597                         unsigned int iOffsetPalette;
1598                         unsigned int iOffsetColorData;
1599                         unsigned int iOffsetMaskData;
1600
1601                         unsigned int iLengthScanLineMask;
1602                         unsigned int iNumEntriesPalette;
1603
1604                         iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1605 /*
1606                         FIXME("DEBUG: bitmap size is %d x %d\n",
1607                                 pInfoBitmap->bmiHeader.biWidth,
1608                                 pInfoBitmap->bmiHeader.biHeight);
1609                         FIXME("DEBUG: bitmap bpp is %d\n",
1610                                 pInfoBitmap->bmiHeader.biBitCount);
1611                         FIXME("DEBUG: bitmap nplanes is %d\n",
1612                                 pInfoBitmap->bmiHeader.biPlanes);
1613                         FIXME("DEBUG: bitmap biSizeImage is %u\n",
1614                                 pInfoBitmap->bmiHeader.biSizeImage);
1615 */
1616                         /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1617                         iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1618                         pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1619
1620                         /* Fill out the CURSORICONFILEDIR */
1621                         pIconDir = (CURSORICONFILEDIR *)pIconData;
1622                         pIconDir->idType = 1;
1623                         pIconDir->idCount = 1;
1624
1625                         /* Fill out the CURSORICONFILEDIRENTRY */
1626                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1627                         pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1628                         pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1629                         pIconEntry->bColorCount =
1630                                 (pInfoBitmap->bmiHeader.biBitCount < 8)
1631                                 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1632                                 : 0;
1633                         pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1634                         pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1635                         pIconEntry->dwDIBSize = 0;
1636                         pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1637
1638                         /* Fill out the BITMAPINFOHEADER */
1639                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1640                         *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1641
1642                         /*      Find out whether a palette exists for the bitmap */
1643                         if (    (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1644                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 24)
1645                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1646                                 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1647                                 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256; 
1648                         } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1649                                 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1650                                 iNumEntriesPalette = 3;
1651                         } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1652                                 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1653                         } else {
1654                                 iNumEntriesPalette = 0;
1655                         }
1656
1657                         /*  Add bitmap size and header size to icon data size. */
1658                         iOffsetPalette = iDataSize;
1659                         iDataSize += iNumEntriesPalette * sizeof(DWORD);
1660                         iOffsetColorData = iDataSize;
1661                         iDataSize += pIconBitmapHeader->biSizeImage;
1662                         iOffsetMaskData = iDataSize;
1663                         iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1664                         pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1665                         pIconBitmapHeader->biHeight *= 2;
1666                         pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1667                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1668                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1669                         pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1670
1671                         /* Get the actual bitmap data from the icon bitmap */
1672                         GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1673                                 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1674                         if (iNumEntriesPalette > 0) {
1675                                 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1676                                         iNumEntriesPalette * sizeof(RGBQUAD));
1677                         }
1678
1679                         /* Reset all values so that GetDIBits call succeeds */
1680                         memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1681                         memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1682                         pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1683 /*
1684             if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1685                                 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1686                                         pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1687
1688                 printf("ERROR: unable to get bitmap mask (error %u)\n",
1689                                         GetLastError());
1690
1691                         }
1692 */
1693             GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1694             GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1695
1696                         /* Write out everything produced so far to the stream */
1697                         *ppBuffer = pIconData; *pLength = iDataSize;
1698                         iSuccess = 1;
1699                 } else {
1700 /*
1701                         printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1702                                 GetLastError());
1703 */
1704                 }
1705                 /*
1706                         Remarks (from MSDN entry on GetIconInfo):
1707
1708                         GetIconInfo creates bitmaps for the hbmMask and hbmColor
1709                         members of ICONINFO. The calling application must manage
1710                         these bitmaps and delete them when they are no longer
1711                         necessary.
1712                  */
1713                 if (hDC) ReleaseDC(0, hDC);
1714                 DeleteObject(infoIcon.hbmMask);
1715                 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1716                 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1717         } else {
1718                 printf("ERROR: Unable to get icon information (error %u)\n",
1719                         GetLastError());
1720         }
1721         return iSuccess;
1722 }
1723
1724 static HRESULT WINAPI OLEPictureImpl_Save(
1725   IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1726 {
1727     HRESULT hResult = E_NOTIMPL;
1728     void * pIconData;
1729     unsigned int iDataSize;
1730     ULONG dummy;
1731     int iSerializeResult = 0;
1732     OLEPictureImpl *This = impl_from_IPersistStream(iface);
1733
1734     TRACE("%p %p %d\n", This, pStm, fClearDirty);
1735
1736     switch (This->desc.picType) {
1737     case PICTYPE_ICON:
1738         if (This->bIsDirty || !This->data) {
1739             if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1740                 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1741                 hResult = E_FAIL;
1742                 break;
1743             }
1744             HeapFree(GetProcessHeap(), 0, This->data);
1745             This->data = pIconData;
1746             This->datalen = iDataSize;
1747         }
1748         if (This->loadtime_magic != 0xdeadbeef) {
1749             DWORD header[2];
1750
1751             header[0] = This->loadtime_magic;
1752             header[1] = This->datalen;
1753             IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1754         }
1755         IStream_Write(pStm, This->data, This->datalen, &dummy);
1756
1757         hResult = S_OK;
1758         break;
1759     case PICTYPE_BITMAP:
1760         if (This->bIsDirty) {
1761             switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1762             case BITMAP_FORMAT_BMP:
1763                 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1764                 break;
1765             case BITMAP_FORMAT_JPEG:
1766                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1767                 break;
1768             case BITMAP_FORMAT_GIF:
1769                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1770                 break;
1771             case BITMAP_FORMAT_PNG:
1772                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1773                 break;
1774             default:
1775                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1776                 break;
1777             }
1778             if (iSerializeResult) {
1779                 /*
1780                 if (This->loadtime_magic != 0xdeadbeef) {
1781                 */
1782                 if (1) {
1783                     DWORD header[2];
1784
1785                     header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1786                     header[1] = iDataSize;
1787                     IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1788                 }
1789                 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1790
1791                 HeapFree(GetProcessHeap(), 0, This->data);
1792                 This->data = pIconData;
1793                 This->datalen = iDataSize;
1794                 hResult = S_OK;
1795             }
1796         } else {
1797             /*
1798             if (This->loadtime_magic != 0xdeadbeef) {
1799             */
1800             if (1) {
1801                 DWORD header[2];
1802
1803                 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1804                 header[1] = This->datalen;
1805                 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1806             }
1807             IStream_Write(pStm, This->data, This->datalen, &dummy);
1808             hResult = S_OK;
1809         }
1810         break;
1811     case PICTYPE_METAFILE:
1812         FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1813         break;
1814     case PICTYPE_ENHMETAFILE:
1815         FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1816         break;
1817     default:
1818         FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1819         break;
1820     }
1821     if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1822     return hResult;
1823 }
1824
1825 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1826   IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1827 {
1828   OLEPictureImpl *This = impl_from_IPersistStream(iface);
1829   FIXME("(%p,%p),stub!\n",This,pcbSize);
1830   return E_NOTIMPL;
1831 }
1832
1833
1834 /************************************************************************
1835  *    IDispatch
1836  */
1837
1838 /************************************************************************
1839  * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1840  *
1841  * See Windows documentation for more details on IUnknown methods.
1842  */
1843 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1844   IDispatch* iface,
1845   REFIID     riid,
1846   VOID**     ppvoid)
1847 {
1848   OLEPictureImpl *This = impl_from_IDispatch(iface);
1849
1850   return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1851 }
1852
1853 /************************************************************************
1854  * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1855  *
1856  * See Windows documentation for more details on IUnknown methods.
1857  */
1858 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1859   IDispatch* iface)
1860 {
1861   OLEPictureImpl *This = impl_from_IDispatch(iface);
1862
1863   return IPicture_AddRef(&This->IPicture_iface);
1864 }
1865
1866 /************************************************************************
1867  * OLEPictureImpl_IDispatch_Release (IUnknown)
1868  *
1869  * See Windows documentation for more details on IUnknown methods.
1870  */
1871 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1872   IDispatch* iface)
1873 {
1874   OLEPictureImpl *This = impl_from_IDispatch(iface);
1875
1876   return IPicture_Release(&This->IPicture_iface);
1877 }
1878
1879 /************************************************************************
1880  * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1881  *
1882  * See Windows documentation for more details on IDispatch methods.
1883  */
1884 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1885   IDispatch*    iface,
1886   unsigned int* pctinfo)
1887 {
1888   TRACE("(%p)\n", pctinfo);
1889
1890   *pctinfo = 1;
1891
1892   return S_OK;
1893 }
1894
1895 /************************************************************************
1896  * OLEPictureImpl_GetTypeInfo (IDispatch)
1897  *
1898  * See Windows documentation for more details on IDispatch methods.
1899  */
1900 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1901   IDispatch*  iface,
1902   UINT      iTInfo,
1903   LCID        lcid,
1904   ITypeInfo** ppTInfo)
1905 {
1906   static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1907   ITypeLib *tl;
1908   HRESULT hres;
1909
1910   TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1911
1912   if (iTInfo != 0)
1913     return E_FAIL;
1914
1915   hres = LoadTypeLib(stdole2tlb, &tl);
1916   if (FAILED(hres))
1917   {
1918     ERR("Could not load stdole2.tlb\n");
1919     return hres;
1920   }
1921
1922   hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1923   if (FAILED(hres))
1924     ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1925
1926   return hres;
1927 }
1928
1929 /************************************************************************
1930  * OLEPictureImpl_GetIDsOfNames (IDispatch)
1931  *
1932  * See Windows documentation for more details on IDispatch methods.
1933  */
1934 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1935   IDispatch*  iface,
1936   REFIID      riid,
1937   LPOLESTR* rgszNames,
1938   UINT      cNames,
1939   LCID        lcid,
1940   DISPID*     rgDispId)
1941 {
1942   ITypeInfo * pTInfo;
1943   HRESULT hres;
1944
1945   TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1946         rgszNames, cNames, (int)lcid, rgDispId);
1947
1948   if (cNames == 0)
1949   {
1950     return E_INVALIDARG;
1951   }
1952   else
1953   {
1954     /* retrieve type information */
1955     hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1956
1957     if (FAILED(hres))
1958     {
1959       ERR("GetTypeInfo failed.\n");
1960       return hres;
1961     }
1962
1963     /* convert names to DISPIDs */
1964     hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1965     ITypeInfo_Release(pTInfo);
1966
1967     return hres;
1968   }
1969 }
1970
1971 /************************************************************************
1972  * OLEPictureImpl_Invoke (IDispatch)
1973  *
1974  * See Windows documentation for more details on IDispatch methods.
1975  */
1976 static HRESULT WINAPI OLEPictureImpl_Invoke(
1977   IDispatch*  iface,
1978   DISPID      dispIdMember,
1979   REFIID      riid,
1980   LCID        lcid,
1981   WORD        wFlags,
1982   DISPPARAMS* pDispParams,
1983   VARIANT*    pVarResult,
1984   EXCEPINFO*  pExepInfo,
1985   UINT*     puArgErr)
1986 {
1987   OLEPictureImpl *This = impl_from_IDispatch(iface);
1988
1989   /* validate parameters */
1990
1991   if (!IsEqualIID(riid, &IID_NULL))
1992   {
1993     ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
1994     return DISP_E_UNKNOWNNAME;
1995   }
1996
1997   if (!pDispParams)
1998   {
1999     ERR("null pDispParams not allowed\n");
2000     return DISP_E_PARAMNOTOPTIONAL;
2001   }
2002
2003   if (wFlags & DISPATCH_PROPERTYGET)
2004   {
2005     if (pDispParams->cArgs != 0)
2006     {
2007       ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2008       return DISP_E_BADPARAMCOUNT;
2009     }
2010     if (!pVarResult)
2011     {
2012       ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2013       return DISP_E_PARAMNOTOPTIONAL;
2014     }
2015   }
2016   else if (wFlags & DISPATCH_PROPERTYPUT)
2017   {
2018     if (pDispParams->cArgs != 1)
2019     {
2020       ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2021       return DISP_E_BADPARAMCOUNT;
2022     }
2023   }
2024
2025   switch (dispIdMember)
2026   {
2027   case DISPID_PICT_HANDLE:
2028     if (wFlags & DISPATCH_PROPERTYGET)
2029     {
2030       TRACE("DISPID_PICT_HANDLE\n");
2031       V_VT(pVarResult) = VT_I4;
2032       return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2033     }
2034     break;
2035   case DISPID_PICT_HPAL:
2036     if (wFlags & DISPATCH_PROPERTYGET)
2037     {
2038       TRACE("DISPID_PICT_HPAL\n");
2039       V_VT(pVarResult) = VT_I4;
2040       return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2041     }
2042     else if (wFlags & DISPATCH_PROPERTYPUT)
2043     {
2044       VARIANTARG vararg;
2045       HRESULT hr;
2046       TRACE("DISPID_PICT_HPAL\n");
2047
2048       VariantInit(&vararg);
2049       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2050       if (FAILED(hr))
2051         return hr;
2052
2053       hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2054
2055       VariantClear(&vararg);
2056       return hr;
2057     }
2058     break;
2059   case DISPID_PICT_TYPE:
2060     if (wFlags & DISPATCH_PROPERTYGET)
2061     {
2062       TRACE("DISPID_PICT_TYPE\n");
2063       V_VT(pVarResult) = VT_I2;
2064       return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2065     }
2066     break;
2067   case DISPID_PICT_WIDTH:
2068     if (wFlags & DISPATCH_PROPERTYGET)
2069     {
2070       TRACE("DISPID_PICT_WIDTH\n");
2071       V_VT(pVarResult) = VT_I4;
2072       return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2073     }
2074     break;
2075   case DISPID_PICT_HEIGHT:
2076     if (wFlags & DISPATCH_PROPERTYGET)
2077     {
2078       TRACE("DISPID_PICT_HEIGHT\n");
2079       V_VT(pVarResult) = VT_I4;
2080       return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2081     }
2082     break;
2083   }
2084
2085   ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2086   return DISP_E_MEMBERNOTFOUND;
2087 }
2088
2089
2090 static const IPictureVtbl OLEPictureImpl_VTable =
2091 {
2092   OLEPictureImpl_QueryInterface,
2093   OLEPictureImpl_AddRef,
2094   OLEPictureImpl_Release,
2095   OLEPictureImpl_get_Handle,
2096   OLEPictureImpl_get_hPal,
2097   OLEPictureImpl_get_Type,
2098   OLEPictureImpl_get_Width,
2099   OLEPictureImpl_get_Height,
2100   OLEPictureImpl_Render,
2101   OLEPictureImpl_set_hPal,
2102   OLEPictureImpl_get_CurDC,
2103   OLEPictureImpl_SelectPicture,
2104   OLEPictureImpl_get_KeepOriginalFormat,
2105   OLEPictureImpl_put_KeepOriginalFormat,
2106   OLEPictureImpl_PictureChanged,
2107   OLEPictureImpl_SaveAsFile,
2108   OLEPictureImpl_get_Attributes
2109 };
2110
2111 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2112 {
2113   OLEPictureImpl_IDispatch_QueryInterface,
2114   OLEPictureImpl_IDispatch_AddRef,
2115   OLEPictureImpl_IDispatch_Release,
2116   OLEPictureImpl_GetTypeInfoCount,
2117   OLEPictureImpl_GetTypeInfo,
2118   OLEPictureImpl_GetIDsOfNames,
2119   OLEPictureImpl_Invoke
2120 };
2121
2122 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2123 {
2124   OLEPictureImpl_IPersistStream_QueryInterface,
2125   OLEPictureImpl_IPersistStream_AddRef,
2126   OLEPictureImpl_IPersistStream_Release,
2127   OLEPictureImpl_GetClassID,
2128   OLEPictureImpl_IsDirty,
2129   OLEPictureImpl_Load,
2130   OLEPictureImpl_Save,
2131   OLEPictureImpl_GetSizeMax
2132 };
2133
2134 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2135 {
2136   OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2137   OLEPictureImpl_IConnectionPointContainer_AddRef,
2138   OLEPictureImpl_IConnectionPointContainer_Release,
2139   OLEPictureImpl_EnumConnectionPoints,
2140   OLEPictureImpl_FindConnectionPoint
2141 };
2142
2143 /***********************************************************************
2144  * OleCreatePictureIndirect (OLEAUT32.419)
2145  */
2146 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2147                             BOOL Own, void **ppvObj )
2148 {
2149   OLEPictureImpl* newPict;
2150   HRESULT hr;
2151
2152   TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2153
2154   *ppvObj = NULL;
2155
2156   newPict = OLEPictureImpl_Construct(lpPictDesc, Own);
2157
2158   if (newPict == NULL)
2159     return E_OUTOFMEMORY;
2160
2161   /*
2162    * Make sure it supports the interface required by the caller.
2163    */
2164   hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2165
2166   /*
2167    * Release the reference obtained in the constructor. If
2168    * the QueryInterface was unsuccessful, it will free the class.
2169    */
2170   IPicture_Release(&newPict->IPicture_iface);
2171
2172   return hr;
2173 }
2174
2175
2176 /***********************************************************************
2177  * OleLoadPicture (OLEAUT32.418)
2178  */
2179 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2180                             REFIID riid, LPVOID *ppvObj )
2181 {
2182   LPPERSISTSTREAM ps;
2183   IPicture      *newpic;
2184   HRESULT hr;
2185
2186   TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2187         lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2188
2189   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2190   if (hr != S_OK)
2191     return hr;
2192   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2193   if (hr != S_OK) {
2194       ERR("Could not get IPersistStream iface from Ole Picture?\n");
2195       IPicture_Release(newpic);
2196       *ppvObj = NULL;
2197       return hr;
2198   }
2199   hr = IPersistStream_Load(ps,lpstream);
2200   IPersistStream_Release(ps);
2201   if (FAILED(hr))
2202   {
2203       ERR("IPersistStream_Load failed\n");
2204       IPicture_Release(newpic);
2205       *ppvObj = NULL;
2206       return hr;
2207   }
2208   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2209   if (hr != S_OK)
2210       ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2211   IPicture_Release(newpic);
2212   return hr;
2213 }
2214
2215 /***********************************************************************
2216  * OleLoadPictureEx (OLEAUT32.401)
2217  */
2218 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2219                             REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2220 {
2221   LPPERSISTSTREAM ps;
2222   IPicture      *newpic;
2223   HRESULT hr;
2224
2225   FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2226         lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2227
2228   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2229   if (hr != S_OK)
2230     return hr;
2231   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2232   if (hr != S_OK) {
2233       ERR("Could not get IPersistStream iface from Ole Picture?\n");
2234       IPicture_Release(newpic);
2235       *ppvObj = NULL;
2236       return hr;
2237   }
2238   hr = IPersistStream_Load(ps,lpstream);
2239   IPersistStream_Release(ps);
2240   if (FAILED(hr))
2241   {
2242       ERR("IPersistStream_Load failed\n");
2243       IPicture_Release(newpic);
2244       *ppvObj = NULL;
2245       return hr;
2246   }
2247   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2248   if (hr != S_OK)
2249       ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2250   IPicture_Release(newpic);
2251   return hr;
2252 }
2253
2254 /***********************************************************************
2255  * OleLoadPicturePath (OLEAUT32.424)
2256  */
2257 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2258                 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2259                 LPVOID *ppvRet )
2260 {
2261   static const WCHAR file[] = { 'f','i','l','e',':',0 };
2262   IPicture *ipicture;
2263   HANDLE hFile;
2264   DWORD dwFileSize;
2265   HGLOBAL hGlobal = NULL;
2266   DWORD dwBytesRead = 0;
2267   IStream *stream;
2268   BOOL bRead;
2269   IPersistStream *pStream;
2270   HRESULT hRes;
2271   HRESULT init_res;
2272   WCHAR *file_candidate;
2273   WCHAR path_buf[MAX_PATH];
2274
2275   TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2276         debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2277         debugstr_guid(riid), ppvRet);
2278
2279   if (!szURLorPath || !ppvRet)
2280       return E_INVALIDARG;
2281
2282   *ppvRet = NULL;
2283
2284   /* Convert file URLs to DOS paths. */
2285   if (strncmpW(szURLorPath, file, 5) == 0) {
2286       DWORD size;
2287       hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2288                                 sizeof(path_buf)/sizeof(WCHAR), &size, 0);
2289       if (FAILED(hRes))
2290           return hRes;
2291
2292       file_candidate = path_buf;
2293   }
2294   else
2295       file_candidate = szURLorPath;
2296
2297   /* Handle candidate DOS paths separately. */
2298   if (file_candidate[1] == ':') {
2299       hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2300                           0, NULL);
2301       if (hFile == INVALID_HANDLE_VALUE)
2302           return INET_E_RESOURCE_NOT_FOUND;
2303
2304       dwFileSize = GetFileSize(hFile, NULL);
2305       if (dwFileSize != INVALID_FILE_SIZE )
2306       {
2307           hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2308           if ( hGlobal)
2309           {
2310               bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2311               if (!bRead)
2312               {
2313                   GlobalFree(hGlobal);
2314                   hGlobal = 0;
2315               }
2316           }
2317       }
2318       CloseHandle(hFile);
2319       
2320       if (!hGlobal)
2321           return INET_E_RESOURCE_NOT_FOUND;
2322
2323       hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2324       if (FAILED(hRes)) 
2325       {
2326           GlobalFree(hGlobal);
2327           return hRes;
2328       }
2329   } else {
2330       IMoniker *pmnk;
2331       IBindCtx *pbc;
2332
2333       hRes = CreateBindCtx(0, &pbc);
2334       if (SUCCEEDED(hRes)) 
2335       {
2336           hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2337           if (SUCCEEDED(hRes))
2338           {              
2339               hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2340               IMoniker_Release(pmnk);
2341           }
2342           IBindCtx_Release(pbc);
2343       }
2344       if (FAILED(hRes))
2345           return hRes;
2346   }
2347
2348   init_res = CoInitialize(NULL);
2349
2350   hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2351                           &IID_IPicture, (LPVOID*)&ipicture);
2352   if (SUCCEEDED(hRes)) {
2353       hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2354
2355       if (SUCCEEDED(hRes)) {
2356           hRes = IPersistStream_Load(pStream, stream);
2357
2358           if (SUCCEEDED(hRes)) {
2359               hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2360
2361               if (FAILED(hRes))
2362                   ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2363           }
2364           IPersistStream_Release(pStream);
2365       }
2366       IPicture_Release(ipicture);
2367   }
2368
2369   IStream_Release(stream);
2370
2371   if (SUCCEEDED(init_res))
2372       CoUninitialize();
2373
2374   return hRes;
2375 }
2376
2377 /*******************************************************************************
2378  * StdPic ClassFactory
2379  */
2380 typedef struct
2381 {
2382     /* IUnknown fields */
2383     IClassFactory IClassFactory_iface;
2384     LONG          ref;
2385 } IClassFactoryImpl;
2386
2387 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2388 {
2389        return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2390 }
2391
2392 static HRESULT WINAPI
2393 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2394         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2395
2396         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2397         return E_NOINTERFACE;
2398 }
2399
2400 static ULONG WINAPI
2401 SPCF_AddRef(LPCLASSFACTORY iface) {
2402         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2403         return InterlockedIncrement(&This->ref);
2404 }
2405
2406 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2407         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2408         /* static class, won't be  freed */
2409         return InterlockedDecrement(&This->ref);
2410 }
2411
2412 static HRESULT WINAPI SPCF_CreateInstance(
2413         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2414 ) {
2415     /* Creates an uninitialized picture */
2416     return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2417
2418 }
2419
2420 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2421         IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2422         FIXME("(%p)->(%d),stub!\n",This,dolock);
2423         return S_OK;
2424 }
2425
2426 static const IClassFactoryVtbl SPCF_Vtbl = {
2427         SPCF_QueryInterface,
2428         SPCF_AddRef,
2429         SPCF_Release,
2430         SPCF_CreateInstance,
2431         SPCF_LockServer
2432 };
2433 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2434
2435 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }