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