advapi32/tests: Changed an invalid comment.
[wine.git] / dlls / oleaut32 / olepicture.c
blob599042cf7498bdf967e65b2fca888c186b65b1cd
1 /*
2 * OLE Picture object
4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
8 * Copyright 2008 Kirill K. Smirnov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * BUGS
26 * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
27 * Lots of methods are just stubs.
30 * NOTES (or things that msdn doesn't tell you)
32 * The width and height properties are returned in HIMETRIC units (0.01mm)
33 * IPicture::Render also uses these to select a region of the src picture.
34 * A bitmap's size is converted into these units by using the screen resolution
35 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
39 #include "config.h"
40 #include "wine/port.h"
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <string.h>
49 #define COBJMACROS
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
53 #include "winerror.h"
54 #include "windef.h"
55 #include "winbase.h"
56 #include "wingdi.h"
57 #include "winuser.h"
58 #include "ole2.h"
59 #include "olectl.h"
60 #include "oleauto.h"
61 #include "connpt.h"
62 #include "urlmon.h"
63 #include "initguid.h"
64 #include "wincodec.h"
65 #include "wine/debug.h"
66 #include "wine/unicode.h"
67 #include "wine/library.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(olepicture);
71 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
72 #define BITMAP_FORMAT_JPEG 0xd8ff
73 #define BITMAP_FORMAT_GIF 0x4947
74 #define BITMAP_FORMAT_PNG 0x5089
75 #define BITMAP_FORMAT_APM 0xcdd7
77 #include "pshpack1.h"
79 /* Header for Aldus Placable Metafiles - a standard metafile follows */
80 typedef struct _APM_HEADER
82 DWORD key;
83 WORD handle;
84 SHORT left;
85 SHORT top;
86 SHORT right;
87 SHORT bottom;
88 WORD inch;
89 DWORD reserved;
90 WORD checksum;
91 } APM_HEADER;
93 typedef struct {
94 BYTE bWidth;
95 BYTE bHeight;
96 BYTE bColorCount;
97 BYTE bReserved;
98 WORD xHotspot;
99 WORD yHotspot;
100 DWORD dwDIBSize;
101 DWORD dwDIBOffset;
102 } CURSORICONFILEDIRENTRY;
104 typedef struct
106 WORD idReserved;
107 WORD idType;
108 WORD idCount;
109 CURSORICONFILEDIRENTRY idEntries[1];
110 } CURSORICONFILEDIR;
112 #include "poppack.h"
114 /*************************************************************************
115 * Declaration of implementation class
118 typedef struct OLEPictureImpl {
121 * IPicture handles IUnknown
124 IPicture IPicture_iface;
125 IDispatch IDispatch_iface;
126 IPersistStream IPersistStream_iface;
127 IConnectionPointContainer IConnectionPointContainer_iface;
129 /* Object reference count */
130 LONG ref;
132 /* We own the object and must destroy it ourselves */
133 BOOL fOwn;
135 /* Picture description */
136 PICTDESC desc;
138 /* These are the pixel size of a bitmap */
139 DWORD origWidth;
140 DWORD origHeight;
142 /* And these are the size of the picture converted into HIMETRIC units */
143 OLE_XSIZE_HIMETRIC himetricWidth;
144 OLE_YSIZE_HIMETRIC himetricHeight;
146 IConnectionPoint *pCP;
148 BOOL keepOrigFormat;
149 HDC hDCCur;
150 HBITMAP stock_bitmap;
152 /* Bitmap transparency mask */
153 HBITMAP hbmMask;
154 HBITMAP hbmXor;
155 COLORREF rgbTrans;
157 /* data */
158 void* data;
159 int datalen;
160 BOOL bIsDirty; /* Set to TRUE if picture has changed */
161 unsigned int loadtime_magic; /* If a length header was found, saves value */
162 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
163 } OLEPictureImpl;
165 static inline OLEPictureImpl *impl_from_IPicture(IPicture *iface)
167 return CONTAINING_RECORD(iface, OLEPictureImpl, IPicture_iface);
170 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
172 return CONTAINING_RECORD(iface, OLEPictureImpl, IDispatch_iface);
175 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
177 return CONTAINING_RECORD(iface, OLEPictureImpl, IPersistStream_iface);
180 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
182 return CONTAINING_RECORD(iface, OLEPictureImpl, IConnectionPointContainer_iface);
186 * Predeclare VTables. They get initialized at the end.
188 static const IPictureVtbl OLEPictureImpl_VTable;
189 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
190 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
191 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
193 /* pixels to HIMETRIC units conversion */
194 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
196 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
199 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
201 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
204 /***********************************************************************
205 * Implementation of the OLEPictureImpl class.
208 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
210 BITMAP bm;
211 HDC hdcRef;
213 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
214 if(GetObjectW(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
215 ERR("GetObject fails\n");
216 return;
218 This->origWidth = bm.bmWidth;
219 This->origHeight = bm.bmHeight;
221 TRACE("width %d, height %d, bpp %d\n", bm.bmWidth, bm.bmHeight, bm.bmBitsPixel);
223 /* The width and height are stored in HIMETRIC units (0.01 mm),
224 so we take our pixel width divide by pixels per inch and
225 multiply by 25.4 * 100 */
226 /* Should we use GetBitmapDimension if available? */
227 hdcRef = CreateCompatibleDC(0);
229 This->himetricWidth = xpixels_to_himetric(bm.bmWidth, hdcRef);
230 This->himetricHeight = ypixels_to_himetric(bm.bmHeight, hdcRef);
231 This->stock_bitmap = GetCurrentObject( hdcRef, OBJ_BITMAP );
233 This->loadtime_format = BITMAP_FORMAT_BMP;
235 DeleteDC(hdcRef);
238 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
240 ICONINFO infoIcon;
242 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
243 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
244 HDC hdcRef;
245 BITMAP bm;
247 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
248 if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
249 ERR("GetObject fails on icon bitmap\n");
250 return;
253 This->origWidth = bm.bmWidth;
254 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
255 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
256 hdcRef = GetDC(0);
258 This->himetricWidth = xpixels_to_himetric(This->origWidth, hdcRef);
259 This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
261 ReleaseDC(0, hdcRef);
263 DeleteObject(infoIcon.hbmMask);
264 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
265 } else {
266 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
270 /************************************************************************
271 * OLEPictureImpl_Construct
273 * This method will construct a new instance of the OLEPictureImpl
274 * class.
276 * The caller of this method must release the object when it's
277 * done with it.
279 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
281 OLEPictureImpl* newObject = 0;
283 if (pictDesc)
284 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
287 * Allocate space for the object.
289 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
291 if (newObject==0)
292 return newObject;
295 * Initialize the virtual function table.
297 newObject->IPicture_iface.lpVtbl = &OLEPictureImpl_VTable;
298 newObject->IDispatch_iface.lpVtbl = &OLEPictureImpl_IDispatch_VTable;
299 newObject->IPersistStream_iface.lpVtbl = &OLEPictureImpl_IPersistStream_VTable;
300 newObject->IConnectionPointContainer_iface.lpVtbl = &OLEPictureImpl_IConnectionPointContainer_VTable;
302 newObject->pCP = NULL;
303 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
304 if (!newObject->pCP)
306 HeapFree(GetProcessHeap(), 0, newObject);
307 return NULL;
311 * Start with one reference count. The caller of this function
312 * must release the interface pointer when it is done.
314 newObject->ref = 1;
315 newObject->hDCCur = 0;
317 newObject->fOwn = fOwn;
319 /* dunno about original value */
320 newObject->keepOrigFormat = TRUE;
322 newObject->hbmMask = NULL;
323 newObject->hbmXor = NULL;
324 newObject->loadtime_magic = 0xdeadbeef;
325 newObject->loadtime_format = 0;
326 newObject->bIsDirty = FALSE;
328 if (pictDesc) {
329 newObject->desc = *pictDesc;
331 switch(pictDesc->picType) {
332 case PICTYPE_BITMAP:
333 OLEPictureImpl_SetBitmap(newObject);
334 break;
336 case PICTYPE_METAFILE:
337 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
338 newObject->himetricWidth = pictDesc->u.wmf.xExt;
339 newObject->himetricHeight = pictDesc->u.wmf.yExt;
340 break;
342 case PICTYPE_NONE:
343 /* not sure what to do here */
344 newObject->himetricWidth = newObject->himetricHeight = 0;
345 break;
347 case PICTYPE_ICON:
348 OLEPictureImpl_SetIcon(newObject);
349 break;
350 case PICTYPE_ENHMETAFILE:
351 default:
352 FIXME("Unsupported type %d\n", pictDesc->picType);
353 newObject->himetricWidth = newObject->himetricHeight = 0;
354 break;
356 } else {
357 newObject->desc.picType = PICTYPE_UNINITIALIZED;
360 TRACE("returning %p\n", newObject);
361 return newObject;
364 /************************************************************************
365 * OLEPictureImpl_Destroy
367 * This method is called by the Release method when the reference
368 * count goes down to 0. It will free all resources used by
369 * this object. */
370 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
372 TRACE("(%p)\n", Obj);
374 if (Obj->pCP)
375 IConnectionPoint_Release(Obj->pCP);
377 if(Obj->fOwn) { /* We need to destroy the picture */
378 switch(Obj->desc.picType) {
379 case PICTYPE_BITMAP:
380 DeleteObject(Obj->desc.u.bmp.hbitmap);
381 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
382 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
383 break;
384 case PICTYPE_METAFILE:
385 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
386 break;
387 case PICTYPE_ICON:
388 DestroyIcon(Obj->desc.u.icon.hicon);
389 break;
390 case PICTYPE_ENHMETAFILE:
391 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
392 break;
393 case PICTYPE_NONE:
394 case PICTYPE_UNINITIALIZED:
395 /* Nothing to do */
396 break;
397 default:
398 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
399 break;
402 HeapFree(GetProcessHeap(), 0, Obj->data);
403 HeapFree(GetProcessHeap(), 0, Obj);
407 /************************************************************************
408 * OLEPictureImpl_AddRef (IUnknown)
410 * See Windows documentation for more details on IUnknown methods.
412 static ULONG WINAPI OLEPictureImpl_AddRef(
413 IPicture* iface)
415 OLEPictureImpl *This = impl_from_IPicture(iface);
416 ULONG refCount = InterlockedIncrement(&This->ref);
418 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
420 return refCount;
423 /************************************************************************
424 * OLEPictureImpl_Release (IUnknown)
426 * See Windows documentation for more details on IUnknown methods.
428 static ULONG WINAPI OLEPictureImpl_Release(
429 IPicture* iface)
431 OLEPictureImpl *This = impl_from_IPicture(iface);
432 ULONG refCount = InterlockedDecrement(&This->ref);
434 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
437 * If the reference count goes down to 0, perform suicide.
439 if (!refCount) OLEPictureImpl_Destroy(This);
441 return refCount;
444 /************************************************************************
445 * OLEPictureImpl_QueryInterface (IUnknown)
447 * See Windows documentation for more details on IUnknown methods.
449 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
450 IPicture* iface,
451 REFIID riid,
452 void** ppvObject)
454 OLEPictureImpl *This = impl_from_IPicture(iface);
456 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
458 if (!ppvObject)
459 return E_INVALIDARG;
461 *ppvObject = 0;
463 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
464 *ppvObject = This;
465 else if (IsEqualIID(&IID_IDispatch, riid))
466 *ppvObject = &This->IDispatch_iface;
467 else if (IsEqualIID(&IID_IPictureDisp, riid))
468 *ppvObject = &This->IDispatch_iface;
469 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
470 *ppvObject = &This->IPersistStream_iface;
471 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
472 *ppvObject = &This->IConnectionPointContainer_iface;
474 if (!*ppvObject)
476 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
477 return E_NOINTERFACE;
480 IPicture_AddRef(iface);
482 return S_OK;
485 /***********************************************************************
486 * OLEPicture_SendNotify (internal)
488 * Sends notification messages of changed properties to any interested
489 * connections.
491 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
493 IEnumConnections *pEnum;
494 CONNECTDATA CD;
496 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
497 return;
498 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
499 IPropertyNotifySink *sink;
501 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
502 IPropertyNotifySink_OnChanged(sink, dispID);
503 IPropertyNotifySink_Release(sink);
504 IUnknown_Release(CD.pUnk);
506 IEnumConnections_Release(pEnum);
509 /************************************************************************
510 * OLEPictureImpl_get_Handle
512 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
513 OLE_HANDLE *phandle)
515 OLEPictureImpl *This = impl_from_IPicture(iface);
516 TRACE("(%p)->(%p)\n", This, phandle);
518 if(!phandle)
519 return E_POINTER;
521 switch(This->desc.picType) {
522 case PICTYPE_NONE:
523 case PICTYPE_UNINITIALIZED:
524 *phandle = 0;
525 break;
526 case PICTYPE_BITMAP:
527 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
528 break;
529 case PICTYPE_METAFILE:
530 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
531 break;
532 case PICTYPE_ICON:
533 *phandle = HandleToUlong(This->desc.u.icon.hicon);
534 break;
535 case PICTYPE_ENHMETAFILE:
536 *phandle = HandleToUlong(This->desc.u.emf.hemf);
537 break;
538 default:
539 FIXME("Unimplemented type %d\n", This->desc.picType);
540 return E_NOTIMPL;
542 TRACE("returning handle %08x\n", *phandle);
543 return S_OK;
546 /************************************************************************
547 * OLEPictureImpl_get_hPal
549 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
550 OLE_HANDLE *phandle)
552 OLEPictureImpl *This = impl_from_IPicture(iface);
553 HRESULT hres;
554 TRACE("(%p)->(%p)\n", This, phandle);
556 if (!phandle)
557 return E_POINTER;
559 switch (This->desc.picType) {
560 case (UINT)PICTYPE_UNINITIALIZED:
561 case PICTYPE_NONE:
562 *phandle = 0;
563 hres = S_FALSE;
564 break;
565 case PICTYPE_BITMAP:
566 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
567 hres = S_OK;
568 break;
569 case PICTYPE_METAFILE:
570 hres = E_FAIL;
571 break;
572 case PICTYPE_ICON:
573 case PICTYPE_ENHMETAFILE:
574 default:
575 FIXME("unimplemented for type %d. Returning 0 palette.\n",
576 This->desc.picType);
577 *phandle = 0;
578 hres = S_OK;
581 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
582 return hres;
585 /************************************************************************
586 * OLEPictureImpl_get_Type
588 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
589 short *ptype)
591 OLEPictureImpl *This = impl_from_IPicture(iface);
592 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
594 if(!ptype)
595 return E_POINTER;
597 *ptype = This->desc.picType;
598 return S_OK;
601 /************************************************************************
602 * OLEPictureImpl_get_Width
604 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
605 OLE_XSIZE_HIMETRIC *pwidth)
607 OLEPictureImpl *This = impl_from_IPicture(iface);
608 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
609 *pwidth = This->himetricWidth;
610 return S_OK;
613 /************************************************************************
614 * OLEPictureImpl_get_Height
616 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
617 OLE_YSIZE_HIMETRIC *pheight)
619 OLEPictureImpl *This = impl_from_IPicture(iface);
620 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
621 *pheight = This->himetricHeight;
622 return S_OK;
625 /************************************************************************
626 * OLEPictureImpl_Render
628 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
629 LONG x, LONG y, LONG cx, LONG cy,
630 OLE_XPOS_HIMETRIC xSrc,
631 OLE_YPOS_HIMETRIC ySrc,
632 OLE_XSIZE_HIMETRIC cxSrc,
633 OLE_YSIZE_HIMETRIC cySrc,
634 LPCRECT prcWBounds)
636 OLEPictureImpl *This = impl_from_IPicture(iface);
637 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
638 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
639 if(prcWBounds)
640 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
641 prcWBounds->right, prcWBounds->bottom);
643 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
644 return CTL_E_INVALIDPROPERTYVALUE;
648 * While the documentation suggests this to be here (or after rendering?)
649 * it does cause an endless recursion in my sample app. -MM 20010804
650 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
653 switch(This->desc.picType) {
654 case PICTYPE_UNINITIALIZED:
655 case PICTYPE_NONE:
656 /* nothing to do */
657 return S_OK;
658 case PICTYPE_BITMAP:
660 HBITMAP hbmpOld;
661 HDC hdcBmp;
663 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
664 NB y-axis gets flipped */
666 hdcBmp = CreateCompatibleDC(0);
667 SetMapMode(hdcBmp, MM_ANISOTROPIC);
668 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
669 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
670 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
671 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
673 if (This->hbmMask) {
674 HDC hdcMask = CreateCompatibleDC(0);
675 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
677 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
679 SetMapMode(hdcMask, MM_ANISOTROPIC);
680 SetWindowOrgEx(hdcMask, 0, 0, NULL);
681 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
682 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
683 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
685 SetBkColor(hdc, RGB(255, 255, 255));
686 SetTextColor(hdc, RGB(0, 0, 0));
687 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
688 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
690 SelectObject(hdcMask, hOldbm);
691 DeleteDC(hdcMask);
692 } else {
693 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
694 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
697 SelectObject(hdcBmp, hbmpOld);
698 DeleteDC(hdcBmp);
700 break;
701 case PICTYPE_ICON:
702 FIXME("Not quite correct implementation of rendering icons...\n");
703 DrawIconEx(hdc, x, y, This->desc.u.icon.hicon, cx, cy, 0, NULL, DI_NORMAL);
704 break;
706 case PICTYPE_METAFILE:
708 POINT prevOrg, prevWndOrg;
709 SIZE prevExt, prevWndExt;
710 int oldmode;
712 /* Render the WMF to the appropriate location by setting the
713 appropriate ratio between "device units" and "logical units" */
714 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
715 /* For the "source rectangle" the y-axis must be inverted */
716 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
717 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
718 /* For the "destination rectangle" no inversion is necessary */
719 SetViewportOrgEx(hdc, x, y, &prevOrg);
720 SetViewportExtEx(hdc, cx, cy, &prevExt);
722 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
723 ERR("PlayMetaFile failed!\n");
725 /* We're done, restore the DC to the previous settings for converting
726 logical units to device units */
727 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
728 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
729 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
730 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
731 SetMapMode(hdc, oldmode);
732 break;
735 case PICTYPE_ENHMETAFILE:
737 RECT rc = { x, y, x + cx, y + cy };
738 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
739 break;
742 default:
743 FIXME("type %d not implemented\n", This->desc.picType);
744 return E_NOTIMPL;
746 return S_OK;
749 /************************************************************************
750 * OLEPictureImpl_set_hPal
752 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
753 OLE_HANDLE hpal)
755 OLEPictureImpl *This = impl_from_IPicture(iface);
756 FIXME("(%p)->(%08x): stub\n", This, hpal);
757 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
758 return E_NOTIMPL;
761 /************************************************************************
762 * OLEPictureImpl_get_CurDC
764 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
765 HDC *phdc)
767 OLEPictureImpl *This = impl_from_IPicture(iface);
768 TRACE("(%p), returning %p\n", This, This->hDCCur);
769 if (phdc) *phdc = This->hDCCur;
770 return S_OK;
773 /************************************************************************
774 * OLEPictureImpl_SelectPicture
776 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
777 HDC hdcIn,
778 HDC *phdcOut,
779 OLE_HANDLE *phbmpOut)
781 OLEPictureImpl *This = impl_from_IPicture(iface);
782 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
783 if (This->desc.picType == PICTYPE_BITMAP) {
784 if (phdcOut)
785 *phdcOut = This->hDCCur;
786 if (This->hDCCur) SelectObject(This->hDCCur,This->stock_bitmap);
787 if (hdcIn) SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
788 This->hDCCur = hdcIn;
789 if (phbmpOut)
790 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
791 return S_OK;
792 } else {
793 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
794 return E_FAIL;
798 /************************************************************************
799 * OLEPictureImpl_get_KeepOriginalFormat
801 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
802 BOOL *pfKeep)
804 OLEPictureImpl *This = impl_from_IPicture(iface);
805 TRACE("(%p)->(%p)\n", This, pfKeep);
806 if (!pfKeep)
807 return E_POINTER;
808 *pfKeep = This->keepOrigFormat;
809 return S_OK;
812 /************************************************************************
813 * OLEPictureImpl_put_KeepOriginalFormat
815 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
816 BOOL keep)
818 OLEPictureImpl *This = impl_from_IPicture(iface);
819 TRACE("(%p)->(%d)\n", This, keep);
820 This->keepOrigFormat = keep;
821 /* FIXME: what DISPID notification here? */
822 return S_OK;
825 /************************************************************************
826 * OLEPictureImpl_PictureChanged
828 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
830 OLEPictureImpl *This = impl_from_IPicture(iface);
831 TRACE("(%p)->()\n", This);
832 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
833 This->bIsDirty = TRUE;
834 return S_OK;
837 /************************************************************************
838 * OLEPictureImpl_SaveAsFile
840 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
841 IStream *pstream,
842 BOOL SaveMemCopy,
843 LONG *pcbSize)
845 OLEPictureImpl *This = impl_from_IPicture(iface);
846 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
847 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
850 /************************************************************************
851 * OLEPictureImpl_get_Attributes
853 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
854 DWORD *pdwAttr)
856 OLEPictureImpl *This = impl_from_IPicture(iface);
857 TRACE("(%p)->(%p).\n", This, pdwAttr);
859 if(!pdwAttr)
860 return E_POINTER;
862 *pdwAttr = 0;
863 switch (This->desc.picType) {
864 case PICTYPE_UNINITIALIZED:
865 case PICTYPE_NONE: break;
866 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
867 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
868 case PICTYPE_ENHMETAFILE: /* fall through */
869 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
870 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
872 return S_OK;
876 /************************************************************************
877 * IConnectionPointContainer
879 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
880 IConnectionPointContainer* iface,
881 REFIID riid,
882 VOID** ppvoid)
884 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
886 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
889 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
890 IConnectionPointContainer* iface)
892 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
894 return IPicture_AddRef(&This->IPicture_iface);
897 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
898 IConnectionPointContainer* iface)
900 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
902 return IPicture_Release(&This->IPicture_iface);
905 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
906 IConnectionPointContainer* iface,
907 IEnumConnectionPoints** ppEnum)
909 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
911 FIXME("(%p,%p), stub!\n",This,ppEnum);
912 return E_NOTIMPL;
915 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
916 IConnectionPointContainer* iface,
917 REFIID riid,
918 IConnectionPoint **ppCP)
920 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
921 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
922 if (!ppCP)
923 return E_POINTER;
924 *ppCP = NULL;
925 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
926 return IConnectionPoint_QueryInterface(This->pCP, &IID_IConnectionPoint, (void**)ppCP);
927 FIXME("no connection point for %s\n",debugstr_guid(riid));
928 return CONNECT_E_NOCONNECTION;
932 /************************************************************************
933 * IPersistStream
936 /************************************************************************
937 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
939 * See Windows documentation for more details on IUnknown methods.
941 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
942 IPersistStream* iface,
943 REFIID riid,
944 VOID** ppvoid)
946 OLEPictureImpl *This = impl_from_IPersistStream(iface);
948 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
951 /************************************************************************
952 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
954 * See Windows documentation for more details on IUnknown methods.
956 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
957 IPersistStream* iface)
959 OLEPictureImpl *This = impl_from_IPersistStream(iface);
961 return IPicture_AddRef(&This->IPicture_iface);
964 /************************************************************************
965 * OLEPictureImpl_IPersistStream_Release (IUnknown)
967 * See Windows documentation for more details on IUnknown methods.
969 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
970 IPersistStream* iface)
972 OLEPictureImpl *This = impl_from_IPersistStream(iface);
974 return IPicture_Release(&This->IPicture_iface);
977 /************************************************************************
978 * OLEPictureImpl_IPersistStream_GetClassID
980 static HRESULT WINAPI OLEPictureImpl_GetClassID(
981 IPersistStream* iface,CLSID* pClassID)
983 TRACE("(%p)\n", pClassID);
984 *pClassID = CLSID_StdPicture;
985 return S_OK;
988 /************************************************************************
989 * OLEPictureImpl_IPersistStream_IsDirty
991 static HRESULT WINAPI OLEPictureImpl_IsDirty(
992 IPersistStream* iface)
994 OLEPictureImpl *This = impl_from_IPersistStream(iface);
995 FIXME("(%p),stub!\n",This);
996 return E_NOTIMPL;
999 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1001 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1002 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1003 HDC hdcref;
1005 /* Does not matter whether this is a coreheader or not, we only use
1006 * components which are in both
1008 hdcref = GetDC(0);
1009 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1010 hdcref,
1011 &(bi->bmiHeader),
1012 CBM_INIT,
1013 xbuf+bfh->bfOffBits,
1015 DIB_RGB_COLORS
1017 ReleaseDC(0, hdcref);
1018 if (This->desc.u.bmp.hbitmap == 0)
1019 return E_FAIL;
1020 This->desc.picType = PICTYPE_BITMAP;
1021 OLEPictureImpl_SetBitmap(This);
1022 return S_OK;
1025 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1027 HRESULT hr;
1028 BITMAPINFOHEADER bih;
1029 HDC hdcref;
1030 UINT width, height;
1031 UINT stride, buffersize;
1032 LPBYTE bits=NULL;
1033 WICRect rc;
1034 IWICBitmapSource *real_source;
1035 UINT x, y;
1036 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1037 BOOL has_alpha=FALSE;
1039 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1040 if (FAILED(hr)) return hr;
1042 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1043 if (FAILED(hr)) goto end;
1045 bih.biSize = sizeof(bih);
1046 bih.biWidth = width;
1047 bih.biHeight = -height;
1048 bih.biPlanes = 1;
1049 bih.biBitCount = 32;
1050 bih.biCompression = BI_RGB;
1051 bih.biSizeImage = 0;
1052 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1053 bih.biYPelsPerMeter = 4085;
1054 bih.biClrUsed = 0;
1055 bih.biClrImportant = 0;
1057 stride = 4 * width;
1058 buffersize = stride * height;
1060 bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1061 if (!bits)
1063 hr = E_OUTOFMEMORY;
1064 goto end;
1067 rc.X = 0;
1068 rc.Y = 0;
1069 rc.Width = width;
1070 rc.Height = height;
1071 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1072 if (FAILED(hr))
1073 goto end;
1075 hdcref = GetDC(0);
1076 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1077 hdcref,
1078 &bih,
1079 CBM_INIT,
1080 bits,
1081 (BITMAPINFO*)&bih,
1082 DIB_RGB_COLORS);
1084 if (This->desc.u.bmp.hbitmap == 0)
1086 hr = E_FAIL;
1087 ReleaseDC(0, hdcref);
1088 goto end;
1091 This->desc.picType = PICTYPE_BITMAP;
1092 OLEPictureImpl_SetBitmap(This);
1094 /* set transparent pixels to black, all others to white */
1095 for(y = 0; y < height; y++){
1096 for(x = 0; x < width; x++){
1097 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1098 if((*pixel & 0x80000000) == 0)
1100 has_alpha = TRUE;
1101 *pixel = black;
1103 else
1104 *pixel = white;
1108 if (has_alpha)
1110 HDC hdcBmp, hdcXor, hdcMask;
1111 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1113 This->hbmXor = CreateDIBitmap(
1114 hdcref,
1115 &bih,
1116 CBM_INIT,
1117 bits,
1118 (BITMAPINFO*)&bih,
1119 DIB_RGB_COLORS
1122 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1123 hdcBmp = CreateCompatibleDC(NULL);
1124 hdcXor = CreateCompatibleDC(NULL);
1125 hdcMask = CreateCompatibleDC(NULL);
1127 hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1128 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1129 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1131 SetBkColor(hdcXor,black);
1132 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1133 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1135 SelectObject(hdcBmp,hbmoldBmp);
1136 SelectObject(hdcXor,hbmoldXor);
1137 SelectObject(hdcMask,hbmoldMask);
1139 DeleteDC(hdcBmp);
1140 DeleteDC(hdcXor);
1141 DeleteDC(hdcMask);
1144 ReleaseDC(0, hdcref);
1146 end:
1147 HeapFree(GetProcessHeap(), 0, bits);
1148 IWICBitmapSource_Release(real_source);
1149 return hr;
1152 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1154 HRESULT hr;
1155 IWICImagingFactory *factory;
1156 IWICBitmapDecoder *decoder;
1157 IWICBitmapFrameDecode *framedecode;
1158 HRESULT initresult;
1159 IWICStream *stream;
1161 initresult = CoInitialize(NULL);
1163 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1164 &IID_IWICImagingFactory, (void**)&factory);
1165 if (SUCCEEDED(hr)) /* created factory */
1167 hr = IWICImagingFactory_CreateStream(factory, &stream);
1168 IWICImagingFactory_Release(factory);
1171 if (SUCCEEDED(hr)) /* created stream */
1173 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1175 if (SUCCEEDED(hr)) /* initialized stream */
1177 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1178 &IID_IWICBitmapDecoder, (void**)&decoder);
1179 if (SUCCEEDED(hr)) /* created decoder */
1181 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1183 if (SUCCEEDED(hr)) /* initialized decoder */
1184 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1186 IWICBitmapDecoder_Release(decoder);
1190 IWICStream_Release(stream);
1193 if (SUCCEEDED(hr)) /* got framedecode */
1195 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1196 IWICBitmapFrameDecode_Release(framedecode);
1199 if (SUCCEEDED(initresult)) CoUninitialize();
1200 return hr;
1203 /*****************************************************
1204 * start of Icon-specific code
1207 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1209 HICON hicon;
1210 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1211 HDC hdcRef;
1212 int i;
1215 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1216 FIXME("icon.idType=%d\n",cifd->idType);
1217 FIXME("icon.idCount=%d\n",cifd->idCount);
1219 for (i=0;i<cifd->idCount;i++) {
1220 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1221 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1222 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1223 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1224 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1225 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1226 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1227 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1230 i=0;
1231 /* If we have more than one icon, try to find the best.
1232 * this currently means '32 pixel wide'.
1234 if (cifd->idCount!=1) {
1235 for (i=0;i<cifd->idCount;i++) {
1236 if (cifd->idEntries[i].bWidth == 32)
1237 break;
1239 if (i==cifd->idCount) i=0;
1241 if (cifd->idType == 2)
1243 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, cifd->idEntries[i].dwDIBSize + 4);
1244 memcpy(buf, &cifd->idEntries[i].xHotspot, 4);
1245 memcpy(buf + 4, xbuf+cifd->idEntries[i].dwDIBOffset, cifd->idEntries[i].dwDIBSize);
1246 hicon = CreateIconFromResourceEx(
1247 buf,
1248 cifd->idEntries[i].dwDIBSize + 4,
1249 FALSE, /* is cursor */
1250 0x00030000,
1251 cifd->idEntries[i].bWidth,
1252 cifd->idEntries[i].bHeight,
1255 HeapFree(GetProcessHeap(), 0, buf);
1257 else
1259 hicon = CreateIconFromResourceEx(
1260 xbuf+cifd->idEntries[i].dwDIBOffset,
1261 cifd->idEntries[i].dwDIBSize,
1262 TRUE, /* is icon */
1263 0x00030000,
1264 cifd->idEntries[i].bWidth,
1265 cifd->idEntries[i].bHeight,
1269 if (!hicon) {
1270 ERR("CreateIcon failed.\n");
1271 return E_FAIL;
1272 } else {
1273 This->desc.picType = PICTYPE_ICON;
1274 This->desc.u.icon.hicon = hicon;
1275 This->origWidth = cifd->idEntries[i].bWidth;
1276 This->origHeight = cifd->idEntries[i].bHeight;
1277 hdcRef = CreateCompatibleDC(0);
1278 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1279 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1280 DeleteDC(hdcRef);
1281 return S_OK;
1285 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1286 const BYTE *data, ULONG size)
1288 HENHMETAFILE hemf;
1289 ENHMETAHEADER hdr;
1291 hemf = SetEnhMetaFileBits(size, data);
1292 if (!hemf) return E_FAIL;
1294 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1296 This->desc.picType = PICTYPE_ENHMETAFILE;
1297 This->desc.u.emf.hemf = hemf;
1299 This->origWidth = 0;
1300 This->origHeight = 0;
1301 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1302 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1304 return S_OK;
1307 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1308 const BYTE *data, ULONG size)
1310 const APM_HEADER *header = (const APM_HEADER *)data;
1311 HMETAFILE hmf;
1313 if (size < sizeof(APM_HEADER))
1314 return E_FAIL;
1315 if (header->key != 0x9ac6cdd7)
1316 return E_FAIL;
1318 /* SetMetaFileBitsEx performs data check on its own */
1319 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1320 if (!hmf) return E_FAIL;
1322 This->desc.picType = PICTYPE_METAFILE;
1323 This->desc.u.wmf.hmeta = hmf;
1324 This->desc.u.wmf.xExt = 0;
1325 This->desc.u.wmf.yExt = 0;
1327 This->origWidth = 0;
1328 This->origHeight = 0;
1329 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1330 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1331 return S_OK;
1334 /************************************************************************
1335 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1337 * Loads the binary data from the IStream. Starts at current position.
1338 * There appears to be an 2 DWORD header:
1339 * DWORD magic;
1340 * DWORD len;
1342 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1344 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1345 HRESULT hr;
1346 BOOL headerisdata;
1347 BOOL statfailed = FALSE;
1348 ULONG xread, toread;
1349 ULONG headerread;
1350 BYTE *xbuf;
1351 DWORD header[2];
1352 WORD magic;
1353 STATSTG statstg;
1354 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1356 TRACE("(%p,%p)\n",This,pStm);
1358 /****************************************************************************************
1359 * Part 1: Load the data
1361 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1362 * out whether we do.
1364 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1365 * compound file. This may explain most, if not all, of the cases of "no
1366 * header", and the header validation should take this into account.
1367 * At least in Visual Basic 6, resource streams, valid headers are
1368 * header[0] == "lt\0\0",
1369 * header[1] == length_of_stream.
1371 * Also handle streams where we do not have a working "Stat" method by
1372 * reading all data until the end of the stream.
1374 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1375 if (hr != S_OK) {
1376 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1377 statfailed = TRUE;
1378 /* we will read at least 8 byte ... just right below */
1379 statstg.cbSize.QuadPart = 8;
1382 toread = 0;
1383 headerread = 0;
1384 headerisdata = FALSE;
1385 do {
1386 hr = IStream_Read(pStm, header, 8, &xread);
1387 if (hr != S_OK || xread!=8) {
1388 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1389 return (hr?hr:E_FAIL);
1391 headerread += xread;
1392 xread = 0;
1394 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1395 if (toread != 0 && toread != header[1])
1396 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1397 toread, header[1]);
1398 toread = header[1];
1399 if (statfailed)
1401 statstg.cbSize.QuadPart = header[1] + 8;
1402 statfailed = FALSE;
1404 if (toread == 0) break;
1405 } else {
1406 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1407 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1408 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1409 (header[0] == EMR_HEADER) || /* EMF header */
1410 (header[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1411 (header[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1412 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1413 (header[1]==0)
1414 ) {/* Found start of bitmap data */
1415 headerisdata = TRUE;
1416 if (toread == 0)
1417 toread = statstg.cbSize.QuadPart-8;
1418 else toread -= 8;
1419 xread = 8;
1420 } else {
1421 FIXME("Unknown stream header magic: %08x\n", header[0]);
1422 toread = header[1];
1425 } while (!headerisdata);
1427 if (statfailed) { /* we don't know the size ... read all we get */
1428 unsigned int sizeinc = 4096;
1429 unsigned int origsize = sizeinc;
1430 ULONG nread = 42;
1432 TRACE("Reading all data from stream.\n");
1433 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1434 if (headerisdata)
1435 memcpy (xbuf, header, 8);
1436 while (1) {
1437 while (xread < origsize) {
1438 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1439 xread += nread;
1440 if (hr != S_OK || !nread)
1441 break;
1443 if (!nread || hr != S_OK) /* done, or error */
1444 break;
1445 if (xread == origsize) {
1446 origsize += sizeinc;
1447 sizeinc = 2*sizeinc; /* exponential increase */
1448 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1451 if (hr != S_OK)
1452 TRACE("hr in no-stat loader case is %08x\n", hr);
1453 TRACE("loaded %d bytes.\n", xread);
1454 This->datalen = xread;
1455 This->data = xbuf;
1456 } else {
1457 This->datalen = toread+(headerisdata?8:0);
1458 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1459 if (!xbuf)
1460 return E_OUTOFMEMORY;
1462 if (headerisdata)
1463 memcpy (xbuf, header, 8);
1465 while (xread < This->datalen) {
1466 ULONG nread;
1467 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1468 xread += nread;
1469 if (hr != S_OK || !nread)
1470 break;
1472 if (xread != This->datalen)
1473 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1475 if (This->datalen == 0) { /* Marks the "NONE" picture */
1476 This->desc.picType = PICTYPE_NONE;
1477 return S_OK;
1481 /****************************************************************************************
1482 * Part 2: Process the loaded data
1485 magic = xbuf[0] + (xbuf[1]<<8);
1486 This->loadtime_format = magic;
1488 switch (magic) {
1489 case BITMAP_FORMAT_GIF: /* GIF */
1490 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1491 break;
1492 case BITMAP_FORMAT_JPEG: /* JPEG */
1493 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1494 break;
1495 case BITMAP_FORMAT_BMP: /* Bitmap */
1496 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1497 break;
1498 case BITMAP_FORMAT_PNG: /* PNG */
1499 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1500 break;
1501 case BITMAP_FORMAT_APM: /* APM */
1502 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1503 break;
1504 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1505 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1506 break;
1508 default:
1510 unsigned int i;
1512 /* let's see if it's a EMF */
1513 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1514 if (hr == S_OK) break;
1516 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1517 hr=E_FAIL;
1518 for (i=0;i<xread+8;i++) {
1519 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1520 else MESSAGE("%02x ",xbuf[i-8]);
1521 if (i % 10 == 9) MESSAGE("\n");
1523 MESSAGE("\n");
1524 break;
1527 This->bIsDirty = FALSE;
1529 /* FIXME: this notify is not really documented */
1530 if (hr==S_OK)
1531 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1532 return hr;
1535 static BOOL serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1537 BOOL success = FALSE;
1538 HDC hDC;
1539 BITMAPINFO * pInfoBitmap;
1540 int iNumPaletteEntries;
1541 unsigned char * pPixelData;
1542 BITMAPFILEHEADER * pFileHeader;
1543 BITMAPINFO * pInfoHeader;
1545 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1546 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1548 /* Find out bitmap size and padded length */
1549 hDC = GetDC(0);
1550 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1551 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1553 /* Fetch bitmap palette & pixel data */
1555 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1556 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1558 /* Calculate the total length required for the BMP data */
1559 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1560 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1561 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1562 } else {
1563 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1564 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1565 else
1566 iNumPaletteEntries = 0;
1568 *pLength =
1569 sizeof(BITMAPFILEHEADER) +
1570 sizeof(BITMAPINFOHEADER) +
1571 iNumPaletteEntries * sizeof(RGBQUAD) +
1572 pInfoBitmap->bmiHeader.biSizeImage;
1573 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1575 /* Fill the BITMAPFILEHEADER */
1576 pFileHeader = *ppBuffer;
1577 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1578 pFileHeader->bfSize = *pLength;
1579 pFileHeader->bfOffBits =
1580 sizeof(BITMAPFILEHEADER) +
1581 sizeof(BITMAPINFOHEADER) +
1582 iNumPaletteEntries * sizeof(RGBQUAD);
1584 /* Fill the BITMAPINFOHEADER and the palette data */
1585 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1586 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1587 memcpy(
1588 (unsigned char *)(*ppBuffer) +
1589 sizeof(BITMAPFILEHEADER) +
1590 sizeof(BITMAPINFOHEADER) +
1591 iNumPaletteEntries * sizeof(RGBQUAD),
1592 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1593 success = TRUE;
1595 HeapFree(GetProcessHeap(), 0, pPixelData);
1596 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1597 return success;
1600 static BOOL serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1602 ICONINFO infoIcon;
1603 BOOL success = FALSE;
1605 *ppBuffer = NULL; *pLength = 0;
1606 if (GetIconInfo(hIcon, &infoIcon)) {
1607 HDC hDC;
1608 BITMAPINFO * pInfoBitmap;
1609 unsigned char * pIconData = NULL;
1610 unsigned int iDataSize = 0;
1612 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1614 /* Find out icon size */
1615 hDC = GetDC(0);
1616 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1617 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1618 if (1) {
1619 /* Auxiliary pointers */
1620 CURSORICONFILEDIR * pIconDir;
1621 CURSORICONFILEDIRENTRY * pIconEntry;
1622 BITMAPINFOHEADER * pIconBitmapHeader;
1623 unsigned int iOffsetPalette;
1624 unsigned int iOffsetColorData;
1625 unsigned int iOffsetMaskData;
1627 unsigned int iLengthScanLineMask;
1628 unsigned int iNumEntriesPalette;
1630 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1632 FIXME("DEBUG: bitmap size is %d x %d\n",
1633 pInfoBitmap->bmiHeader.biWidth,
1634 pInfoBitmap->bmiHeader.biHeight);
1635 FIXME("DEBUG: bitmap bpp is %d\n",
1636 pInfoBitmap->bmiHeader.biBitCount);
1637 FIXME("DEBUG: bitmap nplanes is %d\n",
1638 pInfoBitmap->bmiHeader.biPlanes);
1639 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1640 pInfoBitmap->bmiHeader.biSizeImage);
1642 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1643 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1644 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1646 /* Fill out the CURSORICONFILEDIR */
1647 pIconDir = (CURSORICONFILEDIR *)pIconData;
1648 pIconDir->idType = 1;
1649 pIconDir->idCount = 1;
1650 pIconDir->idReserved = 0;
1652 /* Fill out the CURSORICONFILEDIRENTRY */
1653 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1654 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1655 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1656 pIconEntry->bColorCount =
1657 (pInfoBitmap->bmiHeader.biBitCount < 8)
1658 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1659 : 0;
1660 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1661 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1662 pIconEntry->dwDIBSize = 0;
1663 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1665 /* Fill out the BITMAPINFOHEADER */
1666 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1667 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1669 /* Find out whether a palette exists for the bitmap */
1670 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1671 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1672 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1673 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1674 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1675 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1676 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1677 iNumEntriesPalette = 3;
1678 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1679 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1680 } else {
1681 iNumEntriesPalette = 0;
1684 /* Add bitmap size and header size to icon data size. */
1685 iOffsetPalette = iDataSize;
1686 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1687 iOffsetColorData = iDataSize;
1688 iDataSize += pIconBitmapHeader->biSizeImage;
1689 iOffsetMaskData = iDataSize;
1690 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1691 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1692 pIconBitmapHeader->biHeight *= 2;
1693 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1694 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1695 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1696 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1698 /* Get the actual bitmap data from the icon bitmap */
1699 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1700 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1701 if (iNumEntriesPalette > 0) {
1702 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1703 iNumEntriesPalette * sizeof(RGBQUAD));
1706 /* Reset all values so that GetDIBits call succeeds */
1707 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1708 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1709 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1711 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1712 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1713 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1715 printf("ERROR: unable to get bitmap mask (error %u)\n",
1716 GetLastError());
1720 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1721 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1723 /* Write out everything produced so far to the stream */
1724 *ppBuffer = pIconData; *pLength = iDataSize;
1725 success = TRUE;
1726 } else {
1728 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1729 GetLastError());
1733 Remarks (from MSDN entry on GetIconInfo):
1735 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1736 members of ICONINFO. The calling application must manage
1737 these bitmaps and delete them when they are no longer
1738 necessary.
1740 if (hDC) ReleaseDC(0, hDC);
1741 DeleteObject(infoIcon.hbmMask);
1742 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1743 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1744 } else {
1745 printf("ERROR: Unable to get icon information (error %u)\n",
1746 GetLastError());
1748 return success;
1751 static HRESULT WINAPI OLEPictureImpl_Save(
1752 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1754 HRESULT hResult = E_NOTIMPL;
1755 void * pIconData;
1756 unsigned int iDataSize;
1757 DWORD header[2];
1758 ULONG dummy;
1759 BOOL serializeResult = FALSE;
1760 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1762 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1764 switch (This->desc.picType) {
1765 case PICTYPE_NONE:
1766 header[0] = 0x0000746c;
1767 header[1] = 0;
1768 hResult = IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1769 break;
1771 case PICTYPE_ICON:
1772 if (This->bIsDirty || !This->data) {
1773 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1774 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1775 hResult = E_FAIL;
1776 break;
1778 HeapFree(GetProcessHeap(), 0, This->data);
1779 This->data = pIconData;
1780 This->datalen = iDataSize;
1783 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1784 header[1] = This->datalen;
1785 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1786 IStream_Write(pStm, This->data, This->datalen, &dummy);
1787 hResult = S_OK;
1788 break;
1789 case PICTYPE_BITMAP:
1790 if (This->bIsDirty || !This->data) {
1791 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1792 case BITMAP_FORMAT_BMP:
1793 serializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1794 break;
1795 case BITMAP_FORMAT_JPEG:
1796 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1797 break;
1798 case BITMAP_FORMAT_GIF:
1799 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1800 break;
1801 case BITMAP_FORMAT_PNG:
1802 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1803 break;
1804 default:
1805 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1806 break;
1809 if (!serializeResult)
1811 hResult = E_FAIL;
1812 break;
1815 HeapFree(GetProcessHeap(), 0, This->data);
1816 This->data = pIconData;
1817 This->datalen = iDataSize;
1820 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1821 header[1] = This->datalen;
1822 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1823 IStream_Write(pStm, This->data, This->datalen, &dummy);
1824 hResult = S_OK;
1825 break;
1826 case PICTYPE_METAFILE:
1827 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1828 break;
1829 case PICTYPE_ENHMETAFILE:
1830 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1831 break;
1832 default:
1833 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1834 break;
1836 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1837 return hResult;
1840 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1841 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1843 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1844 FIXME("(%p,%p),stub!\n",This,pcbSize);
1845 return E_NOTIMPL;
1849 /************************************************************************
1850 * IDispatch
1853 /************************************************************************
1854 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1856 * See Windows documentation for more details on IUnknown methods.
1858 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1859 IDispatch* iface,
1860 REFIID riid,
1861 VOID** ppvoid)
1863 OLEPictureImpl *This = impl_from_IDispatch(iface);
1865 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1868 /************************************************************************
1869 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1871 * See Windows documentation for more details on IUnknown methods.
1873 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1874 IDispatch* iface)
1876 OLEPictureImpl *This = impl_from_IDispatch(iface);
1878 return IPicture_AddRef(&This->IPicture_iface);
1881 /************************************************************************
1882 * OLEPictureImpl_IDispatch_Release (IUnknown)
1884 * See Windows documentation for more details on IUnknown methods.
1886 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1887 IDispatch* iface)
1889 OLEPictureImpl *This = impl_from_IDispatch(iface);
1891 return IPicture_Release(&This->IPicture_iface);
1894 /************************************************************************
1895 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1897 * See Windows documentation for more details on IDispatch methods.
1899 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1900 IDispatch* iface,
1901 unsigned int* pctinfo)
1903 TRACE("(%p)\n", pctinfo);
1905 *pctinfo = 1;
1907 return S_OK;
1910 /************************************************************************
1911 * OLEPictureImpl_GetTypeInfo (IDispatch)
1913 * See Windows documentation for more details on IDispatch methods.
1915 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1916 IDispatch* iface,
1917 UINT iTInfo,
1918 LCID lcid,
1919 ITypeInfo** ppTInfo)
1921 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1922 ITypeLib *tl;
1923 HRESULT hres;
1925 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1927 if (iTInfo != 0)
1928 return E_FAIL;
1930 hres = LoadTypeLib(stdole2tlb, &tl);
1931 if (FAILED(hres))
1933 ERR("Could not load stdole2.tlb\n");
1934 return hres;
1937 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1938 if (FAILED(hres))
1939 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1941 return hres;
1944 /************************************************************************
1945 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1947 * See Windows documentation for more details on IDispatch methods.
1949 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1950 IDispatch* iface,
1951 REFIID riid,
1952 LPOLESTR* rgszNames,
1953 UINT cNames,
1954 LCID lcid,
1955 DISPID* rgDispId)
1957 ITypeInfo * pTInfo;
1958 HRESULT hres;
1960 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1961 rgszNames, cNames, (int)lcid, rgDispId);
1963 if (cNames == 0)
1965 return E_INVALIDARG;
1967 else
1969 /* retrieve type information */
1970 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1972 if (FAILED(hres))
1974 ERR("GetTypeInfo failed.\n");
1975 return hres;
1978 /* convert names to DISPIDs */
1979 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1980 ITypeInfo_Release(pTInfo);
1982 return hres;
1986 /************************************************************************
1987 * OLEPictureImpl_Invoke (IDispatch)
1989 * See Windows documentation for more details on IDispatch methods.
1991 static HRESULT WINAPI OLEPictureImpl_Invoke(
1992 IDispatch* iface,
1993 DISPID dispIdMember,
1994 REFIID riid,
1995 LCID lcid,
1996 WORD wFlags,
1997 DISPPARAMS* pDispParams,
1998 VARIANT* pVarResult,
1999 EXCEPINFO* pExepInfo,
2000 UINT* puArgErr)
2002 OLEPictureImpl *This = impl_from_IDispatch(iface);
2003 HRESULT hr;
2005 /* validate parameters */
2007 if (!IsEqualIID(riid, &IID_NULL))
2009 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2010 return DISP_E_UNKNOWNNAME;
2013 if (!pDispParams)
2015 ERR("null pDispParams not allowed\n");
2016 return DISP_E_PARAMNOTOPTIONAL;
2019 if (wFlags & DISPATCH_PROPERTYGET)
2021 if (pDispParams->cArgs != 0)
2023 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2024 return DISP_E_BADPARAMCOUNT;
2026 if (!pVarResult)
2028 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2029 return DISP_E_PARAMNOTOPTIONAL;
2032 else if (wFlags & DISPATCH_PROPERTYPUT)
2034 if (pDispParams->cArgs != 1)
2036 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2037 return DISP_E_BADPARAMCOUNT;
2041 switch (dispIdMember)
2043 case DISPID_PICT_HANDLE:
2044 if (wFlags & DISPATCH_PROPERTYGET)
2046 TRACE("DISPID_PICT_HANDLE\n");
2047 V_VT(pVarResult) = VT_I4;
2048 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2050 break;
2051 case DISPID_PICT_HPAL:
2052 if (wFlags & DISPATCH_PROPERTYGET)
2054 TRACE("DISPID_PICT_HPAL\n");
2055 V_VT(pVarResult) = VT_I4;
2056 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2058 else if (wFlags & DISPATCH_PROPERTYPUT)
2060 VARIANTARG vararg;
2062 TRACE("DISPID_PICT_HPAL\n");
2064 VariantInit(&vararg);
2065 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2066 if (FAILED(hr))
2067 return hr;
2069 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2071 VariantClear(&vararg);
2072 return hr;
2074 break;
2075 case DISPID_PICT_TYPE:
2076 if (wFlags & DISPATCH_PROPERTYGET)
2078 TRACE("DISPID_PICT_TYPE\n");
2079 V_VT(pVarResult) = VT_I2;
2080 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2082 break;
2083 case DISPID_PICT_WIDTH:
2084 if (wFlags & DISPATCH_PROPERTYGET)
2086 TRACE("DISPID_PICT_WIDTH\n");
2087 V_VT(pVarResult) = VT_I4;
2088 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2090 break;
2091 case DISPID_PICT_HEIGHT:
2092 if (wFlags & DISPATCH_PROPERTYGET)
2094 TRACE("DISPID_PICT_HEIGHT\n");
2095 V_VT(pVarResult) = VT_I4;
2096 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2098 break;
2099 case DISPID_PICT_RENDER:
2100 if (wFlags & DISPATCH_METHOD)
2102 VARIANTARG *args = pDispParams->rgvarg;
2103 int i;
2105 TRACE("DISPID_PICT_RENDER\n");
2107 if (pDispParams->cArgs != 10)
2108 return DISP_E_BADPARAMCOUNT;
2110 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2111 for (i = 0; i < pDispParams->cArgs; i++)
2112 if (V_VT(&args[i]) != VT_I4)
2114 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i, V_VT(&args[i]));
2115 return DISP_E_TYPEMISMATCH;
2118 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2119 currently Render() doesn't use it at all so for now NULL is passed. */
2120 return IPicture_Render(&This->IPicture_iface,
2121 LongToHandle(V_I4(&args[9])),
2122 V_I4(&args[8]),
2123 V_I4(&args[7]),
2124 V_I4(&args[6]),
2125 V_I4(&args[5]),
2126 V_I4(&args[4]),
2127 V_I4(&args[3]),
2128 V_I4(&args[2]),
2129 V_I4(&args[1]),
2130 NULL);
2132 break;
2135 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2136 return DISP_E_MEMBERNOTFOUND;
2140 static const IPictureVtbl OLEPictureImpl_VTable =
2142 OLEPictureImpl_QueryInterface,
2143 OLEPictureImpl_AddRef,
2144 OLEPictureImpl_Release,
2145 OLEPictureImpl_get_Handle,
2146 OLEPictureImpl_get_hPal,
2147 OLEPictureImpl_get_Type,
2148 OLEPictureImpl_get_Width,
2149 OLEPictureImpl_get_Height,
2150 OLEPictureImpl_Render,
2151 OLEPictureImpl_set_hPal,
2152 OLEPictureImpl_get_CurDC,
2153 OLEPictureImpl_SelectPicture,
2154 OLEPictureImpl_get_KeepOriginalFormat,
2155 OLEPictureImpl_put_KeepOriginalFormat,
2156 OLEPictureImpl_PictureChanged,
2157 OLEPictureImpl_SaveAsFile,
2158 OLEPictureImpl_get_Attributes
2161 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2163 OLEPictureImpl_IDispatch_QueryInterface,
2164 OLEPictureImpl_IDispatch_AddRef,
2165 OLEPictureImpl_IDispatch_Release,
2166 OLEPictureImpl_GetTypeInfoCount,
2167 OLEPictureImpl_GetTypeInfo,
2168 OLEPictureImpl_GetIDsOfNames,
2169 OLEPictureImpl_Invoke
2172 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2174 OLEPictureImpl_IPersistStream_QueryInterface,
2175 OLEPictureImpl_IPersistStream_AddRef,
2176 OLEPictureImpl_IPersistStream_Release,
2177 OLEPictureImpl_GetClassID,
2178 OLEPictureImpl_IsDirty,
2179 OLEPictureImpl_Load,
2180 OLEPictureImpl_Save,
2181 OLEPictureImpl_GetSizeMax
2184 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2186 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2187 OLEPictureImpl_IConnectionPointContainer_AddRef,
2188 OLEPictureImpl_IConnectionPointContainer_Release,
2189 OLEPictureImpl_EnumConnectionPoints,
2190 OLEPictureImpl_FindConnectionPoint
2193 /***********************************************************************
2194 * OleCreatePictureIndirect (OLEAUT32.419)
2196 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2197 BOOL Own, void **ppvObj )
2199 OLEPictureImpl* newPict;
2200 HRESULT hr;
2202 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2204 *ppvObj = NULL;
2206 newPict = OLEPictureImpl_Construct(lpPictDesc, Own);
2208 if (newPict == NULL)
2209 return E_OUTOFMEMORY;
2212 * Make sure it supports the interface required by the caller.
2214 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2217 * Release the reference obtained in the constructor. If
2218 * the QueryInterface was unsuccessful, it will free the class.
2220 IPicture_Release(&newPict->IPicture_iface);
2222 return hr;
2226 /***********************************************************************
2227 * OleLoadPicture (OLEAUT32.418)
2229 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2230 REFIID riid, LPVOID *ppvObj )
2232 LPPERSISTSTREAM ps;
2233 IPicture *newpic;
2234 HRESULT hr;
2236 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2237 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2239 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2240 if (hr != S_OK)
2241 return hr;
2242 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2243 if (hr != S_OK) {
2244 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2245 IPicture_Release(newpic);
2246 *ppvObj = NULL;
2247 return hr;
2249 hr = IPersistStream_Load(ps,lpstream);
2250 IPersistStream_Release(ps);
2251 if (FAILED(hr))
2253 ERR("IPersistStream_Load failed\n");
2254 IPicture_Release(newpic);
2255 *ppvObj = NULL;
2256 return hr;
2258 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2259 if (hr != S_OK)
2260 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2261 IPicture_Release(newpic);
2262 return hr;
2265 /***********************************************************************
2266 * OleLoadPictureEx (OLEAUT32.401)
2268 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2269 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2271 LPPERSISTSTREAM ps;
2272 IPicture *newpic;
2273 HRESULT hr;
2275 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2276 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2278 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2279 if (hr != S_OK)
2280 return hr;
2281 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2282 if (hr != S_OK) {
2283 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2284 IPicture_Release(newpic);
2285 *ppvObj = NULL;
2286 return hr;
2288 hr = IPersistStream_Load(ps,lpstream);
2289 IPersistStream_Release(ps);
2290 if (FAILED(hr))
2292 ERR("IPersistStream_Load failed\n");
2293 IPicture_Release(newpic);
2294 *ppvObj = NULL;
2295 return hr;
2297 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2298 if (hr != S_OK)
2299 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2300 IPicture_Release(newpic);
2301 return hr;
2304 /***********************************************************************
2305 * OleLoadPicturePath (OLEAUT32.424)
2307 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2308 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2309 LPVOID *ppvRet )
2311 static const WCHAR file[] = { 'f','i','l','e',':',0 };
2312 IPicture *ipicture;
2313 HANDLE hFile;
2314 DWORD dwFileSize;
2315 HGLOBAL hGlobal = NULL;
2316 DWORD dwBytesRead;
2317 IStream *stream;
2318 BOOL bRead;
2319 IPersistStream *pStream;
2320 HRESULT hRes;
2321 HRESULT init_res;
2322 WCHAR *file_candidate;
2323 WCHAR path_buf[MAX_PATH];
2325 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2326 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2327 debugstr_guid(riid), ppvRet);
2329 if (!szURLorPath || !ppvRet)
2330 return E_INVALIDARG;
2332 *ppvRet = NULL;
2334 /* Convert file URLs to DOS paths. */
2335 if (strncmpW(szURLorPath, file, 5) == 0) {
2336 DWORD size;
2337 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2338 sizeof(path_buf)/sizeof(WCHAR), &size, 0);
2339 if (FAILED(hRes))
2340 return hRes;
2342 file_candidate = path_buf;
2344 else
2345 file_candidate = szURLorPath;
2347 /* Handle candidate DOS paths separately. */
2348 if (file_candidate[1] == ':') {
2349 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2350 0, NULL);
2351 if (hFile == INVALID_HANDLE_VALUE)
2352 return INET_E_RESOURCE_NOT_FOUND;
2354 dwFileSize = GetFileSize(hFile, NULL);
2355 if (dwFileSize != INVALID_FILE_SIZE )
2357 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2358 if ( hGlobal)
2360 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL) && dwBytesRead == dwFileSize;
2361 if (!bRead)
2363 GlobalFree(hGlobal);
2364 hGlobal = 0;
2368 CloseHandle(hFile);
2370 if (!hGlobal)
2371 return INET_E_RESOURCE_NOT_FOUND;
2373 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2374 if (FAILED(hRes))
2376 GlobalFree(hGlobal);
2377 return hRes;
2379 } else {
2380 IMoniker *pmnk;
2381 IBindCtx *pbc;
2383 hRes = CreateBindCtx(0, &pbc);
2384 if (SUCCEEDED(hRes))
2386 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2387 if (SUCCEEDED(hRes))
2389 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2390 IMoniker_Release(pmnk);
2392 IBindCtx_Release(pbc);
2394 if (FAILED(hRes))
2395 return hRes;
2398 init_res = CoInitialize(NULL);
2400 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2401 &IID_IPicture, (LPVOID*)&ipicture);
2402 if (SUCCEEDED(hRes)) {
2403 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2405 if (SUCCEEDED(hRes)) {
2406 hRes = IPersistStream_Load(pStream, stream);
2408 if (SUCCEEDED(hRes)) {
2409 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2411 if (FAILED(hRes))
2412 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2414 IPersistStream_Release(pStream);
2416 IPicture_Release(ipicture);
2419 IStream_Release(stream);
2421 if (SUCCEEDED(init_res))
2422 CoUninitialize();
2424 return hRes;
2427 /*******************************************************************************
2428 * StdPic ClassFactory
2430 typedef struct
2432 /* IUnknown fields */
2433 IClassFactory IClassFactory_iface;
2434 LONG ref;
2435 } IClassFactoryImpl;
2437 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2439 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2442 static HRESULT WINAPI
2443 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2444 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2446 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2447 return E_NOINTERFACE;
2450 static ULONG WINAPI
2451 SPCF_AddRef(LPCLASSFACTORY iface) {
2452 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2453 return InterlockedIncrement(&This->ref);
2456 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2457 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2458 /* static class, won't be freed */
2459 return InterlockedDecrement(&This->ref);
2462 static HRESULT WINAPI SPCF_CreateInstance(
2463 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2465 /* Creates an uninitialized picture */
2466 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2470 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2471 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2472 FIXME("(%p)->(%d),stub!\n",This,dolock);
2473 return S_OK;
2476 static const IClassFactoryVtbl SPCF_Vtbl = {
2477 SPCF_QueryInterface,
2478 SPCF_AddRef,
2479 SPCF_Release,
2480 SPCF_CreateInstance,
2481 SPCF_LockServer
2483 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2485 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }