oleaut32: Rewrite MSFT_ReadName and MSFT_ReadString to need one less allocation and...
[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   BYTE          *xbuf;
1404   DWORD         header[2];
1405   WORD          magic;
1406   STATSTG       statstg;
1407   OLEPictureImpl *This = impl_from_IPersistStream(iface);
1408   
1409   TRACE("(%p,%p)\n",This,pStm);
1410
1411   /****************************************************************************************
1412    * Part 1: Load the data
1413    */
1414   /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1415    * out whether we do.
1416    *
1417    * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1418    * compound file. This may explain most, if not all, of the cases of "no
1419    * header", and the header validation should take this into account.
1420    * At least in Visual Basic 6, resource streams, valid headers are
1421    *    header[0] == "lt\0\0",
1422    *    header[1] == length_of_stream.
1423    *
1424    * Also handle streams where we do not have a working "Stat" method by
1425    * reading all data until the end of the stream.
1426    */
1427   hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1428   if (hr) {
1429       TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1430       statfailed = TRUE;
1431       /* we will read at least 8 byte ... just right below */
1432       statstg.cbSize.QuadPart = 8;
1433   }
1434   hr=IStream_Read(pStm,header,8,&xread);
1435   if (hr || xread!=8) {
1436       FIXME("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1437       return hr;
1438   }
1439
1440   headerisdata = FALSE;
1441   xread = 0;
1442   if (!memcmp(&(header[0]),"lt\0\0", 4) && (header[1] <= statstg.cbSize.QuadPart-8)) {
1443       toread = header[1];
1444   } else {
1445       if (!memcmp(&(header[0]), "GIF8",     4) ||   /* GIF header */
1446           !memcmp(&(header[0]), "BM",       2) ||   /* BMP header */
1447           !memcmp(&(header[0]), "\xff\xd8", 2) ||   /* JPEG header */
1448           (header[1] > statstg.cbSize.QuadPart)||   /* invalid size */
1449           (header[1]==0)
1450       ) {/* Incorrect header, assume none. */
1451           headerisdata = TRUE;
1452           toread = statstg.cbSize.QuadPart-8;
1453           xread = 8;
1454       } else {
1455           FIXME("Unknown stream header magic: %08x\n", header[0]);
1456           toread = header[1];
1457       }
1458   }
1459
1460   if (statfailed) { /* we don't know the size ... read all we get */
1461       int sizeinc = 4096;
1462       int origsize = sizeinc;
1463       ULONG nread = 42;
1464
1465       TRACE("Reading all data from stream.\n");
1466       xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1467       if (headerisdata)
1468           memcpy (xbuf, &header, 8);
1469       while (1) {
1470           while (xread < origsize) {
1471               hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1472               xread+=nread;
1473               if (hr || !nread)
1474                   break;
1475           }
1476           if (!nread || hr) /* done, or error */
1477               break;
1478           if (xread == origsize) {
1479               origsize += sizeinc;
1480               sizeinc = 2*sizeinc; /* exponential increase */
1481               xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1482           }
1483       }
1484       if (hr)
1485           TRACE("hr in no-stat loader case is %08x\n", hr);
1486       TRACE("loaded %d bytes.\n", xread);
1487       This->datalen = xread;
1488       This->data    = xbuf;
1489   } else {
1490       This->datalen = toread+(headerisdata?8:0);
1491       xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1492
1493       if (headerisdata)
1494           memcpy (xbuf, &header, 8);
1495
1496       while (xread < This->datalen) {
1497           ULONG nread;
1498           hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1499           xread+=nread;
1500           if (hr || !nread)
1501               break;
1502       }
1503       if (xread != This->datalen)
1504           FIXME("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1505   }
1506   if (This->datalen == 0) { /* Marks the "NONE" picture */
1507       This->desc.picType = PICTYPE_NONE;
1508       return S_OK;
1509   }
1510
1511
1512   /****************************************************************************************
1513    * Part 2: Process the loaded data
1514    */
1515
1516   magic = xbuf[0] + (xbuf[1]<<8);
1517   switch (magic) {
1518   case 0x4947: /* GIF */
1519     hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1520     break;
1521   case 0xd8ff: /* JPEG */
1522     hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1523     break;
1524   case 0x4d42: /* Bitmap */
1525     hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1526     break;
1527   case 0x0000: { /* ICON , first word is dwReserved */
1528     hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1529     break;
1530   }
1531   default:
1532   {
1533     unsigned int i;
1534     FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1535     hr=E_FAIL;
1536     for (i=0;i<xread+8;i++) {
1537         if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
1538         else MESSAGE("%02x ",xbuf[i-8]);
1539         if (i % 10 == 9) MESSAGE("\n");
1540     }
1541     MESSAGE("\n");
1542     break;
1543   }
1544   }
1545   This->bIsDirty = FALSE;
1546
1547   /* FIXME: this notify is not really documented */
1548   if (hr==S_OK)
1549       OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1550   return hr;
1551 }
1552
1553 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1554 {
1555     int iSuccess = 0;
1556     HDC hDC;
1557     BITMAPINFO * pInfoBitmap;
1558     int iNumPaletteEntries;
1559     unsigned char * pPixelData;
1560     BITMAPFILEHEADER * pFileHeader;
1561     BITMAPINFO * pInfoHeader;
1562
1563     pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1564         sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1565
1566     /* Find out bitmap size and padded length */
1567     hDC = GetDC(0);
1568     pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1569     GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1570
1571     /* Fetch bitmap palette & pixel data */
1572
1573     pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1574     GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1575
1576     /* Calculate the total length required for the BMP data */
1577     if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1578         iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1579         if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1580     } else {
1581         if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1582             iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1583         else
1584             iNumPaletteEntries = 0;
1585     }
1586     *pLength =
1587         sizeof(BITMAPFILEHEADER) +
1588         sizeof(BITMAPINFOHEADER) +
1589         iNumPaletteEntries * sizeof(RGBQUAD) +
1590         pInfoBitmap->bmiHeader.biSizeImage;
1591     *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1592
1593     /* Fill the BITMAPFILEHEADER */
1594     pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1595     pFileHeader->bfType = 0x4d42;
1596     pFileHeader->bfSize = *pLength;
1597     pFileHeader->bfOffBits =
1598         sizeof(BITMAPFILEHEADER) +
1599         sizeof(BITMAPINFOHEADER) +
1600         iNumPaletteEntries * sizeof(RGBQUAD);
1601
1602     /* Fill the BITMAPINFOHEADER and the palette data */
1603     pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1604     memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1605     memcpy(
1606         (unsigned char *)(*ppBuffer) +
1607             sizeof(BITMAPFILEHEADER) +
1608             sizeof(BITMAPINFOHEADER) +
1609             iNumPaletteEntries * sizeof(RGBQUAD),
1610         pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1611     iSuccess = 1;
1612
1613     HeapFree(GetProcessHeap(), 0, pPixelData);
1614     HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1615     return iSuccess;
1616 }
1617
1618 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1619 {
1620         ICONINFO infoIcon;
1621         int iSuccess = 0;
1622
1623         *ppBuffer = NULL; *pLength = 0;
1624         if (GetIconInfo(hIcon, &infoIcon)) {
1625                 HDC hDC;
1626                 BITMAPINFO * pInfoBitmap;
1627                 unsigned char * pIconData = NULL;
1628                 unsigned int iDataSize = 0;
1629
1630         pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1631
1632                 /* Find out icon size */
1633                 hDC = GetDC(0);
1634                 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1635                 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1636                 if (1) {
1637                         /* Auxiliary pointers */
1638                         CURSORICONFILEDIR * pIconDir;
1639                         CURSORICONFILEDIRENTRY * pIconEntry;
1640                         BITMAPINFOHEADER * pIconBitmapHeader;
1641                         unsigned int iOffsetPalette;
1642                         unsigned int iOffsetColorData;
1643                         unsigned int iOffsetMaskData;
1644
1645                         unsigned int iLengthScanLineColor;
1646                         unsigned int iLengthScanLineMask;
1647                         unsigned int iNumEntriesPalette;
1648
1649                         iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1650                         iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
1651 /*
1652                         FIXME("DEBUG: bitmap size is %d x %d\n",
1653                                 pInfoBitmap->bmiHeader.biWidth,
1654                                 pInfoBitmap->bmiHeader.biHeight);
1655                         FIXME("DEBUG: bitmap bpp is %d\n",
1656                                 pInfoBitmap->bmiHeader.biBitCount);
1657                         FIXME("DEBUG: bitmap nplanes is %d\n",
1658                                 pInfoBitmap->bmiHeader.biPlanes);
1659                         FIXME("DEBUG: bitmap biSizeImage is %u\n",
1660                                 pInfoBitmap->bmiHeader.biSizeImage);
1661 */
1662                         /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1663                         iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1664                         pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1665
1666                         /* Fill out the CURSORICONFILEDIR */
1667                         pIconDir = (CURSORICONFILEDIR *)pIconData;
1668                         pIconDir->idType = 1;
1669                         pIconDir->idCount = 1;
1670
1671                         /* Fill out the CURSORICONFILEDIRENTRY */
1672                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1673                         pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1674                         pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1675                         pIconEntry->bColorCount =
1676                                 (pInfoBitmap->bmiHeader.biBitCount < 8)
1677                                 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1678                                 : 0;
1679                         pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1680                         pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1681                         pIconEntry->dwDIBSize = 0;
1682                         pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1683
1684                         /* Fill out the BITMAPINFOHEADER */
1685                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1686                         memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
1687
1688                         /*      Find out whether a palette exists for the bitmap */
1689                         if (    (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1690                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 24)
1691                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1692                                 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1693                                 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256; 
1694                         } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1695                                 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1696                                 iNumEntriesPalette = 3;
1697                         } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1698                                 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1699                         } else {
1700                                 iNumEntriesPalette = 0;
1701                         }
1702
1703                         /*  Add bitmap size and header size to icon data size. */
1704                         iOffsetPalette = iDataSize;
1705                         iDataSize += iNumEntriesPalette * sizeof(DWORD);
1706                         iOffsetColorData = iDataSize;
1707                         iDataSize += pIconBitmapHeader->biSizeImage;
1708                         iOffsetMaskData = iDataSize;
1709                         iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1710                         pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1711                         pIconBitmapHeader->biHeight *= 2;
1712                         pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1713                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1714                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1715                         pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1716
1717                         /* Get the actual bitmap data from the icon bitmap */
1718                         GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1719                                 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1720                         if (iNumEntriesPalette > 0) {
1721                                 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1722                                         iNumEntriesPalette * sizeof(RGBQUAD));
1723                         }
1724
1725                         /* Reset all values so that GetDIBits call succeeds */
1726                         memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1727                         memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1728                         pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1729 /*
1730             if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1731                                 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1732                                         pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1733
1734                 printf("ERROR: unable to get bitmap mask (error %u)\n",
1735                                         GetLastError());
1736
1737                         }
1738 */
1739             GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1740             GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1741
1742                         /* Write out everything produced so far to the stream */
1743                         *ppBuffer = pIconData; *pLength = iDataSize;
1744                         iSuccess = 1;
1745                 } else {
1746 /*
1747                         printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1748                                 GetLastError());
1749 */
1750                 }
1751                 /*
1752                         Remarks (from MSDN entry on GetIconInfo):
1753
1754                         GetIconInfo creates bitmaps for the hbmMask and hbmColor
1755                         members of ICONINFO. The calling application must manage
1756                         these bitmaps and delete them when they are no longer
1757                         necessary.
1758                  */
1759                 if (hDC) ReleaseDC(0, hDC);
1760                 DeleteObject(infoIcon.hbmMask);
1761                 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1762                 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1763         } else {
1764                 printf("ERROR: Unable to get icon information (error %u)\n",
1765                         GetLastError());
1766         }
1767         return iSuccess;
1768 }
1769
1770 static HRESULT WINAPI OLEPictureImpl_Save(
1771   IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1772 {
1773     HRESULT hResult = E_NOTIMPL;
1774     void * pIconData;
1775     unsigned int iDataSize;
1776     ULONG dummy;
1777     int iSerializeResult = 0;
1778     OLEPictureImpl *This = impl_from_IPersistStream(iface);
1779
1780     TRACE("%p %p %d\n", This, pStm, fClearDirty);
1781
1782     switch (This->desc.picType) {
1783     case PICTYPE_ICON:
1784         if (This->bIsDirty || !This->data) {
1785             if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1786                 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1787                 hResult = E_FAIL;
1788                 break;
1789             }
1790             HeapFree(GetProcessHeap(), 0, This->data);
1791             This->data = pIconData;
1792             This->datalen = iDataSize;
1793         }
1794         if (This->loadtime_magic != 0xdeadbeef) {
1795             DWORD header[2];
1796
1797             header[0] = This->loadtime_magic;
1798             header[1] = This->datalen;
1799             IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1800         }
1801         IStream_Write(pStm, This->data, This->datalen, &dummy);
1802
1803         hResult = S_OK;
1804         break;
1805     case PICTYPE_BITMAP:
1806         if (This->bIsDirty) {
1807             switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) {
1808             case 0x4d42:
1809                 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1810                 break;
1811             case 0xd8ff:
1812                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1813                 break;
1814             case 0x4947:
1815                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1816                 break;
1817             default:
1818                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1819                 break;
1820             }
1821             if (iSerializeResult) {
1822                 /*
1823                 if (This->loadtime_magic != 0xdeadbeef) {
1824                 */
1825                 if (1) {
1826                     DWORD header[2];
1827
1828                     header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1829                     header[1] = iDataSize;
1830                     IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1831                 }
1832                 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1833
1834                 HeapFree(GetProcessHeap(), 0, This->data);
1835                 This->data = pIconData;
1836                 This->datalen = iDataSize;
1837                 hResult = S_OK;
1838             }
1839         } else {
1840             /*
1841             if (This->loadtime_magic != 0xdeadbeef) {
1842             */
1843             if (1) {
1844                 DWORD header[2];
1845
1846                 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1847                 header[1] = This->datalen;
1848                 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1849             }
1850             IStream_Write(pStm, This->data, This->datalen, &dummy);
1851             hResult = S_OK;
1852         }
1853         break;
1854     case PICTYPE_METAFILE:
1855         FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1856         break;
1857     case PICTYPE_ENHMETAFILE:
1858         FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1859         break;
1860     default:
1861         FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1862         break;
1863     }
1864     if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1865     return hResult;
1866 }
1867
1868 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1869   IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1870 {
1871   OLEPictureImpl *This = impl_from_IPersistStream(iface);
1872   FIXME("(%p,%p),stub!\n",This,pcbSize);
1873   return E_NOTIMPL;
1874 }
1875
1876
1877 /************************************************************************
1878  *    IDispatch
1879  */
1880
1881 /************************************************************************
1882  * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1883  *
1884  * See Windows documentation for more details on IUnknown methods.
1885  */
1886 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1887   IDispatch* iface,
1888   REFIID     riid,
1889   VOID**     ppvoid)
1890 {
1891   OLEPictureImpl *This = impl_from_IDispatch(iface);
1892
1893   return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
1894 }
1895
1896 /************************************************************************
1897  * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1898  *
1899  * See Windows documentation for more details on IUnknown methods.
1900  */
1901 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1902   IDispatch* iface)
1903 {
1904   OLEPictureImpl *This = impl_from_IDispatch(iface);
1905
1906   return IPicture_AddRef((IPicture *)This);
1907 }
1908
1909 /************************************************************************
1910  * OLEPictureImpl_IDispatch_Release (IUnknown)
1911  *
1912  * See Windows documentation for more details on IUnknown methods.
1913  */
1914 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1915   IDispatch* iface)
1916 {
1917   OLEPictureImpl *This = impl_from_IDispatch(iface);
1918
1919   return IPicture_Release((IPicture *)This);
1920 }
1921
1922 /************************************************************************
1923  * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1924  *
1925  * See Windows documentation for more details on IDispatch methods.
1926  */
1927 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1928   IDispatch*    iface,
1929   unsigned int* pctinfo)
1930 {
1931   TRACE("(%p)\n", pctinfo);
1932
1933   *pctinfo = 1;
1934
1935   return S_OK;
1936 }
1937
1938 /************************************************************************
1939  * OLEPictureImpl_GetTypeInfo (IDispatch)
1940  *
1941  * See Windows documentation for more details on IDispatch methods.
1942  */
1943 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1944   IDispatch*  iface,
1945   UINT      iTInfo,
1946   LCID        lcid,
1947   ITypeInfo** ppTInfo)
1948 {
1949   static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1950   ITypeLib *tl;
1951   HRESULT hres;
1952
1953   TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1954
1955   if (iTInfo != 0)
1956     return E_FAIL;
1957
1958   hres = LoadTypeLib(stdole2tlb, &tl);
1959   if (FAILED(hres))
1960   {
1961     ERR("Could not load stdole2.tlb\n");
1962     return hres;
1963   }
1964
1965   hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1966   if (FAILED(hres))
1967     ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1968
1969   return hres;
1970 }
1971
1972 /************************************************************************
1973  * OLEPictureImpl_GetIDsOfNames (IDispatch)
1974  *
1975  * See Windows documentation for more details on IDispatch methods.
1976  */
1977 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1978   IDispatch*  iface,
1979   REFIID      riid,
1980   LPOLESTR* rgszNames,
1981   UINT      cNames,
1982   LCID        lcid,
1983   DISPID*     rgDispId)
1984 {
1985   FIXME("():Stub\n");
1986
1987   return E_NOTIMPL;
1988 }
1989
1990 /************************************************************************
1991  * OLEPictureImpl_Invoke (IDispatch)
1992  *
1993  * See Windows documentation for more details on IDispatch methods.
1994  */
1995 static HRESULT WINAPI OLEPictureImpl_Invoke(
1996   IDispatch*  iface,
1997   DISPID      dispIdMember,
1998   REFIID      riid,
1999   LCID        lcid,
2000   WORD        wFlags,
2001   DISPPARAMS* pDispParams,
2002   VARIANT*    pVarResult,
2003   EXCEPINFO*  pExepInfo,
2004   UINT*     puArgErr)
2005 {
2006   OLEPictureImpl *This = impl_from_IDispatch(iface);
2007
2008   /* validate parameters */
2009
2010   if (!IsEqualIID(riid, &IID_NULL))
2011   {
2012     ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2013     return DISP_E_UNKNOWNNAME;
2014   }
2015
2016   if (!pDispParams)
2017   {
2018     ERR("null pDispParams not allowed\n");
2019     return DISP_E_PARAMNOTOPTIONAL;
2020   }
2021
2022   if (wFlags & DISPATCH_PROPERTYGET)
2023   {
2024     if (pDispParams->cArgs != 0)
2025     {
2026       ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2027       return DISP_E_BADPARAMCOUNT;
2028     }
2029     if (!pVarResult)
2030     {
2031       ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2032       return DISP_E_PARAMNOTOPTIONAL;
2033     }
2034   }
2035   else if (wFlags & DISPATCH_PROPERTYPUT)
2036   {
2037     if (pDispParams->cArgs != 1)
2038     {
2039       ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2040       return DISP_E_BADPARAMCOUNT;
2041     }
2042   }
2043
2044   switch (dispIdMember)
2045   {
2046   case DISPID_PICT_HANDLE:
2047     if (wFlags & DISPATCH_PROPERTYGET)
2048     {
2049       TRACE("DISPID_PICT_HANDLE\n");
2050       V_VT(pVarResult) = VT_I4;
2051       return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2052     }
2053     break;
2054   case DISPID_PICT_HPAL:
2055     if (wFlags & DISPATCH_PROPERTYGET)
2056     {
2057       TRACE("DISPID_PICT_HPAL\n");
2058       V_VT(pVarResult) = VT_I4;
2059       return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2060     }
2061     else if (wFlags & DISPATCH_PROPERTYPUT)
2062     {
2063       VARIANTARG vararg;
2064       HRESULT hr;
2065       TRACE("DISPID_PICT_HPAL\n");
2066
2067       VariantInit(&vararg);
2068       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2069       if (FAILED(hr))
2070         return hr;
2071
2072       hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2073
2074       VariantClear(&vararg);
2075       return hr;
2076     }
2077     break;
2078   case DISPID_PICT_TYPE:
2079     if (wFlags & DISPATCH_PROPERTYGET)
2080     {
2081       TRACE("DISPID_PICT_TYPE\n");
2082       V_VT(pVarResult) = VT_I2;
2083       return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2084     }
2085     break;
2086   case DISPID_PICT_WIDTH:
2087     if (wFlags & DISPATCH_PROPERTYGET)
2088     {
2089       TRACE("DISPID_PICT_WIDTH\n");
2090       V_VT(pVarResult) = VT_I4;
2091       return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2092     }
2093     break;
2094   case DISPID_PICT_HEIGHT:
2095     if (wFlags & DISPATCH_PROPERTYGET)
2096     {
2097       TRACE("DISPID_PICT_HEIGHT\n");
2098       V_VT(pVarResult) = VT_I4;
2099       return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2100     }
2101     break;
2102   }
2103
2104   ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2105   return DISP_E_MEMBERNOTFOUND;
2106 }
2107
2108
2109 static const IPictureVtbl OLEPictureImpl_VTable =
2110 {
2111   OLEPictureImpl_QueryInterface,
2112   OLEPictureImpl_AddRef,
2113   OLEPictureImpl_Release,
2114   OLEPictureImpl_get_Handle,
2115   OLEPictureImpl_get_hPal,
2116   OLEPictureImpl_get_Type,
2117   OLEPictureImpl_get_Width,
2118   OLEPictureImpl_get_Height,
2119   OLEPictureImpl_Render,
2120   OLEPictureImpl_set_hPal,
2121   OLEPictureImpl_get_CurDC,
2122   OLEPictureImpl_SelectPicture,
2123   OLEPictureImpl_get_KeepOriginalFormat,
2124   OLEPictureImpl_put_KeepOriginalFormat,
2125   OLEPictureImpl_PictureChanged,
2126   OLEPictureImpl_SaveAsFile,
2127   OLEPictureImpl_get_Attributes
2128 };
2129
2130 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2131 {
2132   OLEPictureImpl_IDispatch_QueryInterface,
2133   OLEPictureImpl_IDispatch_AddRef,
2134   OLEPictureImpl_IDispatch_Release,
2135   OLEPictureImpl_GetTypeInfoCount,
2136   OLEPictureImpl_GetTypeInfo,
2137   OLEPictureImpl_GetIDsOfNames,
2138   OLEPictureImpl_Invoke
2139 };
2140
2141 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2142 {
2143   OLEPictureImpl_IPersistStream_QueryInterface,
2144   OLEPictureImpl_IPersistStream_AddRef,
2145   OLEPictureImpl_IPersistStream_Release,
2146   OLEPictureImpl_GetClassID,
2147   OLEPictureImpl_IsDirty,
2148   OLEPictureImpl_Load,
2149   OLEPictureImpl_Save,
2150   OLEPictureImpl_GetSizeMax
2151 };
2152
2153 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2154 {
2155   OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2156   OLEPictureImpl_IConnectionPointContainer_AddRef,
2157   OLEPictureImpl_IConnectionPointContainer_Release,
2158   OLEPictureImpl_EnumConnectionPoints,
2159   OLEPictureImpl_FindConnectionPoint
2160 };
2161
2162 /***********************************************************************
2163  * OleCreatePictureIndirect (OLEAUT32.419)
2164  */
2165 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2166                             BOOL fOwn, LPVOID *ppvObj )
2167 {
2168   OLEPictureImpl* newPict = NULL;
2169   HRESULT      hr         = S_OK;
2170
2171   TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2172
2173   /*
2174    * Sanity check
2175    */
2176   if (ppvObj==0)
2177     return E_POINTER;
2178
2179   *ppvObj = NULL;
2180
2181   /*
2182    * Try to construct a new instance of the class.
2183    */
2184   newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2185
2186   if (newPict == NULL)
2187     return E_OUTOFMEMORY;
2188
2189   /*
2190    * Make sure it supports the interface required by the caller.
2191    */
2192   hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2193
2194   /*
2195    * Release the reference obtained in the constructor. If
2196    * the QueryInterface was unsuccessful, it will free the class.
2197    */
2198   IPicture_Release((IPicture*)newPict);
2199
2200   return hr;
2201 }
2202
2203
2204 /***********************************************************************
2205  * OleLoadPicture (OLEAUT32.418)
2206  */
2207 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2208                             REFIID riid, LPVOID *ppvObj )
2209 {
2210   LPPERSISTSTREAM ps;
2211   IPicture      *newpic;
2212   HRESULT hr;
2213
2214   TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2215         lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2216
2217   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2218   if (hr)
2219     return hr;
2220   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2221   if (hr) {
2222       FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2223       IPicture_Release(newpic);
2224       *ppvObj = NULL;
2225       return hr;
2226   }
2227   IPersistStream_Load(ps,lpstream);
2228   IPersistStream_Release(ps);
2229   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2230   if (hr)
2231       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2232   IPicture_Release(newpic);
2233   return hr;
2234 }
2235
2236 /***********************************************************************
2237  * OleLoadPictureEx (OLEAUT32.401)
2238  */
2239 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2240                             REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2241 {
2242   LPPERSISTSTREAM ps;
2243   IPicture      *newpic;
2244   HRESULT hr;
2245
2246   FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2247         lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2248
2249   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2250   if (hr)
2251     return hr;
2252   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2253   if (hr) {
2254       FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2255       IPicture_Release(newpic);
2256       *ppvObj = NULL;
2257       return hr;
2258   }
2259   IPersistStream_Load(ps,lpstream);
2260   IPersistStream_Release(ps);
2261   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2262   if (hr)
2263       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2264   IPicture_Release(newpic);
2265   return hr;
2266 }
2267
2268 /***********************************************************************
2269  * OleLoadPicturePath (OLEAUT32.424)
2270  */
2271 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2272                 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2273                 LPVOID *ppvRet )
2274 {
2275   static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2276   IPicture *ipicture;
2277   HANDLE hFile;
2278   DWORD dwFileSize;
2279   HGLOBAL hGlobal = NULL;
2280   DWORD dwBytesRead = 0;
2281   IStream *stream;
2282   BOOL bRead;
2283   IPersistStream *pStream;
2284   HRESULT hRes;
2285
2286   TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2287         debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2288         debugstr_guid(riid), ppvRet);
2289
2290   if (!ppvRet) return E_POINTER;
2291
2292   if (strncmpW(szURLorPath, file, 7) == 0) {        
2293       szURLorPath += 7;
2294   
2295       hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2296                                    0, NULL);
2297       if (hFile == INVALID_HANDLE_VALUE)
2298           return E_UNEXPECTED;
2299
2300       dwFileSize = GetFileSize(hFile, NULL);
2301       if (dwFileSize != INVALID_FILE_SIZE )
2302       {
2303           hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2304           if ( hGlobal)
2305           {
2306               bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2307               if (!bRead)
2308               {
2309                   GlobalFree(hGlobal);
2310                   hGlobal = 0;
2311               }
2312           }
2313       }
2314       CloseHandle(hFile);
2315       
2316       if (!hGlobal)
2317           return E_UNEXPECTED;
2318
2319       hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2320       if (FAILED(hRes)) 
2321       {
2322           GlobalFree(hGlobal);
2323           return hRes;
2324       }
2325   } else {
2326       IMoniker *pmnk;
2327       IBindCtx *pbc;
2328
2329       hRes = CreateBindCtx(0, &pbc);
2330       if (SUCCEEDED(hRes)) 
2331       {
2332           hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2333           if (SUCCEEDED(hRes))
2334           {              
2335               hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2336               IMoniker_Release(pmnk);
2337           }
2338           IBindCtx_Release(pbc);
2339       }
2340       if (FAILED(hRes))
2341           return hRes;
2342   }
2343
2344   hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER, 
2345                    &IID_IPicture, (LPVOID*)&ipicture);
2346   if (hRes != S_OK) {
2347       IStream_Release(stream);
2348       return hRes;
2349   }
2350   
2351   hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2352   if (hRes) {
2353       IStream_Release(stream);
2354       IPicture_Release(ipicture);
2355       return hRes;
2356   }
2357
2358   hRes = IPersistStream_Load(pStream, stream); 
2359   IPersistStream_Release(pStream);
2360   IStream_Release(stream);
2361
2362   if (hRes) {
2363       IPicture_Release(ipicture);
2364       return hRes;
2365   }
2366
2367   hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2368   if (hRes)
2369       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2370   
2371   IPicture_Release(ipicture);
2372   return hRes;
2373 }
2374
2375 /*******************************************************************************
2376  * StdPic ClassFactory
2377  */
2378 typedef struct
2379 {
2380     /* IUnknown fields */
2381     const IClassFactoryVtbl    *lpVtbl;
2382     LONG                        ref;
2383 } IClassFactoryImpl;
2384
2385 static HRESULT WINAPI
2386 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2387         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2388
2389         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2390         return E_NOINTERFACE;
2391 }
2392
2393 static ULONG WINAPI
2394 SPCF_AddRef(LPCLASSFACTORY iface) {
2395         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2396         return InterlockedIncrement(&This->ref);
2397 }
2398
2399 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2400         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2401         /* static class, won't be  freed */
2402         return InterlockedDecrement(&This->ref);
2403 }
2404
2405 static HRESULT WINAPI SPCF_CreateInstance(
2406         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2407 ) {
2408     /* Creates an uninitialized picture */
2409     return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2410
2411 }
2412
2413 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2414         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2415         FIXME("(%p)->(%d),stub!\n",This,dolock);
2416         return S_OK;
2417 }
2418
2419 static const IClassFactoryVtbl SPCF_Vtbl = {
2420         SPCF_QueryInterface,
2421         SPCF_AddRef,
2422         SPCF_Release,
2423         SPCF_CreateInstance,
2424         SPCF_LockServer
2425 };
2426 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2427
2428 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }