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