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