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