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