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