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