Reverse the order for deleting the items in resetcontent to correctly
[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) {
1518         iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1519         if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1520     } else {
1521         if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1522             iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1523         else
1524             iNumPaletteEntries = 0;
1525     }
1526     *pLength =
1527         sizeof(BITMAPFILEHEADER) +
1528         sizeof(BITMAPINFOHEADER) +
1529         iNumPaletteEntries * sizeof(RGBQUAD) +
1530         pInfoBitmap->bmiHeader.biSizeImage;
1531     *ppBuffer = (void *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1532
1533     /* Fill the BITMAPFILEHEADER */
1534     pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1535     pFileHeader->bfType = 0x4d42;
1536     pFileHeader->bfSize = *pLength;
1537     pFileHeader->bfOffBits =
1538         sizeof(BITMAPFILEHEADER) +
1539         sizeof(BITMAPINFOHEADER) +
1540         iNumPaletteEntries * sizeof(RGBQUAD);
1541
1542     /* Fill the BITMAPINFOHEADER and the palette data */
1543     pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1544     memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1545     memcpy(
1546         (unsigned char *)(*ppBuffer) +
1547             sizeof(BITMAPFILEHEADER) +
1548             sizeof(BITMAPINFOHEADER) +
1549             iNumPaletteEntries * sizeof(RGBQUAD),
1550         pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1551     iSuccess = 1;
1552
1553     HeapFree(GetProcessHeap(), 0, pPixelData);
1554     HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1555     return iSuccess;
1556 }
1557
1558 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1559 {
1560         ICONINFO infoIcon;
1561         int iSuccess = 0;
1562
1563         *ppBuffer = NULL; *pLength = 0;
1564         if (GetIconInfo(hIcon, &infoIcon)) {
1565                 HDC hDC;
1566                 BITMAPINFO * pInfoBitmap;
1567                 unsigned char * pIconData = NULL;
1568                 unsigned int iDataSize = 0;
1569
1570         pInfoBitmap = (BITMAPINFO *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1571
1572                 /* Find out icon size */
1573                 hDC = GetDC(0);
1574                 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1575                 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1576                 if (1) {
1577                         /* Auxiliary pointers */
1578                         CURSORICONFILEDIR * pIconDir;
1579                         CURSORICONFILEDIRENTRY * pIconEntry;
1580                         BITMAPINFOHEADER * pIconBitmapHeader;
1581                         unsigned int iOffsetPalette;
1582                         unsigned int iOffsetColorData;
1583                         unsigned int iOffsetMaskData;
1584
1585                         unsigned int iLengthScanLineColor;
1586                         unsigned int iLengthScanLineMask;
1587                         unsigned int iNumEntriesPalette;
1588
1589                         iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1590                         iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
1591 /*
1592                         FIXME("DEBUG: bitmap size is %d x %d\n",
1593                                 pInfoBitmap->bmiHeader.biWidth,
1594                                 pInfoBitmap->bmiHeader.biHeight);
1595                         FIXME("DEBUG: bitmap bpp is %d\n",
1596                                 pInfoBitmap->bmiHeader.biBitCount);
1597                         FIXME("DEBUG: bitmap nplanes is %d\n",
1598                                 pInfoBitmap->bmiHeader.biPlanes);
1599                         FIXME("DEBUG: bitmap biSizeImage is %lu\n",
1600                                 pInfoBitmap->bmiHeader.biSizeImage);
1601 */
1602                         /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1603                         iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1604                         pIconData = (unsigned char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1605
1606                         /* Fill out the CURSORICONFILEDIR */
1607                         pIconDir = (CURSORICONFILEDIR *)pIconData;
1608                         pIconDir->idType = 1;
1609                         pIconDir->idCount = 1;
1610
1611                         /* Fill out the CURSORICONFILEDIRENTRY */
1612                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1613                         pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1614                         pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1615                         pIconEntry->bColorCount =
1616                                 (pInfoBitmap->bmiHeader.biBitCount < 8)
1617                                 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1618                                 : 0;
1619                         pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1620                         pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1621                         pIconEntry->dwDIBSize = 0;
1622                         pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1623
1624                         /* Fill out the BITMAPINFOHEADER */
1625                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1626                         memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
1627
1628                         /*      Find out whether a palette exists for the bitmap */
1629                         if (    (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1630                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 24)
1631                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1632                                 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1633                                 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256; 
1634                         } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1635                                 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1636                                 iNumEntriesPalette = 3;
1637                         } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1638                                 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1639                         } else {
1640                                 iNumEntriesPalette = 0;
1641                         }
1642
1643                         /*  Add bitmap size and header size to icon data size. */
1644                         iOffsetPalette = iDataSize;
1645                         iDataSize += iNumEntriesPalette * sizeof(DWORD);
1646                         iOffsetColorData = iDataSize;
1647                         iDataSize += pIconBitmapHeader->biSizeImage;
1648                         iOffsetMaskData = iDataSize;
1649                         iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1650                         pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1651                         pIconBitmapHeader->biHeight *= 2;
1652                         pIconData = (unsigned char *)HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1653                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1654                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1655                         pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1656
1657                         /* Get the actual bitmap data from the icon bitmap */
1658                         GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1659                                 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1660                         if (iNumEntriesPalette > 0) {
1661                                 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1662                                         iNumEntriesPalette * sizeof(RGBQUAD));
1663                         }
1664
1665                         /* Reset all values so that GetDIBits call succeeds */
1666                         memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1667                         memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1668                         pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1669 /*
1670             if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1671                                 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1672                                         pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1673
1674                 printf("ERROR: unable to get bitmap mask (error %lu)\n",
1675                                         GetLastError());
1676
1677                         }
1678 */
1679             GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1680             GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1681
1682                         /* Write out everything produced so far to the stream */
1683                         *ppBuffer = pIconData; *pLength = iDataSize;
1684                         iSuccess = 1;
1685                 } else {
1686 /*
1687                         printf("ERROR: unable to get bitmap information via GetDIBits() (error %lu)\n",
1688                                 GetLastError());
1689 */
1690                 }
1691                 /*
1692                         Remarks (from MSDN entry on GetIconInfo):
1693
1694                         GetIconInfo creates bitmaps for the hbmMask and hbmColor
1695                         members of ICONINFO. The calling application must manage
1696                         these bitmaps and delete them when they are no longer
1697                         necessary.
1698                  */
1699                 if (hDC) ReleaseDC(0, hDC);
1700                 DeleteObject(infoIcon.hbmMask);
1701                 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1702                 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1703         } else {
1704                 printf("ERROR: Unable to get icon information (error %lu)\n",
1705                         GetLastError());
1706         }
1707         return iSuccess;
1708 }
1709
1710 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1711   IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1712 {
1713   ICOM_THIS_From_IPersistStream(IPicture, iface);
1714   FIXME("(%p,%p),stub!\n",This,pcbSize);
1715   return E_NOTIMPL;
1716 }
1717
1718 /************************************************************************
1719  *    IDispatch
1720  */
1721 /************************************************************************
1722  * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1723  *
1724  * See Windows documentation for more details on IUnknown methods.
1725  */
1726 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1727   IDispatch* iface,
1728   REFIID     riid,
1729   VOID**     ppvoid)
1730 {
1731   ICOM_THIS_From_IDispatch(IPicture, iface);
1732
1733   return IPicture_QueryInterface(This, riid, ppvoid);
1734 }
1735
1736 /************************************************************************
1737  * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1738  *
1739  * See Windows documentation for more details on IUnknown methods.
1740  */
1741 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1742   IDispatch* iface)
1743 {
1744   ICOM_THIS_From_IDispatch(IPicture, iface);
1745
1746   return IPicture_AddRef(This);
1747 }
1748
1749 /************************************************************************
1750  * OLEPictureImpl_IDispatch_Release (IUnknown)
1751  *
1752  * See Windows documentation for more details on IUnknown methods.
1753  */
1754 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1755   IDispatch* iface)
1756 {
1757   ICOM_THIS_From_IDispatch(IPicture, iface);
1758
1759   return IPicture_Release(This);
1760 }
1761
1762 /************************************************************************
1763  * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1764  *
1765  * See Windows documentation for more details on IDispatch methods.
1766  */
1767 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1768   IDispatch*    iface,
1769   unsigned int* pctinfo)
1770 {
1771   FIXME("():Stub\n");
1772
1773   return E_NOTIMPL;
1774 }
1775
1776 /************************************************************************
1777  * OLEPictureImpl_GetTypeInfo (IDispatch)
1778  *
1779  * See Windows documentation for more details on IDispatch methods.
1780  */
1781 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1782   IDispatch*  iface,
1783   UINT      iTInfo,
1784   LCID        lcid,
1785   ITypeInfo** ppTInfo)
1786 {
1787   FIXME("():Stub\n");
1788
1789   return E_NOTIMPL;
1790 }
1791
1792 /************************************************************************
1793  * OLEPictureImpl_GetIDsOfNames (IDispatch)
1794  *
1795  * See Windows documentation for more details on IDispatch methods.
1796  */
1797 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1798   IDispatch*  iface,
1799   REFIID      riid,
1800   LPOLESTR* rgszNames,
1801   UINT      cNames,
1802   LCID        lcid,
1803   DISPID*     rgDispId)
1804 {
1805   FIXME("():Stub\n");
1806
1807   return E_NOTIMPL;
1808 }
1809
1810 /************************************************************************
1811  * OLEPictureImpl_Invoke (IDispatch)
1812  *
1813  * See Windows documentation for more details on IDispatch methods.
1814  */
1815 static HRESULT WINAPI OLEPictureImpl_Invoke(
1816   IDispatch*  iface,
1817   DISPID      dispIdMember,
1818   REFIID      riid,
1819   LCID        lcid,
1820   WORD        wFlags,
1821   DISPPARAMS* pDispParams,
1822   VARIANT*    pVarResult,
1823   EXCEPINFO*  pExepInfo,
1824   UINT*     puArgErr)
1825 {
1826   FIXME("(dispid: %ld):Stub\n",dispIdMember);
1827
1828   VariantInit(pVarResult);
1829   V_VT(pVarResult) = VT_BOOL;
1830   V_UNION(pVarResult,boolVal) = FALSE;
1831   return S_OK;
1832 }
1833
1834
1835 static IPictureVtbl OLEPictureImpl_VTable =
1836 {
1837   OLEPictureImpl_QueryInterface,
1838   OLEPictureImpl_AddRef,
1839   OLEPictureImpl_Release,
1840   OLEPictureImpl_get_Handle,
1841   OLEPictureImpl_get_hPal,
1842   OLEPictureImpl_get_Type,
1843   OLEPictureImpl_get_Width,
1844   OLEPictureImpl_get_Height,
1845   OLEPictureImpl_Render,
1846   OLEPictureImpl_set_hPal,
1847   OLEPictureImpl_get_CurDC,
1848   OLEPictureImpl_SelectPicture,
1849   OLEPictureImpl_get_KeepOriginalFormat,
1850   OLEPictureImpl_put_KeepOriginalFormat,
1851   OLEPictureImpl_PictureChanged,
1852   OLEPictureImpl_SaveAsFile,
1853   OLEPictureImpl_get_Attributes
1854 };
1855
1856 static IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
1857 {
1858   OLEPictureImpl_IDispatch_QueryInterface,
1859   OLEPictureImpl_IDispatch_AddRef,
1860   OLEPictureImpl_IDispatch_Release,
1861   OLEPictureImpl_GetTypeInfoCount,
1862   OLEPictureImpl_GetTypeInfo,
1863   OLEPictureImpl_GetIDsOfNames,
1864   OLEPictureImpl_Invoke
1865 };
1866
1867 static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
1868 {
1869   OLEPictureImpl_IPersistStream_QueryInterface,
1870   OLEPictureImpl_IPersistStream_AddRef,
1871   OLEPictureImpl_IPersistStream_Release,
1872   OLEPictureImpl_GetClassID,
1873   OLEPictureImpl_IsDirty,
1874   OLEPictureImpl_Load,
1875   OLEPictureImpl_Save,
1876   OLEPictureImpl_GetSizeMax
1877 };
1878
1879 static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
1880 {
1881   OLEPictureImpl_IConnectionPointContainer_QueryInterface,
1882   OLEPictureImpl_IConnectionPointContainer_AddRef,
1883   OLEPictureImpl_IConnectionPointContainer_Release,
1884   OLEPictureImpl_EnumConnectionPoints,
1885   OLEPictureImpl_FindConnectionPoint
1886 };
1887
1888 /***********************************************************************
1889  * OleCreatePictureIndirect (OLEAUT32.419)
1890  */
1891 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
1892                             BOOL fOwn, LPVOID *ppvObj )
1893 {
1894   OLEPictureImpl* newPict = NULL;
1895   HRESULT      hr         = S_OK;
1896
1897   TRACE("(%p,%p,%d,%p)\n", lpPictDesc, riid, fOwn, ppvObj);
1898
1899   /*
1900    * Sanity check
1901    */
1902   if (ppvObj==0)
1903     return E_POINTER;
1904
1905   *ppvObj = NULL;
1906
1907   /*
1908    * Try to construct a new instance of the class.
1909    */
1910   newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
1911
1912   if (newPict == NULL)
1913     return E_OUTOFMEMORY;
1914
1915   /*
1916    * Make sure it supports the interface required by the caller.
1917    */
1918   hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
1919
1920   /*
1921    * Release the reference obtained in the constructor. If
1922    * the QueryInterface was unsuccessful, it will free the class.
1923    */
1924   IPicture_Release((IPicture*)newPict);
1925
1926   return hr;
1927 }
1928
1929
1930 /***********************************************************************
1931  * OleLoadPicture (OLEAUT32.418)
1932  */
1933 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
1934                             REFIID riid, LPVOID *ppvObj )
1935 {
1936   LPPERSISTSTREAM ps;
1937   IPicture      *newpic;
1938   HRESULT hr;
1939
1940   TRACE("(%p,%ld,%d,%s,%p), partially implemented.\n",
1941         lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
1942
1943   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
1944   if (hr)
1945     return hr;
1946   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
1947   if (hr) {
1948       FIXME("Could not get IPersistStream iface from Ole Picture?\n");
1949       IPicture_Release(newpic);
1950       *ppvObj = NULL;
1951       return hr;
1952   }
1953   IPersistStream_Load(ps,lpstream);
1954   IPersistStream_Release(ps);
1955   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
1956   if (hr)
1957       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
1958   IPicture_Release(newpic);
1959   return hr;
1960 }
1961
1962 /***********************************************************************
1963  * OleLoadPictureEx (OLEAUT32.401)
1964  */
1965 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
1966                             REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
1967 {
1968   LPPERSISTSTREAM ps;
1969   IPicture      *newpic;
1970   HRESULT hr;
1971
1972   FIXME("(%p,%ld,%d,%s,x=%ld,y=%ld,f=%lx,%p), partially implemented.\n",
1973         lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
1974
1975   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
1976   if (hr)
1977     return hr;
1978   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
1979   if (hr) {
1980       FIXME("Could not get IPersistStream iface from Ole Picture?\n");
1981       IPicture_Release(newpic);
1982       *ppvObj = NULL;
1983       return hr;
1984   }
1985   IPersistStream_Load(ps,lpstream);
1986   IPersistStream_Release(ps);
1987   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
1988   if (hr)
1989       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
1990   IPicture_Release(newpic);
1991   return hr;
1992 }
1993
1994 /*******************************************************************************
1995  * StdPic ClassFactory
1996  */
1997 typedef struct
1998 {
1999     /* IUnknown fields */
2000     IClassFactoryVtbl          *lpVtbl;
2001     DWORD                       ref;
2002 } IClassFactoryImpl;
2003
2004 static HRESULT WINAPI
2005 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2006         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2007
2008         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2009         return E_NOINTERFACE;
2010 }
2011
2012 static ULONG WINAPI
2013 SPCF_AddRef(LPCLASSFACTORY iface) {
2014         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2015         return InterlockedIncrement(&This->ref);
2016 }
2017
2018 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2019         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2020         /* static class, won't be  freed */
2021         return InterlockedDecrement(&This->ref);
2022 }
2023
2024 static HRESULT WINAPI SPCF_CreateInstance(
2025         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2026 ) {
2027         PICTDESC        pd;
2028
2029         FIXME("(%p,%p,%s,%p), creating stdpic with PICTYPE_NONE.\n",iface,pOuter,debugstr_guid(riid),ppobj);
2030         pd.cbSizeofstruct = sizeof(pd);
2031         pd.picType = PICTYPE_NONE;
2032         return OleCreatePictureIndirect(&pd,riid,TRUE,ppobj);
2033
2034 }
2035
2036 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2037         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2038         FIXME("(%p)->(%d),stub!\n",This,dolock);
2039         return S_OK;
2040 }
2041
2042 static IClassFactoryVtbl SPCF_Vtbl = {
2043         SPCF_QueryInterface,
2044         SPCF_AddRef,
2045         SPCF_Release,
2046         SPCF_CreateInstance,
2047         SPCF_LockServer
2048 };
2049 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2050
2051 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }