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