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