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