Mark links to dir with FILE_ATTRIBUTE_REPARSE_POINT, so modern
[wine] / dlls / oleaut32 / olepicture.c
1 /*
2  * OLE Picture object
3  *
4  * Implementation of OLE IPicture and related interfaces
5  *
6  * Copyright 2000 Huw D M Davies for CodeWeavers.
7  * Copyright 2001 Marcus Meissner
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * BUGS
24  *
25  * Support PICTYPE_BITMAP and PICTYPE_ICON, altough only bitmaps very well..
26  * Lots of methods are just stubs.
27  *
28  *
29  * NOTES (or things that msdn doesn't tell you)
30  *
31  * The width and height properties are returned in HIMETRIC units (0.01mm)
32  * IPicture::Render also uses these to select a region of the src picture.
33  * A bitmap's size is converted into these units by using the screen resolution
34  * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
35  *
36  */
37
38 #include "config.h"
39 #include "wine/port.h"
40
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <string.h>
47
48 /* Must be before wine includes, the header has things conflicting with
49  * WINE headers.
50  */
51 #ifdef HAVE_GIF_LIB_H
52 # include <gif_lib.h>
53 # ifndef SONAME_LIBUNGIF
54 #  define SONAME_LIBUNGIF "libungif.so"
55 # endif
56 # ifndef SONAME_LIBGIF
57 #  define SONAME_LIBGIF "libgif.so"
58 # endif
59 #endif
60
61 #define COBJMACROS
62 #define NONAMELESSUNION
63 #define NONAMELESSSTRUCT
64
65 #include "winerror.h"
66 #include "windef.h"
67 #include "winbase.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "ole2.h"
71 #include "olectl.h"
72 #include "oleauto.h"
73 #include "connpt.h"
74 #include "urlmon.h"
75 #include "wine/debug.h"
76 #include "wine/unicode.h"
77
78 #include "wine/wingdi16.h"
79 #include "cursoricon.h"
80
81 #ifdef HAVE_JPEGLIB_H
82 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
83 #define XMD_H
84 #define UINT8 JPEG_UINT8
85 #define UINT16 JPEG_UINT16
86 #undef FAR
87 # include <jpeglib.h>
88 #undef UINT16
89 #ifndef SONAME_LIBJPEG
90 #define SONAME_LIBJPEG "libjpeg.so"
91 #endif
92 #endif
93
94 WINE_DEFAULT_DEBUG_CHANNEL(ole);
95
96 /*************************************************************************
97  *  Declaration of implementation class
98  */
99
100 typedef struct OLEPictureImpl {
101
102   /*
103    * IPicture handles IUnknown
104    */
105
106     IPictureVtbl       *lpvtbl1;
107     IDispatchVtbl      *lpvtbl2;
108     IPersistStreamVtbl *lpvtbl3;
109     IConnectionPointContainerVtbl *lpvtbl4;
110
111   /* Object reference count */
112     DWORD ref;
113
114   /* We own the object and must destroy it ourselves */
115     BOOL fOwn;
116
117   /* Picture description */
118     PICTDESC desc;
119
120   /* These are the pixel size of a bitmap */
121     DWORD origWidth;
122     DWORD origHeight;
123
124   /* And these are the size of the picture converted into HIMETRIC units */
125     OLE_XSIZE_HIMETRIC himetricWidth;
126     OLE_YSIZE_HIMETRIC himetricHeight;
127
128     IConnectionPoint *pCP;
129
130     BOOL keepOrigFormat;
131     HDC hDCCur;
132
133   /* Bitmap transparency mask */
134     HBITMAP hbmMask;
135     HBITMAP hbmXor;
136     COLORREF rgbTrans;
137
138   /* data */
139     void* data;
140     int datalen;
141     BOOL bIsDirty;                  /* Set to TRUE if picture has changed */
142     unsigned int loadtime_magic;    /* If a length header was found, saves value */
143     unsigned int loadtime_format;   /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
144 } OLEPictureImpl;
145
146 /*
147  * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
148  */
149 #define ICOM_THIS_From_IDispatch(impl, name) \
150     impl *This = (impl*)(((char*)name)-sizeof(void*));
151 #define ICOM_THIS_From_IPersistStream(impl, name) \
152     impl *This = (impl*)(((char*)name)-2*sizeof(void*));
153 #define ICOM_THIS_From_IConnectionPointContainer(impl, name) \
154     impl *This = (impl*)(((char*)name)-3*sizeof(void*));
155
156 /*
157  * Predeclare VTables.  They get initialized at the end.
158  */
159 static IPictureVtbl OLEPictureImpl_VTable;
160 static IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
161 static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
162 static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
163
164 /***********************************************************************
165  * Implementation of the OLEPictureImpl class.
166  */
167
168 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
169   BITMAP bm;
170   HDC hdcRef;
171
172   TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
173   if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
174     ERR("GetObject fails\n");
175     return;
176   }
177   This->origWidth = bm.bmWidth;
178   This->origHeight = bm.bmHeight;
179   /* The width and height are stored in HIMETRIC units (0.01 mm),
180      so we take our pixel width divide by pixels per inch and
181      multiply by 25.4 * 100 */
182   /* Should we use GetBitmapDimension if available? */
183   hdcRef = CreateCompatibleDC(0);
184   This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
185   This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
186   DeleteDC(hdcRef);
187 }
188
189 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
190 {
191     ICONINFO infoIcon;
192
193     TRACE("icon handle %p\n", This->desc.u.icon.hicon);
194     if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
195         HDC hdcRef;
196         BITMAP bm;
197
198         TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
199         if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
200             ERR("GetObject fails on icon bitmap\n");
201             return;
202         }
203
204         This->origWidth = bm.bmWidth;
205         This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
206         /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
207         hdcRef = GetDC(0);
208         This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
209         This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
210         ReleaseDC(0, hdcRef);
211
212         DeleteObject(infoIcon.hbmMask);
213         if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
214     } else {
215         ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
216     }
217 }
218
219 /************************************************************************
220  * OLEPictureImpl_Construct
221  *
222  * This method will construct a new instance of the OLEPictureImpl
223  * class.
224  *
225  * The caller of this method must release the object when it's
226  * done with it.
227  */
228 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
229 {
230   OLEPictureImpl* newObject = 0;
231
232   if (pictDesc)
233       TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
234
235   /*
236    * Allocate space for the object.
237    */
238   newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
239
240   if (newObject==0)
241     return newObject;
242
243   /*
244    * Initialize the virtual function table.
245    */
246   newObject->lpvtbl1 = &OLEPictureImpl_VTable;
247   newObject->lpvtbl2 = &OLEPictureImpl_IDispatch_VTable;
248   newObject->lpvtbl3 = &OLEPictureImpl_IPersistStream_VTable;
249   newObject->lpvtbl4 = &OLEPictureImpl_IConnectionPointContainer_VTable;
250
251   CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
252
253   /*
254    * Start with one reference count. The caller of this function
255    * must release the interface pointer when it is done.
256    */
257   newObject->ref        = 1;
258   newObject->hDCCur     = 0;
259
260   newObject->fOwn       = fOwn;
261
262   /* dunno about original value */
263   newObject->keepOrigFormat = TRUE;
264
265   newObject->hbmMask = NULL;
266   newObject->hbmXor = NULL;
267   newObject->loadtime_magic = 0xdeadbeef;
268   newObject->loadtime_format = 0;
269   newObject->bIsDirty = FALSE;
270
271   if (pictDesc) {
272       if(pictDesc->cbSizeofstruct != sizeof(PICTDESC)) {
273           FIXME("struct size = %d\n", pictDesc->cbSizeofstruct);
274       }
275       memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC));
276
277
278       switch(pictDesc->picType) {
279       case PICTYPE_BITMAP:
280         OLEPictureImpl_SetBitmap(newObject);
281         break;
282
283       case PICTYPE_METAFILE:
284         TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
285         newObject->himetricWidth = pictDesc->u.wmf.xExt;
286         newObject->himetricHeight = pictDesc->u.wmf.yExt;
287         break;
288
289       case PICTYPE_NONE:
290         /* not sure what to do here */
291         newObject->himetricWidth = newObject->himetricHeight = 0;
292         break;
293
294       case PICTYPE_ICON:
295         OLEPictureImpl_SetIcon(newObject);
296         break;
297       case PICTYPE_ENHMETAFILE:
298       default:
299         FIXME("Unsupported type %d\n", pictDesc->picType);
300         newObject->himetricWidth = newObject->himetricHeight = 0;
301         break;
302       }
303   } else {
304       newObject->desc.picType = PICTYPE_UNINITIALIZED;
305   }
306
307   TRACE("returning %p\n", newObject);
308   return newObject;
309 }
310
311 /************************************************************************
312  * OLEPictureImpl_Destroy
313  *
314  * This method is called by the Release method when the reference
315  * count goes down to 0. It will free all resources used by
316  * this object.  */
317 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
318 {
319   TRACE("(%p)\n", Obj);
320
321   if(Obj->fOwn) { /* We need to destroy the picture */
322     switch(Obj->desc.picType) {
323     case PICTYPE_BITMAP:
324       DeleteObject(Obj->desc.u.bmp.hbitmap);
325       if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
326       if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
327       break;
328     case PICTYPE_METAFILE:
329       DeleteMetaFile(Obj->desc.u.wmf.hmeta);
330       break;
331     case PICTYPE_ICON:
332       DestroyIcon(Obj->desc.u.icon.hicon);
333       break;
334     case PICTYPE_ENHMETAFILE:
335       DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
336       break;
337     default:
338       FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
339       break;
340     }
341   }
342   HeapFree(GetProcessHeap(), 0, Obj->data);
343   HeapFree(GetProcessHeap(), 0, Obj);
344 }
345
346 static ULONG WINAPI OLEPictureImpl_AddRef(IPicture* iface);
347
348 /************************************************************************
349  * OLEPictureImpl_QueryInterface (IUnknown)
350  *
351  * See Windows documentation for more details on IUnknown methods.
352  */
353 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
354   IPicture*  iface,
355   REFIID  riid,
356   void**  ppvObject)
357 {
358   OLEPictureImpl *This = (OLEPictureImpl *)iface;
359   TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
360
361   /*
362    * Perform a sanity check on the parameters.
363    */
364   if ( (This==0) || (ppvObject==0) )
365     return E_INVALIDARG;
366
367   /*
368    * Initialize the return parameter.
369    */
370   *ppvObject = 0;
371
372   /*
373    * Compare the riid with the interface IDs implemented by this object.
374    */
375   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
376   {
377     *ppvObject = (IPicture*)This;
378   }
379   else if (memcmp(&IID_IPicture, riid, sizeof(IID_IPicture)) == 0)
380   {
381     *ppvObject = (IPicture*)This;
382   }
383   else if (memcmp(&IID_IDispatch, riid, sizeof(IID_IDispatch)) == 0)
384   {
385     *ppvObject = (IDispatch*)&(This->lpvtbl2);
386   }
387   else if (memcmp(&IID_IPictureDisp, riid, sizeof(IID_IPictureDisp)) == 0)
388   {
389     *ppvObject = (IDispatch*)&(This->lpvtbl2);
390   }
391   else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0)
392   {
393   *ppvObject = (IPersistStream*)&(This->lpvtbl3);
394   }
395   else if (memcmp(&IID_IConnectionPointContainer, riid, sizeof(IID_IConnectionPointContainer)) == 0)
396   {
397   *ppvObject = (IConnectionPointContainer*)&(This->lpvtbl4);
398   }
399   /*
400    * Check that we obtained an interface.
401    */
402   if ((*ppvObject)==0)
403   {
404     FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
405     return E_NOINTERFACE;
406   }
407
408   /*
409    * Query Interface always increases the reference count by one when it is
410    * successful
411    */
412   OLEPictureImpl_AddRef((IPicture*)This);
413
414   return S_OK;
415 }
416 /***********************************************************************
417  *    OLEPicture_SendNotify (internal)
418  *
419  * Sends notification messages of changed properties to any interested
420  * connections.
421  */
422 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
423 {
424   IEnumConnections *pEnum;
425   CONNECTDATA CD;
426
427   if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
428       return;
429   while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
430     IPropertyNotifySink *sink;
431
432     IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
433     IPropertyNotifySink_OnChanged(sink, dispID);
434     IPropertyNotifySink_Release(sink);
435     IUnknown_Release(CD.pUnk);
436   }
437   IEnumConnections_Release(pEnum);
438   return;
439 }
440
441 /************************************************************************
442  * OLEPictureImpl_AddRef (IUnknown)
443  *
444  * See Windows documentation for more details on IUnknown methods.
445  */
446 static ULONG WINAPI OLEPictureImpl_AddRef(
447   IPicture* iface)
448 {
449   OLEPictureImpl *This = (OLEPictureImpl *)iface;
450   ULONG refCount = InterlockedIncrement(&This->ref);
451
452   TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1);
453
454   return refCount;
455 }
456
457 /************************************************************************
458  * OLEPictureImpl_Release (IUnknown)
459  *
460  * See Windows documentation for more details on IUnknown methods.
461  */
462 static ULONG WINAPI OLEPictureImpl_Release(
463       IPicture* iface)
464 {
465   OLEPictureImpl *This = (OLEPictureImpl *)iface;
466   ULONG refCount = InterlockedDecrement(&This->ref);
467
468   TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1);
469
470   /*
471    * If the reference count goes down to 0, perform suicide.
472    */
473   if (!refCount) OLEPictureImpl_Destroy(This);
474
475   return refCount;
476 }
477
478
479 /************************************************************************
480  * OLEPictureImpl_get_Handle
481  */
482 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
483                                                 OLE_HANDLE *phandle)
484 {
485   OLEPictureImpl *This = (OLEPictureImpl *)iface;
486   TRACE("(%p)->(%p)\n", This, phandle);
487   switch(This->desc.picType) {
488   case PICTYPE_BITMAP:
489     *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
490     break;
491   case PICTYPE_METAFILE:
492     *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
493     break;
494   case PICTYPE_ICON:
495     *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
496     break;
497   case PICTYPE_ENHMETAFILE:
498     *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
499     break;
500   default:
501     FIXME("Unimplemented type %d\n", This->desc.picType);
502     return E_NOTIMPL;
503   }
504   TRACE("returning handle %08x\n", *phandle);
505   return S_OK;
506 }
507
508 /************************************************************************
509  * OLEPictureImpl_get_hPal
510  */
511 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
512                                               OLE_HANDLE *phandle)
513 {
514   OLEPictureImpl *This = (OLEPictureImpl *)iface;
515   FIXME("(%p)->(%p): stub\n", This, phandle);
516   return E_NOTIMPL;
517 }
518
519 /************************************************************************
520  * OLEPictureImpl_get_Type
521  */
522 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
523                                               short *ptype)
524 {
525   OLEPictureImpl *This = (OLEPictureImpl *)iface;
526   TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
527   *ptype = This->desc.picType;
528   return S_OK;
529 }
530
531 /************************************************************************
532  * OLEPictureImpl_get_Width
533  */
534 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
535                                                OLE_XSIZE_HIMETRIC *pwidth)
536 {
537   OLEPictureImpl *This = (OLEPictureImpl *)iface;
538   TRACE("(%p)->(%p): width is %ld\n", This, pwidth, This->himetricWidth);
539   *pwidth = This->himetricWidth;
540   return S_OK;
541 }
542
543 /************************************************************************
544  * OLEPictureImpl_get_Height
545  */
546 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
547                                                 OLE_YSIZE_HIMETRIC *pheight)
548 {
549   OLEPictureImpl *This = (OLEPictureImpl *)iface;
550   TRACE("(%p)->(%p): height is %ld\n", This, pheight, This->himetricHeight);
551   *pheight = This->himetricHeight;
552   return S_OK;
553 }
554
555 /************************************************************************
556  * OLEPictureImpl_Render
557  */
558 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
559                                             LONG x, LONG y, LONG cx, LONG cy,
560                                             OLE_XPOS_HIMETRIC xSrc,
561                                             OLE_YPOS_HIMETRIC ySrc,
562                                             OLE_XSIZE_HIMETRIC cxSrc,
563                                             OLE_YSIZE_HIMETRIC cySrc,
564                                             LPCRECT prcWBounds)
565 {
566   OLEPictureImpl *This = (OLEPictureImpl *)iface;
567   TRACE("(%p)->(%p, (%ld,%ld), (%ld,%ld) <- (%ld,%ld), (%ld,%ld), %p)\n",
568         This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
569   if(prcWBounds)
570     TRACE("prcWBounds (%ld,%ld) - (%ld,%ld)\n", prcWBounds->left, prcWBounds->top,
571           prcWBounds->right, prcWBounds->bottom);
572
573   /*
574    * While the documentation suggests this to be here (or after rendering?)
575    * it does cause an endless recursion in my sample app. -MM 20010804
576   OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
577    */
578
579   switch(This->desc.picType) {
580   case PICTYPE_BITMAP:
581     {
582       HBITMAP hbmpOld;
583       HDC hdcBmp;
584
585       /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
586          NB y-axis gets flipped */
587
588       hdcBmp = CreateCompatibleDC(0);
589       SetMapMode(hdcBmp, MM_ANISOTROPIC);
590       SetWindowOrgEx(hdcBmp, 0, 0, NULL);
591       SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
592       SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
593       SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
594
595       if (This->hbmMask) {
596           HDC hdcMask = CreateCompatibleDC(0);
597           HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
598
599           hbmpOld = SelectObject(hdcBmp, This->hbmXor);
600
601           SetMapMode(hdcMask, MM_ANISOTROPIC);
602           SetWindowOrgEx(hdcMask, 0, 0, NULL);
603           SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
604           SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
605           SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
606           
607           SetBkColor(hdc, RGB(255, 255, 255));    
608           SetTextColor(hdc, RGB(0, 0, 0));        
609           StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND); 
610           StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
611
612           SelectObject(hdcMask, hOldbm);
613           DeleteDC(hdcMask);
614       } else {
615           hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
616           StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
617       }
618
619       SelectObject(hdcBmp, hbmpOld);
620       DeleteDC(hdcBmp);
621     }
622     break;
623   case PICTYPE_ICON:
624     FIXME("Not quite correct implementation of rendering icons...\n");
625     DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
626     break;
627
628   case PICTYPE_METAFILE:
629   case PICTYPE_ENHMETAFILE:
630   default:
631     FIXME("type %d not implemented\n", This->desc.picType);
632     return E_NOTIMPL;
633   }
634   return S_OK;
635 }
636
637 /************************************************************************
638  * OLEPictureImpl_set_hPal
639  */
640 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
641                                               OLE_HANDLE hpal)
642 {
643   OLEPictureImpl *This = (OLEPictureImpl *)iface;
644   FIXME("(%p)->(%08x): stub\n", This, hpal);
645   OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
646   return E_NOTIMPL;
647 }
648
649 /************************************************************************
650  * OLEPictureImpl_get_CurDC
651  */
652 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
653                                                HDC *phdc)
654 {
655   OLEPictureImpl *This = (OLEPictureImpl *)iface;
656   TRACE("(%p), returning %p\n", This, This->hDCCur);
657   if (phdc) *phdc = This->hDCCur;
658   return S_OK;
659 }
660
661 /************************************************************************
662  * OLEPictureImpl_SelectPicture
663  */
664 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
665                                                    HDC hdcIn,
666                                                    HDC *phdcOut,
667                                                    OLE_HANDLE *phbmpOut)
668 {
669   OLEPictureImpl *This = (OLEPictureImpl *)iface;
670   TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
671   if (This->desc.picType == PICTYPE_BITMAP) {
672       SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
673
674       if (phdcOut)
675           *phdcOut = This->hDCCur;
676       This->hDCCur = hdcIn;
677       if (phbmpOut)
678           *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
679       return S_OK;
680   } else {
681       FIXME("Don't know how to select picture type %d\n",This->desc.picType);
682       return E_FAIL;
683   }
684 }
685
686 /************************************************************************
687  * OLEPictureImpl_get_KeepOriginalFormat
688  */
689 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
690                                                             BOOL *pfKeep)
691 {
692   OLEPictureImpl *This = (OLEPictureImpl *)iface;
693   TRACE("(%p)->(%p)\n", This, pfKeep);
694   if (!pfKeep)
695       return E_POINTER;
696   *pfKeep = This->keepOrigFormat;
697   return S_OK;
698 }
699
700 /************************************************************************
701  * OLEPictureImpl_put_KeepOriginalFormat
702  */
703 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
704                                                             BOOL keep)
705 {
706   OLEPictureImpl *This = (OLEPictureImpl *)iface;
707   TRACE("(%p)->(%d)\n", This, keep);
708   This->keepOrigFormat = keep;
709   /* FIXME: what DISPID notification here? */
710   return S_OK;
711 }
712
713 /************************************************************************
714  * OLEPictureImpl_PictureChanged
715  */
716 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
717 {
718   OLEPictureImpl *This = (OLEPictureImpl *)iface;
719   TRACE("(%p)->()\n", This);
720   OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
721   This->bIsDirty = TRUE;
722   return S_OK;
723 }
724
725 /************************************************************************
726  * OLEPictureImpl_SaveAsFile
727  */
728 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
729                                                 IStream *pstream,
730                                                 BOOL SaveMemCopy,
731                                                 LONG *pcbSize)
732 {
733   OLEPictureImpl *This = (OLEPictureImpl *)iface;
734   FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
735   return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
736 }
737
738 /************************************************************************
739  * OLEPictureImpl_get_Attributes
740  */
741 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
742                                                     DWORD *pdwAttr)
743 {
744   OLEPictureImpl *This = (OLEPictureImpl *)iface;
745   TRACE("(%p)->(%p).\n", This, pdwAttr);
746   *pdwAttr = 0;
747   switch (This->desc.picType) {
748   case PICTYPE_BITMAP:  if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break;       /* not 'truly' scalable, see MSDN. */
749   case PICTYPE_ICON: *pdwAttr     = PICTURE_TRANSPARENT;break;
750   case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
751   default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
752   }
753   return S_OK;
754 }
755
756
757 /************************************************************************
758  *    IConnectionPointContainer
759  */
760
761 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
762   IConnectionPointContainer* iface,
763   REFIID riid,
764   VOID** ppvoid
765 ) {
766   ICOM_THIS_From_IConnectionPointContainer(IPicture,iface);
767
768   return IPicture_QueryInterface(This,riid,ppvoid);
769 }
770
771 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
772   IConnectionPointContainer* iface)
773 {
774   ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
775
776   return IPicture_AddRef(This);
777 }
778
779 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
780   IConnectionPointContainer* iface)
781 {
782   ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
783
784   return IPicture_Release(This);
785 }
786
787 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
788   IConnectionPointContainer* iface,
789   IEnumConnectionPoints** ppEnum
790 ) {
791   ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
792
793   FIXME("(%p,%p), stub!\n",This,ppEnum);
794   return E_NOTIMPL;
795 }
796
797 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
798   IConnectionPointContainer* iface,
799   REFIID riid,
800   IConnectionPoint **ppCP
801 ) {
802   ICOM_THIS_From_IConnectionPointContainer(OLEPictureImpl, iface);
803   TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
804   if (!ppCP)
805       return E_POINTER;
806   *ppCP = NULL;
807   if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
808       return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
809   FIXME("tried to find connection point on %s?\n",debugstr_guid(riid));
810   return 0x80040200;
811 }
812 /************************************************************************
813  *    IPersistStream
814  */
815 /************************************************************************
816  * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
817  *
818  * See Windows documentation for more details on IUnknown methods.
819  */
820 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
821   IPersistStream* iface,
822   REFIID     riid,
823   VOID**     ppvoid)
824 {
825   ICOM_THIS_From_IPersistStream(IPicture, iface);
826
827   return IPicture_QueryInterface(This, riid, ppvoid);
828 }
829
830 /************************************************************************
831  * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
832  *
833  * See Windows documentation for more details on IUnknown methods.
834  */
835 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
836   IPersistStream* iface)
837 {
838   ICOM_THIS_From_IPersistStream(IPicture, iface);
839
840   return IPicture_AddRef(This);
841 }
842
843 /************************************************************************
844  * OLEPictureImpl_IPersistStream_Release (IUnknown)
845  *
846  * See Windows documentation for more details on IUnknown methods.
847  */
848 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
849   IPersistStream* iface)
850 {
851   ICOM_THIS_From_IPersistStream(IPicture, iface);
852
853   return IPicture_Release(This);
854 }
855
856 /************************************************************************
857  * OLEPictureImpl_IPersistStream_GetClassID
858  */
859 static HRESULT WINAPI OLEPictureImpl_GetClassID(
860   IPersistStream* iface,CLSID* pClassID)
861 {
862   ICOM_THIS_From_IPersistStream(IPicture, iface);
863   FIXME("(%p),stub!\n",This);
864   return E_FAIL;
865 }
866
867 /************************************************************************
868  * OLEPictureImpl_IPersistStream_IsDirty
869  */
870 static HRESULT WINAPI OLEPictureImpl_IsDirty(
871   IPersistStream* iface)
872 {
873   ICOM_THIS_From_IPersistStream(IPicture, iface);
874   FIXME("(%p),stub!\n",This);
875   return E_NOTIMPL;
876 }
877
878 #ifdef HAVE_JPEGLIB_H
879
880 static void *libjpeg_handle;
881 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
882 MAKE_FUNCPTR(jpeg_std_error);
883 MAKE_FUNCPTR(jpeg_CreateDecompress);
884 MAKE_FUNCPTR(jpeg_read_header);
885 MAKE_FUNCPTR(jpeg_start_decompress);
886 MAKE_FUNCPTR(jpeg_read_scanlines);
887 MAKE_FUNCPTR(jpeg_finish_decompress);
888 MAKE_FUNCPTR(jpeg_destroy_decompress);
889 #undef MAKE_FUNCPTR
890
891 static void *load_libjpeg(void)
892 {
893     if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
894
895 #define LOAD_FUNCPTR(f) \
896     if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
897         libjpeg_handle = NULL; \
898         return NULL; \
899     }
900
901         LOAD_FUNCPTR(jpeg_std_error);
902         LOAD_FUNCPTR(jpeg_CreateDecompress);
903         LOAD_FUNCPTR(jpeg_read_header);
904         LOAD_FUNCPTR(jpeg_start_decompress);
905         LOAD_FUNCPTR(jpeg_read_scanlines);
906         LOAD_FUNCPTR(jpeg_finish_decompress);
907         LOAD_FUNCPTR(jpeg_destroy_decompress);
908 #undef LOAD_FUNCPTR
909     }
910     return libjpeg_handle;
911 }
912
913 /* for the jpeg decompressor source manager. */
914 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
915
916 static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
917     ERR("(), should not get here.\n");
918     return FALSE;
919 }
920
921 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
922     TRACE("Skipping %ld bytes...\n", num_bytes);
923     cinfo->src->next_input_byte += num_bytes;
924     cinfo->src->bytes_in_buffer -= num_bytes;
925 }
926
927 static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
928     ERR("(desired=%d), should not get here.\n",desired);
929     return FALSE;
930 }
931 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
932 #endif /* HAVE_JPEGLIB_H */
933
934 #ifdef HAVE_GIF_LIB_H
935
936 static void *libungif_handle;
937 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
938 MAKE_FUNCPTR(DGifOpen);
939 MAKE_FUNCPTR(DGifSlurp);
940 MAKE_FUNCPTR(DGifCloseFile);
941 #undef MAKE_FUNCPTR
942
943 struct gifdata {
944     unsigned char *data;
945     unsigned int curoff;
946     unsigned int len;
947 };
948
949 static void *load_libungif(void)
950 {
951     if(((libungif_handle = wine_dlopen(SONAME_LIBUNGIF, RTLD_NOW, NULL, 0)) != NULL) ||
952        ((libungif_handle = wine_dlopen(SONAME_LIBGIF  , RTLD_NOW, NULL, 0)) != NULL)
953     ) {
954
955 #define LOAD_FUNCPTR(f) \
956     if((p##f = wine_dlsym(libungif_handle, #f, NULL, 0)) == NULL) { \
957         libungif_handle = NULL; \
958         return NULL; \
959     }
960
961         LOAD_FUNCPTR(DGifOpen);
962         LOAD_FUNCPTR(DGifSlurp);
963         LOAD_FUNCPTR(DGifCloseFile);
964 #undef LOAD_FUNCPTR
965     }
966     return libungif_handle;
967 }
968
969 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
970     struct gifdata *gd = (struct gifdata*)gif->UserData;
971
972     if (len+gd->curoff > gd->len) {
973         FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
974         len = gd->len - gd->curoff;
975     }
976     memcpy(data, gd->data+gd->curoff, len);
977     gd->curoff += len;
978     return len;
979 }
980
981 #endif  /* HAVE_GIF_LIB_H */
982
983 /************************************************************************
984  * OLEPictureImpl_IPersistStream_Load (IUnknown)
985  *
986  * Loads the binary data from the IStream. Starts at current position.
987  * There appears to be an 2 DWORD header:
988  *      DWORD magic;
989  *      DWORD len;
990  *
991  * Currently implemented: BITMAP, ICON, JPEG, GIF
992  */
993 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
994   HRESULT       hr = E_FAIL;
995   ULONG         xread;
996   BYTE          *xbuf;
997   DWORD         header[2];
998   WORD          magic;
999   STATSTG       statstg;
1000   ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface);
1001   
1002   TRACE("(%p,%p)\n",This,pStm);
1003
1004   /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1005    * out whether we do.
1006    *
1007    * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1008    * compound file. This may explain most, if not all, of the cases of "no header",
1009    * and the header validation should take this into account. At least in Visual Basic 6,
1010    * resource streams, valid headers are
1011    *    header[0] == "lt\0\0",
1012    *    header[1] == length_of_stream.
1013    */
1014   hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1015   if (hr)
1016     FIXME("Stat failed with hres %lx\n",hr);
1017   hr=IStream_Read(pStm,header,8,&xread);
1018   if (hr || xread!=8) {
1019       FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
1020       return hr;
1021   }
1022   if (!memcmp(&(header[0]), "GIF8",     4) ||   /* GIF header */
1023       !memcmp(&(header[0]), "BM",       2) ||   /* BMP header */
1024       !memcmp(&(header[0]), "\xff\xd8", 2) ||   /* JPEG header */
1025       header[1] > statstg.cbSize.QuadPart || (header[1]==0)) {/* Incorrect header, assume none. */
1026     xread = 8;
1027     xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,statstg.cbSize.QuadPart);
1028     memcpy(xbuf,&header,8);
1029     This->datalen = statstg.cbSize.QuadPart;
1030     while (xread < This->datalen) {
1031       ULONG nread;
1032       hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1033       xread+=nread;
1034       if (hr || !nread)
1035         break;
1036     }
1037     if (xread != This->datalen)
1038       FIXME("Could only read %ld of %d bytes in no-header case?\n",xread,This->datalen);
1039   } else {
1040     xread = 0;
1041     xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]);
1042     This->datalen = header[1];
1043     while (xread < header[1]) {
1044       ULONG nread;
1045       hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread);
1046       xread+=nread;
1047       if (hr || !nread)
1048         break;
1049     }
1050     if (xread != header[1])
1051       FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]);
1052   }
1053   magic = xbuf[0] + (xbuf[1]<<8);
1054   switch (magic) {
1055   case 0x4947: { /* GIF */
1056 #ifdef HAVE_GIF_LIB_H
1057     struct gifdata      gd;
1058     GifFileType         *gif;
1059     BITMAPINFO          *bmi;
1060     HDC                 hdcref;
1061     LPBYTE              bytes;
1062     int                 i,j,ret;
1063     GifImageDesc        *gid;
1064     SavedImage          *si;
1065     ColorMapObject      *cm;
1066     int                 transparent = -1;
1067     ExtensionBlock      *eb;
1068     int                 padding;
1069
1070     if(!libungif_handle) {
1071         if(!load_libungif()) {
1072             FIXME("Failed reading GIF because unable to find %s/%s\n", SONAME_LIBUNGIF, SONAME_LIBGIF);
1073             return E_FAIL;
1074         }
1075     }
1076
1077     gd.data   = xbuf;
1078     gd.curoff = 0;
1079     gd.len    = xread;
1080     gif = pDGifOpen((void*)&gd, _gif_inputfunc);
1081     ret = pDGifSlurp(gif);
1082     if (ret == GIF_ERROR) {
1083       FIXME("Failed reading GIF using libgif.\n");
1084       return E_FAIL;
1085     }
1086     TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1087     TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1088     TRACE("imgcnt %d\n", gif->ImageCount);
1089     if (gif->ImageCount<1) {
1090       FIXME("GIF stream does not have images inside?\n");
1091       return E_FAIL;
1092     }
1093     TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1094       gif->Image.Width, gif->Image.Height,
1095       gif->Image.Left, gif->Image.Top,
1096       gif->Image.Interlace
1097     );
1098     /* */
1099     padding = (gif->SWidth+3) & ~3;
1100     bmi  = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(1<<gif->SColorResolution)*sizeof(RGBQUAD));
1101     bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1102     si   = gif->SavedImages+0;
1103     gid  = &(si->ImageDesc);
1104     cm   = gid->ColorMap;
1105     if (!cm) cm = gif->SColorMap;
1106     
1107     /* look for the transparent color extension */
1108     for (i = 0; i < si->ExtensionBlockCount; ++i) {
1109         eb = si->ExtensionBlocks + i;
1110         if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1111             if ((eb->Bytes[0] & 1) == 1) {
1112                 transparent = (unsigned char)eb->Bytes[3];
1113             }
1114         }
1115     }
1116
1117     for (i=0;i<(1<<gif->SColorResolution);i++) {
1118       bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1119       bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1120       bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1121       if (i == transparent) {
1122           This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1123                                bmi->bmiColors[i].rgbGreen,
1124                                bmi->bmiColors[i].rgbBlue);
1125       }
1126     }
1127
1128     /* Map to in picture coordinates */
1129     for (i = 0, j = 0; i < gid->Height; i++) {
1130         if (gif->Image.Interlace) {
1131             memcpy(
1132                 bytes + (gid->Top + j) * padding + gid->Left,
1133                 si->RasterBits + i * gid->Width,
1134                 gid->Width);
1135
1136             /* Lower bits of interlaced counter encode current interlace */
1137             if (j & 1) j += 2;      /* Currently filling odd rows */
1138             else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1139             else j += 8;            /* Currently filling every 8th row or 4th row in-between */
1140
1141             if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1142                 /* End of current interlace, go to next interlace */
1143                 if (j & 2) j = 1;       /* Next iteration fills odd rows */
1144                 else if (j & 4) j = 2;  /* Next iteration fills even rows not mod 4 and not mod 8 */
1145                 else j = 4;             /* Next iteration fills rows in-between rows mod 6 */
1146             }
1147         } else {
1148             memcpy(
1149                 bytes + (gid->Top + i) * padding + gid->Left,
1150                 si->RasterBits + i * gid->Width,
1151                 gid->Width);
1152         }
1153     }
1154
1155     bmi->bmiHeader.biSize               = sizeof(BITMAPINFOHEADER);
1156     bmi->bmiHeader.biWidth              = gif->SWidth;
1157     bmi->bmiHeader.biHeight             = -gif->SHeight;
1158     bmi->bmiHeader.biPlanes             = 1;
1159     bmi->bmiHeader.biBitCount           = 8;
1160     bmi->bmiHeader.biCompression        = BI_RGB;
1161     bmi->bmiHeader.biSizeImage          = padding*gif->SHeight;
1162     bmi->bmiHeader.biXPelsPerMeter      = 0;
1163     bmi->bmiHeader.biYPelsPerMeter      = 0;
1164     bmi->bmiHeader.biClrUsed            = 1 << gif->SColorResolution;
1165     bmi->bmiHeader.biClrImportant       = 0;
1166
1167     hdcref = GetDC(0);
1168     This->desc.u.bmp.hbitmap=CreateDIBitmap(
1169             hdcref,
1170             &bmi->bmiHeader,
1171             CBM_INIT,
1172             bytes,
1173             bmi,
1174             DIB_RGB_COLORS
1175     );
1176
1177     if (transparent > -1) {
1178         /* Create the Mask */
1179         HDC hdc = CreateCompatibleDC(0);
1180         HDC hdcMask = CreateCompatibleDC(0);
1181         HBITMAP hOldbitmap; 
1182         HBITMAP hOldbitmapmask;
1183
1184         unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1185         HBITMAP hTempMask;
1186
1187         This->hbmXor = CreateDIBitmap(
1188             hdcref,
1189             &bmi->bmiHeader,
1190             CBM_INIT,
1191             bytes,
1192             bmi,
1193             DIB_RGB_COLORS
1194         );
1195
1196         bmi->bmiColors[0].rgbRed = 0;
1197         bmi->bmiColors[0].rgbGreen = 0;
1198         bmi->bmiColors[0].rgbBlue = 0;
1199         bmi->bmiColors[1].rgbRed = 255;
1200         bmi->bmiColors[1].rgbGreen = 255;
1201         bmi->bmiColors[1].rgbBlue = 255;
1202
1203         bmi->bmiHeader.biBitCount               = 1;
1204         bmi->bmiHeader.biSizeImage              = monopadding*gif->SHeight;
1205         bmi->bmiHeader.biClrUsed                = 2;
1206
1207         for (i = 0; i < gif->SHeight; i++) {
1208             unsigned char * colorPointer = bytes + padding * i;
1209             unsigned char * monoPointer = bytes + monopadding * i;
1210             for (j = 0; j < gif->SWidth; j++) {
1211                 unsigned char pixel = colorPointer[j];
1212                 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1213                 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1214             }
1215         }
1216         hdcref = GetDC(0);
1217         hTempMask = CreateDIBitmap(
1218                 hdcref,
1219                 &bmi->bmiHeader,
1220                 CBM_INIT,
1221                 bytes,
1222                 bmi,
1223                 DIB_RGB_COLORS
1224         );
1225         DeleteDC(hdcref);
1226
1227         bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1228         This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1229         hOldbitmap = SelectObject(hdc, hTempMask);
1230         hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1231
1232         SetBkColor(hdc, RGB(255, 255, 255));
1233         BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1234
1235         /* We no longer need the original bitmap, so we apply the first
1236            transformation with the mask to speed up the rendering */
1237         SelectObject(hdc, This->hbmXor);
1238         SetBkColor(hdc, RGB(0,0,0));
1239         SetTextColor(hdc, RGB(255,255,255));
1240         BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 
1241                  hdcMask, 0, 0,  SRCAND);
1242
1243         SelectObject(hdc, hOldbitmap);
1244         SelectObject(hdcMask, hOldbitmapmask);
1245         DeleteDC(hdcMask);
1246         DeleteDC(hdc);
1247         DeleteObject(hTempMask);
1248     }
1249     
1250     DeleteDC(hdcref);
1251     This->desc.picType = PICTYPE_BITMAP;
1252     OLEPictureImpl_SetBitmap(This);
1253     pDGifCloseFile(gif);
1254     HeapFree(GetProcessHeap(),0,bytes);
1255     return S_OK;
1256 #else
1257     FIXME("Trying to load GIF, but no support for libgif/libungif compiled in.\n");
1258     return E_FAIL;
1259 #endif
1260   }
1261   case 0xd8ff: { /* JPEG */
1262 #ifdef HAVE_JPEGLIB_H
1263     struct jpeg_decompress_struct       jd;
1264     struct jpeg_error_mgr               jerr;
1265     int                                 ret;
1266     JDIMENSION                          x;
1267     JSAMPROW                            samprow,oldsamprow;
1268     BITMAPINFOHEADER                    bmi;
1269     LPBYTE                              bits;
1270     HDC                                 hdcref;
1271     struct jpeg_source_mgr              xjsm;
1272     LPBYTE                              oldbits;
1273     unsigned int i;
1274
1275     if(!libjpeg_handle) {
1276         if(!load_libjpeg()) {
1277             FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1278             return E_FAIL;
1279         }
1280     }
1281
1282     /* This is basically so we can use in-memory data for jpeg decompression.
1283      * We need to have all the functions.
1284      */
1285     xjsm.next_input_byte        = xbuf;
1286     xjsm.bytes_in_buffer        = xread;
1287     xjsm.init_source            = _jpeg_init_source;
1288     xjsm.fill_input_buffer      = _jpeg_fill_input_buffer;
1289     xjsm.skip_input_data        = _jpeg_skip_input_data;
1290     xjsm.resync_to_restart      = _jpeg_resync_to_restart;
1291     xjsm.term_source            = _jpeg_term_source;
1292
1293     jd.err = pjpeg_std_error(&jerr);
1294     /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1295      * jpeg_create_decompress(&jd); */
1296     pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct));
1297     jd.src = &xjsm;
1298     ret=pjpeg_read_header(&jd,TRUE);
1299     jd.out_color_space = JCS_RGB;
1300     pjpeg_start_decompress(&jd);
1301     if (ret != JPEG_HEADER_OK) {
1302         ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1303         HeapFree(GetProcessHeap(),0,xbuf);
1304         return E_FAIL;
1305     }
1306
1307     bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1308                      (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1309     samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1310
1311     oldbits = bits;
1312     oldsamprow = samprow;
1313     while ( jd.output_scanline<jd.output_height ) {
1314       x = pjpeg_read_scanlines(&jd,&samprow,1);
1315       if (x != 1) {
1316         FIXME("failed to read current scanline?\n");
1317         break;
1318       }
1319       /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1320       for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1321         *(bits++) = *(samprow+2);
1322         *(bits++) = *(samprow+1);
1323         *(bits++) = *(samprow);
1324       }
1325       bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1326       samprow = oldsamprow;
1327     }
1328     bits = oldbits;
1329
1330     bmi.biSize          = sizeof(bmi);
1331     bmi.biWidth         =  jd.output_width;
1332     bmi.biHeight        = -jd.output_height;
1333     bmi.biPlanes        = 1;
1334     bmi.biBitCount      = jd.output_components<<3;
1335     bmi.biCompression   = BI_RGB;
1336     bmi.biSizeImage     = jd.output_height*jd.output_width*jd.output_components;
1337     bmi.biXPelsPerMeter = 0;
1338     bmi.biYPelsPerMeter = 0;
1339     bmi.biClrUsed       = 0;
1340     bmi.biClrImportant  = 0;
1341
1342     HeapFree(GetProcessHeap(),0,samprow);
1343     pjpeg_finish_decompress(&jd);
1344     pjpeg_destroy_decompress(&jd);
1345     hdcref = GetDC(0);
1346     This->desc.u.bmp.hbitmap=CreateDIBitmap(
1347             hdcref,
1348             &bmi,
1349             CBM_INIT,
1350             bits,
1351             (BITMAPINFO*)&bmi,
1352             DIB_RGB_COLORS
1353     );
1354     DeleteDC(hdcref);
1355     This->desc.picType = PICTYPE_BITMAP;
1356     OLEPictureImpl_SetBitmap(This);
1357     hr = S_OK;
1358     HeapFree(GetProcessHeap(),0,bits);
1359 #else
1360     ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1361     hr = E_FAIL;
1362 #endif
1363     break;
1364   }
1365   case 0x4d42: { /* Bitmap */
1366     BITMAPFILEHEADER    *bfh = (BITMAPFILEHEADER*)xbuf;
1367     BITMAPINFO          *bi = (BITMAPINFO*)(bfh+1);
1368     HDC                 hdcref;
1369
1370     /* Does not matter whether this is a coreheader or not, we only use
1371      * components which are in both
1372      */
1373     hdcref = GetDC(0);
1374     This->desc.u.bmp.hbitmap = CreateDIBitmap(
1375         hdcref,
1376         &(bi->bmiHeader),
1377         CBM_INIT,
1378         xbuf+bfh->bfOffBits,
1379         bi,
1380        DIB_RGB_COLORS
1381     );
1382     DeleteDC(hdcref);
1383     This->desc.picType = PICTYPE_BITMAP;
1384     OLEPictureImpl_SetBitmap(This);
1385     hr = S_OK;
1386     break;
1387   }
1388   case 0x0000: { /* ICON , first word is dwReserved */
1389     HICON hicon;
1390     CURSORICONFILEDIR   *cifd = (CURSORICONFILEDIR*)xbuf;
1391     HDC hdcRef;
1392     int i;
1393
1394     /*
1395     FIXME("icon.idReserved=%d\n",cifd->idReserved);
1396     FIXME("icon.idType=%d\n",cifd->idType);
1397     FIXME("icon.idCount=%d\n",cifd->idCount);
1398
1399     for (i=0;i<cifd->idCount;i++) {
1400         FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1401         FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1402         FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1403         FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1404         FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1405         FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1406         FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1407         FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1408     }
1409     */
1410     i=0;
1411     /* If we have more than one icon, try to find the best.
1412      * this currently means '32 pixel wide'.
1413      */
1414     if (cifd->idCount!=1) {
1415         for (i=0;i<cifd->idCount;i++) {
1416             if (cifd->idEntries[i].bWidth == 32)
1417                 break;
1418         }
1419         if (i==cifd->idCount) i=0;
1420     }
1421
1422     hicon = CreateIconFromResourceEx(
1423                 xbuf+cifd->idEntries[i].dwDIBOffset,
1424                 cifd->idEntries[i].dwDIBSize,
1425                 TRUE, /* is icon */
1426                 0x00030000,
1427                 cifd->idEntries[i].bWidth,
1428                 cifd->idEntries[i].bHeight,
1429                 0
1430     );
1431     if (!hicon) {
1432         FIXME("CreateIcon failed.\n");
1433         hr = E_FAIL;
1434     } else {
1435         This->desc.picType = PICTYPE_ICON;
1436         This->desc.u.icon.hicon = hicon;
1437         This->origWidth = cifd->idEntries[i].bWidth;
1438         This->origHeight = cifd->idEntries[i].bHeight;
1439         hdcRef = CreateCompatibleDC(0);
1440         This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1441         This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1442         DeleteDC(hdcRef);
1443         hr = S_OK;
1444     }
1445     break;
1446   }
1447   default:
1448   {
1449     unsigned int i;
1450     FIXME("Unknown magic %04x, %ld read bytes:\n",magic,xread);
1451     hr=E_FAIL;
1452     for (i=0;i<xread+8;i++) {
1453         if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
1454         else MESSAGE("%02x ",xbuf[i-8]);
1455         if (i % 10 == 9) MESSAGE("\n");
1456     }
1457     MESSAGE("\n");
1458     break;
1459   }
1460   }
1461   This->bIsDirty = FALSE;
1462
1463   /* FIXME: this notify is not really documented */
1464   if (hr==S_OK)
1465       OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1466   return hr;
1467 }
1468
1469 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength);
1470 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength);
1471 static HRESULT WINAPI OLEPictureImpl_Save(
1472   IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1473 {
1474     HRESULT hResult = E_NOTIMPL;
1475     void * pIconData;
1476     unsigned int iDataSize;
1477     ULONG dummy;
1478     int iSerializeResult = 0;
1479
1480   ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface);
1481
1482     switch (This->desc.picType) {
1483     case PICTYPE_ICON:
1484         if (This->bIsDirty) {
1485             if (serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1486                 if (This->loadtime_magic != 0xdeadbeef) {
1487                     DWORD header[2];
1488
1489                     header[0] = This->loadtime_magic;
1490                     header[1] = iDataSize;
1491                     IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1492                 }
1493                 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1494
1495                 HeapFree(GetProcessHeap(), 0, This->data);
1496                 This->data = pIconData;
1497                 This->datalen = iDataSize;
1498                 hResult = S_OK;
1499             } else {
1500                 FIXME("(%p,%p,%d), unable to serializeIcon()!\n",This,pStm,fClearDirty);
1501                 hResult = E_FAIL;
1502             }
1503         } else {
1504             if (This->loadtime_magic != 0xdeadbeef) {
1505                 DWORD header[2];
1506
1507                 header[0] = This->loadtime_magic;
1508                 header[1] = This->datalen;
1509                 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1510             }
1511             IStream_Write(pStm, This->data, This->datalen, &dummy);
1512             hResult = S_OK;
1513         }
1514         break;
1515     case PICTYPE_BITMAP:
1516         if (This->bIsDirty) {
1517             switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) {
1518             case 0x4d42:
1519                 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1520                 break;
1521             case 0xd8ff:
1522                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1523                 break;
1524             case 0x4947:
1525                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1526                 break;
1527             default:
1528                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1529                 break;
1530             }
1531             if (iSerializeResult) {
1532                 /*
1533                 if (This->loadtime_magic != 0xdeadbeef) {
1534                 */
1535                 if (1) {
1536                     DWORD header[2];
1537
1538                     header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1539                     header[1] = iDataSize;
1540                     IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1541                 }
1542                 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1543
1544                 HeapFree(GetProcessHeap(), 0, This->data);
1545                 This->data = pIconData;
1546                 This->datalen = iDataSize;
1547                 hResult = S_OK;
1548             }
1549         } else {
1550             /*
1551             if (This->loadtime_magic != 0xdeadbeef) {
1552             */
1553             if (1) {
1554                 DWORD header[2];
1555
1556                 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1557                 header[1] = This->datalen;
1558                 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1559             }
1560             IStream_Write(pStm, This->data, This->datalen, &dummy);
1561             hResult = S_OK;
1562         }
1563         break;
1564     case PICTYPE_METAFILE:
1565         FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1566         break;
1567     case PICTYPE_ENHMETAFILE:
1568         FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1569         break;
1570     default:
1571         FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1572         break;
1573     }
1574     if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1575     return hResult;
1576 }
1577
1578 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1579 {
1580     int iSuccess = 0;
1581     HDC hDC;
1582     BITMAPINFO * pInfoBitmap;
1583     int iNumPaletteEntries;
1584     unsigned char * pPixelData;
1585     BITMAPFILEHEADER * pFileHeader;
1586     BITMAPINFO * pInfoHeader;
1587
1588     pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1589         sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1590
1591     /* Find out bitmap size and padded length */
1592     hDC = GetDC(0);
1593     pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1594     GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1595
1596     /* Fetch bitmap palette & pixel data */
1597
1598     pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1599     GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1600
1601     /* Calculate the total length required for the BMP data */
1602     if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1603         iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1604         if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1605     } else {
1606         if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1607             iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1608         else
1609             iNumPaletteEntries = 0;
1610     }
1611     *pLength =
1612         sizeof(BITMAPFILEHEADER) +
1613         sizeof(BITMAPINFOHEADER) +
1614         iNumPaletteEntries * sizeof(RGBQUAD) +
1615         pInfoBitmap->bmiHeader.biSizeImage;
1616     *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1617
1618     /* Fill the BITMAPFILEHEADER */
1619     pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1620     pFileHeader->bfType = 0x4d42;
1621     pFileHeader->bfSize = *pLength;
1622     pFileHeader->bfOffBits =
1623         sizeof(BITMAPFILEHEADER) +
1624         sizeof(BITMAPINFOHEADER) +
1625         iNumPaletteEntries * sizeof(RGBQUAD);
1626
1627     /* Fill the BITMAPINFOHEADER and the palette data */
1628     pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1629     memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1630     memcpy(
1631         (unsigned char *)(*ppBuffer) +
1632             sizeof(BITMAPFILEHEADER) +
1633             sizeof(BITMAPINFOHEADER) +
1634             iNumPaletteEntries * sizeof(RGBQUAD),
1635         pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1636     iSuccess = 1;
1637
1638     HeapFree(GetProcessHeap(), 0, pPixelData);
1639     HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1640     return iSuccess;
1641 }
1642
1643 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1644 {
1645         ICONINFO infoIcon;
1646         int iSuccess = 0;
1647
1648         *ppBuffer = NULL; *pLength = 0;
1649         if (GetIconInfo(hIcon, &infoIcon)) {
1650                 HDC hDC;
1651                 BITMAPINFO * pInfoBitmap;
1652                 unsigned char * pIconData = NULL;
1653                 unsigned int iDataSize = 0;
1654
1655         pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1656
1657                 /* Find out icon size */
1658                 hDC = GetDC(0);
1659                 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1660                 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1661                 if (1) {
1662                         /* Auxiliary pointers */
1663                         CURSORICONFILEDIR * pIconDir;
1664                         CURSORICONFILEDIRENTRY * pIconEntry;
1665                         BITMAPINFOHEADER * pIconBitmapHeader;
1666                         unsigned int iOffsetPalette;
1667                         unsigned int iOffsetColorData;
1668                         unsigned int iOffsetMaskData;
1669
1670                         unsigned int iLengthScanLineColor;
1671                         unsigned int iLengthScanLineMask;
1672                         unsigned int iNumEntriesPalette;
1673
1674                         iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1675                         iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
1676 /*
1677                         FIXME("DEBUG: bitmap size is %d x %d\n",
1678                                 pInfoBitmap->bmiHeader.biWidth,
1679                                 pInfoBitmap->bmiHeader.biHeight);
1680                         FIXME("DEBUG: bitmap bpp is %d\n",
1681                                 pInfoBitmap->bmiHeader.biBitCount);
1682                         FIXME("DEBUG: bitmap nplanes is %d\n",
1683                                 pInfoBitmap->bmiHeader.biPlanes);
1684                         FIXME("DEBUG: bitmap biSizeImage is %lu\n",
1685                                 pInfoBitmap->bmiHeader.biSizeImage);
1686 */
1687                         /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1688                         iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1689                         pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1690
1691                         /* Fill out the CURSORICONFILEDIR */
1692                         pIconDir = (CURSORICONFILEDIR *)pIconData;
1693                         pIconDir->idType = 1;
1694                         pIconDir->idCount = 1;
1695
1696                         /* Fill out the CURSORICONFILEDIRENTRY */
1697                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1698                         pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1699                         pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1700                         pIconEntry->bColorCount =
1701                                 (pInfoBitmap->bmiHeader.biBitCount < 8)
1702                                 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1703                                 : 0;
1704                         pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1705                         pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1706                         pIconEntry->dwDIBSize = 0;
1707                         pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1708
1709                         /* Fill out the BITMAPINFOHEADER */
1710                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1711                         memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
1712
1713                         /*      Find out whether a palette exists for the bitmap */
1714                         if (    (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1715                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 24)
1716                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1717                                 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1718                                 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256; 
1719                         } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1720                                 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1721                                 iNumEntriesPalette = 3;
1722                         } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1723                                 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1724                         } else {
1725                                 iNumEntriesPalette = 0;
1726                         }
1727
1728                         /*  Add bitmap size and header size to icon data size. */
1729                         iOffsetPalette = iDataSize;
1730                         iDataSize += iNumEntriesPalette * sizeof(DWORD);
1731                         iOffsetColorData = iDataSize;
1732                         iDataSize += pIconBitmapHeader->biSizeImage;
1733                         iOffsetMaskData = iDataSize;
1734                         iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1735                         pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1736                         pIconBitmapHeader->biHeight *= 2;
1737                         pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1738                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1739                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1740                         pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1741
1742                         /* Get the actual bitmap data from the icon bitmap */
1743                         GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1744                                 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1745                         if (iNumEntriesPalette > 0) {
1746                                 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1747                                         iNumEntriesPalette * sizeof(RGBQUAD));
1748                         }
1749
1750                         /* Reset all values so that GetDIBits call succeeds */
1751                         memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1752                         memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1753                         pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1754 /*
1755             if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1756                                 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1757                                         pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1758
1759                 printf("ERROR: unable to get bitmap mask (error %lu)\n",
1760                                         GetLastError());
1761
1762                         }
1763 */
1764             GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1765             GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1766
1767                         /* Write out everything produced so far to the stream */
1768                         *ppBuffer = pIconData; *pLength = iDataSize;
1769                         iSuccess = 1;
1770                 } else {
1771 /*
1772                         printf("ERROR: unable to get bitmap information via GetDIBits() (error %lu)\n",
1773                                 GetLastError());
1774 */
1775                 }
1776                 /*
1777                         Remarks (from MSDN entry on GetIconInfo):
1778
1779                         GetIconInfo creates bitmaps for the hbmMask and hbmColor
1780                         members of ICONINFO. The calling application must manage
1781                         these bitmaps and delete them when they are no longer
1782                         necessary.
1783                  */
1784                 if (hDC) ReleaseDC(0, hDC);
1785                 DeleteObject(infoIcon.hbmMask);
1786                 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1787                 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1788         } else {
1789                 printf("ERROR: Unable to get icon information (error %lu)\n",
1790                         GetLastError());
1791         }
1792         return iSuccess;
1793 }
1794
1795 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1796   IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1797 {
1798   ICOM_THIS_From_IPersistStream(IPicture, iface);
1799   FIXME("(%p,%p),stub!\n",This,pcbSize);
1800   return E_NOTIMPL;
1801 }
1802
1803 /************************************************************************
1804  *    IDispatch
1805  */
1806 /************************************************************************
1807  * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1808  *
1809  * See Windows documentation for more details on IUnknown methods.
1810  */
1811 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1812   IDispatch* iface,
1813   REFIID     riid,
1814   VOID**     ppvoid)
1815 {
1816   ICOM_THIS_From_IDispatch(IPicture, iface);
1817
1818   return IPicture_QueryInterface(This, riid, ppvoid);
1819 }
1820
1821 /************************************************************************
1822  * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1823  *
1824  * See Windows documentation for more details on IUnknown methods.
1825  */
1826 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1827   IDispatch* iface)
1828 {
1829   ICOM_THIS_From_IDispatch(IPicture, iface);
1830
1831   return IPicture_AddRef(This);
1832 }
1833
1834 /************************************************************************
1835  * OLEPictureImpl_IDispatch_Release (IUnknown)
1836  *
1837  * See Windows documentation for more details on IUnknown methods.
1838  */
1839 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1840   IDispatch* iface)
1841 {
1842   ICOM_THIS_From_IDispatch(IPicture, iface);
1843
1844   return IPicture_Release(This);
1845 }
1846
1847 /************************************************************************
1848  * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1849  *
1850  * See Windows documentation for more details on IDispatch methods.
1851  */
1852 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1853   IDispatch*    iface,
1854   unsigned int* pctinfo)
1855 {
1856   FIXME("():Stub\n");
1857
1858   return E_NOTIMPL;
1859 }
1860
1861 /************************************************************************
1862  * OLEPictureImpl_GetTypeInfo (IDispatch)
1863  *
1864  * See Windows documentation for more details on IDispatch methods.
1865  */
1866 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1867   IDispatch*  iface,
1868   UINT      iTInfo,
1869   LCID        lcid,
1870   ITypeInfo** ppTInfo)
1871 {
1872   FIXME("():Stub\n");
1873
1874   return E_NOTIMPL;
1875 }
1876
1877 /************************************************************************
1878  * OLEPictureImpl_GetIDsOfNames (IDispatch)
1879  *
1880  * See Windows documentation for more details on IDispatch methods.
1881  */
1882 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1883   IDispatch*  iface,
1884   REFIID      riid,
1885   LPOLESTR* rgszNames,
1886   UINT      cNames,
1887   LCID        lcid,
1888   DISPID*     rgDispId)
1889 {
1890   FIXME("():Stub\n");
1891
1892   return E_NOTIMPL;
1893 }
1894
1895 /************************************************************************
1896  * OLEPictureImpl_Invoke (IDispatch)
1897  *
1898  * See Windows documentation for more details on IDispatch methods.
1899  */
1900 static HRESULT WINAPI OLEPictureImpl_Invoke(
1901   IDispatch*  iface,
1902   DISPID      dispIdMember,
1903   REFIID      riid,
1904   LCID        lcid,
1905   WORD        wFlags,
1906   DISPPARAMS* pDispParams,
1907   VARIANT*    pVarResult,
1908   EXCEPINFO*  pExepInfo,
1909   UINT*     puArgErr)
1910 {
1911   FIXME("(dispid: %ld):Stub\n",dispIdMember);
1912
1913   VariantInit(pVarResult);
1914   V_VT(pVarResult) = VT_BOOL;
1915   V_BOOL(pVarResult) = FALSE;
1916   return S_OK;
1917 }
1918
1919
1920 static IPictureVtbl OLEPictureImpl_VTable =
1921 {
1922   OLEPictureImpl_QueryInterface,
1923   OLEPictureImpl_AddRef,
1924   OLEPictureImpl_Release,
1925   OLEPictureImpl_get_Handle,
1926   OLEPictureImpl_get_hPal,
1927   OLEPictureImpl_get_Type,
1928   OLEPictureImpl_get_Width,
1929   OLEPictureImpl_get_Height,
1930   OLEPictureImpl_Render,
1931   OLEPictureImpl_set_hPal,
1932   OLEPictureImpl_get_CurDC,
1933   OLEPictureImpl_SelectPicture,
1934   OLEPictureImpl_get_KeepOriginalFormat,
1935   OLEPictureImpl_put_KeepOriginalFormat,
1936   OLEPictureImpl_PictureChanged,
1937   OLEPictureImpl_SaveAsFile,
1938   OLEPictureImpl_get_Attributes
1939 };
1940
1941 static IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
1942 {
1943   OLEPictureImpl_IDispatch_QueryInterface,
1944   OLEPictureImpl_IDispatch_AddRef,
1945   OLEPictureImpl_IDispatch_Release,
1946   OLEPictureImpl_GetTypeInfoCount,
1947   OLEPictureImpl_GetTypeInfo,
1948   OLEPictureImpl_GetIDsOfNames,
1949   OLEPictureImpl_Invoke
1950 };
1951
1952 static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
1953 {
1954   OLEPictureImpl_IPersistStream_QueryInterface,
1955   OLEPictureImpl_IPersistStream_AddRef,
1956   OLEPictureImpl_IPersistStream_Release,
1957   OLEPictureImpl_GetClassID,
1958   OLEPictureImpl_IsDirty,
1959   OLEPictureImpl_Load,
1960   OLEPictureImpl_Save,
1961   OLEPictureImpl_GetSizeMax
1962 };
1963
1964 static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
1965 {
1966   OLEPictureImpl_IConnectionPointContainer_QueryInterface,
1967   OLEPictureImpl_IConnectionPointContainer_AddRef,
1968   OLEPictureImpl_IConnectionPointContainer_Release,
1969   OLEPictureImpl_EnumConnectionPoints,
1970   OLEPictureImpl_FindConnectionPoint
1971 };
1972
1973 /***********************************************************************
1974  * OleCreatePictureIndirect (OLEAUT32.419)
1975  */
1976 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
1977                             BOOL fOwn, LPVOID *ppvObj )
1978 {
1979   OLEPictureImpl* newPict = NULL;
1980   HRESULT      hr         = S_OK;
1981
1982   TRACE("(%p,%p,%d,%p)\n", lpPictDesc, riid, fOwn, ppvObj);
1983
1984   /*
1985    * Sanity check
1986    */
1987   if (ppvObj==0)
1988     return E_POINTER;
1989
1990   *ppvObj = NULL;
1991
1992   /*
1993    * Try to construct a new instance of the class.
1994    */
1995   newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
1996
1997   if (newPict == NULL)
1998     return E_OUTOFMEMORY;
1999
2000   /*
2001    * Make sure it supports the interface required by the caller.
2002    */
2003   hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2004
2005   /*
2006    * Release the reference obtained in the constructor. If
2007    * the QueryInterface was unsuccessful, it will free the class.
2008    */
2009   IPicture_Release((IPicture*)newPict);
2010
2011   return hr;
2012 }
2013
2014
2015 /***********************************************************************
2016  * OleLoadPicture (OLEAUT32.418)
2017  */
2018 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2019                             REFIID riid, LPVOID *ppvObj )
2020 {
2021   LPPERSISTSTREAM ps;
2022   IPicture      *newpic;
2023   HRESULT hr;
2024
2025   TRACE("(%p,%ld,%d,%s,%p), partially implemented.\n",
2026         lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2027
2028   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2029   if (hr)
2030     return hr;
2031   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2032   if (hr) {
2033       FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2034       IPicture_Release(newpic);
2035       *ppvObj = NULL;
2036       return hr;
2037   }
2038   IPersistStream_Load(ps,lpstream);
2039   IPersistStream_Release(ps);
2040   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2041   if (hr)
2042       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2043   IPicture_Release(newpic);
2044   return hr;
2045 }
2046
2047 /***********************************************************************
2048  * OleLoadPictureEx (OLEAUT32.401)
2049  */
2050 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2051                             REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2052 {
2053   LPPERSISTSTREAM ps;
2054   IPicture      *newpic;
2055   HRESULT hr;
2056
2057   FIXME("(%p,%ld,%d,%s,x=%ld,y=%ld,f=%lx,%p), partially implemented.\n",
2058         lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2059
2060   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2061   if (hr)
2062     return hr;
2063   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2064   if (hr) {
2065       FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2066       IPicture_Release(newpic);
2067       *ppvObj = NULL;
2068       return hr;
2069   }
2070   IPersistStream_Load(ps,lpstream);
2071   IPersistStream_Release(ps);
2072   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2073   if (hr)
2074       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2075   IPicture_Release(newpic);
2076   return hr;
2077 }
2078
2079 /***********************************************************************
2080  * OleLoadPicturePath (OLEAUT32.424)
2081  */
2082 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2083                 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2084                 LPVOID *ppvRet )
2085 {
2086   static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2087   IPicture *ipicture;
2088   HANDLE hFile;
2089   DWORD dwFileSize;
2090   HGLOBAL hGlobal = NULL;
2091   DWORD dwBytesRead = 0;
2092   IStream *stream;
2093   BOOL bRead;
2094   IPersistStream *pStream;
2095   HRESULT hRes;
2096
2097   TRACE("(%s,%p,%ld,%08lx,%s,%p): stub\n",
2098         debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2099         debugstr_guid(riid), ppvRet);
2100
2101   if (!ppvRet) return E_POINTER;
2102
2103   if (strncmpW(szURLorPath, file, 7) == 0) {        
2104       szURLorPath += 7;
2105   
2106       hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2107                                    0, NULL);
2108       if (hFile == INVALID_HANDLE_VALUE)
2109           return E_UNEXPECTED;
2110
2111       dwFileSize = GetFileSize(hFile, NULL);
2112       if (dwFileSize != INVALID_FILE_SIZE )
2113       {
2114           hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2115           if ( hGlobal)
2116           {
2117               bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2118               if (!bRead)
2119               {
2120                   GlobalFree(hGlobal);
2121                   hGlobal = 0;
2122               }
2123           }
2124       }
2125       CloseHandle(hFile);
2126       
2127       if (!hGlobal)
2128           return E_UNEXPECTED;
2129
2130       hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2131       if (FAILED(hRes)) 
2132       {
2133           GlobalFree(hGlobal);
2134           return hRes;
2135       }
2136   } else {
2137       IMoniker *pmnk;
2138       IBindCtx *pbc;
2139
2140       hRes = CreateBindCtx(0, &pbc);
2141       if (SUCCEEDED(hRes)) 
2142       {
2143           hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2144           if (SUCCEEDED(hRes))
2145           {              
2146               hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2147               IMoniker_Release(pmnk);
2148           }
2149           IBindCtx_Release(pbc);
2150       }
2151       if (FAILED(hRes))
2152           return hRes;
2153   }
2154
2155   hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER, 
2156                    &IID_IPicture, (LPVOID*)&ipicture);
2157   if (hRes != S_OK) {
2158       IStream_Release(stream);
2159       return hRes;
2160   }
2161   
2162   hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2163   if (hRes) {
2164       IStream_Release(stream);
2165       IPicture_Release(ipicture);
2166       return hRes;
2167   }
2168
2169   hRes = IPersistStream_Load(pStream, stream); 
2170   IPersistStream_Release(pStream);
2171   IStream_Release(stream);
2172
2173   if (hRes) {
2174       IPicture_Release(ipicture);
2175       return hRes;
2176   }
2177
2178   hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2179   if (hRes)
2180       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2181   
2182   IPicture_Release(ipicture);
2183   return hRes;
2184 }
2185
2186 /*******************************************************************************
2187  * StdPic ClassFactory
2188  */
2189 typedef struct
2190 {
2191     /* IUnknown fields */
2192     IClassFactoryVtbl          *lpVtbl;
2193     DWORD                       ref;
2194 } IClassFactoryImpl;
2195
2196 static HRESULT WINAPI
2197 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2198         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2199
2200         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2201         return E_NOINTERFACE;
2202 }
2203
2204 static ULONG WINAPI
2205 SPCF_AddRef(LPCLASSFACTORY iface) {
2206         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2207         return InterlockedIncrement(&This->ref);
2208 }
2209
2210 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2211         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2212         /* static class, won't be  freed */
2213         return InterlockedDecrement(&This->ref);
2214 }
2215
2216 static HRESULT WINAPI SPCF_CreateInstance(
2217         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2218 ) {
2219     /* Creates an uninitialized picture */
2220     return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2221
2222 }
2223
2224 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2225         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2226         FIXME("(%p)->(%d),stub!\n",This,dolock);
2227         return S_OK;
2228 }
2229
2230 static IClassFactoryVtbl SPCF_Vtbl = {
2231         SPCF_QueryInterface,
2232         SPCF_AddRef,
2233         SPCF_Release,
2234         SPCF_CreateInstance,
2235         SPCF_LockServer
2236 };
2237 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2238
2239 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }