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