crypt32: Make sure we show Unicode characters (Dutch translation).
[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         hTempMask = CreateDIBitmap(
1236                 hdcref,
1237                 &bmi->bmiHeader,
1238                 CBM_INIT,
1239                 bytes,
1240                 bmi,
1241                 DIB_RGB_COLORS
1242         );
1243
1244         bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1245         This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1246         hOldbitmap = SelectObject(hdc, hTempMask);
1247         hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1248
1249         SetBkColor(hdc, RGB(255, 255, 255));
1250         BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1251
1252         /* We no longer need the original bitmap, so we apply the first
1253            transformation with the mask to speed up the rendering */
1254         SelectObject(hdc, This->hbmXor);
1255         SetBkColor(hdc, RGB(0,0,0));
1256         SetTextColor(hdc, RGB(255,255,255));
1257         BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 
1258                  hdcMask, 0, 0,  SRCAND);
1259
1260         SelectObject(hdc, hOldbitmap);
1261         SelectObject(hdcMask, hOldbitmapmask);
1262         DeleteDC(hdcMask);
1263         DeleteDC(hdc);
1264         DeleteObject(hTempMask);
1265     }
1266     
1267     ReleaseDC(0, hdcref);
1268     This->desc.picType = PICTYPE_BITMAP;
1269     OLEPictureImpl_SetBitmap(This);
1270     DGifCloseFile(gif);
1271     HeapFree(GetProcessHeap(),0,bmi);
1272     HeapFree(GetProcessHeap(),0,bytes);
1273     return S_OK;
1274 }
1275
1276 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1277 {
1278 #ifdef SONAME_LIBJPEG
1279     struct jpeg_decompress_struct       jd;
1280     struct jpeg_error_mgr               jerr;
1281     int                                 ret;
1282     JDIMENSION                          x;
1283     JSAMPROW                            samprow,oldsamprow;
1284     BITMAPINFOHEADER                    bmi;
1285     LPBYTE                              bits;
1286     HDC                                 hdcref;
1287     struct jpeg_source_mgr              xjsm;
1288     LPBYTE                              oldbits;
1289     unsigned int i;
1290
1291     if(!libjpeg_handle) {
1292         if(!load_libjpeg()) {
1293             ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1294             return E_FAIL;
1295         }
1296     }
1297
1298     /* This is basically so we can use in-memory data for jpeg decompression.
1299      * We need to have all the functions.
1300      */
1301     xjsm.next_input_byte        = xbuf;
1302     xjsm.bytes_in_buffer        = xread;
1303     xjsm.init_source            = _jpeg_init_source;
1304     xjsm.fill_input_buffer      = _jpeg_fill_input_buffer;
1305     xjsm.skip_input_data        = _jpeg_skip_input_data;
1306     xjsm.resync_to_restart      = _jpeg_resync_to_restart;
1307     xjsm.term_source            = _jpeg_term_source;
1308
1309     jd.err = pjpeg_std_error(&jerr);
1310     /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1311      * jpeg_create_decompress(&jd); */
1312     pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1313     jd.src = &xjsm;
1314     ret=pjpeg_read_header(&jd,TRUE);
1315     jd.out_color_space = JCS_RGB;
1316     pjpeg_start_decompress(&jd);
1317     if (ret != JPEG_HEADER_OK) {
1318         ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1319         HeapFree(GetProcessHeap(),0,xbuf);
1320         return E_FAIL;
1321     }
1322
1323     bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1324                      (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1325     samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1326
1327     oldbits = bits;
1328     oldsamprow = samprow;
1329     while ( jd.output_scanline<jd.output_height ) {
1330       x = pjpeg_read_scanlines(&jd,&samprow,1);
1331       if (x != 1) {
1332         ERR("failed to read current scanline?\n");
1333         break;
1334       }
1335       /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1336       for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1337         *(bits++) = *(samprow+2);
1338         *(bits++) = *(samprow+1);
1339         *(bits++) = *(samprow);
1340       }
1341       bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1342       samprow = oldsamprow;
1343     }
1344     bits = oldbits;
1345
1346     bmi.biSize          = sizeof(bmi);
1347     bmi.biWidth         =  jd.output_width;
1348     bmi.biHeight        = -jd.output_height;
1349     bmi.biPlanes        = 1;
1350     bmi.biBitCount      = jd.output_components<<3;
1351     bmi.biCompression   = BI_RGB;
1352     bmi.biSizeImage     = jd.output_height*jd.output_width*jd.output_components;
1353     bmi.biXPelsPerMeter = 0;
1354     bmi.biYPelsPerMeter = 0;
1355     bmi.biClrUsed       = 0;
1356     bmi.biClrImportant  = 0;
1357
1358     HeapFree(GetProcessHeap(),0,samprow);
1359     pjpeg_finish_decompress(&jd);
1360     pjpeg_destroy_decompress(&jd);
1361     hdcref = GetDC(0);
1362     This->desc.u.bmp.hbitmap=CreateDIBitmap(
1363             hdcref,
1364             &bmi,
1365             CBM_INIT,
1366             bits,
1367             (BITMAPINFO*)&bmi,
1368             DIB_RGB_COLORS
1369     );
1370     ReleaseDC(0, hdcref);
1371     This->desc.picType = PICTYPE_BITMAP;
1372     OLEPictureImpl_SetBitmap(This);
1373     HeapFree(GetProcessHeap(),0,bits);
1374     return S_OK;
1375 #else
1376     ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1377     return E_FAIL;
1378 #endif
1379 }
1380
1381 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1382 {
1383     BITMAPFILEHEADER    *bfh = (BITMAPFILEHEADER*)xbuf;
1384     BITMAPINFO          *bi = (BITMAPINFO*)(bfh+1);
1385     HDC                 hdcref;
1386
1387     /* Does not matter whether this is a coreheader or not, we only use
1388      * components which are in both
1389      */
1390     hdcref = GetDC(0);
1391     This->desc.u.bmp.hbitmap = CreateDIBitmap(
1392         hdcref,
1393         &(bi->bmiHeader),
1394         CBM_INIT,
1395         xbuf+bfh->bfOffBits,
1396         bi,
1397        DIB_RGB_COLORS
1398     );
1399     ReleaseDC(0, hdcref);
1400     if (This->desc.u.bmp.hbitmap == 0)
1401         return E_FAIL;
1402     This->desc.picType = PICTYPE_BITMAP;
1403     OLEPictureImpl_SetBitmap(This);
1404     return S_OK;
1405 }
1406
1407 /*****************************************************
1408 *   start of PNG-specific code
1409 *   currently only supports colortype PNG_COLOR_TYPE_RGB
1410 */
1411 #ifdef SONAME_LIBPNG
1412 typedef struct{
1413     ULONG position;
1414     ULONG size;
1415     BYTE * buff;
1416 } png_io;
1417
1418 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1419     png_size_t length)
1420 {
1421     png_io * io_ptr = png_ptr->io_ptr;
1422
1423     if(length + io_ptr->position > io_ptr->size){
1424         length = io_ptr->size - io_ptr->position;
1425     }
1426
1427     memcpy(data, io_ptr->buff + io_ptr->position, length);
1428
1429     io_ptr->position += length;
1430 }
1431
1432 static void *libpng_handle;
1433 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1434 MAKE_FUNCPTR(png_create_read_struct);
1435 MAKE_FUNCPTR(png_create_info_struct);
1436 MAKE_FUNCPTR(png_set_read_fn);
1437 MAKE_FUNCPTR(png_read_info);
1438 MAKE_FUNCPTR(png_read_image);
1439 MAKE_FUNCPTR(png_get_rowbytes);
1440 MAKE_FUNCPTR(png_set_bgr);
1441 MAKE_FUNCPTR(png_destroy_read_struct);
1442 MAKE_FUNCPTR(png_set_palette_to_rgb);
1443 MAKE_FUNCPTR(png_read_update_info);
1444 MAKE_FUNCPTR(png_get_tRNS);
1445 MAKE_FUNCPTR(png_get_PLTE);
1446 MAKE_FUNCPTR(png_set_expand);
1447 #undef MAKE_FUNCPTR
1448
1449 static void *load_libpng(void)
1450 {
1451     if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1452
1453 #define LOAD_FUNCPTR(f) \
1454     if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1455         libpng_handle = NULL; \
1456         return NULL; \
1457     }
1458         LOAD_FUNCPTR(png_create_read_struct);
1459         LOAD_FUNCPTR(png_create_info_struct);
1460         LOAD_FUNCPTR(png_set_read_fn);
1461         LOAD_FUNCPTR(png_read_info);
1462         LOAD_FUNCPTR(png_read_image);
1463         LOAD_FUNCPTR(png_get_rowbytes);
1464         LOAD_FUNCPTR(png_set_bgr);
1465         LOAD_FUNCPTR(png_destroy_read_struct);
1466         LOAD_FUNCPTR(png_set_palette_to_rgb);
1467         LOAD_FUNCPTR(png_read_update_info);
1468         LOAD_FUNCPTR(png_get_tRNS);
1469         LOAD_FUNCPTR(png_get_PLTE);
1470         LOAD_FUNCPTR(png_set_expand);
1471
1472 #undef LOAD_FUNCPTR
1473     }
1474     return libpng_handle;
1475 }
1476 #endif /* SONAME_LIBPNG */
1477
1478 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1479 {
1480 #ifdef SONAME_LIBPNG
1481     png_io              io;
1482     png_structp         png_ptr = NULL;
1483     png_infop           info_ptr = NULL;
1484     INT                 row, rowsize, height, width, num_trans, i, j;
1485     png_bytep*          row_pointers = NULL;
1486     png_bytep           pngdata = NULL;
1487     BITMAPINFOHEADER    bmi;
1488     HDC                 hdcref = NULL, hdcXor, hdcMask;
1489     HRESULT             ret;
1490     BOOL                transparency;
1491     png_bytep           trans;
1492     png_color_16p       trans_values;
1493     COLORREF            white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1494     HBITMAP             hbmoldXor, hbmoldMask, temp;
1495
1496     if(!libpng_handle) {
1497         if(!load_libpng()) {
1498             ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1499             return E_FAIL;
1500         }
1501     }
1502
1503     io.size     = xread;
1504     io.position = 0;
1505     io.buff     = xbuf;
1506
1507     png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1508         NULL, NULL, NULL);
1509
1510     if(setjmp(png_jmpbuf(png_ptr))){
1511         TRACE("Error in libpng\n");
1512         ret = E_FAIL;
1513         goto end;
1514     }
1515
1516     info_ptr = ppng_create_info_struct(png_ptr);
1517     ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1518     ppng_read_info(png_ptr, info_ptr);
1519
1520     if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1521          png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1522          png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1523         FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1524         ret = E_FAIL;
1525         goto end;
1526     }
1527
1528     transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1529                        == PNG_INFO_tRNS);
1530
1531     /* sets format from anything to RGBA */
1532     ppng_set_expand(png_ptr);
1533     /* sets format to BGRA */
1534     ppng_set_bgr(png_ptr);
1535
1536     ppng_read_update_info(png_ptr, info_ptr);
1537
1538     rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1539     /* align rowsize to 4-byte boundary */
1540     rowsize = (rowsize + 3) & ~3;
1541     height = info_ptr->height;
1542     width = info_ptr->width;
1543
1544     pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1545     row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1546
1547     if(!pngdata || !row_pointers){
1548         ret = E_FAIL;
1549         goto end;
1550     }
1551
1552     for (row = 0; row < height; row++){
1553         row_pointers[row] = pngdata + row * rowsize;
1554     }
1555
1556     ppng_read_image(png_ptr, row_pointers);
1557
1558     bmi.biSize          = sizeof(bmi);
1559     bmi.biWidth         = width;
1560     bmi.biHeight        = -height;
1561     bmi.biPlanes        = 1;
1562     bmi.biBitCount      = info_ptr->channels * 8;
1563     bmi.biCompression   = BI_RGB;
1564     bmi.biSizeImage     = height * rowsize;
1565     bmi.biXPelsPerMeter = 0;
1566     bmi.biYPelsPerMeter = 0;
1567     bmi.biClrUsed       = 0;
1568     bmi.biClrImportant  = 0;
1569
1570     hdcref = GetDC(0);
1571     This->desc.u.bmp.hbitmap = CreateDIBitmap(
1572         hdcref,
1573         &bmi,
1574         CBM_INIT,
1575         pngdata,
1576         (BITMAPINFO*)&bmi,
1577         DIB_RGB_COLORS
1578     );
1579
1580     /* only fully-transparent alpha is handled */
1581     if((info_ptr->channels != 4) || !transparency){
1582         ReleaseDC(0, hdcref);
1583         goto succ;
1584     }
1585
1586     This->hbmXor = CreateDIBitmap(
1587         hdcref,
1588         &bmi,
1589         CBM_INIT,
1590         pngdata,
1591         (BITMAPINFO*)&bmi,
1592         DIB_RGB_COLORS
1593     );
1594
1595     /* set transparent pixels to black, all others to white */
1596     for(i = 0; i < height; i++){
1597         for(j = 3; j < rowsize; j += 4){
1598             if(row_pointers[i][j] == 0)
1599                 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1600             else
1601                 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1602         }
1603     }
1604
1605     temp = CreateDIBitmap(
1606         hdcref,
1607         &bmi,
1608         CBM_INIT,
1609         pngdata,
1610         (BITMAPINFO*)&bmi,
1611         DIB_RGB_COLORS
1612     );
1613
1614     ReleaseDC(0, hdcref);
1615
1616     This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1617     hdcXor = CreateCompatibleDC(NULL);
1618     hdcMask = CreateCompatibleDC(NULL);
1619
1620     hbmoldXor = SelectObject(hdcXor,temp);
1621     hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1622     SetBkColor(hdcXor,black);
1623     BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1624
1625     SelectObject(hdcXor,This->hbmXor);
1626     DeleteObject(temp);
1627
1628     SetTextColor(hdcXor,white);
1629     SetBkColor(hdcXor,black);
1630     BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1631
1632     SelectObject(hdcXor,hbmoldXor);
1633     SelectObject(hdcMask,hbmoldMask);
1634
1635     DeleteDC(hdcXor);
1636     DeleteDC(hdcMask);
1637
1638 succ:
1639     This->desc.picType = PICTYPE_BITMAP;
1640     OLEPictureImpl_SetBitmap(This);
1641     ret = S_OK;
1642
1643 end:
1644     if(png_ptr)
1645         ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1646     HeapFree(GetProcessHeap(), 0, row_pointers);
1647     HeapFree(GetProcessHeap(), 0, pngdata);
1648     return ret;
1649 #else /* SONAME_LIBPNG */
1650     ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1651     return E_FAIL;
1652 #endif
1653 }
1654
1655 /*****************************************************
1656 *   start of Icon-specific code
1657 */
1658
1659 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1660 {
1661     HICON hicon;
1662     CURSORICONFILEDIR   *cifd = (CURSORICONFILEDIR*)xbuf;
1663     HDC hdcRef;
1664     int i;
1665
1666     /*
1667     FIXME("icon.idReserved=%d\n",cifd->idReserved);
1668     FIXME("icon.idType=%d\n",cifd->idType);
1669     FIXME("icon.idCount=%d\n",cifd->idCount);
1670
1671     for (i=0;i<cifd->idCount;i++) {
1672         FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1673         FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1674         FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1675         FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1676         FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1677         FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1678         FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1679         FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1680     }
1681     */
1682     i=0;
1683     /* If we have more than one icon, try to find the best.
1684      * this currently means '32 pixel wide'.
1685      */
1686     if (cifd->idCount!=1) {
1687         for (i=0;i<cifd->idCount;i++) {
1688             if (cifd->idEntries[i].bWidth == 32)
1689                 break;
1690         }
1691         if (i==cifd->idCount) i=0;
1692     }
1693
1694     hicon = CreateIconFromResourceEx(
1695                 xbuf+cifd->idEntries[i].dwDIBOffset,
1696                 cifd->idEntries[i].dwDIBSize,
1697                 TRUE, /* is icon */
1698                 0x00030000,
1699                 cifd->idEntries[i].bWidth,
1700                 cifd->idEntries[i].bHeight,
1701                 0
1702     );
1703     if (!hicon) {
1704         ERR("CreateIcon failed.\n");
1705         return E_FAIL;
1706     } else {
1707         This->desc.picType = PICTYPE_ICON;
1708         This->desc.u.icon.hicon = hicon;
1709         This->origWidth = cifd->idEntries[i].bWidth;
1710         This->origHeight = cifd->idEntries[i].bHeight;
1711         hdcRef = CreateCompatibleDC(0);
1712         This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1713         This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1714         DeleteDC(hdcRef);
1715         return S_OK;
1716     }
1717 }
1718
1719 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1720                                               const BYTE *data, ULONG size)
1721 {
1722     HENHMETAFILE hemf;
1723     ENHMETAHEADER hdr;
1724
1725     hemf = SetEnhMetaFileBits(size, data);
1726     if (!hemf) return E_FAIL;
1727
1728     GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1729
1730     This->desc.picType = PICTYPE_ENHMETAFILE;
1731     This->desc.u.emf.hemf = hemf;
1732
1733     This->origWidth = 0;
1734     This->origHeight = 0;
1735     This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1736     This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1737
1738     return S_OK;
1739 }
1740
1741 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1742                                       const BYTE *data, ULONG size)
1743 {
1744     APM_HEADER *header = (APM_HEADER *)data;
1745     HMETAFILE hmf;
1746
1747     if (size < sizeof(APM_HEADER))
1748         return E_FAIL;
1749     if (header->key != 0x9ac6cdd7)
1750         return E_FAIL;
1751
1752     /* SetMetaFileBitsEx performs data check on its own */
1753     hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1754     if (!hmf) return E_FAIL;
1755
1756     This->desc.picType = PICTYPE_METAFILE;
1757     This->desc.u.wmf.hmeta = hmf;
1758     This->desc.u.wmf.xExt = 0;
1759     This->desc.u.wmf.yExt = 0;
1760
1761     This->origWidth = 0;
1762     This->origHeight = 0;
1763     This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1764     This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1765     return S_OK;
1766 }
1767
1768 /************************************************************************
1769  * BITMAP FORMAT FLAGS -
1770  *   Flags that differentiate between different types of bitmaps.
1771  */
1772
1773 #define BITMAP_FORMAT_BMP   0x4d42 /* "BM" */
1774 #define BITMAP_FORMAT_JPEG  0xd8ff
1775 #define BITMAP_FORMAT_GIF   0x4947
1776 #define BITMAP_FORMAT_PNG   0x5089
1777 #define BITMAP_FORMAT_APM   0xcdd7
1778
1779 /************************************************************************
1780  * OLEPictureImpl_IPersistStream_Load (IUnknown)
1781  *
1782  * Loads the binary data from the IStream. Starts at current position.
1783  * There appears to be an 2 DWORD header:
1784  *      DWORD magic;
1785  *      DWORD len;
1786  *
1787  * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1788  */
1789 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1790   HRESULT       hr = E_FAIL;
1791   BOOL          headerisdata = FALSE;
1792   BOOL          statfailed = FALSE;
1793   ULONG         xread, toread;
1794   ULONG         headerread;
1795   BYTE          *xbuf;
1796   DWORD         header[2];
1797   WORD          magic;
1798   STATSTG       statstg;
1799   OLEPictureImpl *This = impl_from_IPersistStream(iface);
1800   
1801   TRACE("(%p,%p)\n",This,pStm);
1802
1803   /****************************************************************************************
1804    * Part 1: Load the data
1805    */
1806   /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1807    * out whether we do.
1808    *
1809    * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1810    * compound file. This may explain most, if not all, of the cases of "no
1811    * header", and the header validation should take this into account.
1812    * At least in Visual Basic 6, resource streams, valid headers are
1813    *    header[0] == "lt\0\0",
1814    *    header[1] == length_of_stream.
1815    *
1816    * Also handle streams where we do not have a working "Stat" method by
1817    * reading all data until the end of the stream.
1818    */
1819   hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1820   if (hr) {
1821       TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1822       statfailed = TRUE;
1823       /* we will read at least 8 byte ... just right below */
1824       statstg.cbSize.QuadPart = 8;
1825   }
1826
1827   toread = 0;
1828   headerread = 0;
1829   headerisdata = FALSE;
1830   do {
1831       hr=IStream_Read(pStm,header,8,&xread);
1832       if (hr || xread!=8) {
1833           ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1834           return (hr?hr:E_FAIL);
1835       }
1836       headerread += xread;
1837       xread = 0;
1838       
1839       if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1840           if (toread != 0 && toread != header[1]) 
1841               FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1842                   toread, header[1]);
1843           toread = header[1];
1844           if (toread == 0) break;
1845       } else {
1846           if (!memcmp(&(header[0]), "GIF8",     4) ||   /* GIF header */
1847               !memcmp(&(header[0]), "BM",       2) ||   /* BMP header */
1848               !memcmp(&(header[0]), "\xff\xd8", 2) ||   /* JPEG header */
1849               (header[0] == EMR_HEADER)            ||   /* EMF header */
1850               (header[1] > statstg.cbSize.QuadPart)||   /* invalid size */
1851               (header[1]==0)
1852           ) {/* Found start of bitmap data */
1853               headerisdata = TRUE;
1854               if (toread == 0) 
1855                   toread = statstg.cbSize.QuadPart-8;
1856               else toread -= 8;
1857               xread = 8;
1858           } else {
1859               FIXME("Unknown stream header magic: %08x\n", header[0]);
1860               toread = header[1];
1861           }
1862       }
1863   } while (!headerisdata);
1864
1865   if (statfailed) { /* we don't know the size ... read all we get */
1866       int sizeinc = 4096;
1867       int origsize = sizeinc;
1868       ULONG nread = 42;
1869
1870       TRACE("Reading all data from stream.\n");
1871       xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1872       if (headerisdata)
1873           memcpy (xbuf, header, 8);
1874       while (1) {
1875           while (xread < origsize) {
1876               hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1877               xread+=nread;
1878               if (hr || !nread)
1879                   break;
1880           }
1881           if (!nread || hr) /* done, or error */
1882               break;
1883           if (xread == origsize) {
1884               origsize += sizeinc;
1885               sizeinc = 2*sizeinc; /* exponential increase */
1886               xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1887           }
1888       }
1889       if (hr)
1890           TRACE("hr in no-stat loader case is %08x\n", hr);
1891       TRACE("loaded %d bytes.\n", xread);
1892       This->datalen = xread;
1893       This->data    = xbuf;
1894   } else {
1895       This->datalen = toread+(headerisdata?8:0);
1896       xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1897       if (!xbuf)
1898           return E_OUTOFMEMORY;
1899
1900       if (headerisdata)
1901           memcpy (xbuf, header, 8);
1902
1903       while (xread < This->datalen) {
1904           ULONG nread;
1905           hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1906           xread+=nread;
1907           if (hr || !nread)
1908               break;
1909       }
1910       if (xread != This->datalen)
1911           ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1912   }
1913   if (This->datalen == 0) { /* Marks the "NONE" picture */
1914       This->desc.picType = PICTYPE_NONE;
1915       return S_OK;
1916   }
1917
1918
1919   /****************************************************************************************
1920    * Part 2: Process the loaded data
1921    */
1922
1923   magic = xbuf[0] + (xbuf[1]<<8);
1924   This->loadtime_format = magic;
1925
1926   switch (magic) {
1927   case BITMAP_FORMAT_GIF: /* GIF */
1928     hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1929     break;
1930   case BITMAP_FORMAT_JPEG: /* JPEG */
1931     hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1932     break;
1933   case BITMAP_FORMAT_BMP: /* Bitmap */
1934     hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1935     break;
1936   case BITMAP_FORMAT_PNG: /* PNG */
1937     hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1938     break;
1939   case BITMAP_FORMAT_APM: /* APM */
1940     hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1941     break;
1942   case 0x0000: { /* ICON , first word is dwReserved */
1943     hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1944     break;
1945   }
1946   default:
1947   {
1948     unsigned int i;
1949
1950     /* let's see if it's a EMF */
1951     hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1952     if (hr == S_OK) break;
1953
1954     FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1955     hr=E_FAIL;
1956     for (i=0;i<xread+8;i++) {
1957         if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1958         else MESSAGE("%02x ",xbuf[i-8]);
1959         if (i % 10 == 9) MESSAGE("\n");
1960     }
1961     MESSAGE("\n");
1962     break;
1963   }
1964   }
1965   This->bIsDirty = FALSE;
1966
1967   /* FIXME: this notify is not really documented */
1968   if (hr==S_OK)
1969       OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1970   return hr;
1971 }
1972
1973 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1974 {
1975     int iSuccess = 0;
1976     HDC hDC;
1977     BITMAPINFO * pInfoBitmap;
1978     int iNumPaletteEntries;
1979     unsigned char * pPixelData;
1980     BITMAPFILEHEADER * pFileHeader;
1981     BITMAPINFO * pInfoHeader;
1982
1983     pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1984         sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1985
1986     /* Find out bitmap size and padded length */
1987     hDC = GetDC(0);
1988     pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1989     GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1990
1991     /* Fetch bitmap palette & pixel data */
1992
1993     pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1994     GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1995
1996     /* Calculate the total length required for the BMP data */
1997     if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1998         iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1999         if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
2000     } else {
2001         if (pInfoBitmap->bmiHeader.biBitCount <= 8)
2002             iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
2003         else
2004             iNumPaletteEntries = 0;
2005     }
2006     *pLength =
2007         sizeof(BITMAPFILEHEADER) +
2008         sizeof(BITMAPINFOHEADER) +
2009         iNumPaletteEntries * sizeof(RGBQUAD) +
2010         pInfoBitmap->bmiHeader.biSizeImage;
2011     *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
2012
2013     /* Fill the BITMAPFILEHEADER */
2014     pFileHeader = *ppBuffer;
2015     pFileHeader->bfType = BITMAP_FORMAT_BMP;
2016     pFileHeader->bfSize = *pLength;
2017     pFileHeader->bfOffBits =
2018         sizeof(BITMAPFILEHEADER) +
2019         sizeof(BITMAPINFOHEADER) +
2020         iNumPaletteEntries * sizeof(RGBQUAD);
2021
2022     /* Fill the BITMAPINFOHEADER and the palette data */
2023     pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
2024     memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
2025     memcpy(
2026         (unsigned char *)(*ppBuffer) +
2027             sizeof(BITMAPFILEHEADER) +
2028             sizeof(BITMAPINFOHEADER) +
2029             iNumPaletteEntries * sizeof(RGBQUAD),
2030         pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2031     iSuccess = 1;
2032
2033     HeapFree(GetProcessHeap(), 0, pPixelData);
2034     HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2035     return iSuccess;
2036 }
2037
2038 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2039 {
2040         ICONINFO infoIcon;
2041         int iSuccess = 0;
2042
2043         *ppBuffer = NULL; *pLength = 0;
2044         if (GetIconInfo(hIcon, &infoIcon)) {
2045                 HDC hDC;
2046                 BITMAPINFO * pInfoBitmap;
2047                 unsigned char * pIconData = NULL;
2048                 unsigned int iDataSize = 0;
2049
2050         pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2051
2052                 /* Find out icon size */
2053                 hDC = GetDC(0);
2054                 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2055                 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2056                 if (1) {
2057                         /* Auxiliary pointers */
2058                         CURSORICONFILEDIR * pIconDir;
2059                         CURSORICONFILEDIRENTRY * pIconEntry;
2060                         BITMAPINFOHEADER * pIconBitmapHeader;
2061                         unsigned int iOffsetPalette;
2062                         unsigned int iOffsetColorData;
2063                         unsigned int iOffsetMaskData;
2064
2065                         unsigned int iLengthScanLineColor;
2066                         unsigned int iLengthScanLineMask;
2067                         unsigned int iNumEntriesPalette;
2068
2069                         iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2070                         iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2071 /*
2072                         FIXME("DEBUG: bitmap size is %d x %d\n",
2073                                 pInfoBitmap->bmiHeader.biWidth,
2074                                 pInfoBitmap->bmiHeader.biHeight);
2075                         FIXME("DEBUG: bitmap bpp is %d\n",
2076                                 pInfoBitmap->bmiHeader.biBitCount);
2077                         FIXME("DEBUG: bitmap nplanes is %d\n",
2078                                 pInfoBitmap->bmiHeader.biPlanes);
2079                         FIXME("DEBUG: bitmap biSizeImage is %u\n",
2080                                 pInfoBitmap->bmiHeader.biSizeImage);
2081 */
2082                         /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2083                         iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2084                         pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2085
2086                         /* Fill out the CURSORICONFILEDIR */
2087                         pIconDir = (CURSORICONFILEDIR *)pIconData;
2088                         pIconDir->idType = 1;
2089                         pIconDir->idCount = 1;
2090
2091                         /* Fill out the CURSORICONFILEDIRENTRY */
2092                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2093                         pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2094                         pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2095                         pIconEntry->bColorCount =
2096                                 (pInfoBitmap->bmiHeader.biBitCount < 8)
2097                                 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2098                                 : 0;
2099                         pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2100                         pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2101                         pIconEntry->dwDIBSize = 0;
2102                         pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2103
2104                         /* Fill out the BITMAPINFOHEADER */
2105                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2106                         *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2107
2108                         /*      Find out whether a palette exists for the bitmap */
2109                         if (    (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2110                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 24)
2111                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2112                                 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2113                                 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256; 
2114                         } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2115                                 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2116                                 iNumEntriesPalette = 3;
2117                         } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2118                                 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2119                         } else {
2120                                 iNumEntriesPalette = 0;
2121                         }
2122
2123                         /*  Add bitmap size and header size to icon data size. */
2124                         iOffsetPalette = iDataSize;
2125                         iDataSize += iNumEntriesPalette * sizeof(DWORD);
2126                         iOffsetColorData = iDataSize;
2127                         iDataSize += pIconBitmapHeader->biSizeImage;
2128                         iOffsetMaskData = iDataSize;
2129                         iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2130                         pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2131                         pIconBitmapHeader->biHeight *= 2;
2132                         pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2133                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2134                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2135                         pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2136
2137                         /* Get the actual bitmap data from the icon bitmap */
2138                         GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2139                                 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2140                         if (iNumEntriesPalette > 0) {
2141                                 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2142                                         iNumEntriesPalette * sizeof(RGBQUAD));
2143                         }
2144
2145                         /* Reset all values so that GetDIBits call succeeds */
2146                         memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2147                         memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2148                         pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2149 /*
2150             if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2151                                 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2152                                         pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2153
2154                 printf("ERROR: unable to get bitmap mask (error %u)\n",
2155                                         GetLastError());
2156
2157                         }
2158 */
2159             GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2160             GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2161
2162                         /* Write out everything produced so far to the stream */
2163                         *ppBuffer = pIconData; *pLength = iDataSize;
2164                         iSuccess = 1;
2165                 } else {
2166 /*
2167                         printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2168                                 GetLastError());
2169 */
2170                 }
2171                 /*
2172                         Remarks (from MSDN entry on GetIconInfo):
2173
2174                         GetIconInfo creates bitmaps for the hbmMask and hbmColor
2175                         members of ICONINFO. The calling application must manage
2176                         these bitmaps and delete them when they are no longer
2177                         necessary.
2178                  */
2179                 if (hDC) ReleaseDC(0, hDC);
2180                 DeleteObject(infoIcon.hbmMask);
2181                 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2182                 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2183         } else {
2184                 printf("ERROR: Unable to get icon information (error %u)\n",
2185                         GetLastError());
2186         }
2187         return iSuccess;
2188 }
2189
2190 static HRESULT WINAPI OLEPictureImpl_Save(
2191   IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2192 {
2193     HRESULT hResult = E_NOTIMPL;
2194     void * pIconData;
2195     unsigned int iDataSize;
2196     ULONG dummy;
2197     int iSerializeResult = 0;
2198     OLEPictureImpl *This = impl_from_IPersistStream(iface);
2199
2200     TRACE("%p %p %d\n", This, pStm, fClearDirty);
2201
2202     switch (This->desc.picType) {
2203     case PICTYPE_ICON:
2204         if (This->bIsDirty || !This->data) {
2205             if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2206                 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2207                 hResult = E_FAIL;
2208                 break;
2209             }
2210             HeapFree(GetProcessHeap(), 0, This->data);
2211             This->data = pIconData;
2212             This->datalen = iDataSize;
2213         }
2214         if (This->loadtime_magic != 0xdeadbeef) {
2215             DWORD header[2];
2216
2217             header[0] = This->loadtime_magic;
2218             header[1] = This->datalen;
2219             IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2220         }
2221         IStream_Write(pStm, This->data, This->datalen, &dummy);
2222
2223         hResult = S_OK;
2224         break;
2225     case PICTYPE_BITMAP:
2226         if (This->bIsDirty) {
2227             switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2228             case BITMAP_FORMAT_BMP:
2229                 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2230                 break;
2231             case BITMAP_FORMAT_JPEG:
2232                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2233                 break;
2234             case BITMAP_FORMAT_GIF:
2235                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2236                 break;
2237             case BITMAP_FORMAT_PNG:
2238                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2239                 break;
2240             default:
2241                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2242                 break;
2243             }
2244             if (iSerializeResult) {
2245                 /*
2246                 if (This->loadtime_magic != 0xdeadbeef) {
2247                 */
2248                 if (1) {
2249                     DWORD header[2];
2250
2251                     header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2252                     header[1] = iDataSize;
2253                     IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2254                 }
2255                 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2256
2257                 HeapFree(GetProcessHeap(), 0, This->data);
2258                 This->data = pIconData;
2259                 This->datalen = iDataSize;
2260                 hResult = S_OK;
2261             }
2262         } else {
2263             /*
2264             if (This->loadtime_magic != 0xdeadbeef) {
2265             */
2266             if (1) {
2267                 DWORD header[2];
2268
2269                 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2270                 header[1] = This->datalen;
2271                 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2272             }
2273             IStream_Write(pStm, This->data, This->datalen, &dummy);
2274             hResult = S_OK;
2275         }
2276         break;
2277     case PICTYPE_METAFILE:
2278         FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2279         break;
2280     case PICTYPE_ENHMETAFILE:
2281         FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2282         break;
2283     default:
2284         FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2285         break;
2286     }
2287     if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2288     return hResult;
2289 }
2290
2291 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2292   IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2293 {
2294   OLEPictureImpl *This = impl_from_IPersistStream(iface);
2295   FIXME("(%p,%p),stub!\n",This,pcbSize);
2296   return E_NOTIMPL;
2297 }
2298
2299
2300 /************************************************************************
2301  *    IDispatch
2302  */
2303
2304 /************************************************************************
2305  * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2306  *
2307  * See Windows documentation for more details on IUnknown methods.
2308  */
2309 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2310   IDispatch* iface,
2311   REFIID     riid,
2312   VOID**     ppvoid)
2313 {
2314   OLEPictureImpl *This = impl_from_IDispatch(iface);
2315
2316   return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2317 }
2318
2319 /************************************************************************
2320  * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2321  *
2322  * See Windows documentation for more details on IUnknown methods.
2323  */
2324 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2325   IDispatch* iface)
2326 {
2327   OLEPictureImpl *This = impl_from_IDispatch(iface);
2328
2329   return IPicture_AddRef((IPicture *)This);
2330 }
2331
2332 /************************************************************************
2333  * OLEPictureImpl_IDispatch_Release (IUnknown)
2334  *
2335  * See Windows documentation for more details on IUnknown methods.
2336  */
2337 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2338   IDispatch* iface)
2339 {
2340   OLEPictureImpl *This = impl_from_IDispatch(iface);
2341
2342   return IPicture_Release((IPicture *)This);
2343 }
2344
2345 /************************************************************************
2346  * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2347  *
2348  * See Windows documentation for more details on IDispatch methods.
2349  */
2350 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2351   IDispatch*    iface,
2352   unsigned int* pctinfo)
2353 {
2354   TRACE("(%p)\n", pctinfo);
2355
2356   *pctinfo = 1;
2357
2358   return S_OK;
2359 }
2360
2361 /************************************************************************
2362  * OLEPictureImpl_GetTypeInfo (IDispatch)
2363  *
2364  * See Windows documentation for more details on IDispatch methods.
2365  */
2366 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2367   IDispatch*  iface,
2368   UINT      iTInfo,
2369   LCID        lcid,
2370   ITypeInfo** ppTInfo)
2371 {
2372   static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2373   ITypeLib *tl;
2374   HRESULT hres;
2375
2376   TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2377
2378   if (iTInfo != 0)
2379     return E_FAIL;
2380
2381   hres = LoadTypeLib(stdole2tlb, &tl);
2382   if (FAILED(hres))
2383   {
2384     ERR("Could not load stdole2.tlb\n");
2385     return hres;
2386   }
2387
2388   hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2389   if (FAILED(hres))
2390     ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2391
2392   return hres;
2393 }
2394
2395 /************************************************************************
2396  * OLEPictureImpl_GetIDsOfNames (IDispatch)
2397  *
2398  * See Windows documentation for more details on IDispatch methods.
2399  */
2400 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2401   IDispatch*  iface,
2402   REFIID      riid,
2403   LPOLESTR* rgszNames,
2404   UINT      cNames,
2405   LCID        lcid,
2406   DISPID*     rgDispId)
2407 {
2408   ITypeInfo * pTInfo;
2409   HRESULT hres;
2410
2411   TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2412         rgszNames, cNames, (int)lcid, rgDispId);
2413
2414   if (cNames == 0)
2415   {
2416     return E_INVALIDARG;
2417   }
2418   else
2419   {
2420     /* retrieve type information */
2421     hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2422
2423     if (FAILED(hres))
2424     {
2425       ERR("GetTypeInfo failed.\n");
2426       return hres;
2427     }
2428
2429     /* convert names to DISPIDs */
2430     hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2431     ITypeInfo_Release(pTInfo);
2432
2433     return hres;
2434   }
2435 }
2436
2437 /************************************************************************
2438  * OLEPictureImpl_Invoke (IDispatch)
2439  *
2440  * See Windows documentation for more details on IDispatch methods.
2441  */
2442 static HRESULT WINAPI OLEPictureImpl_Invoke(
2443   IDispatch*  iface,
2444   DISPID      dispIdMember,
2445   REFIID      riid,
2446   LCID        lcid,
2447   WORD        wFlags,
2448   DISPPARAMS* pDispParams,
2449   VARIANT*    pVarResult,
2450   EXCEPINFO*  pExepInfo,
2451   UINT*     puArgErr)
2452 {
2453   OLEPictureImpl *This = impl_from_IDispatch(iface);
2454
2455   /* validate parameters */
2456
2457   if (!IsEqualIID(riid, &IID_NULL))
2458   {
2459     ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2460     return DISP_E_UNKNOWNNAME;
2461   }
2462
2463   if (!pDispParams)
2464   {
2465     ERR("null pDispParams not allowed\n");
2466     return DISP_E_PARAMNOTOPTIONAL;
2467   }
2468
2469   if (wFlags & DISPATCH_PROPERTYGET)
2470   {
2471     if (pDispParams->cArgs != 0)
2472     {
2473       ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2474       return DISP_E_BADPARAMCOUNT;
2475     }
2476     if (!pVarResult)
2477     {
2478       ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2479       return DISP_E_PARAMNOTOPTIONAL;
2480     }
2481   }
2482   else if (wFlags & DISPATCH_PROPERTYPUT)
2483   {
2484     if (pDispParams->cArgs != 1)
2485     {
2486       ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2487       return DISP_E_BADPARAMCOUNT;
2488     }
2489   }
2490
2491   switch (dispIdMember)
2492   {
2493   case DISPID_PICT_HANDLE:
2494     if (wFlags & DISPATCH_PROPERTYGET)
2495     {
2496       TRACE("DISPID_PICT_HANDLE\n");
2497       V_VT(pVarResult) = VT_I4;
2498       return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2499     }
2500     break;
2501   case DISPID_PICT_HPAL:
2502     if (wFlags & DISPATCH_PROPERTYGET)
2503     {
2504       TRACE("DISPID_PICT_HPAL\n");
2505       V_VT(pVarResult) = VT_I4;
2506       return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2507     }
2508     else if (wFlags & DISPATCH_PROPERTYPUT)
2509     {
2510       VARIANTARG vararg;
2511       HRESULT hr;
2512       TRACE("DISPID_PICT_HPAL\n");
2513
2514       VariantInit(&vararg);
2515       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2516       if (FAILED(hr))
2517         return hr;
2518
2519       hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2520
2521       VariantClear(&vararg);
2522       return hr;
2523     }
2524     break;
2525   case DISPID_PICT_TYPE:
2526     if (wFlags & DISPATCH_PROPERTYGET)
2527     {
2528       TRACE("DISPID_PICT_TYPE\n");
2529       V_VT(pVarResult) = VT_I2;
2530       return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2531     }
2532     break;
2533   case DISPID_PICT_WIDTH:
2534     if (wFlags & DISPATCH_PROPERTYGET)
2535     {
2536       TRACE("DISPID_PICT_WIDTH\n");
2537       V_VT(pVarResult) = VT_I4;
2538       return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2539     }
2540     break;
2541   case DISPID_PICT_HEIGHT:
2542     if (wFlags & DISPATCH_PROPERTYGET)
2543     {
2544       TRACE("DISPID_PICT_HEIGHT\n");
2545       V_VT(pVarResult) = VT_I4;
2546       return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2547     }
2548     break;
2549   }
2550
2551   ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2552   return DISP_E_MEMBERNOTFOUND;
2553 }
2554
2555
2556 static const IPictureVtbl OLEPictureImpl_VTable =
2557 {
2558   OLEPictureImpl_QueryInterface,
2559   OLEPictureImpl_AddRef,
2560   OLEPictureImpl_Release,
2561   OLEPictureImpl_get_Handle,
2562   OLEPictureImpl_get_hPal,
2563   OLEPictureImpl_get_Type,
2564   OLEPictureImpl_get_Width,
2565   OLEPictureImpl_get_Height,
2566   OLEPictureImpl_Render,
2567   OLEPictureImpl_set_hPal,
2568   OLEPictureImpl_get_CurDC,
2569   OLEPictureImpl_SelectPicture,
2570   OLEPictureImpl_get_KeepOriginalFormat,
2571   OLEPictureImpl_put_KeepOriginalFormat,
2572   OLEPictureImpl_PictureChanged,
2573   OLEPictureImpl_SaveAsFile,
2574   OLEPictureImpl_get_Attributes
2575 };
2576
2577 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2578 {
2579   OLEPictureImpl_IDispatch_QueryInterface,
2580   OLEPictureImpl_IDispatch_AddRef,
2581   OLEPictureImpl_IDispatch_Release,
2582   OLEPictureImpl_GetTypeInfoCount,
2583   OLEPictureImpl_GetTypeInfo,
2584   OLEPictureImpl_GetIDsOfNames,
2585   OLEPictureImpl_Invoke
2586 };
2587
2588 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2589 {
2590   OLEPictureImpl_IPersistStream_QueryInterface,
2591   OLEPictureImpl_IPersistStream_AddRef,
2592   OLEPictureImpl_IPersistStream_Release,
2593   OLEPictureImpl_GetClassID,
2594   OLEPictureImpl_IsDirty,
2595   OLEPictureImpl_Load,
2596   OLEPictureImpl_Save,
2597   OLEPictureImpl_GetSizeMax
2598 };
2599
2600 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2601 {
2602   OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2603   OLEPictureImpl_IConnectionPointContainer_AddRef,
2604   OLEPictureImpl_IConnectionPointContainer_Release,
2605   OLEPictureImpl_EnumConnectionPoints,
2606   OLEPictureImpl_FindConnectionPoint
2607 };
2608
2609 /***********************************************************************
2610  * OleCreatePictureIndirect (OLEAUT32.419)
2611  */
2612 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2613                             BOOL fOwn, LPVOID *ppvObj )
2614 {
2615   OLEPictureImpl* newPict = NULL;
2616   HRESULT      hr         = S_OK;
2617
2618   TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2619
2620   /*
2621    * Sanity check
2622    */
2623   if (ppvObj==0)
2624     return E_POINTER;
2625
2626   *ppvObj = NULL;
2627
2628   /*
2629    * Try to construct a new instance of the class.
2630    */
2631   newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2632
2633   if (newPict == NULL)
2634     return E_OUTOFMEMORY;
2635
2636   /*
2637    * Make sure it supports the interface required by the caller.
2638    */
2639   hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2640
2641   /*
2642    * Release the reference obtained in the constructor. If
2643    * the QueryInterface was unsuccessful, it will free the class.
2644    */
2645   IPicture_Release((IPicture*)newPict);
2646
2647   return hr;
2648 }
2649
2650
2651 /***********************************************************************
2652  * OleLoadPicture (OLEAUT32.418)
2653  */
2654 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2655                             REFIID riid, LPVOID *ppvObj )
2656 {
2657   LPPERSISTSTREAM ps;
2658   IPicture      *newpic;
2659   HRESULT hr;
2660
2661   TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2662         lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2663
2664   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2665   if (hr)
2666     return hr;
2667   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2668   if (hr) {
2669       ERR("Could not get IPersistStream iface from Ole Picture?\n");
2670       IPicture_Release(newpic);
2671       *ppvObj = NULL;
2672       return hr;
2673   }
2674   hr = IPersistStream_Load(ps,lpstream);
2675   IPersistStream_Release(ps);
2676   if (FAILED(hr))
2677   {
2678       ERR("IPersistStream_Load failed\n");
2679       IPicture_Release(newpic);
2680       *ppvObj = NULL;
2681       return hr;
2682   }
2683   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2684   if (hr)
2685       ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2686   IPicture_Release(newpic);
2687   return hr;
2688 }
2689
2690 /***********************************************************************
2691  * OleLoadPictureEx (OLEAUT32.401)
2692  */
2693 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2694                             REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2695 {
2696   LPPERSISTSTREAM ps;
2697   IPicture      *newpic;
2698   HRESULT hr;
2699
2700   FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2701         lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2702
2703   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2704   if (hr)
2705     return hr;
2706   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2707   if (hr) {
2708       ERR("Could not get IPersistStream iface from Ole Picture?\n");
2709       IPicture_Release(newpic);
2710       *ppvObj = NULL;
2711       return hr;
2712   }
2713   hr = IPersistStream_Load(ps,lpstream);
2714   IPersistStream_Release(ps);
2715   if (FAILED(hr))
2716   {
2717       ERR("IPersistStream_Load failed\n");
2718       IPicture_Release(newpic);
2719       *ppvObj = NULL;
2720       return hr;
2721   }
2722   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2723   if (hr)
2724       ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2725   IPicture_Release(newpic);
2726   return hr;
2727 }
2728
2729 /***********************************************************************
2730  * OleLoadPicturePath (OLEAUT32.424)
2731  */
2732 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2733                 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2734                 LPVOID *ppvRet )
2735 {
2736   static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2737   IPicture *ipicture;
2738   HANDLE hFile;
2739   DWORD dwFileSize;
2740   HGLOBAL hGlobal = NULL;
2741   DWORD dwBytesRead = 0;
2742   IStream *stream;
2743   BOOL bRead;
2744   IPersistStream *pStream;
2745   HRESULT hRes;
2746
2747   TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2748         debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2749         debugstr_guid(riid), ppvRet);
2750
2751   if (!ppvRet) return E_POINTER;
2752
2753   if (strncmpW(szURLorPath, file, 7) == 0) {        
2754       szURLorPath += 7;
2755   
2756       hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2757                                    0, NULL);
2758       if (hFile == INVALID_HANDLE_VALUE)
2759           return E_UNEXPECTED;
2760
2761       dwFileSize = GetFileSize(hFile, NULL);
2762       if (dwFileSize != INVALID_FILE_SIZE )
2763       {
2764           hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2765           if ( hGlobal)
2766           {
2767               bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2768               if (!bRead)
2769               {
2770                   GlobalFree(hGlobal);
2771                   hGlobal = 0;
2772               }
2773           }
2774       }
2775       CloseHandle(hFile);
2776       
2777       if (!hGlobal)
2778           return E_UNEXPECTED;
2779
2780       hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2781       if (FAILED(hRes)) 
2782       {
2783           GlobalFree(hGlobal);
2784           return hRes;
2785       }
2786   } else {
2787       IMoniker *pmnk;
2788       IBindCtx *pbc;
2789
2790       hRes = CreateBindCtx(0, &pbc);
2791       if (SUCCEEDED(hRes)) 
2792       {
2793           hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2794           if (SUCCEEDED(hRes))
2795           {              
2796               hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2797               IMoniker_Release(pmnk);
2798           }
2799           IBindCtx_Release(pbc);
2800       }
2801       if (FAILED(hRes))
2802           return hRes;
2803   }
2804
2805   hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER, 
2806                    &IID_IPicture, (LPVOID*)&ipicture);
2807   if (hRes != S_OK) {
2808       IStream_Release(stream);
2809       return hRes;
2810   }
2811   
2812   hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2813   if (hRes) {
2814       IStream_Release(stream);
2815       IPicture_Release(ipicture);
2816       return hRes;
2817   }
2818
2819   hRes = IPersistStream_Load(pStream, stream); 
2820   IPersistStream_Release(pStream);
2821   IStream_Release(stream);
2822
2823   if (hRes) {
2824       IPicture_Release(ipicture);
2825       return hRes;
2826   }
2827
2828   hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2829   if (hRes)
2830       ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2831   
2832   IPicture_Release(ipicture);
2833   return hRes;
2834 }
2835
2836 /*******************************************************************************
2837  * StdPic ClassFactory
2838  */
2839 typedef struct
2840 {
2841     /* IUnknown fields */
2842     const IClassFactoryVtbl    *lpVtbl;
2843     LONG                        ref;
2844 } IClassFactoryImpl;
2845
2846 static HRESULT WINAPI
2847 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2848         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2849
2850         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2851         return E_NOINTERFACE;
2852 }
2853
2854 static ULONG WINAPI
2855 SPCF_AddRef(LPCLASSFACTORY iface) {
2856         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2857         return InterlockedIncrement(&This->ref);
2858 }
2859
2860 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2861         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2862         /* static class, won't be  freed */
2863         return InterlockedDecrement(&This->ref);
2864 }
2865
2866 static HRESULT WINAPI SPCF_CreateInstance(
2867         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2868 ) {
2869     /* Creates an uninitialized picture */
2870     return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2871
2872 }
2873
2874 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2875         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2876         FIXME("(%p)->(%d),stub!\n",This,dolock);
2877         return S_OK;
2878 }
2879
2880 static const IClassFactoryVtbl SPCF_Vtbl = {
2881         SPCF_QueryInterface,
2882         SPCF_AddRef,
2883         SPCF_Release,
2884         SPCF_CreateInstance,
2885         SPCF_LockServer
2886 };
2887 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2888
2889 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }