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