4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 * Support PICTYPE_BITMAP and PICTYPE_ICON, altough only bitmaps very well..
26 * Lots of methods are just stubs.
29 * NOTES (or things that msdn doesn't tell you)
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).
39 #include "wine/port.h"
48 /* Must be before wine includes, the header has things conflicting with
53 # ifndef SONAME_LIBUNGIF
54 # define SONAME_LIBUNGIF "libungif.so"
56 # ifndef SONAME_LIBGIF
57 # define SONAME_LIBGIF "libgif.so"
62 #define NONAMELESSUNION
63 #define NONAMELESSSTRUCT
74 #include "wine/debug.h"
76 #include "wine/wingdi16.h"
77 #include "cursoricon.h"
80 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
82 #define UINT8 JPEG_UINT8
83 #define UINT16 JPEG_UINT16
87 #ifndef SONAME_LIBJPEG
88 #define SONAME_LIBJPEG "libjpeg.so"
92 WINE_DEFAULT_DEBUG_CHANNEL(ole);
94 /*************************************************************************
95 * Declaration of implementation class
98 typedef struct OLEPictureImpl {
101 * IPicture handles IUnknown
104 IPictureVtbl *lpvtbl1;
105 IDispatchVtbl *lpvtbl2;
106 IPersistStreamVtbl *lpvtbl3;
107 IConnectionPointContainerVtbl *lpvtbl4;
109 /* Object referenece count */
112 /* We own the object and must destroy it ourselves */
115 /* Picture description */
118 /* These are the pixel size of a bitmap */
122 /* And these are the size of the picture converted into HIMETRIC units */
123 OLE_XSIZE_HIMETRIC himetricWidth;
124 OLE_YSIZE_HIMETRIC himetricHeight;
126 IConnectionPoint *pCP;
131 /* Bitmap transparency mask */
138 BOOL bIsDirty; /* Set to TRUE if picture has changed */
139 unsigned int loadtime_magic; /* If a length header was found, saves value */
140 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
144 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
146 #define ICOM_THIS_From_IDispatch(impl, name) \
147 impl *This = (impl*)(((char*)name)-sizeof(void*));
148 #define ICOM_THIS_From_IPersistStream(impl, name) \
149 impl *This = (impl*)(((char*)name)-2*sizeof(void*));
150 #define ICOM_THIS_From_IConnectionPointContainer(impl, name) \
151 impl *This = (impl*)(((char*)name)-3*sizeof(void*));
154 * Predeclare VTables. They get initialized at the end.
156 static IPictureVtbl OLEPictureImpl_VTable;
157 static IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
158 static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
159 static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
161 /***********************************************************************
162 * Implementation of the OLEPictureImpl class.
165 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
169 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
170 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
171 ERR("GetObject fails\n");
174 This->origWidth = bm.bmWidth;
175 This->origHeight = bm.bmHeight;
176 /* The width and height are stored in HIMETRIC units (0.01 mm),
177 so we take our pixel width divide by pixels per inch and
178 multiply by 25.4 * 100 */
179 /* Should we use GetBitmapDimension if available? */
180 hdcRef = CreateCompatibleDC(0);
181 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
182 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
186 /************************************************************************
187 * OLEPictureImpl_Construct
189 * This method will construct a new instance of the OLEPictureImpl
192 * The caller of this method must release the object when it's
195 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
197 OLEPictureImpl* newObject = 0;
200 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
203 * Allocate space for the object.
205 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
211 * Initialize the virtual function table.
213 newObject->lpvtbl1 = &OLEPictureImpl_VTable;
214 newObject->lpvtbl2 = &OLEPictureImpl_IDispatch_VTable;
215 newObject->lpvtbl3 = &OLEPictureImpl_IPersistStream_VTable;
216 newObject->lpvtbl4 = &OLEPictureImpl_IConnectionPointContainer_VTable;
218 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
221 * Start with one reference count. The caller of this function
222 * must release the interface pointer when it is done.
225 newObject->hDCCur = 0;
227 newObject->fOwn = fOwn;
229 /* dunno about original value */
230 newObject->keepOrigFormat = TRUE;
232 newObject->hbmMask = NULL;
233 newObject->loadtime_magic = 0xdeadbeef;
234 newObject->loadtime_format = 0;
235 newObject->bIsDirty = FALSE;
238 if(pictDesc->cbSizeofstruct != sizeof(PICTDESC)) {
239 FIXME("struct size = %d\n", pictDesc->cbSizeofstruct);
241 memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC));
244 switch(pictDesc->picType) {
246 OLEPictureImpl_SetBitmap(newObject);
249 case PICTYPE_METAFILE:
250 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
251 newObject->himetricWidth = pictDesc->u.wmf.xExt;
252 newObject->himetricHeight = pictDesc->u.wmf.yExt;
256 /* not sure what to do here */
257 newObject->himetricWidth = newObject->himetricHeight = 0;
261 case PICTYPE_ENHMETAFILE:
263 FIXME("Unsupported type %d\n", pictDesc->picType);
264 newObject->himetricWidth = newObject->himetricHeight = 0;
268 newObject->desc.picType = PICTYPE_UNINITIALIZED;
271 TRACE("returning %p\n", newObject);
275 /************************************************************************
276 * OLEPictureImpl_Destroy
278 * This method is called by the Release method when the reference
279 * count goes down to 0. It will free all resources used by
281 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
283 TRACE("(%p)\n", Obj);
285 if(Obj->fOwn) { /* We need to destroy the picture */
286 switch(Obj->desc.picType) {
288 DeleteObject(Obj->desc.u.bmp.hbitmap);
290 case PICTYPE_METAFILE:
291 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
294 DestroyIcon(Obj->desc.u.icon.hicon);
296 case PICTYPE_ENHMETAFILE:
297 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
300 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
304 if (Obj->data) HeapFree(GetProcessHeap(), 0, Obj->data);
305 HeapFree(GetProcessHeap(), 0, Obj);
308 static ULONG WINAPI OLEPictureImpl_AddRef(IPicture* iface);
310 /************************************************************************
311 * OLEPictureImpl_QueryInterface (IUnknown)
313 * See Windows documentation for more details on IUnknown methods.
315 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
320 OLEPictureImpl *This = (OLEPictureImpl *)iface;
321 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
324 * Perform a sanity check on the parameters.
326 if ( (This==0) || (ppvObject==0) )
330 * Initialize the return parameter.
335 * Compare the riid with the interface IDs implemented by this object.
337 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
339 *ppvObject = (IPicture*)This;
341 else if (memcmp(&IID_IPicture, riid, sizeof(IID_IPicture)) == 0)
343 *ppvObject = (IPicture*)This;
345 else if (memcmp(&IID_IDispatch, riid, sizeof(IID_IDispatch)) == 0)
347 *ppvObject = (IDispatch*)&(This->lpvtbl2);
349 else if (memcmp(&IID_IPictureDisp, riid, sizeof(IID_IPictureDisp)) == 0)
351 *ppvObject = (IDispatch*)&(This->lpvtbl2);
353 else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0)
355 *ppvObject = (IPersistStream*)&(This->lpvtbl3);
357 else if (memcmp(&IID_IConnectionPointContainer, riid, sizeof(IID_IConnectionPointContainer)) == 0)
359 *ppvObject = (IConnectionPointContainer*)&(This->lpvtbl4);
362 * Check that we obtained an interface.
366 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
367 return E_NOINTERFACE;
371 * Query Interface always increases the reference count by one when it is
374 OLEPictureImpl_AddRef((IPicture*)This);
378 /***********************************************************************
379 * OLEPicture_SendNotify (internal)
381 * Sends notification messages of changed properties to any interested
384 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
386 IEnumConnections *pEnum;
389 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
391 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
392 IPropertyNotifySink *sink;
394 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
395 IPropertyNotifySink_OnChanged(sink, dispID);
396 IPropertyNotifySink_Release(sink);
397 IUnknown_Release(CD.pUnk);
399 IEnumConnections_Release(pEnum);
403 /************************************************************************
404 * OLEPictureImpl_AddRef (IUnknown)
406 * See Windows documentation for more details on IUnknown methods.
408 static ULONG WINAPI OLEPictureImpl_AddRef(
411 OLEPictureImpl *This = (OLEPictureImpl *)iface;
412 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
413 return InterlockedIncrement(&This->ref);
416 /************************************************************************
417 * OLEPictureImpl_Release (IUnknown)
419 * See Windows documentation for more details on IUnknown methods.
421 static ULONG WINAPI OLEPictureImpl_Release(
424 OLEPictureImpl *This = (OLEPictureImpl *)iface;
426 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
429 * Decrease the reference count on this object.
431 ret = InterlockedDecrement(&This->ref);
434 * If the reference count goes down to 0, perform suicide.
436 if (ret==0) OLEPictureImpl_Destroy(This);
442 /************************************************************************
443 * OLEPictureImpl_get_Handle
445 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
448 OLEPictureImpl *This = (OLEPictureImpl *)iface;
449 TRACE("(%p)->(%p)\n", This, phandle);
450 switch(This->desc.picType) {
452 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
454 case PICTYPE_METAFILE:
455 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
458 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
460 case PICTYPE_ENHMETAFILE:
461 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
464 FIXME("Unimplemented type %d\n", This->desc.picType);
467 TRACE("returning handle %08x\n", *phandle);
471 /************************************************************************
472 * OLEPictureImpl_get_hPal
474 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
477 OLEPictureImpl *This = (OLEPictureImpl *)iface;
478 FIXME("(%p)->(%p): stub\n", This, phandle);
482 /************************************************************************
483 * OLEPictureImpl_get_Type
485 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
488 OLEPictureImpl *This = (OLEPictureImpl *)iface;
489 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
490 *ptype = This->desc.picType;
494 /************************************************************************
495 * OLEPictureImpl_get_Width
497 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
498 OLE_XSIZE_HIMETRIC *pwidth)
500 OLEPictureImpl *This = (OLEPictureImpl *)iface;
501 TRACE("(%p)->(%p): width is %ld\n", This, pwidth, This->himetricWidth);
502 *pwidth = This->himetricWidth;
506 /************************************************************************
507 * OLEPictureImpl_get_Height
509 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
510 OLE_YSIZE_HIMETRIC *pheight)
512 OLEPictureImpl *This = (OLEPictureImpl *)iface;
513 TRACE("(%p)->(%p): height is %ld\n", This, pheight, This->himetricHeight);
514 *pheight = This->himetricHeight;
518 /************************************************************************
519 * OLEPictureImpl_Render
521 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
522 long x, long y, long cx, long cy,
523 OLE_XPOS_HIMETRIC xSrc,
524 OLE_YPOS_HIMETRIC ySrc,
525 OLE_XSIZE_HIMETRIC cxSrc,
526 OLE_YSIZE_HIMETRIC cySrc,
529 OLEPictureImpl *This = (OLEPictureImpl *)iface;
530 TRACE("(%p)->(%p, (%ld,%ld), (%ld,%ld) <- (%ld,%ld), (%ld,%ld), %p)\n",
531 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
533 TRACE("prcWBounds (%ld,%ld) - (%ld,%ld)\n", prcWBounds->left, prcWBounds->top,
534 prcWBounds->right, prcWBounds->bottom);
537 * While the documentation suggests this to be here (or after rendering?)
538 * it does cause an endless recursion in my sample app. -MM 20010804
539 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
542 switch(This->desc.picType) {
548 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
549 NB y-axis gets flipped */
551 hdcBmp = CreateCompatibleDC(0);
552 SetMapMode(hdcBmp, MM_ANISOTROPIC);
553 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
554 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
555 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
556 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
558 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
561 HDC hdcMask = CreateCompatibleDC(0);
562 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
564 SetMapMode(hdcMask, MM_ANISOTROPIC);
565 SetWindowOrgEx(hdcMask, 0, 0, NULL);
566 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
567 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
568 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
570 SetBkColor(hdc, RGB(255, 255, 255));
571 SetTextColor(hdc, RGB(0, 0, 0));
572 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
573 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
575 SelectObject(hdcMask, hOldbm);
578 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
580 SelectObject(hdcBmp, hbmpOld);
585 FIXME("Not quite correct implementation of rendering icons...\n");
586 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
589 case PICTYPE_METAFILE:
590 case PICTYPE_ENHMETAFILE:
592 FIXME("type %d not implemented\n", This->desc.picType);
598 /************************************************************************
599 * OLEPictureImpl_set_hPal
601 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
604 OLEPictureImpl *This = (OLEPictureImpl *)iface;
605 FIXME("(%p)->(%08x): stub\n", This, hpal);
606 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
610 /************************************************************************
611 * OLEPictureImpl_get_CurDC
613 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
616 OLEPictureImpl *This = (OLEPictureImpl *)iface;
617 TRACE("(%p), returning %p\n", This, This->hDCCur);
618 if (phdc) *phdc = This->hDCCur;
622 /************************************************************************
623 * OLEPictureImpl_SelectPicture
625 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
628 OLE_HANDLE *phbmpOut)
630 OLEPictureImpl *This = (OLEPictureImpl *)iface;
631 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
632 if (This->desc.picType == PICTYPE_BITMAP) {
633 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
636 *phdcOut = This->hDCCur;
637 This->hDCCur = hdcIn;
639 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
642 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
647 /************************************************************************
648 * OLEPictureImpl_get_KeepOriginalFormat
650 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
653 OLEPictureImpl *This = (OLEPictureImpl *)iface;
654 TRACE("(%p)->(%p)\n", This, pfKeep);
657 *pfKeep = This->keepOrigFormat;
661 /************************************************************************
662 * OLEPictureImpl_put_KeepOriginalFormat
664 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
667 OLEPictureImpl *This = (OLEPictureImpl *)iface;
668 TRACE("(%p)->(%d)\n", This, keep);
669 This->keepOrigFormat = keep;
670 /* FIXME: what DISPID notification here? */
674 /************************************************************************
675 * OLEPictureImpl_PictureChanged
677 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
679 OLEPictureImpl *This = (OLEPictureImpl *)iface;
680 TRACE("(%p)->()\n", This);
681 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
682 This->bIsDirty = TRUE;
686 /************************************************************************
687 * OLEPictureImpl_SaveAsFile
689 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
694 OLEPictureImpl *This = (OLEPictureImpl *)iface;
695 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
696 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
699 /************************************************************************
700 * OLEPictureImpl_get_Attributes
702 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
705 OLEPictureImpl *This = (OLEPictureImpl *)iface;
706 TRACE("(%p)->(%p).\n", This, pdwAttr);
708 switch (This->desc.picType) {
709 case PICTYPE_BITMAP: break; /* not 'truely' scalable, see MSDN. */
710 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
711 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
712 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
718 /************************************************************************
719 * IConnectionPointContainer
722 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
723 IConnectionPointContainer* iface,
727 ICOM_THIS_From_IConnectionPointContainer(IPicture,iface);
729 return IPicture_QueryInterface(This,riid,ppvoid);
732 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
733 IConnectionPointContainer* iface)
735 ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
737 return IPicture_AddRef(This);
740 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
741 IConnectionPointContainer* iface)
743 ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
745 return IPicture_Release(This);
748 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
749 IConnectionPointContainer* iface,
750 IEnumConnectionPoints** ppEnum
752 ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
754 FIXME("(%p,%p), stub!\n",This,ppEnum);
758 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
759 IConnectionPointContainer* iface,
761 IConnectionPoint **ppCP
763 ICOM_THIS_From_IConnectionPointContainer(OLEPictureImpl, iface);
764 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
768 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
769 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
770 FIXME("tried to find connection point on %s?\n",debugstr_guid(riid));
773 /************************************************************************
776 /************************************************************************
777 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
779 * See Windows documentation for more details on IUnknown methods.
781 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
782 IPersistStream* iface,
786 ICOM_THIS_From_IPersistStream(IPicture, iface);
788 return IPicture_QueryInterface(This, riid, ppvoid);
791 /************************************************************************
792 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
794 * See Windows documentation for more details on IUnknown methods.
796 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
797 IPersistStream* iface)
799 ICOM_THIS_From_IPersistStream(IPicture, iface);
801 return IPicture_AddRef(This);
804 /************************************************************************
805 * OLEPictureImpl_IPersistStream_Release (IUnknown)
807 * See Windows documentation for more details on IUnknown methods.
809 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
810 IPersistStream* iface)
812 ICOM_THIS_From_IPersistStream(IPicture, iface);
814 return IPicture_Release(This);
817 /************************************************************************
818 * OLEPictureImpl_IPersistStream_GetClassID
820 static HRESULT WINAPI OLEPictureImpl_GetClassID(
821 IPersistStream* iface,CLSID* pClassID)
823 ICOM_THIS_From_IPersistStream(IPicture, iface);
824 FIXME("(%p),stub!\n",This);
828 /************************************************************************
829 * OLEPictureImpl_IPersistStream_IsDirty
831 static HRESULT WINAPI OLEPictureImpl_IsDirty(
832 IPersistStream* iface)
834 ICOM_THIS_From_IPersistStream(IPicture, iface);
835 FIXME("(%p),stub!\n",This);
839 #ifdef HAVE_JPEGLIB_H
841 static void *libjpeg_handle;
842 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
843 MAKE_FUNCPTR(jpeg_std_error);
844 MAKE_FUNCPTR(jpeg_CreateDecompress);
845 MAKE_FUNCPTR(jpeg_read_header);
846 MAKE_FUNCPTR(jpeg_start_decompress);
847 MAKE_FUNCPTR(jpeg_read_scanlines);
848 MAKE_FUNCPTR(jpeg_finish_decompress);
849 MAKE_FUNCPTR(jpeg_destroy_decompress);
852 static void *load_libjpeg(void)
854 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
856 #define LOAD_FUNCPTR(f) \
857 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
858 libjpeg_handle = NULL; \
862 LOAD_FUNCPTR(jpeg_std_error);
863 LOAD_FUNCPTR(jpeg_CreateDecompress);
864 LOAD_FUNCPTR(jpeg_read_header);
865 LOAD_FUNCPTR(jpeg_start_decompress);
866 LOAD_FUNCPTR(jpeg_read_scanlines);
867 LOAD_FUNCPTR(jpeg_finish_decompress);
868 LOAD_FUNCPTR(jpeg_destroy_decompress);
871 return libjpeg_handle;
874 /* for the jpeg decompressor source manager. */
875 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
877 static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
878 ERR("(), should not get here.\n");
882 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
883 TRACE("Skipping %ld bytes...\n", num_bytes);
884 cinfo->src->next_input_byte += num_bytes;
885 cinfo->src->bytes_in_buffer -= num_bytes;
888 static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
889 ERR("(desired=%d), should not get here.\n",desired);
892 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
893 #endif /* HAVE_JPEGLIB_H */
895 #ifdef HAVE_GIF_LIB_H
897 static void *libungif_handle;
898 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
899 MAKE_FUNCPTR(DGifOpen);
900 MAKE_FUNCPTR(DGifSlurp);
901 MAKE_FUNCPTR(DGifCloseFile);
910 static void *load_libungif(void)
912 if(((libungif_handle = wine_dlopen(SONAME_LIBUNGIF, RTLD_NOW, NULL, 0)) != NULL) ||
913 ((libungif_handle = wine_dlopen(SONAME_LIBGIF , RTLD_NOW, NULL, 0)) != NULL)
916 #define LOAD_FUNCPTR(f) \
917 if((p##f = wine_dlsym(libungif_handle, #f, NULL, 0)) == NULL) { \
918 libungif_handle = NULL; \
922 LOAD_FUNCPTR(DGifOpen);
923 LOAD_FUNCPTR(DGifSlurp);
924 LOAD_FUNCPTR(DGifCloseFile);
927 return libungif_handle;
930 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
931 struct gifdata *gd = (struct gifdata*)gif->UserData;
933 if (len+gd->curoff > gd->len) {
934 FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
935 len = gd->len - gd->curoff;
937 memcpy(data, gd->data+gd->curoff, len);
942 #endif /* HAVE_GIF_LIB_H */
944 /************************************************************************
945 * OLEPictureImpl_IPersistStream_Load (IUnknown)
947 * Loads the binary data from the IStream. Starts at current position.
948 * There appears to be an 2 DWORD header:
952 * Currently implemented: BITMAP, ICON, JPEG, GIF
954 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
961 ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface);
963 TRACE("(%p,%p)\n",This,pStm);
965 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
968 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
969 * compound file. This may explain most, if not all, of the cases of "no header",
970 * and the header validation should take this into account. At least in Visual Basic 6,
971 * resource streams, valid headers are
972 * header[0] == "lt\0\0",
973 * header[1] == length_of_stream.
975 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
977 FIXME("Stat failed with hres %lx\n",hr);
978 hr=IStream_Read(pStm,header,8,&xread);
979 if (hr || xread!=8) {
980 FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
983 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
984 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
985 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
986 header[1] > statstg.cbSize.QuadPart || (header[1]==0)) {/* Incorrect header, assume none. */
988 xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,statstg.cbSize.QuadPart);
989 memcpy(xbuf,&header,8);
990 This->datalen = statstg.cbSize.QuadPart;
991 while (xread < This->datalen) {
993 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
998 if (xread != This->datalen)
999 FIXME("Could only read %ld of %d bytes in no-header case?\n",xread,This->datalen);
1002 xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]);
1003 This->datalen = header[1];
1004 while (xread < header[1]) {
1006 hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread);
1011 if (xread != header[1])
1012 FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]);
1014 magic = xbuf[0] + (xbuf[1]<<8);
1016 case 0x4947: { /* GIF */
1017 #ifdef HAVE_GIF_LIB_H
1027 int transparent = -1;
1031 if(!libungif_handle) {
1032 if(!load_libungif()) {
1033 FIXME("Failed reading GIF because unable to find %s/%s\n", SONAME_LIBUNGIF, SONAME_LIBGIF);
1041 gif = pDGifOpen((void*)&gd, _gif_inputfunc);
1042 ret = pDGifSlurp(gif);
1043 if (ret == GIF_ERROR) {
1044 FIXME("Failed reading GIF using libgif.\n");
1047 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1048 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1049 TRACE("imgcnt %d\n", gif->ImageCount);
1050 if (gif->ImageCount<1) {
1051 FIXME("GIF stream does not have images inside?\n");
1054 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1055 gif->Image.Width, gif->Image.Height,
1056 gif->Image.Left, gif->Image.Top,
1057 gif->Image.Interlace
1060 padding = (gif->SWidth+3) & ~3;
1061 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(1<<gif->SColorResolution)*sizeof(RGBQUAD));
1062 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1063 si = gif->SavedImages+0;
1064 gid = &(si->ImageDesc);
1066 if (!cm) cm = gif->SColorMap;
1068 /* look for the transparent color extension */
1069 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1070 eb = si->ExtensionBlocks + i;
1071 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1072 if ((eb->Bytes[0] & 1) == 1) {
1073 transparent = eb->Bytes[3];
1078 for (i=0;i<(1<<gif->SColorResolution);i++) {
1079 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1080 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1081 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1082 if (i == transparent) {
1083 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1084 bmi->bmiColors[i].rgbGreen,
1085 bmi->bmiColors[i].rgbBlue);
1089 /* Map to in picture coordinates */
1090 for (i = 0, j = 0; i < gid->Height; i++) {
1091 if (gif->Image.Interlace) {
1093 bytes + (gid->Top + j) * padding + gid->Left,
1094 si->RasterBits + i * gid->Width,
1097 /* Lower bits of interlaced counter encode current interlace */
1098 if (j & 1) j += 2; /* Currently filling odd rows */
1099 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1100 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1102 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1103 /* End of current interlace, go to next interlace */
1104 if (j & 2) j = 1; /* Next iteration fills odd rows */
1105 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1106 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1110 bytes + (gid->Top + i) * padding + gid->Left,
1111 si->RasterBits + i * gid->Width,
1116 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1117 bmi->bmiHeader.biWidth = gif->SWidth;
1118 bmi->bmiHeader.biHeight = -gif->SHeight;
1119 bmi->bmiHeader.biPlanes = 1;
1120 bmi->bmiHeader.biBitCount = 8;
1121 bmi->bmiHeader.biCompression = BI_RGB;
1122 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1123 bmi->bmiHeader.biXPelsPerMeter = 0;
1124 bmi->bmiHeader.biYPelsPerMeter = 0;
1125 bmi->bmiHeader.biClrUsed = 1 << gif->SColorResolution;
1126 bmi->bmiHeader.biClrImportant = 0;
1129 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1138 if (transparent > -1) {
1139 /* Create the Mask */
1140 HDC hdc = CreateCompatibleDC(0);
1141 HDC hdcMask = CreateCompatibleDC(0);
1143 HBITMAP hOldbitmapmask;
1145 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1147 hOldbitmap = SelectObject(hdc,This->desc.u.bmp.hbitmap);
1148 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1149 SetBkColor(hdc, This->rgbTrans);
1150 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1152 /* We no longer need the original bitmap, so we apply the first
1153 transformation with the mask to speed up the rendering */
1154 SetBkColor(hdc, RGB(0,0,0));
1155 SetTextColor(hdc, RGB(255,255,255));
1156 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1157 hdcMask, 0, 0, SRCAND);
1159 SelectObject(hdc, hOldbitmap);
1160 SelectObject(hdcMask, hOldbitmapmask);
1166 This->desc.picType = PICTYPE_BITMAP;
1167 OLEPictureImpl_SetBitmap(This);
1168 pDGifCloseFile(gif);
1169 HeapFree(GetProcessHeap(),0,bytes);
1172 FIXME("Trying to load GIF, but no support for libgif/libungif compiled in.\n");
1177 case 0xd8ff: { /* JPEG */
1178 #ifdef HAVE_JPEGLIB_H
1179 struct jpeg_decompress_struct jd;
1180 struct jpeg_error_mgr jerr;
1183 JSAMPROW samprow,oldsamprow;
1184 BITMAPINFOHEADER bmi;
1187 struct jpeg_source_mgr xjsm;
1191 if(!libjpeg_handle) {
1192 if(!load_libjpeg()) {
1193 FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1198 /* This is basically so we can use in-memory data for jpeg decompression.
1199 * We need to have all the functions.
1201 xjsm.next_input_byte = xbuf;
1202 xjsm.bytes_in_buffer = xread;
1203 xjsm.init_source = _jpeg_init_source;
1204 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1205 xjsm.skip_input_data = _jpeg_skip_input_data;
1206 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1207 xjsm.term_source = _jpeg_term_source;
1209 jd.err = pjpeg_std_error(&jerr);
1210 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1211 * jpeg_create_decompress(&jd); */
1212 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct));
1214 ret=pjpeg_read_header(&jd,TRUE);
1215 jd.out_color_space = JCS_RGB;
1216 pjpeg_start_decompress(&jd);
1217 if (ret != JPEG_HEADER_OK) {
1218 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1219 HeapFree(GetProcessHeap(),0,xbuf);
1223 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1224 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1225 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1228 oldsamprow = samprow;
1229 while ( jd.output_scanline<jd.output_height ) {
1230 x = pjpeg_read_scanlines(&jd,&samprow,1);
1232 FIXME("failed to read current scanline?\n");
1235 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1236 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1237 *(bits++) = *(samprow+2);
1238 *(bits++) = *(samprow+1);
1239 *(bits++) = *(samprow);
1241 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1242 samprow = oldsamprow;
1246 bmi.biSize = sizeof(bmi);
1247 bmi.biWidth = jd.output_width;
1248 bmi.biHeight = -jd.output_height;
1250 bmi.biBitCount = jd.output_components<<3;
1251 bmi.biCompression = BI_RGB;
1252 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1253 bmi.biXPelsPerMeter = 0;
1254 bmi.biYPelsPerMeter = 0;
1256 bmi.biClrImportant = 0;
1258 HeapFree(GetProcessHeap(),0,samprow);
1259 pjpeg_finish_decompress(&jd);
1260 pjpeg_destroy_decompress(&jd);
1262 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1271 This->desc.picType = PICTYPE_BITMAP;
1272 OLEPictureImpl_SetBitmap(This);
1274 HeapFree(GetProcessHeap(),0,bits);
1276 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1281 case 0x4d42: { /* Bitmap */
1282 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1283 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1286 /* Does not matter whether this is a coreheader or not, we only use
1287 * components which are in both
1290 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1294 xbuf+bfh->bfOffBits,
1296 (bi->bmiHeader.biBitCount<=8)?DIB_PAL_COLORS:DIB_RGB_COLORS
1299 This->desc.picType = PICTYPE_BITMAP;
1300 OLEPictureImpl_SetBitmap(This);
1304 case 0x0000: { /* ICON , first word is dwReserved */
1306 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1311 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1312 FIXME("icon.idType=%d\n",cifd->idType);
1313 FIXME("icon.idCount=%d\n",cifd->idCount);
1315 for (i=0;i<cifd->idCount;i++) {
1316 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1317 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1318 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1319 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1320 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1321 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1322 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1323 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1327 /* If we have more than one icon, try to find the best.
1328 * this currently means '32 pixel wide'.
1330 if (cifd->idCount!=1) {
1331 for (i=0;i<cifd->idCount;i++) {
1332 if (cifd->idEntries[i].bWidth == 32)
1335 if (i==cifd->idCount) i=0;
1338 hicon = CreateIconFromResourceEx(
1339 xbuf+cifd->idEntries[i].dwDIBOffset,
1340 cifd->idEntries[i].dwDIBSize,
1343 cifd->idEntries[i].bWidth,
1344 cifd->idEntries[i].bHeight,
1348 FIXME("CreateIcon failed.\n");
1351 This->desc.picType = PICTYPE_ICON;
1352 This->desc.u.icon.hicon = hicon;
1353 This->origWidth = cifd->idEntries[i].bWidth;
1354 This->origHeight = cifd->idEntries[i].bHeight;
1355 hdcRef = CreateCompatibleDC(0);
1356 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1357 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1366 FIXME("Unknown magic %04x, %ld read bytes:\n",magic,xread);
1368 for (i=0;i<xread+8;i++) {
1369 if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
1370 else MESSAGE("%02x ",xbuf[i-8]);
1371 if (i % 10 == 9) MESSAGE("\n");
1377 This->bIsDirty = FALSE;
1379 /* FIXME: this notify is not really documented */
1381 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1385 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength);
1386 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength);
1387 static HRESULT WINAPI OLEPictureImpl_Save(
1388 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1390 HRESULT hResult = E_NOTIMPL;
1392 unsigned int iDataSize;
1394 int iSerializeResult = 0;
1396 ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface);
1398 switch (This->desc.picType) {
1400 if (This->bIsDirty) {
1401 if (serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1402 if (This->loadtime_magic != 0xdeadbeef) {
1405 header[0] = This->loadtime_magic;
1406 header[1] = iDataSize;
1407 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1409 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1411 HeapFree(GetProcessHeap(), 0, This->data);
1412 This->data = pIconData;
1413 This->datalen = iDataSize;
1416 FIXME("(%p,%p,%d), unable to serializeIcon()!\n",This,pStm,fClearDirty);
1420 if (This->loadtime_magic != 0xdeadbeef) {
1423 header[0] = This->loadtime_magic;
1424 header[1] = This->datalen;
1425 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1427 IStream_Write(pStm, This->data, This->datalen, &dummy);
1431 case PICTYPE_BITMAP:
1432 if (This->bIsDirty) {
1433 switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) {
1435 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1438 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1441 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1444 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1447 if (iSerializeResult) {
1449 if (This->loadtime_magic != 0xdeadbeef) {
1454 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1455 header[1] = iDataSize;
1456 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1458 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1460 HeapFree(GetProcessHeap(), 0, This->data);
1461 This->data = pIconData;
1462 This->datalen = iDataSize;
1467 if (This->loadtime_magic != 0xdeadbeef) {
1472 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1473 header[1] = This->datalen;
1474 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1476 IStream_Write(pStm, This->data, This->datalen, &dummy);
1480 case PICTYPE_METAFILE:
1481 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1483 case PICTYPE_ENHMETAFILE:
1484 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1487 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1490 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1494 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1498 BITMAPINFO * pInfoBitmap;
1499 int iNumPaletteEntries;
1500 unsigned char * pPixelData;
1501 BITMAPFILEHEADER * pFileHeader;
1502 BITMAPINFO * pInfoHeader;
1504 pInfoBitmap = (BITMAPINFO *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1505 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1507 /* Find out bitmap size and padded length */
1509 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1510 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1512 /* Fetch bitmap palette & pixel data */
1514 pPixelData = (unsigned char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1515 pInfoBitmap->bmiHeader.biSizeImage);
1516 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1518 /* Calculate the total length required for the BMP data */
1519 if (pInfoBitmap->bmiHeader.biClrUsed != 0) iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1520 else if (pInfoBitmap->bmiHeader.biBitCount <= 8) iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1521 else iNumPaletteEntries = 0;
1523 sizeof(BITMAPFILEHEADER) +
1524 sizeof(BITMAPINFOHEADER) +
1525 iNumPaletteEntries * sizeof(RGBQUAD) +
1526 pInfoBitmap->bmiHeader.biSizeImage;
1527 *ppBuffer = (void *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1529 /* Fill the BITMAPFILEHEADER */
1530 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1531 pFileHeader->bfType = 0x4d42;
1532 pFileHeader->bfSize = *pLength;
1533 pFileHeader->bfOffBits =
1534 sizeof(BITMAPFILEHEADER) +
1535 sizeof(BITMAPINFOHEADER) +
1536 iNumPaletteEntries * sizeof(RGBQUAD);
1538 /* Fill the BITMAPINFOHEADER and the palette data */
1539 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1540 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1542 (unsigned char *)(*ppBuffer) +
1543 sizeof(BITMAPFILEHEADER) +
1544 sizeof(BITMAPINFOHEADER) +
1545 iNumPaletteEntries * sizeof(RGBQUAD),
1546 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1549 HeapFree(GetProcessHeap(), 0, pPixelData);
1550 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1554 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1559 *ppBuffer = NULL; *pLength = 0;
1560 if (GetIconInfo(hIcon, &infoIcon)) {
1562 BITMAPINFO * pInfoBitmap;
1563 unsigned char * pIconData = NULL;
1564 unsigned int iDataSize = 0;
1566 pInfoBitmap = (BITMAPINFO *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1568 /* Find out icon size */
1570 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1571 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1573 /* Auxiliary pointers */
1574 CURSORICONFILEDIR * pIconDir;
1575 CURSORICONFILEDIRENTRY * pIconEntry;
1576 BITMAPINFOHEADER * pIconBitmapHeader;
1577 unsigned int iOffsetPalette;
1578 unsigned int iOffsetColorData;
1579 unsigned int iOffsetMaskData;
1581 unsigned int iLengthScanLineColor;
1582 unsigned int iLengthScanLineMask;
1583 unsigned int iNumEntriesPalette;
1585 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1586 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
1588 FIXME("DEBUG: bitmap size is %d x %d\n",
1589 pInfoBitmap->bmiHeader.biWidth,
1590 pInfoBitmap->bmiHeader.biHeight);
1591 FIXME("DEBUG: bitmap bpp is %d\n",
1592 pInfoBitmap->bmiHeader.biBitCount);
1593 FIXME("DEBUG: bitmap nplanes is %d\n",
1594 pInfoBitmap->bmiHeader.biPlanes);
1595 FIXME("DEBUG: bitmap biSizeImage is %lu\n",
1596 pInfoBitmap->bmiHeader.biSizeImage);
1598 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1599 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1600 pIconData = (unsigned char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1602 /* Fill out the CURSORICONFILEDIR */
1603 pIconDir = (CURSORICONFILEDIR *)pIconData;
1604 pIconDir->idType = 1;
1605 pIconDir->idCount = 1;
1607 /* Fill out the CURSORICONFILEDIRENTRY */
1608 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1609 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1610 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1611 pIconEntry->bColorCount =
1612 (pInfoBitmap->bmiHeader.biBitCount < 8)
1613 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1615 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1616 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1617 pIconEntry->dwDIBSize = 0;
1618 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1620 /* Fill out the BITMAPINFOHEADER */
1621 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1622 memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
1624 /* Find out whether a palette exists for the bitmap */
1625 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1626 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1627 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1628 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1629 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1630 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1631 iNumEntriesPalette = 3;
1632 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1633 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1635 iNumEntriesPalette = 0;
1638 /* Add bitmap size and header size to icon data size. */
1639 iOffsetPalette = iDataSize;
1640 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1641 iOffsetColorData = iDataSize;
1642 iDataSize += pIconBitmapHeader->biSizeImage;
1643 iOffsetMaskData = iDataSize;
1644 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1645 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1646 pIconBitmapHeader->biHeight *= 2;
1647 pIconData = (unsigned char *)HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1648 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1649 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1650 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1652 /* Get the actual bitmap data from the icon bitmap */
1653 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1654 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1655 if (iNumEntriesPalette > 0) {
1656 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1657 iNumEntriesPalette * sizeof(RGBQUAD));
1660 /* Reset all values so that GetDIBits call succeeds */
1661 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1662 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1663 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1665 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1666 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1667 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1669 printf("ERROR: unable to get bitmap mask (error %lu)\n",
1674 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1675 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1677 /* Write out everything produced so far to the stream */
1678 *ppBuffer = pIconData; *pLength = iDataSize;
1682 printf("ERROR: unable to get bitmap information via GetDIBits() (error %lu)\n",
1687 Remarks (from MSDN entry on GetIconInfo):
1689 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1690 members of ICONINFO. The calling application must manage
1691 these bitmaps and delete them when they are no longer
1694 if (hDC) ReleaseDC(0, hDC);
1695 DeleteObject(infoIcon.hbmMask);
1696 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1697 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1699 printf("ERROR: Unable to get icon information (error %lu)\n",
1705 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1706 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1708 ICOM_THIS_From_IPersistStream(IPicture, iface);
1709 FIXME("(%p,%p),stub!\n",This,pcbSize);
1713 /************************************************************************
1716 /************************************************************************
1717 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1719 * See Windows documentation for more details on IUnknown methods.
1721 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1726 ICOM_THIS_From_IDispatch(IPicture, iface);
1728 return IPicture_QueryInterface(This, riid, ppvoid);
1731 /************************************************************************
1732 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1734 * See Windows documentation for more details on IUnknown methods.
1736 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1739 ICOM_THIS_From_IDispatch(IPicture, iface);
1741 return IPicture_AddRef(This);
1744 /************************************************************************
1745 * OLEPictureImpl_IDispatch_Release (IUnknown)
1747 * See Windows documentation for more details on IUnknown methods.
1749 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1752 ICOM_THIS_From_IDispatch(IPicture, iface);
1754 return IPicture_Release(This);
1757 /************************************************************************
1758 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1760 * See Windows documentation for more details on IDispatch methods.
1762 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1764 unsigned int* pctinfo)
1771 /************************************************************************
1772 * OLEPictureImpl_GetTypeInfo (IDispatch)
1774 * See Windows documentation for more details on IDispatch methods.
1776 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1780 ITypeInfo** ppTInfo)
1787 /************************************************************************
1788 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1790 * See Windows documentation for more details on IDispatch methods.
1792 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1795 LPOLESTR* rgszNames,
1805 /************************************************************************
1806 * OLEPictureImpl_Invoke (IDispatch)
1808 * See Windows documentation for more details on IDispatch methods.
1810 static HRESULT WINAPI OLEPictureImpl_Invoke(
1812 DISPID dispIdMember,
1816 DISPPARAMS* pDispParams,
1817 VARIANT* pVarResult,
1818 EXCEPINFO* pExepInfo,
1821 FIXME("(dispid: %ld):Stub\n",dispIdMember);
1823 VariantInit(pVarResult);
1824 V_VT(pVarResult) = VT_BOOL;
1825 V_UNION(pVarResult,boolVal) = FALSE;
1830 static IPictureVtbl OLEPictureImpl_VTable =
1832 OLEPictureImpl_QueryInterface,
1833 OLEPictureImpl_AddRef,
1834 OLEPictureImpl_Release,
1835 OLEPictureImpl_get_Handle,
1836 OLEPictureImpl_get_hPal,
1837 OLEPictureImpl_get_Type,
1838 OLEPictureImpl_get_Width,
1839 OLEPictureImpl_get_Height,
1840 OLEPictureImpl_Render,
1841 OLEPictureImpl_set_hPal,
1842 OLEPictureImpl_get_CurDC,
1843 OLEPictureImpl_SelectPicture,
1844 OLEPictureImpl_get_KeepOriginalFormat,
1845 OLEPictureImpl_put_KeepOriginalFormat,
1846 OLEPictureImpl_PictureChanged,
1847 OLEPictureImpl_SaveAsFile,
1848 OLEPictureImpl_get_Attributes
1851 static IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
1853 OLEPictureImpl_IDispatch_QueryInterface,
1854 OLEPictureImpl_IDispatch_AddRef,
1855 OLEPictureImpl_IDispatch_Release,
1856 OLEPictureImpl_GetTypeInfoCount,
1857 OLEPictureImpl_GetTypeInfo,
1858 OLEPictureImpl_GetIDsOfNames,
1859 OLEPictureImpl_Invoke
1862 static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
1864 OLEPictureImpl_IPersistStream_QueryInterface,
1865 OLEPictureImpl_IPersistStream_AddRef,
1866 OLEPictureImpl_IPersistStream_Release,
1867 OLEPictureImpl_GetClassID,
1868 OLEPictureImpl_IsDirty,
1869 OLEPictureImpl_Load,
1870 OLEPictureImpl_Save,
1871 OLEPictureImpl_GetSizeMax
1874 static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
1876 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
1877 OLEPictureImpl_IConnectionPointContainer_AddRef,
1878 OLEPictureImpl_IConnectionPointContainer_Release,
1879 OLEPictureImpl_EnumConnectionPoints,
1880 OLEPictureImpl_FindConnectionPoint
1883 /***********************************************************************
1884 * OleCreatePictureIndirect (OLEAUT32.419)
1886 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
1887 BOOL fOwn, LPVOID *ppvObj )
1889 OLEPictureImpl* newPict = NULL;
1892 TRACE("(%p,%p,%d,%p)\n", lpPictDesc, riid, fOwn, ppvObj);
1903 * Try to construct a new instance of the class.
1905 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
1907 if (newPict == NULL)
1908 return E_OUTOFMEMORY;
1911 * Make sure it supports the interface required by the caller.
1913 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
1916 * Release the reference obtained in the constructor. If
1917 * the QueryInterface was unsuccessful, it will free the class.
1919 IPicture_Release((IPicture*)newPict);
1925 /***********************************************************************
1926 * OleLoadPicture (OLEAUT32.418)
1928 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
1929 REFIID riid, LPVOID *ppvObj )
1935 TRACE("(%p,%ld,%d,%s,%p), partially implemented.\n",
1936 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
1938 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
1941 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
1943 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
1944 IPicture_Release(newpic);
1948 IPersistStream_Load(ps,lpstream);
1949 IPersistStream_Release(ps);
1950 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
1952 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
1953 IPicture_Release(newpic);
1957 /***********************************************************************
1958 * OleLoadPictureEx (OLEAUT32.401)
1960 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
1961 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
1967 FIXME("(%p,%ld,%d,%s,x=%ld,y=%ld,f=%lx,%p), partially implemented.\n",
1968 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
1970 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
1973 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
1975 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
1976 IPicture_Release(newpic);
1980 IPersistStream_Load(ps,lpstream);
1981 IPersistStream_Release(ps);
1982 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
1984 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
1985 IPicture_Release(newpic);
1989 /*******************************************************************************
1990 * StdPic ClassFactory
1994 /* IUnknown fields */
1995 IClassFactoryVtbl *lpVtbl;
1997 } IClassFactoryImpl;
1999 static HRESULT WINAPI
2000 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2001 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2003 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2004 return E_NOINTERFACE;
2008 SPCF_AddRef(LPCLASSFACTORY iface) {
2009 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2010 return InterlockedIncrement(&This->ref);
2013 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2014 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2015 /* static class, won't be freed */
2016 return InterlockedDecrement(&This->ref);
2019 static HRESULT WINAPI SPCF_CreateInstance(
2020 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2024 FIXME("(%p,%p,%s,%p), creating stdpic with PICTYPE_NONE.\n",iface,pOuter,debugstr_guid(riid),ppobj);
2025 pd.cbSizeofstruct = sizeof(pd);
2026 pd.picType = PICTYPE_NONE;
2027 return OleCreatePictureIndirect(&pd,riid,TRUE,ppobj);
2031 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2032 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2033 FIXME("(%p)->(%d),stub!\n",This,dolock);
2037 static IClassFactoryVtbl SPCF_Vtbl = {
2038 SPCF_QueryInterface,
2041 SPCF_CreateInstance,
2044 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2046 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }