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