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