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