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