crypt32: Introduce function to encode an array of items as a set.
[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 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, cx, 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         FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1448         ret = E_FAIL;
1449         goto pngend;
1450     }
1451
1452     if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE){
1453         ppng_set_palette_to_rgb(png_ptr);
1454         set_bgr = TRUE;
1455     }
1456
1457     if (png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1458         png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
1459         set_bgr){
1460         ppng_set_bgr(png_ptr);
1461     }
1462
1463     ppng_read_update_info(png_ptr, info_ptr);
1464
1465     rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1466     /* align rowsize to 4-byte boundary */
1467     rowsize = (rowsize + 3) & ~3;
1468     height = info_ptr->height;
1469     width = info_ptr->width;
1470
1471     pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1472     row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1473
1474     if(!pngdata || !row_pointers){
1475         ret = E_FAIL;
1476         goto pngend;
1477     }
1478
1479     for (row = 0; row < height; row++){
1480         row_pointers[row] = pngdata + row * rowsize;
1481     }
1482
1483     ppng_read_image(png_ptr, row_pointers);
1484
1485     bmi.biSize          = sizeof(bmi);
1486     bmi.biWidth         = width;
1487     bmi.biHeight        = -height;
1488     bmi.biPlanes        = 1;
1489     bmi.biBitCount      = info_ptr->channels * 8;
1490     bmi.biCompression   = BI_RGB;
1491     bmi.biSizeImage     = height * rowsize;
1492     bmi.biXPelsPerMeter = 0;
1493     bmi.biYPelsPerMeter = 0;
1494     bmi.biClrUsed       = 0;
1495     bmi.biClrImportant  = 0;
1496
1497     hdcref = GetDC(0);
1498     This->desc.u.bmp.hbitmap = CreateDIBitmap(
1499         hdcref,
1500         &bmi,
1501         CBM_INIT,
1502         pngdata,
1503         (BITMAPINFO*)&bmi,
1504         DIB_RGB_COLORS
1505     );
1506     ReleaseDC(0, hdcref);
1507     This->desc.picType = PICTYPE_BITMAP;
1508     OLEPictureImpl_SetBitmap(This);
1509     ret = S_OK;
1510
1511 pngend:
1512     if(png_ptr)
1513         ppng_destroy_read_struct(&png_ptr,
1514                                 (info_ptr ? &info_ptr : (png_infopp) NULL),
1515                                 (png_infopp)NULL);
1516     HeapFree(GetProcessHeap(), 0, row_pointers);
1517     HeapFree(GetProcessHeap(), 0, pngdata);
1518     return ret;
1519 #else /* SONAME_LIBPNG */
1520     ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1521     return E_FAIL;
1522 #endif
1523 }
1524
1525 /*****************************************************
1526 *   start of Icon-specific code
1527 */
1528
1529 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1530 {
1531     HICON hicon;
1532     CURSORICONFILEDIR   *cifd = (CURSORICONFILEDIR*)xbuf;
1533     HDC hdcRef;
1534     int i;
1535
1536     /*
1537     FIXME("icon.idReserved=%d\n",cifd->idReserved);
1538     FIXME("icon.idType=%d\n",cifd->idType);
1539     FIXME("icon.idCount=%d\n",cifd->idCount);
1540
1541     for (i=0;i<cifd->idCount;i++) {
1542         FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1543         FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1544         FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1545         FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1546         FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1547         FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1548         FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1549         FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1550     }
1551     */
1552     i=0;
1553     /* If we have more than one icon, try to find the best.
1554      * this currently means '32 pixel wide'.
1555      */
1556     if (cifd->idCount!=1) {
1557         for (i=0;i<cifd->idCount;i++) {
1558             if (cifd->idEntries[i].bWidth == 32)
1559                 break;
1560         }
1561         if (i==cifd->idCount) i=0;
1562     }
1563
1564     hicon = CreateIconFromResourceEx(
1565                 xbuf+cifd->idEntries[i].dwDIBOffset,
1566                 cifd->idEntries[i].dwDIBSize,
1567                 TRUE, /* is icon */
1568                 0x00030000,
1569                 cifd->idEntries[i].bWidth,
1570                 cifd->idEntries[i].bHeight,
1571                 0
1572     );
1573     if (!hicon) {
1574         FIXME("CreateIcon failed.\n");
1575         return E_FAIL;
1576     } else {
1577         This->desc.picType = PICTYPE_ICON;
1578         This->desc.u.icon.hicon = hicon;
1579         This->origWidth = cifd->idEntries[i].bWidth;
1580         This->origHeight = cifd->idEntries[i].bHeight;
1581         hdcRef = CreateCompatibleDC(0);
1582         This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1583         This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1584         DeleteDC(hdcRef);
1585         return S_OK;
1586     }
1587 }
1588
1589 static HRESULT OLEPictureImpl_LoadMetafile(OLEPictureImpl *This,
1590                                            const BYTE *data, ULONG size)
1591 {
1592     HMETAFILE hmf;
1593     HENHMETAFILE hemf;
1594
1595     /* SetMetaFileBitsEx performs data check on its own */
1596     hmf = SetMetaFileBitsEx(size, data);
1597     if (hmf)
1598     {
1599         This->desc.picType = PICTYPE_METAFILE;
1600         This->desc.u.wmf.hmeta = hmf;
1601         This->desc.u.wmf.xExt = 0;
1602         This->desc.u.wmf.yExt = 0;
1603
1604         This->origWidth = 0;
1605         This->origHeight = 0;
1606         This->himetricWidth = 0;
1607         This->himetricHeight = 0;
1608
1609         return S_OK;
1610     }
1611
1612     hemf = SetEnhMetaFileBits(size, data);
1613     if (!hemf) return E_FAIL;
1614
1615     This->desc.picType = PICTYPE_ENHMETAFILE;
1616     This->desc.u.emf.hemf = hemf;
1617
1618     This->origWidth = 0;
1619     This->origHeight = 0;
1620     This->himetricWidth = 0;
1621     This->himetricHeight = 0;
1622
1623     return S_OK;
1624 }
1625
1626 /************************************************************************
1627  * OLEPictureImpl_IPersistStream_Load (IUnknown)
1628  *
1629  * Loads the binary data from the IStream. Starts at current position.
1630  * There appears to be an 2 DWORD header:
1631  *      DWORD magic;
1632  *      DWORD len;
1633  *
1634  * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1635  */
1636 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1637   HRESULT       hr = E_FAIL;
1638   BOOL          headerisdata = FALSE;
1639   BOOL          statfailed = FALSE;
1640   ULONG         xread, toread;
1641   ULONG         headerread;
1642   BYTE          *xbuf;
1643   DWORD         header[2];
1644   WORD          magic;
1645   STATSTG       statstg;
1646   OLEPictureImpl *This = impl_from_IPersistStream(iface);
1647   
1648   TRACE("(%p,%p)\n",This,pStm);
1649
1650   /****************************************************************************************
1651    * Part 1: Load the data
1652    */
1653   /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1654    * out whether we do.
1655    *
1656    * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1657    * compound file. This may explain most, if not all, of the cases of "no
1658    * header", and the header validation should take this into account.
1659    * At least in Visual Basic 6, resource streams, valid headers are
1660    *    header[0] == "lt\0\0",
1661    *    header[1] == length_of_stream.
1662    *
1663    * Also handle streams where we do not have a working "Stat" method by
1664    * reading all data until the end of the stream.
1665    */
1666   hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1667   if (hr) {
1668       TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1669       statfailed = TRUE;
1670       /* we will read at least 8 byte ... just right below */
1671       statstg.cbSize.QuadPart = 8;
1672   }
1673
1674   toread = 0;
1675   headerread = 0;
1676   headerisdata = FALSE;
1677   do {
1678       hr=IStream_Read(pStm,header,8,&xread);
1679       if (hr || xread!=8) {
1680           FIXME("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1681           return hr;
1682       }
1683       headerread += xread;
1684       xread = 0;
1685       
1686       if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1687           if (toread != 0 && toread != header[1]) 
1688               FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1689                   toread, header[1]);
1690           toread = header[1];
1691           if (toread == 0) break;
1692       } else {
1693           if (!memcmp(&(header[0]), "GIF8",     4) ||   /* GIF header */
1694               !memcmp(&(header[0]), "BM",       2) ||   /* BMP header */
1695               !memcmp(&(header[0]), "\xff\xd8", 2) ||   /* JPEG header */
1696               (header[1] > statstg.cbSize.QuadPart)||   /* invalid size */
1697               (header[1]==0)
1698           ) {/* Found start of bitmap data */
1699               headerisdata = TRUE;
1700               if (toread == 0) 
1701                   toread = statstg.cbSize.QuadPart-8;
1702               else toread -= 8;
1703               xread = 8;
1704           } else {
1705               FIXME("Unknown stream header magic: %08x\n", header[0]);
1706               toread = header[1];
1707           }
1708       }
1709   } while (!headerisdata);
1710
1711   if (statfailed) { /* we don't know the size ... read all we get */
1712       int sizeinc = 4096;
1713       int origsize = sizeinc;
1714       ULONG nread = 42;
1715
1716       TRACE("Reading all data from stream.\n");
1717       xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1718       if (headerisdata)
1719           memcpy (xbuf, &header, 8);
1720       while (1) {
1721           while (xread < origsize) {
1722               hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1723               xread+=nread;
1724               if (hr || !nread)
1725                   break;
1726           }
1727           if (!nread || hr) /* done, or error */
1728               break;
1729           if (xread == origsize) {
1730               origsize += sizeinc;
1731               sizeinc = 2*sizeinc; /* exponential increase */
1732               xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1733           }
1734       }
1735       if (hr)
1736           TRACE("hr in no-stat loader case is %08x\n", hr);
1737       TRACE("loaded %d bytes.\n", xread);
1738       This->datalen = xread;
1739       This->data    = xbuf;
1740   } else {
1741       This->datalen = toread+(headerisdata?8:0);
1742       xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1743
1744       if (headerisdata)
1745           memcpy (xbuf, &header, 8);
1746
1747       while (xread < This->datalen) {
1748           ULONG nread;
1749           hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1750           xread+=nread;
1751           if (hr || !nread)
1752               break;
1753       }
1754       if (xread != This->datalen)
1755           FIXME("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1756   }
1757   if (This->datalen == 0) { /* Marks the "NONE" picture */
1758       This->desc.picType = PICTYPE_NONE;
1759       return S_OK;
1760   }
1761
1762
1763   /****************************************************************************************
1764    * Part 2: Process the loaded data
1765    */
1766
1767   magic = xbuf[0] + (xbuf[1]<<8);
1768   This->loadtime_format = magic;
1769
1770   switch (magic) {
1771   case 0x4947: /* GIF */
1772     hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1773     break;
1774   case 0xd8ff: /* JPEG */
1775     hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1776     break;
1777   case 0x4d42: /* Bitmap */
1778     hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1779     break;
1780   case 0x5089: /* PNG */
1781     hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1782     break;
1783   case 0x0000: { /* ICON , first word is dwReserved */
1784     hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1785     break;
1786   }
1787   default:
1788   {
1789     unsigned int i;
1790
1791     /* let's see if it's a metafile */
1792     hr = OLEPictureImpl_LoadMetafile(This, xbuf, xread);
1793     if (hr == S_OK) break;
1794
1795     FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1796     hr=E_FAIL;
1797     for (i=0;i<xread+8;i++) {
1798         if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
1799         else MESSAGE("%02x ",xbuf[i-8]);
1800         if (i % 10 == 9) MESSAGE("\n");
1801     }
1802     MESSAGE("\n");
1803     break;
1804   }
1805   }
1806   This->bIsDirty = FALSE;
1807
1808   /* FIXME: this notify is not really documented */
1809   if (hr==S_OK)
1810       OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1811   return hr;
1812 }
1813
1814 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1815 {
1816     int iSuccess = 0;
1817     HDC hDC;
1818     BITMAPINFO * pInfoBitmap;
1819     int iNumPaletteEntries;
1820     unsigned char * pPixelData;
1821     BITMAPFILEHEADER * pFileHeader;
1822     BITMAPINFO * pInfoHeader;
1823
1824     pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1825         sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1826
1827     /* Find out bitmap size and padded length */
1828     hDC = GetDC(0);
1829     pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1830     GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1831
1832     /* Fetch bitmap palette & pixel data */
1833
1834     pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1835     GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1836
1837     /* Calculate the total length required for the BMP data */
1838     if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1839         iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1840         if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1841     } else {
1842         if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1843             iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1844         else
1845             iNumPaletteEntries = 0;
1846     }
1847     *pLength =
1848         sizeof(BITMAPFILEHEADER) +
1849         sizeof(BITMAPINFOHEADER) +
1850         iNumPaletteEntries * sizeof(RGBQUAD) +
1851         pInfoBitmap->bmiHeader.biSizeImage;
1852     *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1853
1854     /* Fill the BITMAPFILEHEADER */
1855     pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1856     pFileHeader->bfType = 0x4d42;
1857     pFileHeader->bfSize = *pLength;
1858     pFileHeader->bfOffBits =
1859         sizeof(BITMAPFILEHEADER) +
1860         sizeof(BITMAPINFOHEADER) +
1861         iNumPaletteEntries * sizeof(RGBQUAD);
1862
1863     /* Fill the BITMAPINFOHEADER and the palette data */
1864     pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1865     memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1866     memcpy(
1867         (unsigned char *)(*ppBuffer) +
1868             sizeof(BITMAPFILEHEADER) +
1869             sizeof(BITMAPINFOHEADER) +
1870             iNumPaletteEntries * sizeof(RGBQUAD),
1871         pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1872     iSuccess = 1;
1873
1874     HeapFree(GetProcessHeap(), 0, pPixelData);
1875     HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1876     return iSuccess;
1877 }
1878
1879 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1880 {
1881         ICONINFO infoIcon;
1882         int iSuccess = 0;
1883
1884         *ppBuffer = NULL; *pLength = 0;
1885         if (GetIconInfo(hIcon, &infoIcon)) {
1886                 HDC hDC;
1887                 BITMAPINFO * pInfoBitmap;
1888                 unsigned char * pIconData = NULL;
1889                 unsigned int iDataSize = 0;
1890
1891         pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1892
1893                 /* Find out icon size */
1894                 hDC = GetDC(0);
1895                 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1896                 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1897                 if (1) {
1898                         /* Auxiliary pointers */
1899                         CURSORICONFILEDIR * pIconDir;
1900                         CURSORICONFILEDIRENTRY * pIconEntry;
1901                         BITMAPINFOHEADER * pIconBitmapHeader;
1902                         unsigned int iOffsetPalette;
1903                         unsigned int iOffsetColorData;
1904                         unsigned int iOffsetMaskData;
1905
1906                         unsigned int iLengthScanLineColor;
1907                         unsigned int iLengthScanLineMask;
1908                         unsigned int iNumEntriesPalette;
1909
1910                         iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1911                         iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
1912 /*
1913                         FIXME("DEBUG: bitmap size is %d x %d\n",
1914                                 pInfoBitmap->bmiHeader.biWidth,
1915                                 pInfoBitmap->bmiHeader.biHeight);
1916                         FIXME("DEBUG: bitmap bpp is %d\n",
1917                                 pInfoBitmap->bmiHeader.biBitCount);
1918                         FIXME("DEBUG: bitmap nplanes is %d\n",
1919                                 pInfoBitmap->bmiHeader.biPlanes);
1920                         FIXME("DEBUG: bitmap biSizeImage is %u\n",
1921                                 pInfoBitmap->bmiHeader.biSizeImage);
1922 */
1923                         /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1924                         iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1925                         pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1926
1927                         /* Fill out the CURSORICONFILEDIR */
1928                         pIconDir = (CURSORICONFILEDIR *)pIconData;
1929                         pIconDir->idType = 1;
1930                         pIconDir->idCount = 1;
1931
1932                         /* Fill out the CURSORICONFILEDIRENTRY */
1933                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1934                         pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1935                         pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1936                         pIconEntry->bColorCount =
1937                                 (pInfoBitmap->bmiHeader.biBitCount < 8)
1938                                 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1939                                 : 0;
1940                         pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1941                         pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1942                         pIconEntry->dwDIBSize = 0;
1943                         pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1944
1945                         /* Fill out the BITMAPINFOHEADER */
1946                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1947                         memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
1948
1949                         /*      Find out whether a palette exists for the bitmap */
1950                         if (    (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1951                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 24)
1952                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1953                                 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1954                                 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256; 
1955                         } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1956                                 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1957                                 iNumEntriesPalette = 3;
1958                         } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1959                                 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1960                         } else {
1961                                 iNumEntriesPalette = 0;
1962                         }
1963
1964                         /*  Add bitmap size and header size to icon data size. */
1965                         iOffsetPalette = iDataSize;
1966                         iDataSize += iNumEntriesPalette * sizeof(DWORD);
1967                         iOffsetColorData = iDataSize;
1968                         iDataSize += pIconBitmapHeader->biSizeImage;
1969                         iOffsetMaskData = iDataSize;
1970                         iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1971                         pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1972                         pIconBitmapHeader->biHeight *= 2;
1973                         pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1974                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1975                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1976                         pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1977
1978                         /* Get the actual bitmap data from the icon bitmap */
1979                         GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1980                                 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1981                         if (iNumEntriesPalette > 0) {
1982                                 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1983                                         iNumEntriesPalette * sizeof(RGBQUAD));
1984                         }
1985
1986                         /* Reset all values so that GetDIBits call succeeds */
1987                         memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1988                         memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1989                         pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1990 /*
1991             if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1992                                 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1993                                         pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1994
1995                 printf("ERROR: unable to get bitmap mask (error %u)\n",
1996                                         GetLastError());
1997
1998                         }
1999 */
2000             GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2001             GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2002
2003                         /* Write out everything produced so far to the stream */
2004                         *ppBuffer = pIconData; *pLength = iDataSize;
2005                         iSuccess = 1;
2006                 } else {
2007 /*
2008                         printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2009                                 GetLastError());
2010 */
2011                 }
2012                 /*
2013                         Remarks (from MSDN entry on GetIconInfo):
2014
2015                         GetIconInfo creates bitmaps for the hbmMask and hbmColor
2016                         members of ICONINFO. The calling application must manage
2017                         these bitmaps and delete them when they are no longer
2018                         necessary.
2019                  */
2020                 if (hDC) ReleaseDC(0, hDC);
2021                 DeleteObject(infoIcon.hbmMask);
2022                 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2023                 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2024         } else {
2025                 printf("ERROR: Unable to get icon information (error %u)\n",
2026                         GetLastError());
2027         }
2028         return iSuccess;
2029 }
2030
2031 static HRESULT WINAPI OLEPictureImpl_Save(
2032   IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2033 {
2034     HRESULT hResult = E_NOTIMPL;
2035     void * pIconData;
2036     unsigned int iDataSize;
2037     ULONG dummy;
2038     int iSerializeResult = 0;
2039     OLEPictureImpl *This = impl_from_IPersistStream(iface);
2040
2041     TRACE("%p %p %d\n", This, pStm, fClearDirty);
2042
2043     switch (This->desc.picType) {
2044     case PICTYPE_ICON:
2045         if (This->bIsDirty || !This->data) {
2046             if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2047                 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2048                 hResult = E_FAIL;
2049                 break;
2050             }
2051             HeapFree(GetProcessHeap(), 0, This->data);
2052             This->data = pIconData;
2053             This->datalen = iDataSize;
2054         }
2055         if (This->loadtime_magic != 0xdeadbeef) {
2056             DWORD header[2];
2057
2058             header[0] = This->loadtime_magic;
2059             header[1] = This->datalen;
2060             IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2061         }
2062         IStream_Write(pStm, This->data, This->datalen, &dummy);
2063
2064         hResult = S_OK;
2065         break;
2066     case PICTYPE_BITMAP:
2067         if (This->bIsDirty) {
2068             switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) {
2069             case 0x4d42:
2070                 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2071                 break;
2072             case 0xd8ff:
2073                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2074                 break;
2075             case 0x4947:
2076                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2077                 break;
2078             case 0x5089:
2079                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2080                 break;
2081             default:
2082                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2083                 break;
2084             }
2085             if (iSerializeResult) {
2086                 /*
2087                 if (This->loadtime_magic != 0xdeadbeef) {
2088                 */
2089                 if (1) {
2090                     DWORD header[2];
2091
2092                     header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2093                     header[1] = iDataSize;
2094                     IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2095                 }
2096                 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2097
2098                 HeapFree(GetProcessHeap(), 0, This->data);
2099                 This->data = pIconData;
2100                 This->datalen = iDataSize;
2101                 hResult = S_OK;
2102             }
2103         } else {
2104             /*
2105             if (This->loadtime_magic != 0xdeadbeef) {
2106             */
2107             if (1) {
2108                 DWORD header[2];
2109
2110                 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2111                 header[1] = This->datalen;
2112                 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2113             }
2114             IStream_Write(pStm, This->data, This->datalen, &dummy);
2115             hResult = S_OK;
2116         }
2117         break;
2118     case PICTYPE_METAFILE:
2119         FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2120         break;
2121     case PICTYPE_ENHMETAFILE:
2122         FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2123         break;
2124     default:
2125         FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2126         break;
2127     }
2128     if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2129     return hResult;
2130 }
2131
2132 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2133   IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2134 {
2135   OLEPictureImpl *This = impl_from_IPersistStream(iface);
2136   FIXME("(%p,%p),stub!\n",This,pcbSize);
2137   return E_NOTIMPL;
2138 }
2139
2140
2141 /************************************************************************
2142  *    IDispatch
2143  */
2144
2145 /************************************************************************
2146  * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2147  *
2148  * See Windows documentation for more details on IUnknown methods.
2149  */
2150 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2151   IDispatch* iface,
2152   REFIID     riid,
2153   VOID**     ppvoid)
2154 {
2155   OLEPictureImpl *This = impl_from_IDispatch(iface);
2156
2157   return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2158 }
2159
2160 /************************************************************************
2161  * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2162  *
2163  * See Windows documentation for more details on IUnknown methods.
2164  */
2165 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2166   IDispatch* iface)
2167 {
2168   OLEPictureImpl *This = impl_from_IDispatch(iface);
2169
2170   return IPicture_AddRef((IPicture *)This);
2171 }
2172
2173 /************************************************************************
2174  * OLEPictureImpl_IDispatch_Release (IUnknown)
2175  *
2176  * See Windows documentation for more details on IUnknown methods.
2177  */
2178 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2179   IDispatch* iface)
2180 {
2181   OLEPictureImpl *This = impl_from_IDispatch(iface);
2182
2183   return IPicture_Release((IPicture *)This);
2184 }
2185
2186 /************************************************************************
2187  * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2188  *
2189  * See Windows documentation for more details on IDispatch methods.
2190  */
2191 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2192   IDispatch*    iface,
2193   unsigned int* pctinfo)
2194 {
2195   TRACE("(%p)\n", pctinfo);
2196
2197   *pctinfo = 1;
2198
2199   return S_OK;
2200 }
2201
2202 /************************************************************************
2203  * OLEPictureImpl_GetTypeInfo (IDispatch)
2204  *
2205  * See Windows documentation for more details on IDispatch methods.
2206  */
2207 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2208   IDispatch*  iface,
2209   UINT      iTInfo,
2210   LCID        lcid,
2211   ITypeInfo** ppTInfo)
2212 {
2213   static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2214   ITypeLib *tl;
2215   HRESULT hres;
2216
2217   TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2218
2219   if (iTInfo != 0)
2220     return E_FAIL;
2221
2222   hres = LoadTypeLib(stdole2tlb, &tl);
2223   if (FAILED(hres))
2224   {
2225     ERR("Could not load stdole2.tlb\n");
2226     return hres;
2227   }
2228
2229   hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2230   if (FAILED(hres))
2231     ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2232
2233   return hres;
2234 }
2235
2236 /************************************************************************
2237  * OLEPictureImpl_GetIDsOfNames (IDispatch)
2238  *
2239  * See Windows documentation for more details on IDispatch methods.
2240  */
2241 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2242   IDispatch*  iface,
2243   REFIID      riid,
2244   LPOLESTR* rgszNames,
2245   UINT      cNames,
2246   LCID        lcid,
2247   DISPID*     rgDispId)
2248 {
2249   FIXME("():Stub\n");
2250
2251   return E_NOTIMPL;
2252 }
2253
2254 /************************************************************************
2255  * OLEPictureImpl_Invoke (IDispatch)
2256  *
2257  * See Windows documentation for more details on IDispatch methods.
2258  */
2259 static HRESULT WINAPI OLEPictureImpl_Invoke(
2260   IDispatch*  iface,
2261   DISPID      dispIdMember,
2262   REFIID      riid,
2263   LCID        lcid,
2264   WORD        wFlags,
2265   DISPPARAMS* pDispParams,
2266   VARIANT*    pVarResult,
2267   EXCEPINFO*  pExepInfo,
2268   UINT*     puArgErr)
2269 {
2270   OLEPictureImpl *This = impl_from_IDispatch(iface);
2271
2272   /* validate parameters */
2273
2274   if (!IsEqualIID(riid, &IID_NULL))
2275   {
2276     ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2277     return DISP_E_UNKNOWNNAME;
2278   }
2279
2280   if (!pDispParams)
2281   {
2282     ERR("null pDispParams not allowed\n");
2283     return DISP_E_PARAMNOTOPTIONAL;
2284   }
2285
2286   if (wFlags & DISPATCH_PROPERTYGET)
2287   {
2288     if (pDispParams->cArgs != 0)
2289     {
2290       ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2291       return DISP_E_BADPARAMCOUNT;
2292     }
2293     if (!pVarResult)
2294     {
2295       ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2296       return DISP_E_PARAMNOTOPTIONAL;
2297     }
2298   }
2299   else if (wFlags & DISPATCH_PROPERTYPUT)
2300   {
2301     if (pDispParams->cArgs != 1)
2302     {
2303       ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2304       return DISP_E_BADPARAMCOUNT;
2305     }
2306   }
2307
2308   switch (dispIdMember)
2309   {
2310   case DISPID_PICT_HANDLE:
2311     if (wFlags & DISPATCH_PROPERTYGET)
2312     {
2313       TRACE("DISPID_PICT_HANDLE\n");
2314       V_VT(pVarResult) = VT_I4;
2315       return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2316     }
2317     break;
2318   case DISPID_PICT_HPAL:
2319     if (wFlags & DISPATCH_PROPERTYGET)
2320     {
2321       TRACE("DISPID_PICT_HPAL\n");
2322       V_VT(pVarResult) = VT_I4;
2323       return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2324     }
2325     else if (wFlags & DISPATCH_PROPERTYPUT)
2326     {
2327       VARIANTARG vararg;
2328       HRESULT hr;
2329       TRACE("DISPID_PICT_HPAL\n");
2330
2331       VariantInit(&vararg);
2332       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2333       if (FAILED(hr))
2334         return hr;
2335
2336       hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2337
2338       VariantClear(&vararg);
2339       return hr;
2340     }
2341     break;
2342   case DISPID_PICT_TYPE:
2343     if (wFlags & DISPATCH_PROPERTYGET)
2344     {
2345       TRACE("DISPID_PICT_TYPE\n");
2346       V_VT(pVarResult) = VT_I2;
2347       return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2348     }
2349     break;
2350   case DISPID_PICT_WIDTH:
2351     if (wFlags & DISPATCH_PROPERTYGET)
2352     {
2353       TRACE("DISPID_PICT_WIDTH\n");
2354       V_VT(pVarResult) = VT_I4;
2355       return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2356     }
2357     break;
2358   case DISPID_PICT_HEIGHT:
2359     if (wFlags & DISPATCH_PROPERTYGET)
2360     {
2361       TRACE("DISPID_PICT_HEIGHT\n");
2362       V_VT(pVarResult) = VT_I4;
2363       return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2364     }
2365     break;
2366   }
2367
2368   ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2369   return DISP_E_MEMBERNOTFOUND;
2370 }
2371
2372
2373 static const IPictureVtbl OLEPictureImpl_VTable =
2374 {
2375   OLEPictureImpl_QueryInterface,
2376   OLEPictureImpl_AddRef,
2377   OLEPictureImpl_Release,
2378   OLEPictureImpl_get_Handle,
2379   OLEPictureImpl_get_hPal,
2380   OLEPictureImpl_get_Type,
2381   OLEPictureImpl_get_Width,
2382   OLEPictureImpl_get_Height,
2383   OLEPictureImpl_Render,
2384   OLEPictureImpl_set_hPal,
2385   OLEPictureImpl_get_CurDC,
2386   OLEPictureImpl_SelectPicture,
2387   OLEPictureImpl_get_KeepOriginalFormat,
2388   OLEPictureImpl_put_KeepOriginalFormat,
2389   OLEPictureImpl_PictureChanged,
2390   OLEPictureImpl_SaveAsFile,
2391   OLEPictureImpl_get_Attributes
2392 };
2393
2394 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2395 {
2396   OLEPictureImpl_IDispatch_QueryInterface,
2397   OLEPictureImpl_IDispatch_AddRef,
2398   OLEPictureImpl_IDispatch_Release,
2399   OLEPictureImpl_GetTypeInfoCount,
2400   OLEPictureImpl_GetTypeInfo,
2401   OLEPictureImpl_GetIDsOfNames,
2402   OLEPictureImpl_Invoke
2403 };
2404
2405 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2406 {
2407   OLEPictureImpl_IPersistStream_QueryInterface,
2408   OLEPictureImpl_IPersistStream_AddRef,
2409   OLEPictureImpl_IPersistStream_Release,
2410   OLEPictureImpl_GetClassID,
2411   OLEPictureImpl_IsDirty,
2412   OLEPictureImpl_Load,
2413   OLEPictureImpl_Save,
2414   OLEPictureImpl_GetSizeMax
2415 };
2416
2417 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2418 {
2419   OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2420   OLEPictureImpl_IConnectionPointContainer_AddRef,
2421   OLEPictureImpl_IConnectionPointContainer_Release,
2422   OLEPictureImpl_EnumConnectionPoints,
2423   OLEPictureImpl_FindConnectionPoint
2424 };
2425
2426 /***********************************************************************
2427  * OleCreatePictureIndirect (OLEAUT32.419)
2428  */
2429 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2430                             BOOL fOwn, LPVOID *ppvObj )
2431 {
2432   OLEPictureImpl* newPict = NULL;
2433   HRESULT      hr         = S_OK;
2434
2435   TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2436
2437   /*
2438    * Sanity check
2439    */
2440   if (ppvObj==0)
2441     return E_POINTER;
2442
2443   *ppvObj = NULL;
2444
2445   /*
2446    * Try to construct a new instance of the class.
2447    */
2448   newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2449
2450   if (newPict == NULL)
2451     return E_OUTOFMEMORY;
2452
2453   /*
2454    * Make sure it supports the interface required by the caller.
2455    */
2456   hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2457
2458   /*
2459    * Release the reference obtained in the constructor. If
2460    * the QueryInterface was unsuccessful, it will free the class.
2461    */
2462   IPicture_Release((IPicture*)newPict);
2463
2464   return hr;
2465 }
2466
2467
2468 /***********************************************************************
2469  * OleLoadPicture (OLEAUT32.418)
2470  */
2471 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2472                             REFIID riid, LPVOID *ppvObj )
2473 {
2474   LPPERSISTSTREAM ps;
2475   IPicture      *newpic;
2476   HRESULT hr;
2477
2478   TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2479         lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2480
2481   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2482   if (hr)
2483     return hr;
2484   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2485   if (hr) {
2486       FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2487       IPicture_Release(newpic);
2488       *ppvObj = NULL;
2489       return hr;
2490   }
2491   IPersistStream_Load(ps,lpstream);
2492   IPersistStream_Release(ps);
2493   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2494   if (hr)
2495       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2496   IPicture_Release(newpic);
2497   return hr;
2498 }
2499
2500 /***********************************************************************
2501  * OleLoadPictureEx (OLEAUT32.401)
2502  */
2503 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2504                             REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2505 {
2506   LPPERSISTSTREAM ps;
2507   IPicture      *newpic;
2508   HRESULT hr;
2509
2510   FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2511         lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2512
2513   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2514   if (hr)
2515     return hr;
2516   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2517   if (hr) {
2518       FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2519       IPicture_Release(newpic);
2520       *ppvObj = NULL;
2521       return hr;
2522   }
2523   IPersistStream_Load(ps,lpstream);
2524   IPersistStream_Release(ps);
2525   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2526   if (hr)
2527       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2528   IPicture_Release(newpic);
2529   return hr;
2530 }
2531
2532 /***********************************************************************
2533  * OleLoadPicturePath (OLEAUT32.424)
2534  */
2535 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2536                 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2537                 LPVOID *ppvRet )
2538 {
2539   static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2540   IPicture *ipicture;
2541   HANDLE hFile;
2542   DWORD dwFileSize;
2543   HGLOBAL hGlobal = NULL;
2544   DWORD dwBytesRead = 0;
2545   IStream *stream;
2546   BOOL bRead;
2547   IPersistStream *pStream;
2548   HRESULT hRes;
2549
2550   TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2551         debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2552         debugstr_guid(riid), ppvRet);
2553
2554   if (!ppvRet) return E_POINTER;
2555
2556   if (strncmpW(szURLorPath, file, 7) == 0) {        
2557       szURLorPath += 7;
2558   
2559       hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2560                                    0, NULL);
2561       if (hFile == INVALID_HANDLE_VALUE)
2562           return E_UNEXPECTED;
2563
2564       dwFileSize = GetFileSize(hFile, NULL);
2565       if (dwFileSize != INVALID_FILE_SIZE )
2566       {
2567           hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2568           if ( hGlobal)
2569           {
2570               bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2571               if (!bRead)
2572               {
2573                   GlobalFree(hGlobal);
2574                   hGlobal = 0;
2575               }
2576           }
2577       }
2578       CloseHandle(hFile);
2579       
2580       if (!hGlobal)
2581           return E_UNEXPECTED;
2582
2583       hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2584       if (FAILED(hRes)) 
2585       {
2586           GlobalFree(hGlobal);
2587           return hRes;
2588       }
2589   } else {
2590       IMoniker *pmnk;
2591       IBindCtx *pbc;
2592
2593       hRes = CreateBindCtx(0, &pbc);
2594       if (SUCCEEDED(hRes)) 
2595       {
2596           hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2597           if (SUCCEEDED(hRes))
2598           {              
2599               hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2600               IMoniker_Release(pmnk);
2601           }
2602           IBindCtx_Release(pbc);
2603       }
2604       if (FAILED(hRes))
2605           return hRes;
2606   }
2607
2608   hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER, 
2609                    &IID_IPicture, (LPVOID*)&ipicture);
2610   if (hRes != S_OK) {
2611       IStream_Release(stream);
2612       return hRes;
2613   }
2614   
2615   hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2616   if (hRes) {
2617       IStream_Release(stream);
2618       IPicture_Release(ipicture);
2619       return hRes;
2620   }
2621
2622   hRes = IPersistStream_Load(pStream, stream); 
2623   IPersistStream_Release(pStream);
2624   IStream_Release(stream);
2625
2626   if (hRes) {
2627       IPicture_Release(ipicture);
2628       return hRes;
2629   }
2630
2631   hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2632   if (hRes)
2633       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2634   
2635   IPicture_Release(ipicture);
2636   return hRes;
2637 }
2638
2639 /*******************************************************************************
2640  * StdPic ClassFactory
2641  */
2642 typedef struct
2643 {
2644     /* IUnknown fields */
2645     const IClassFactoryVtbl    *lpVtbl;
2646     LONG                        ref;
2647 } IClassFactoryImpl;
2648
2649 static HRESULT WINAPI
2650 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2651         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2652
2653         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2654         return E_NOINTERFACE;
2655 }
2656
2657 static ULONG WINAPI
2658 SPCF_AddRef(LPCLASSFACTORY iface) {
2659         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2660         return InterlockedIncrement(&This->ref);
2661 }
2662
2663 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2664         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2665         /* static class, won't be  freed */
2666         return InterlockedDecrement(&This->ref);
2667 }
2668
2669 static HRESULT WINAPI SPCF_CreateInstance(
2670         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2671 ) {
2672     /* Creates an uninitialized picture */
2673     return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2674
2675 }
2676
2677 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2678         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2679         FIXME("(%p)->(%d),stub!\n",This,dolock);
2680         return S_OK;
2681 }
2682
2683 static const IClassFactoryVtbl SPCF_Vtbl = {
2684         SPCF_QueryInterface,
2685         SPCF_AddRef,
2686         SPCF_Release,
2687         SPCF_CreateInstance,
2688         SPCF_LockServer
2689 };
2690 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2691
2692 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }