Use DrawFrameControl instead of bitmaps in certain cases.
[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  *
10  * BUGS
11  *
12  * Support PICTYPE_BITMAP and PICTYPE_ICON, altough only bitmaps very well..
13  * Lots of methods are just stubs.
14  *
15  *
16  * NOTES (or things that msdn doesn't tell you)
17  *
18  * The width and height properties are returned in HIMETRIC units (0.01mm)
19  * IPicture::Render also uses these to select a region of the src picture.
20  * A bitmap's size is converted into these units by using the screen resolution
21  * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
22  *
23  */
24
25 #include "config.h"
26
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include "winerror.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "ole2.h"
35 #include "olectl.h"
36 #include "oleauto.h"
37 #include "wine/obj_picture.h"
38 #include "wine/obj_connection.h"
39 #include "connpt.h"
40 #include "debugtools.h"
41
42 #include "wine/wingdi16.h"
43 #include "cursoricon.h"
44
45 #ifdef HAVE_LIBJPEG
46 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
47 #define XMD_H 
48 #define UINT16 JPEG_UINT16
49 #ifdef HAVE_JPEGLIB_H
50 # include <jpeglib.h>
51 #endif
52 #undef UINT16
53 #endif
54
55 DEFAULT_DEBUG_CHANNEL(ole);
56
57 /*************************************************************************
58  *  Declaration of implementation class
59  */
60
61 typedef struct OLEPictureImpl {
62
63   /*
64    * IPicture handles IUnknown
65    */
66
67     ICOM_VTABLE(IPicture)       *lpvtbl1;
68     ICOM_VTABLE(IDispatch)      *lpvtbl2;
69     ICOM_VTABLE(IPersistStream) *lpvtbl3;
70     ICOM_VTABLE(IConnectionPointContainer) *lpvtbl4;
71
72   /* Object referenece count */
73     DWORD ref;
74
75   /* We own the object and must destroy it ourselves */
76     BOOL fOwn;
77   
78   /* Picture description */
79     PICTDESC desc;
80
81   /* These are the pixel size of a bitmap */
82     DWORD origWidth;
83     DWORD origHeight;
84
85   /* And these are the size of the picture converted into HIMETRIC units */
86     OLE_XSIZE_HIMETRIC himetricWidth;
87     OLE_YSIZE_HIMETRIC himetricHeight;
88
89     IConnectionPoint *pCP;
90
91     BOOL keepOrigFormat;
92     HDC hDCCur;
93 } OLEPictureImpl;
94
95 /*
96  * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
97  */
98 #define ICOM_THIS_From_IDispatch(impl, name) \
99     impl *This = (impl*)(((char*)name)-sizeof(void*));
100 #define ICOM_THIS_From_IPersistStream(impl, name) \
101     impl *This = (impl*)(((char*)name)-2*sizeof(void*));
102 #define ICOM_THIS_From_IConnectionPointContainer(impl, name) \
103     impl *This = (impl*)(((char*)name)-3*sizeof(void*));
104
105 /*
106  * Predeclare VTables.  They get initialized at the end.
107  */
108 static ICOM_VTABLE(IPicture) OLEPictureImpl_VTable;
109 static ICOM_VTABLE(IDispatch) OLEPictureImpl_IDispatch_VTable;
110 static ICOM_VTABLE(IPersistStream) OLEPictureImpl_IPersistStream_VTable;
111 static ICOM_VTABLE(IConnectionPointContainer) OLEPictureImpl_IConnectionPointContainer_VTable;
112
113 /***********************************************************************
114  * Implementation of the OLEPictureImpl class.
115  */
116
117 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
118   BITMAP bm;
119   HDC hdcRef;
120
121   TRACE("bitmap handle %08x\n", This->desc.u.bmp.hbitmap);
122   if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
123     ERR("GetObject fails\n");
124     return;
125   }
126   This->origWidth = bm.bmWidth;
127   This->origHeight = bm.bmHeight;
128   /* The width and height are stored in HIMETRIC units (0.01 mm),
129      so we take our pixel width divide by pixels per inch and
130      multiply by 25.4 * 100 */
131   /* Should we use GetBitmapDimension if available? */
132   hdcRef = CreateCompatibleDC(0);
133   This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
134   This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
135   DeleteDC(hdcRef);
136 }
137
138 /************************************************************************
139  * OLEPictureImpl_Construct
140  *
141  * This method will construct a new instance of the OLEPictureImpl
142  * class.
143  *
144  * The caller of this method must release the object when it's
145  * done with it.
146  */
147 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
148 {
149   OLEPictureImpl* newObject = 0;
150
151   if (pictDesc)
152       TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
153
154   /*
155    * Allocate space for the object.
156    */
157   newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEPictureImpl));
158
159   if (newObject==0)
160     return newObject;
161   
162   /*
163    * Initialize the virtual function table.
164    */
165   newObject->lpvtbl1 = &OLEPictureImpl_VTable;
166   newObject->lpvtbl2 = &OLEPictureImpl_IDispatch_VTable;
167   newObject->lpvtbl3 = &OLEPictureImpl_IPersistStream_VTable;
168   newObject->lpvtbl4 = &OLEPictureImpl_IConnectionPointContainer_VTable;
169
170   CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
171
172   /*
173    * Start with one reference count. The caller of this function 
174    * must release the interface pointer when it is done.
175    */
176   newObject->ref        = 1;
177   newObject->hDCCur     = 0;
178
179   newObject->fOwn       = fOwn;
180
181   /* dunno about original value */
182   newObject->keepOrigFormat = TRUE;
183
184   if (pictDesc) {
185       if(pictDesc->cbSizeofstruct != sizeof(PICTDESC)) {
186           FIXME("struct size = %d\n", pictDesc->cbSizeofstruct);
187       }
188       memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC));
189
190
191       switch(pictDesc->picType) {
192       case PICTYPE_BITMAP:
193         OLEPictureImpl_SetBitmap(newObject);
194         break;
195
196       case PICTYPE_METAFILE:
197         TRACE("metafile handle %08x\n", pictDesc->u.wmf.hmeta);
198         newObject->himetricWidth = pictDesc->u.wmf.xExt;
199         newObject->himetricHeight = pictDesc->u.wmf.yExt;
200         break;
201
202       case PICTYPE_ICON:
203       case PICTYPE_ENHMETAFILE:
204       default:
205         FIXME("Unsupported type %d\n", pictDesc->picType);
206         newObject->himetricWidth = newObject->himetricHeight = 0;
207         break;
208       }
209   } else {
210       newObject->desc.picType = PICTYPE_UNINITIALIZED;
211   }
212     
213   TRACE("returning %p\n", newObject);
214   return newObject;
215 }
216
217 /************************************************************************
218  * OLEPictureImpl_Destroy
219  *
220  * This method is called by the Release method when the reference
221  * count goes down to 0. It will free all resources used by
222  * this object.  */
223 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
224
225   TRACE("(%p)\n", Obj);
226
227   if(Obj->fOwn) { /* We need to destroy the picture */
228     switch(Obj->desc.picType) {
229     case PICTYPE_BITMAP:
230       DeleteObject(Obj->desc.u.bmp.hbitmap);
231       break;
232     case PICTYPE_METAFILE:
233       DeleteMetaFile(Obj->desc.u.wmf.hmeta);
234       break;
235     case PICTYPE_ICON:
236       DestroyIcon(Obj->desc.u.icon.hicon);
237       break;
238     case PICTYPE_ENHMETAFILE:
239       DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
240       break;
241     default:
242       FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
243       break;
244     }
245   }
246   HeapFree(GetProcessHeap(), 0, Obj);
247 }
248
249 static ULONG WINAPI OLEPictureImpl_AddRef(IPicture* iface);
250
251 /************************************************************************
252  * OLEPictureImpl_QueryInterface (IUnknown)
253  *
254  * See Windows documentation for more details on IUnknown methods.
255  */
256 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
257   IPicture*  iface,
258   REFIID  riid,
259   void**  ppvObject)
260 {
261   ICOM_THIS(OLEPictureImpl, iface);
262   TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
263
264   /*
265    * Perform a sanity check on the parameters.
266    */
267   if ( (This==0) || (ppvObject==0) )
268     return E_INVALIDARG;
269   
270   /*
271    * Initialize the return parameter.
272    */
273   *ppvObject = 0;
274   
275   /*
276    * Compare the riid with the interface IDs implemented by this object.
277    */
278   if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
279   {
280     *ppvObject = (IPicture*)This;
281   }
282   else if (memcmp(&IID_IPicture, riid, sizeof(IID_IPicture)) == 0) 
283   {
284     *ppvObject = (IPicture*)This;
285   }
286   else if (memcmp(&IID_IDispatch, riid, sizeof(IID_IDispatch)) == 0) 
287   {
288     *ppvObject = (IDispatch*)&(This->lpvtbl2);
289   }
290   else if (memcmp(&IID_IPictureDisp, riid, sizeof(IID_IPictureDisp)) == 0) 
291   {
292     *ppvObject = (IDispatch*)&(This->lpvtbl2);
293   }
294   else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0) 
295   {
296   *ppvObject = (IPersistStream*)&(This->lpvtbl3);
297   }
298   else if (memcmp(&IID_IConnectionPointContainer, riid, sizeof(IID_IConnectionPointContainer)) == 0) 
299   {
300   *ppvObject = (IConnectionPointContainer*)&(This->lpvtbl4);
301   }
302   /*
303    * Check that we obtained an interface.
304    */
305   if ((*ppvObject)==0)
306   {
307     FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
308     return E_NOINTERFACE;
309   }
310   
311   /*
312    * Query Interface always increases the reference count by one when it is
313    * successful
314    */
315   OLEPictureImpl_AddRef((IPicture*)This);
316
317   return S_OK;;
318 }
319 /***********************************************************************
320  *    OLEPicture_SendNotify (internal)
321  *
322  * Sends notification messages of changed properties to any interested
323  * connections.
324  */
325 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
326 {
327   IEnumConnections *pEnum;
328   CONNECTDATA CD;
329
330   if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
331       return;
332   while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
333     IPropertyNotifySink *sink;
334
335     IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
336     IPropertyNotifySink_OnChanged(sink, dispID);
337     IPropertyNotifySink_Release(sink);
338     IUnknown_Release(CD.pUnk);
339   }
340   IEnumConnections_Release(pEnum);
341   return;
342 }
343
344 /************************************************************************
345  * OLEPictureImpl_AddRef (IUnknown)
346  *
347  * See Windows documentation for more details on IUnknown methods.
348  */
349 static ULONG WINAPI OLEPictureImpl_AddRef( 
350   IPicture* iface)
351 {
352   ICOM_THIS(OLEPictureImpl, iface);
353   TRACE("(%p)->(ref=%ld)\n", This, This->ref);
354   This->ref++;
355
356   return This->ref;
357 }
358         
359 /************************************************************************
360  * OLEPictureImpl_Release (IUnknown)
361  *
362  * See Windows documentation for more details on IUnknown methods.
363  */
364 static ULONG WINAPI OLEPictureImpl_Release( 
365       IPicture* iface)
366 {
367   ICOM_THIS(OLEPictureImpl, iface);
368   TRACE("(%p)->(ref=%ld)\n", This, This->ref);
369
370   /*
371    * Decrease the reference count on this object.
372    */
373   This->ref--;
374
375   /*
376    * If the reference count goes down to 0, perform suicide.
377    */
378   if (This->ref==0)
379   {
380     OLEPictureImpl_Destroy(This);
381
382     return 0;
383   }
384   
385   return This->ref;
386 }
387
388
389 /************************************************************************
390  * OLEPictureImpl_get_Handle
391  */ 
392 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
393                                                 OLE_HANDLE *phandle)
394 {
395   ICOM_THIS(OLEPictureImpl, iface);
396   TRACE("(%p)->(%p)\n", This, phandle);
397   switch(This->desc.picType) {
398   case PICTYPE_BITMAP:
399     *phandle = This->desc.u.bmp.hbitmap;
400     break;
401   case PICTYPE_METAFILE:
402     *phandle = This->desc.u.wmf.hmeta;
403     break;
404   case PICTYPE_ICON:
405     *phandle = This->desc.u.icon.hicon;
406     break;
407   case PICTYPE_ENHMETAFILE:
408     *phandle = This->desc.u.emf.hemf;
409     break;
410   default:
411     FIXME("Unimplemented type %d\n", This->desc.picType);
412     return E_NOTIMPL;
413   }
414   TRACE("returning handle %08x\n", *phandle);
415   return S_OK;
416 }
417
418 /************************************************************************
419  * OLEPictureImpl_get_hPal
420  */ 
421 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
422                                               OLE_HANDLE *phandle)
423 {
424   ICOM_THIS(OLEPictureImpl, iface);
425   FIXME("(%p)->(%p): stub\n", This, phandle);
426   return E_NOTIMPL;
427 }
428
429 /************************************************************************
430  * OLEPictureImpl_get_Type
431  */ 
432 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
433                                               short *ptype)
434 {
435   ICOM_THIS(OLEPictureImpl, iface);
436   TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
437   *ptype = This->desc.picType;
438   return S_OK;
439 }
440
441 /************************************************************************
442  * OLEPictureImpl_get_Width
443  */ 
444 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
445                                                OLE_XSIZE_HIMETRIC *pwidth)
446 {
447   ICOM_THIS(OLEPictureImpl, iface);
448   TRACE("(%p)->(%p): width is %ld\n", This, pwidth, This->himetricWidth);
449   *pwidth = This->himetricWidth;
450   return S_OK;
451 }
452
453 /************************************************************************
454  * OLEPictureImpl_get_Height
455  */ 
456 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
457                                                 OLE_YSIZE_HIMETRIC *pheight)
458 {
459   ICOM_THIS(OLEPictureImpl, iface);
460   TRACE("(%p)->(%p): height is %ld\n", This, pheight, This->himetricHeight);
461   *pheight = This->himetricHeight;
462   return S_OK;
463 }
464
465 /************************************************************************
466  * OLEPictureImpl_Render
467  */ 
468 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
469                                             long x, long y, long cx, long cy,
470                                             OLE_XPOS_HIMETRIC xSrc,
471                                             OLE_YPOS_HIMETRIC ySrc,
472                                             OLE_XSIZE_HIMETRIC cxSrc,
473                                             OLE_YSIZE_HIMETRIC cySrc,
474                                             LPCRECT prcWBounds)
475 {
476   ICOM_THIS(OLEPictureImpl, iface);
477   TRACE("(%p)->(%08x, (%ld,%ld), (%ld,%ld) <- (%ld,%ld), (%ld,%ld), %p)\n",
478         This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
479   if(prcWBounds)
480     TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
481           prcWBounds->right, prcWBounds->bottom);
482
483   /*
484    * While the documentation suggests this to be here (or after rendering?)
485    * it does cause an endless recursion in my sample app. -MM 20010804
486   OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
487    */
488
489   switch(This->desc.picType) {
490   case PICTYPE_BITMAP:
491     {
492       HBITMAP hbmpOld;
493       HDC hdcBmp;
494
495       /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
496          NB y-axis gets flipped */
497
498       hdcBmp = CreateCompatibleDC(0);
499       SetMapMode(hdcBmp, MM_ANISOTROPIC);
500       SetWindowOrgEx(hdcBmp, 0, 0, NULL);
501       SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
502       SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
503       SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
504
505       hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
506
507       StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
508
509       SelectObject(hdcBmp, hbmpOld);
510       DeleteDC(hdcBmp);
511     }
512     break;
513   case PICTYPE_ICON:
514     FIXME("Not quite correct implementation of rendering icons...\n");
515     DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
516     break;
517
518   case PICTYPE_METAFILE:
519   case PICTYPE_ENHMETAFILE:
520   default:
521     FIXME("type %d not implemented\n", This->desc.picType);
522     return E_NOTIMPL;
523   }
524   return S_OK;
525 }
526
527 /************************************************************************
528  * OLEPictureImpl_set_hPal
529  */ 
530 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
531                                               OLE_HANDLE hpal)
532 {
533   ICOM_THIS(OLEPictureImpl, iface);
534   FIXME("(%p)->(%08x): stub\n", This, hpal);
535   OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
536   return E_NOTIMPL;
537 }
538
539 /************************************************************************
540  * OLEPictureImpl_get_CurDC
541  */ 
542 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
543                                                HDC *phdc)
544 {
545   ICOM_THIS(OLEPictureImpl, iface);
546   TRACE("(%p), returning %x\n", This, This->hDCCur);
547   if (phdc) *phdc = This->hDCCur;
548   return S_OK;
549 }
550
551 /************************************************************************
552  * OLEPictureImpl_SelectPicture
553  */ 
554 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
555                                                    HDC hdcIn,
556                                                    HDC *phdcOut,
557                                                    OLE_HANDLE *phbmpOut)
558 {
559   ICOM_THIS(OLEPictureImpl, iface);
560   TRACE("(%p)->(%08x, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
561   if (This->desc.picType == PICTYPE_BITMAP) {
562       SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
563
564       if (phdcOut)
565           *phdcOut = This->hDCCur;
566       This->hDCCur = hdcIn;
567       if (phbmpOut)
568           *phbmpOut = This->desc.u.bmp.hbitmap;
569       return S_OK;
570   } else {
571       FIXME("Don't know how to select picture type %d\n",This->desc.picType);
572       return E_FAIL;
573   }
574 }
575
576 /************************************************************************
577  * OLEPictureImpl_get_KeepOriginalFormat
578  */ 
579 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
580                                                             BOOL *pfKeep)
581 {
582   ICOM_THIS(OLEPictureImpl, iface);
583   TRACE("(%p)->(%p)\n", This, pfKeep);
584   if (!pfKeep)
585       return E_POINTER;
586   *pfKeep = This->keepOrigFormat;
587   return S_OK;
588 }
589
590 /************************************************************************
591  * OLEPictureImpl_put_KeepOriginalFormat
592  */ 
593 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
594                                                             BOOL keep)
595 {
596   ICOM_THIS(OLEPictureImpl, iface);
597   TRACE("(%p)->(%d)\n", This, keep);
598   This->keepOrigFormat = keep;
599   /* FIXME: what DISPID notification here? */
600   return S_OK;
601 }
602
603 /************************************************************************
604  * OLEPictureImpl_PictureChanged
605  */ 
606 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
607 {
608   ICOM_THIS(OLEPictureImpl, iface);
609   TRACE("(%p)->()\n", This);
610   OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
611   return S_OK;
612 }
613
614 /************************************************************************
615  * OLEPictureImpl_SaveAsFile
616  */ 
617 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
618                                                 IStream *pstream,
619                                                 BOOL SaveMemCopy,
620                                                 LONG *pcbSize)
621 {
622   ICOM_THIS(OLEPictureImpl, iface);
623   FIXME("(%p)->(%p, %d, %p): stub\n", This, pstream, SaveMemCopy, pcbSize);
624   return E_NOTIMPL;
625 }
626
627 /************************************************************************
628  * OLEPictureImpl_get_Attributes
629  */ 
630 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
631                                                     DWORD *pdwAttr)
632 {
633   ICOM_THIS(OLEPictureImpl, iface);
634   TRACE("(%p)->(%p).\n", This, pdwAttr);
635   *pdwAttr = 0;
636   switch (This->desc.picType) {
637   case PICTYPE_BITMAP:  break;  /* not 'truely' scalable, see MSDN. */
638   case PICTYPE_ICON: *pdwAttr     = PICTURE_TRANSPARENT;break;
639   case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
640   default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
641   }
642   return S_OK;
643 }
644
645
646 /************************************************************************
647  *    IConnectionPointContainer
648  */
649
650 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
651   IConnectionPointContainer* iface,
652   REFIID riid,
653   VOID** ppvoid
654 ) {
655   ICOM_THIS_From_IConnectionPointContainer(IPicture,iface);
656
657   return IPicture_QueryInterface(This,riid,ppvoid);
658 }
659
660 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
661   IConnectionPointContainer* iface)
662 {
663   ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
664
665   return IPicture_AddRef(This);
666 }
667
668 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
669   IConnectionPointContainer* iface)
670 {
671   ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
672
673   return IPicture_Release(This);
674 }
675
676 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
677   IConnectionPointContainer* iface,
678   IEnumConnectionPoints** ppEnum
679 ) {
680   ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
681
682   FIXME("(%p,%p), stub!\n",This,ppEnum);
683   return E_NOTIMPL;
684 }
685
686 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
687   IConnectionPointContainer* iface,
688   REFIID riid,
689   IConnectionPoint **ppCP
690 ) {
691   ICOM_THIS_From_IConnectionPointContainer(OLEPictureImpl, iface);
692   TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
693   if (!ppCP) 
694       return E_POINTER;
695   *ppCP = NULL;
696   if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
697       return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
698   FIXME("tried to find connection point on %s?\n",debugstr_guid(riid));
699   return 0x80040200;
700 }
701 /************************************************************************
702  *    IPersistStream
703  */
704 /************************************************************************
705  * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
706  *
707  * See Windows documentation for more details on IUnknown methods.
708  */
709 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
710   IPersistStream* iface,
711   REFIID     riid,
712   VOID**     ppvoid)
713 {
714   ICOM_THIS_From_IPersistStream(IPicture, iface);
715
716   return IPicture_QueryInterface(This, riid, ppvoid);
717 }
718
719 /************************************************************************
720  * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
721  *
722  * See Windows documentation for more details on IUnknown methods.
723  */
724 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
725   IPersistStream* iface)
726 {
727   ICOM_THIS_From_IPersistStream(IPicture, iface);
728
729   return IPicture_AddRef(This);
730 }
731
732 /************************************************************************
733  * OLEPictureImpl_IPersistStream_Release (IUnknown)
734  *
735  * See Windows documentation for more details on IUnknown methods.
736  */
737 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
738   IPersistStream* iface)
739 {
740   ICOM_THIS_From_IPersistStream(IPicture, iface);
741
742   return IPicture_Release(This);
743 }
744
745 /************************************************************************
746  * OLEPictureImpl_IPersistStream_GetClassID
747  */
748 static HRESULT WINAPI OLEPictureImpl_GetClassID(
749   IPersistStream* iface,CLSID* pClassID)
750 {
751   ICOM_THIS_From_IPersistStream(IPicture, iface);
752   FIXME("(%p),stub!\n",This);
753   return E_NOTIMPL;
754 }
755
756 /************************************************************************
757  * OLEPictureImpl_IPersistStream_IsDirty
758  */
759 static HRESULT WINAPI OLEPictureImpl_IsDirty(
760   IPersistStream* iface)
761 {
762   ICOM_THIS_From_IPersistStream(IPicture, iface);
763   FIXME("(%p),stub!\n",This);
764   return E_NOTIMPL;
765 }
766
767 #ifdef HAVE_LIBJPEG
768 /* for the jpeg decompressor source manager. */
769 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
770
771 static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
772     ERR("(), should not get here.\n");
773     return FALSE;
774 }
775
776 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
777     ERR("(%ld), should not get here.\n",num_bytes);
778 }
779
780 static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
781     ERR("(desired=%d), should not get here.\n",desired);
782     return FALSE;
783 }
784 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
785 #endif /* HAVE_LIBJPEG */
786
787 /************************************************************************
788  * OLEPictureImpl_IPersistStream_Load (IUnknown)
789  *
790  * Loads the binary data from the IStream. Starts at current position.
791  * There appears to be an 2 DWORD header:
792  *      DWORD magic;
793  *      DWORD len;
794  *
795  * Currently implemented: BITMAP, ICON, JPEG.
796  */
797 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
798   HRESULT       hr = E_FAIL;
799   ULONG         xread;
800   BYTE          *xbuf;
801   DWORD         header[2];
802   WORD          magic;
803   ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface);
804
805   TRACE("(%p,%p)\n",This,pStm);
806
807   hr=IStream_Read(pStm,header,8,&xread);
808   if (hr || xread!=8) {
809       FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
810       return hr;
811   }
812   xread = 0;
813   xbuf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]);
814   while (xread < header[1]) {
815     ULONG nread; 
816     hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread);
817     xread+=nread;
818     if (hr || !nread)
819       break;
820   }
821   if (xread != header[1])
822     FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]);
823
824   magic = xbuf[0] + (xbuf[1]<<8);
825   switch (magic) {
826   case 0xd8ff: { /* JPEG */
827 #ifdef HAVE_LIBJPEG
828     struct jpeg_decompress_struct       jd;
829     struct jpeg_error_mgr               jerr;
830     int                                 ret;
831     JDIMENSION                          x;
832     JSAMPROW                            samprow;
833     BITMAPINFOHEADER                    bmi;
834     LPBYTE                              bits;
835     HDC                                 hdcref;
836     struct jpeg_source_mgr              xjsm;
837
838     /* This is basically so we can use in-memory data for jpeg decompression.
839      * We need to have all the functions.
840      */
841     xjsm.next_input_byte        = xbuf;
842     xjsm.bytes_in_buffer        = xread;
843     xjsm.init_source            = _jpeg_init_source;
844     xjsm.fill_input_buffer      = _jpeg_fill_input_buffer;
845     xjsm.skip_input_data        = _jpeg_skip_input_data;
846     xjsm.resync_to_restart      = _jpeg_resync_to_restart;
847     xjsm.term_source            = _jpeg_term_source;
848
849     jd.err = jpeg_std_error(&jerr);
850     jpeg_create_decompress(&jd);
851     jd.src = &xjsm;
852     ret=jpeg_read_header(&jd,TRUE);
853     jpeg_start_decompress(&jd);
854     if (ret != JPEG_HEADER_OK) {
855         ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
856         HeapFree(GetProcessHeap(),0,xbuf);
857         return E_FAIL;
858     }
859     bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(jd.output_height+1)*jd.output_width*jd.output_components);
860     samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
861     while ( jd.output_scanline<jd.output_height ) {
862       x = jpeg_read_scanlines(&jd,&samprow,1);
863       if (x != 1) {
864         FIXME("failed to read current scanline?\n");
865         break;
866       }
867       memcpy( bits+jd.output_scanline*jd.output_width*jd.output_components,
868               samprow,
869               jd.output_width*jd.output_components
870       );
871     }
872     bmi.biSize          = sizeof(bmi);
873     bmi.biWidth         =  jd.output_width;
874     bmi.biHeight        = -jd.output_height;
875     bmi.biPlanes        = 1;
876     bmi.biBitCount      = jd.output_components<<3;
877     bmi.biCompression   = BI_RGB;
878     bmi.biSizeImage     = jd.output_height*jd.output_width*jd.output_components;
879     bmi.biXPelsPerMeter = 0;
880     bmi.biYPelsPerMeter = 0;
881     bmi.biClrUsed       = 0;
882     bmi.biClrImportant  = 0;
883
884     HeapFree(GetProcessHeap(),0,samprow);
885     jpeg_finish_decompress(&jd);
886     jpeg_destroy_decompress(&jd);
887     hdcref = GetDC(0);
888     This->desc.u.bmp.hbitmap=CreateDIBitmap(
889             hdcref,
890             &bmi,
891             CBM_INIT,
892             bits,
893             (BITMAPINFO*)&bmi,
894             DIB_RGB_COLORS
895     );
896     DeleteDC(hdcref);
897     This->desc.picType = PICTYPE_BITMAP;
898     OLEPictureImpl_SetBitmap(This);
899     hr = S_OK;
900     HeapFree(GetProcessHeap(),0,bits);
901 #else
902     ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
903     hr = E_FAIL;
904 #endif
905     break;
906   }
907   case 0x4d42: { /* Bitmap */
908     BITMAPFILEHEADER    *bfh = (BITMAPFILEHEADER*)xbuf;
909     BITMAPINFO          *bi = (BITMAPINFO*)(bfh+1);
910     HDC                 hdcref;
911
912     /* Does not matter whether this is a coreheader or not, we only use
913      * components which are in both
914      */
915     hdcref = GetDC(0);
916     This->desc.u.bmp.hbitmap = CreateDIBitmap(
917         hdcref,
918         &(bi->bmiHeader),
919         CBM_INIT,
920         xbuf+bfh->bfOffBits,
921         bi,
922         (bi->bmiHeader.biBitCount<=8)?DIB_PAL_COLORS:DIB_RGB_COLORS
923     );
924     DeleteDC(hdcref);
925     This->desc.picType = PICTYPE_BITMAP;
926     OLEPictureImpl_SetBitmap(This);
927     hr = S_OK;
928     break;
929   }
930   case 0x0000: { /* ICON , first word is dwReserved */
931     HICON hicon;
932     CURSORICONFILEDIR   *cifd = (CURSORICONFILEDIR*)xbuf;
933     int i;
934
935     /*
936     FIXME("icon.idReserved=%d\n",cifd->idReserved);
937     FIXME("icon.idType=%d\n",cifd->idType);
938     FIXME("icon.idCount=%d\n",cifd->idCount);
939
940     for (i=0;i<cifd->idCount;i++) {
941         FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
942         FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
943         FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
944         FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
945         FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
946         FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
947         FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
948         FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
949     }
950     */
951     i=0;
952     /* If we have more than one icon, try to find the best.
953      * this currently means '32 pixel wide'.
954      */
955     if (cifd->idCount!=1) {
956         for (i=0;i<cifd->idCount;i++) {
957             if (cifd->idEntries[i].bWidth == 32)
958                 break;
959         }
960         if (i==cifd->idCount) i=0;
961     }
962
963     hicon = CreateIconFromResourceEx(
964                 xbuf+cifd->idEntries[i].dwDIBOffset,
965                 cifd->idEntries[i].dwDIBSize,
966                 TRUE, /* is icon */
967                 0x00030000,
968                 cifd->idEntries[i].bWidth,
969                 cifd->idEntries[i].bHeight,
970                 0
971     );
972     if (!hicon) {
973         FIXME("CreateIcon failed.\n");
974         hr = E_FAIL;
975     } else {
976         This->desc.picType = PICTYPE_ICON;
977         This->desc.u.icon.hicon = hicon;
978         hr = S_OK;
979     }
980     break;
981   }
982   default:
983     FIXME("Unknown magic %04x\n",magic);
984     hr=E_FAIL;
985     break;
986   }
987   HeapFree(GetProcessHeap(),0,xbuf);
988
989   /* FIXME: this notify is not really documented */
990   if (hr==S_OK)
991       OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
992   return hr;
993 }
994
995 static HRESULT WINAPI OLEPictureImpl_Save(
996   IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
997 {
998   ICOM_THIS_From_IPersistStream(IPicture, iface);
999   FIXME("(%p,%p,%d),stub!\n",This,pStm,fClearDirty);
1000   return E_NOTIMPL;
1001 }
1002
1003 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1004   IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1005 {
1006   ICOM_THIS_From_IPersistStream(IPicture, iface);
1007   FIXME("(%p,%p),stub!\n",This,pcbSize);
1008   return E_NOTIMPL;
1009 }
1010
1011 /************************************************************************
1012  *    IDispatch
1013  */
1014 /************************************************************************
1015  * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1016  *
1017  * See Windows documentation for more details on IUnknown methods.
1018  */
1019 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1020   IDispatch* iface,
1021   REFIID     riid,
1022   VOID**     ppvoid)
1023 {
1024   ICOM_THIS_From_IDispatch(IPicture, iface);
1025
1026   return IPicture_QueryInterface(This, riid, ppvoid);
1027 }
1028
1029 /************************************************************************
1030  * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1031  *
1032  * See Windows documentation for more details on IUnknown methods.
1033  */
1034 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1035   IDispatch* iface)
1036 {
1037   ICOM_THIS_From_IDispatch(IPicture, iface);
1038
1039   return IPicture_AddRef(This);
1040 }
1041
1042 /************************************************************************
1043  * OLEPictureImpl_IDispatch_Release (IUnknown)
1044  *
1045  * See Windows documentation for more details on IUnknown methods.
1046  */
1047 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1048   IDispatch* iface)
1049 {
1050   ICOM_THIS_From_IDispatch(IPicture, iface);
1051
1052   return IPicture_Release(This);
1053 }
1054
1055 /************************************************************************
1056  * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1057  *
1058  * See Windows documentation for more details on IDispatch methods.
1059  */
1060 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1061   IDispatch*    iface, 
1062   unsigned int* pctinfo)
1063 {
1064   FIXME("():Stub\n");
1065
1066   return E_NOTIMPL;
1067 }
1068
1069 /************************************************************************
1070  * OLEPictureImpl_GetTypeInfo (IDispatch)
1071  *
1072  * See Windows documentation for more details on IDispatch methods.
1073  */
1074 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1075   IDispatch*  iface, 
1076   UINT      iTInfo,
1077   LCID        lcid, 
1078   ITypeInfo** ppTInfo)
1079 {
1080   FIXME("():Stub\n");
1081
1082   return E_NOTIMPL;
1083 }
1084
1085 /************************************************************************
1086  * OLEPictureImpl_GetIDsOfNames (IDispatch)
1087  *
1088  * See Windows documentation for more details on IDispatch methods.
1089  */
1090 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1091   IDispatch*  iface,
1092   REFIID      riid, 
1093   LPOLESTR* rgszNames, 
1094   UINT      cNames, 
1095   LCID        lcid,
1096   DISPID*     rgDispId)
1097 {
1098   FIXME("():Stub\n");
1099
1100   return E_NOTIMPL;
1101 }
1102
1103 /************************************************************************
1104  * OLEPictureImpl_Invoke (IDispatch)
1105  *
1106  * See Windows documentation for more details on IDispatch methods.
1107  */
1108 static HRESULT WINAPI OLEPictureImpl_Invoke(
1109   IDispatch*  iface,
1110   DISPID      dispIdMember, 
1111   REFIID      riid, 
1112   LCID        lcid, 
1113   WORD        wFlags,
1114   DISPPARAMS* pDispParams,
1115   VARIANT*    pVarResult, 
1116   EXCEPINFO*  pExepInfo,
1117   UINT*     puArgErr)
1118 {
1119   FIXME("(dispid: %ld):Stub\n",dispIdMember);
1120
1121   VariantInit(pVarResult);
1122   V_VT(pVarResult) = VT_BOOL;
1123   V_UNION(pVarResult,boolVal) = FALSE;
1124   return S_OK;
1125 }
1126
1127
1128 static ICOM_VTABLE(IPicture) OLEPictureImpl_VTable =
1129 {
1130   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1131   OLEPictureImpl_QueryInterface,
1132   OLEPictureImpl_AddRef,
1133   OLEPictureImpl_Release,
1134   OLEPictureImpl_get_Handle,
1135   OLEPictureImpl_get_hPal,
1136   OLEPictureImpl_get_Type,
1137   OLEPictureImpl_get_Width,
1138   OLEPictureImpl_get_Height,
1139   OLEPictureImpl_Render,
1140   OLEPictureImpl_set_hPal,
1141   OLEPictureImpl_get_CurDC,
1142   OLEPictureImpl_SelectPicture,
1143   OLEPictureImpl_get_KeepOriginalFormat,
1144   OLEPictureImpl_put_KeepOriginalFormat,
1145   OLEPictureImpl_PictureChanged,
1146   OLEPictureImpl_SaveAsFile,
1147   OLEPictureImpl_get_Attributes
1148 };
1149
1150 static ICOM_VTABLE(IDispatch) OLEPictureImpl_IDispatch_VTable =
1151 {
1152   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1153   OLEPictureImpl_IDispatch_QueryInterface,
1154   OLEPictureImpl_IDispatch_AddRef,
1155   OLEPictureImpl_IDispatch_Release,
1156   OLEPictureImpl_GetTypeInfoCount,
1157   OLEPictureImpl_GetTypeInfo,
1158   OLEPictureImpl_GetIDsOfNames,
1159   OLEPictureImpl_Invoke
1160 };
1161
1162 static ICOM_VTABLE(IPersistStream) OLEPictureImpl_IPersistStream_VTable =
1163 {
1164   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1165   OLEPictureImpl_IPersistStream_QueryInterface,
1166   OLEPictureImpl_IPersistStream_AddRef,
1167   OLEPictureImpl_IPersistStream_Release,
1168   OLEPictureImpl_GetClassID,
1169   OLEPictureImpl_IsDirty,
1170   OLEPictureImpl_Load,
1171   OLEPictureImpl_Save,
1172   OLEPictureImpl_GetSizeMax
1173 };
1174
1175 static ICOM_VTABLE(IConnectionPointContainer) OLEPictureImpl_IConnectionPointContainer_VTable =
1176 {
1177   ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1178   OLEPictureImpl_IConnectionPointContainer_QueryInterface,
1179   OLEPictureImpl_IConnectionPointContainer_AddRef,
1180   OLEPictureImpl_IConnectionPointContainer_Release,
1181   OLEPictureImpl_EnumConnectionPoints,
1182   OLEPictureImpl_FindConnectionPoint
1183 };
1184
1185 /***********************************************************************
1186  * OleCreatePictureIndirect (OLEAUT32.419)
1187  */
1188 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
1189                             BOOL fOwn, LPVOID *ppvObj )
1190 {
1191   OLEPictureImpl* newPict = NULL;
1192   HRESULT      hr         = S_OK;
1193
1194   TRACE("(%p,%p,%d,%p)\n", lpPictDesc, riid, fOwn, ppvObj);
1195
1196   /*
1197    * Sanity check
1198    */
1199   if (ppvObj==0)
1200     return E_POINTER;
1201
1202   *ppvObj = NULL;
1203
1204   /*
1205    * Try to construct a new instance of the class.
1206    */
1207   newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
1208
1209   if (newPict == NULL)
1210     return E_OUTOFMEMORY;
1211
1212   /*
1213    * Make sure it supports the interface required by the caller.
1214    */
1215   hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
1216
1217   /*
1218    * Release the reference obtained in the constructor. If
1219    * the QueryInterface was unsuccessful, it will free the class.
1220    */
1221   IPicture_Release((IPicture*)newPict);
1222
1223   return hr;
1224 }
1225
1226
1227 /***********************************************************************
1228  * OleLoadPicture (OLEAUT32.418)
1229  */
1230 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
1231                             REFIID riid, LPVOID *ppvObj )
1232 {
1233   LPPERSISTSTREAM ps;
1234   IPicture      *newpic;
1235   HRESULT hr;
1236
1237   TRACE("(%p,%ld,%d,%s,%p), partially implemented.\n",
1238         lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
1239
1240   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
1241   if (hr)
1242     return hr;
1243   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
1244   if (hr) {
1245       FIXME("Could not get IPersistStream iface from Ole Picture?\n");
1246       IPicture_Release(newpic);
1247       *ppvObj = NULL;
1248       return hr;
1249   }
1250   IPersistStream_Load(ps,lpstream);
1251   IPersistStream_Release(ps);
1252   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
1253   if (hr)
1254       FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
1255   IPicture_Release(newpic);
1256   return hr;
1257 }
1258
1259 /***********************************************************************
1260  * OleLoadPictureEx (OLEAUT32.425)
1261  */
1262 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
1263                             REFIID reed, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
1264 {
1265   FIXME("(%p,%ld,%d,%p,%lx,%lx,%lx,%p), not implemented\n",
1266         lpstream, lSize, fRunmode, reed, xsiz, ysiz, flags, ppvObj);
1267   return S_OK;
1268 }
1269