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