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