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