d2d1: Implement d2d_radial_gradient_brush_SetCenter().
[wine.git] / dlls / oleaut32 / olepicture.c
blobac8b2072071048227695e5cf947dec544038eedd
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
52 #include "winerror.h"
53 #include "windef.h"
54 #include "winbase.h"
55 #include "wingdi.h"
56 #include "winuser.h"
57 #include "ole2.h"
58 #include "olectl.h"
59 #include "oleauto.h"
60 #include "connpt.h"
61 #include "urlmon.h"
62 #include "initguid.h"
63 #include "wincodec.h"
64 #include "wine/debug.h"
65 #include "wine/unicode.h"
66 #include "wine/library.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(olepicture);
70 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
71 #define BITMAP_FORMAT_JPEG 0xd8ff
72 #define BITMAP_FORMAT_GIF 0x4947
73 #define BITMAP_FORMAT_PNG 0x5089
74 #define BITMAP_FORMAT_APM 0xcdd7
76 #include "pshpack1.h"
78 /* Header for Aldus Placable Metafiles - a standard metafile follows */
79 typedef struct _APM_HEADER
81 DWORD key;
82 WORD handle;
83 SHORT left;
84 SHORT top;
85 SHORT right;
86 SHORT bottom;
87 WORD inch;
88 DWORD reserved;
89 WORD checksum;
90 } APM_HEADER;
92 typedef struct {
93 BYTE bWidth;
94 BYTE bHeight;
95 BYTE bColorCount;
96 BYTE bReserved;
97 WORD xHotspot;
98 WORD yHotspot;
99 DWORD dwDIBSize;
100 DWORD dwDIBOffset;
101 } CURSORICONFILEDIRENTRY;
103 typedef struct
105 WORD idReserved;
106 WORD idType;
107 WORD idCount;
108 CURSORICONFILEDIRENTRY idEntries[1];
109 } CURSORICONFILEDIR;
111 #include "poppack.h"
113 /*************************************************************************
114 * Declaration of implementation class
117 typedef struct OLEPictureImpl {
120 * IPicture handles IUnknown
123 IPicture IPicture_iface;
124 IDispatch IDispatch_iface;
125 IPersistStream IPersistStream_iface;
126 IConnectionPointContainer IConnectionPointContainer_iface;
128 /* Object reference count */
129 LONG ref;
131 /* We own the object and must destroy it ourselves */
132 BOOL fOwn;
134 /* Picture description */
135 PICTDESC desc;
137 /* These are the pixel size of a bitmap */
138 DWORD origWidth;
139 DWORD origHeight;
141 /* And these are the size of the picture converted into HIMETRIC units */
142 OLE_XSIZE_HIMETRIC himetricWidth;
143 OLE_YSIZE_HIMETRIC himetricHeight;
145 IConnectionPoint *pCP;
147 BOOL keepOrigFormat;
148 HDC hDCCur;
149 HBITMAP stock_bitmap;
151 /* Bitmap transparency mask */
152 HBITMAP hbmMask;
153 HBITMAP hbmXor;
154 COLORREF rgbTrans;
156 /* data */
157 void* data;
158 int datalen;
159 BOOL bIsDirty; /* Set to TRUE if picture has changed */
160 unsigned int loadtime_magic; /* If a length header was found, saves value */
161 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
162 } OLEPictureImpl;
164 static inline OLEPictureImpl *impl_from_IPicture(IPicture *iface)
166 return CONTAINING_RECORD(iface, OLEPictureImpl, IPicture_iface);
169 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
171 return CONTAINING_RECORD(iface, OLEPictureImpl, IDispatch_iface);
174 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
176 return CONTAINING_RECORD(iface, OLEPictureImpl, IPersistStream_iface);
179 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
181 return CONTAINING_RECORD(iface, OLEPictureImpl, IConnectionPointContainer_iface);
185 * Predeclare VTables. They get initialized at the end.
187 static const IPictureVtbl OLEPictureImpl_VTable;
188 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
189 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
190 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
192 /* pixels to HIMETRIC units conversion */
193 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
195 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
198 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
200 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
203 /***********************************************************************
204 * Implementation of the OLEPictureImpl class.
207 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
209 BITMAP bm;
210 HDC hdcRef;
212 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
213 if(GetObjectW(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
214 ERR("GetObject fails\n");
215 return;
217 This->origWidth = bm.bmWidth;
218 This->origHeight = bm.bmHeight;
220 TRACE("width %d, height %d, bpp %d\n", bm.bmWidth, bm.bmHeight, bm.bmBitsPixel);
222 /* The width and height are stored in HIMETRIC units (0.01 mm),
223 so we take our pixel width divide by pixels per inch and
224 multiply by 25.4 * 100 */
225 /* Should we use GetBitmapDimension if available? */
226 hdcRef = CreateCompatibleDC(0);
228 This->himetricWidth = xpixels_to_himetric(bm.bmWidth, hdcRef);
229 This->himetricHeight = ypixels_to_himetric(bm.bmHeight, hdcRef);
230 This->stock_bitmap = GetCurrentObject( hdcRef, OBJ_BITMAP );
232 This->loadtime_format = BITMAP_FORMAT_BMP;
234 DeleteDC(hdcRef);
237 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
239 ICONINFO infoIcon;
241 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
242 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
243 HDC hdcRef;
244 BITMAP bm;
246 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
247 if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
248 ERR("GetObject fails on icon bitmap\n");
249 return;
252 This->origWidth = bm.bmWidth;
253 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
254 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
255 hdcRef = GetDC(0);
257 This->himetricWidth = xpixels_to_himetric(This->origWidth, hdcRef);
258 This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
260 ReleaseDC(0, hdcRef);
262 DeleteObject(infoIcon.hbmMask);
263 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
264 } else {
265 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
269 /************************************************************************
270 * OLEPictureImpl_Construct
272 * This method will construct a new instance of the OLEPictureImpl
273 * class.
275 * The caller of this method must release the object when it's
276 * done with it.
278 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
280 OLEPictureImpl* newObject = 0;
282 if (pictDesc)
283 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
286 * Allocate space for the object.
288 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
290 if (newObject==0)
291 return newObject;
294 * Initialize the virtual function table.
296 newObject->IPicture_iface.lpVtbl = &OLEPictureImpl_VTable;
297 newObject->IDispatch_iface.lpVtbl = &OLEPictureImpl_IDispatch_VTable;
298 newObject->IPersistStream_iface.lpVtbl = &OLEPictureImpl_IPersistStream_VTable;
299 newObject->IConnectionPointContainer_iface.lpVtbl = &OLEPictureImpl_IConnectionPointContainer_VTable;
301 newObject->pCP = NULL;
302 CreateConnectionPoint((IUnknown*)&newObject->IPicture_iface, &IID_IPropertyNotifySink,
303 &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->IPicture_iface;
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 unsupported 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 %s\n", wine_dbgstr_rect(prcWBounds));
642 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
643 return CTL_E_INVALIDPROPERTYVALUE;
647 * While the documentation suggests this to be here (or after rendering?)
648 * it does cause an endless recursion in my sample app. -MM 20010804
649 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
652 switch(This->desc.picType) {
653 case PICTYPE_UNINITIALIZED:
654 case PICTYPE_NONE:
655 /* nothing to do */
656 return S_OK;
657 case PICTYPE_BITMAP:
659 HBITMAP hbmpOld;
660 HDC hdcBmp;
662 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
663 NB y-axis gets flipped */
665 hdcBmp = CreateCompatibleDC(0);
666 SetMapMode(hdcBmp, MM_ANISOTROPIC);
667 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
668 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
669 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
670 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
672 if (This->hbmMask) {
673 HDC hdcMask = CreateCompatibleDC(0);
674 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
676 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
678 SetMapMode(hdcMask, MM_ANISOTROPIC);
679 SetWindowOrgEx(hdcMask, 0, 0, NULL);
680 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
681 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
682 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
684 SetBkColor(hdc, RGB(255, 255, 255));
685 SetTextColor(hdc, RGB(0, 0, 0));
686 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
687 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
689 SelectObject(hdcMask, hOldbm);
690 DeleteDC(hdcMask);
691 } else {
692 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
693 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
696 SelectObject(hdcBmp, hbmpOld);
697 DeleteDC(hdcBmp);
699 break;
700 case PICTYPE_ICON:
701 FIXME("Not quite correct implementation of rendering icons...\n");
702 DrawIconEx(hdc, x, y, This->desc.u.icon.hicon, cx, cy, 0, NULL, DI_NORMAL);
703 break;
705 case PICTYPE_METAFILE:
707 POINT prevOrg, prevWndOrg;
708 SIZE prevExt, prevWndExt;
709 int oldmode;
711 /* Render the WMF to the appropriate location by setting the
712 appropriate ratio between "device units" and "logical units" */
713 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
714 /* For the "source rectangle" the y-axis must be inverted */
715 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
716 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
717 /* For the "destination rectangle" no inversion is necessary */
718 SetViewportOrgEx(hdc, x, y, &prevOrg);
719 SetViewportExtEx(hdc, cx, cy, &prevExt);
721 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
722 ERR("PlayMetaFile failed!\n");
724 /* We're done, restore the DC to the previous settings for converting
725 logical units to device units */
726 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
727 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
728 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
729 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
730 SetMapMode(hdc, oldmode);
731 break;
734 case PICTYPE_ENHMETAFILE:
736 RECT rc = { x, y, x + cx, y + cy };
737 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
738 break;
741 default:
742 FIXME("type %d not implemented\n", This->desc.picType);
743 return E_NOTIMPL;
745 return S_OK;
748 /************************************************************************
749 * OLEPictureImpl_set_hPal
751 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
752 OLE_HANDLE hpal)
754 OLEPictureImpl *This = impl_from_IPicture(iface);
755 FIXME("(%p)->(%08x): stub\n", This, hpal);
756 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
757 return E_NOTIMPL;
760 /************************************************************************
761 * OLEPictureImpl_get_CurDC
763 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
764 HDC *phdc)
766 OLEPictureImpl *This = impl_from_IPicture(iface);
767 TRACE("(%p), returning %p\n", This, This->hDCCur);
768 if (phdc) *phdc = This->hDCCur;
769 return S_OK;
772 /************************************************************************
773 * OLEPictureImpl_SelectPicture
775 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
776 HDC hdcIn,
777 HDC *phdcOut,
778 OLE_HANDLE *phbmpOut)
780 OLEPictureImpl *This = impl_from_IPicture(iface);
781 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
782 if (This->desc.picType == PICTYPE_BITMAP) {
783 if (phdcOut)
784 *phdcOut = This->hDCCur;
785 if (This->hDCCur) SelectObject(This->hDCCur,This->stock_bitmap);
786 if (hdcIn) SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
787 This->hDCCur = hdcIn;
788 if (phbmpOut)
789 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
790 return S_OK;
791 } else {
792 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
793 return E_FAIL;
797 /************************************************************************
798 * OLEPictureImpl_get_KeepOriginalFormat
800 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
801 BOOL *pfKeep)
803 OLEPictureImpl *This = impl_from_IPicture(iface);
804 TRACE("(%p)->(%p)\n", This, pfKeep);
805 if (!pfKeep)
806 return E_POINTER;
807 *pfKeep = This->keepOrigFormat;
808 return S_OK;
811 /************************************************************************
812 * OLEPictureImpl_put_KeepOriginalFormat
814 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
815 BOOL keep)
817 OLEPictureImpl *This = impl_from_IPicture(iface);
818 TRACE("(%p)->(%d)\n", This, keep);
819 This->keepOrigFormat = keep;
820 /* FIXME: what DISPID notification here? */
821 return S_OK;
824 /************************************************************************
825 * OLEPictureImpl_PictureChanged
827 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
829 OLEPictureImpl *This = impl_from_IPicture(iface);
830 TRACE("(%p)->()\n", This);
831 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
832 This->bIsDirty = TRUE;
833 return S_OK;
836 /************************************************************************
837 * OLEPictureImpl_SaveAsFile
839 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
840 IStream *pstream,
841 BOOL SaveMemCopy,
842 LONG *pcbSize)
844 OLEPictureImpl *This = impl_from_IPicture(iface);
845 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
846 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
849 /************************************************************************
850 * OLEPictureImpl_get_Attributes
852 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
853 DWORD *pdwAttr)
855 OLEPictureImpl *This = impl_from_IPicture(iface);
856 TRACE("(%p)->(%p).\n", This, pdwAttr);
858 if(!pdwAttr)
859 return E_POINTER;
861 *pdwAttr = 0;
862 switch (This->desc.picType) {
863 case PICTYPE_UNINITIALIZED:
864 case PICTYPE_NONE: break;
865 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
866 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
867 case PICTYPE_ENHMETAFILE: /* fall through */
868 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
869 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
871 return S_OK;
875 /************************************************************************
876 * IConnectionPointContainer
878 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
879 IConnectionPointContainer* iface,
880 REFIID riid,
881 VOID** ppvoid)
883 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
885 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
888 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
889 IConnectionPointContainer* iface)
891 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
893 return IPicture_AddRef(&This->IPicture_iface);
896 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
897 IConnectionPointContainer* iface)
899 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
901 return IPicture_Release(&This->IPicture_iface);
904 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
905 IConnectionPointContainer* iface,
906 IEnumConnectionPoints** ppEnum)
908 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
910 FIXME("(%p,%p), stub!\n",This,ppEnum);
911 return E_NOTIMPL;
914 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
915 IConnectionPointContainer* iface,
916 REFIID riid,
917 IConnectionPoint **ppCP)
919 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
920 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
921 if (!ppCP)
922 return E_POINTER;
923 *ppCP = NULL;
924 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
925 return IConnectionPoint_QueryInterface(This->pCP, &IID_IConnectionPoint, (void**)ppCP);
926 FIXME("no connection point for %s\n",debugstr_guid(riid));
927 return CONNECT_E_NOCONNECTION;
931 /************************************************************************
932 * IPersistStream
935 /************************************************************************
936 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
938 * See Windows documentation for more details on IUnknown methods.
940 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
941 IPersistStream* iface,
942 REFIID riid,
943 VOID** ppvoid)
945 OLEPictureImpl *This = impl_from_IPersistStream(iface);
947 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
950 /************************************************************************
951 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
953 * See Windows documentation for more details on IUnknown methods.
955 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
956 IPersistStream* iface)
958 OLEPictureImpl *This = impl_from_IPersistStream(iface);
960 return IPicture_AddRef(&This->IPicture_iface);
963 /************************************************************************
964 * OLEPictureImpl_IPersistStream_Release (IUnknown)
966 * See Windows documentation for more details on IUnknown methods.
968 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
969 IPersistStream* iface)
971 OLEPictureImpl *This = impl_from_IPersistStream(iface);
973 return IPicture_Release(&This->IPicture_iface);
976 /************************************************************************
977 * OLEPictureImpl_IPersistStream_GetClassID
979 static HRESULT WINAPI OLEPictureImpl_GetClassID(
980 IPersistStream* iface,CLSID* pClassID)
982 TRACE("(%p)\n", pClassID);
983 *pClassID = CLSID_StdPicture;
984 return S_OK;
987 /************************************************************************
988 * OLEPictureImpl_IPersistStream_IsDirty
990 static HRESULT WINAPI OLEPictureImpl_IsDirty(
991 IPersistStream* iface)
993 OLEPictureImpl *This = impl_from_IPersistStream(iface);
994 FIXME("(%p),stub!\n",This);
995 return E_NOTIMPL;
998 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1000 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1001 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1002 HDC hdcref;
1004 /* Does not matter whether this is a coreheader or not, we only use
1005 * components which are in both
1007 hdcref = GetDC(0);
1008 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1009 hdcref,
1010 &(bi->bmiHeader),
1011 CBM_INIT,
1012 xbuf+bfh->bfOffBits,
1014 DIB_RGB_COLORS
1016 ReleaseDC(0, hdcref);
1017 if (This->desc.u.bmp.hbitmap == 0)
1018 return E_FAIL;
1019 This->desc.picType = PICTYPE_BITMAP;
1020 OLEPictureImpl_SetBitmap(This);
1021 return S_OK;
1024 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1026 HRESULT hr;
1027 BITMAPINFOHEADER bih;
1028 HDC hdcref;
1029 UINT width, height;
1030 UINT stride, buffersize;
1031 LPBYTE bits=NULL;
1032 WICRect rc;
1033 IWICBitmapSource *real_source;
1034 UINT x, y;
1035 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1036 BOOL has_alpha=FALSE;
1038 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1039 if (FAILED(hr)) return hr;
1041 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1042 if (FAILED(hr)) goto end;
1044 bih.biSize = sizeof(bih);
1045 bih.biWidth = width;
1046 bih.biHeight = -height;
1047 bih.biPlanes = 1;
1048 bih.biBitCount = 32;
1049 bih.biCompression = BI_RGB;
1050 bih.biSizeImage = 0;
1051 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1052 bih.biYPelsPerMeter = 4085;
1053 bih.biClrUsed = 0;
1054 bih.biClrImportant = 0;
1056 stride = 4 * width;
1057 buffersize = stride * height;
1059 bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1060 if (!bits)
1062 hr = E_OUTOFMEMORY;
1063 goto end;
1066 rc.X = 0;
1067 rc.Y = 0;
1068 rc.Width = width;
1069 rc.Height = height;
1070 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1071 if (FAILED(hr))
1072 goto end;
1074 hdcref = GetDC(0);
1075 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1076 hdcref,
1077 &bih,
1078 CBM_INIT,
1079 bits,
1080 (BITMAPINFO*)&bih,
1081 DIB_RGB_COLORS);
1083 if (This->desc.u.bmp.hbitmap == 0)
1085 hr = E_FAIL;
1086 ReleaseDC(0, hdcref);
1087 goto end;
1090 This->desc.picType = PICTYPE_BITMAP;
1091 OLEPictureImpl_SetBitmap(This);
1093 /* set transparent pixels to black, all others to white */
1094 for(y = 0; y < height; y++){
1095 for(x = 0; x < width; x++){
1096 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1097 if((*pixel & 0x80000000) == 0)
1099 has_alpha = TRUE;
1100 *pixel = black;
1102 else
1103 *pixel = white;
1107 if (has_alpha)
1109 HDC hdcBmp, hdcXor, hdcMask;
1110 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1112 This->hbmXor = CreateDIBitmap(
1113 hdcref,
1114 &bih,
1115 CBM_INIT,
1116 bits,
1117 (BITMAPINFO*)&bih,
1118 DIB_RGB_COLORS
1121 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1122 hdcBmp = CreateCompatibleDC(NULL);
1123 hdcXor = CreateCompatibleDC(NULL);
1124 hdcMask = CreateCompatibleDC(NULL);
1126 hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1127 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1128 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1130 SetBkColor(hdcXor,black);
1131 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1132 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1134 SelectObject(hdcBmp,hbmoldBmp);
1135 SelectObject(hdcXor,hbmoldXor);
1136 SelectObject(hdcMask,hbmoldMask);
1138 DeleteDC(hdcBmp);
1139 DeleteDC(hdcXor);
1140 DeleteDC(hdcMask);
1143 ReleaseDC(0, hdcref);
1145 end:
1146 HeapFree(GetProcessHeap(), 0, bits);
1147 IWICBitmapSource_Release(real_source);
1148 return hr;
1151 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1153 HRESULT hr;
1154 IWICImagingFactory *factory;
1155 IWICBitmapDecoder *decoder;
1156 IWICBitmapFrameDecode *framedecode;
1157 HRESULT initresult;
1158 IWICStream *stream;
1160 initresult = CoInitialize(NULL);
1162 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1163 &IID_IWICImagingFactory, (void**)&factory);
1164 if (SUCCEEDED(hr)) /* created factory */
1166 hr = IWICImagingFactory_CreateStream(factory, &stream);
1167 IWICImagingFactory_Release(factory);
1170 if (SUCCEEDED(hr)) /* created stream */
1172 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1174 if (SUCCEEDED(hr)) /* initialized stream */
1176 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1177 &IID_IWICBitmapDecoder, (void**)&decoder);
1178 if (SUCCEEDED(hr)) /* created decoder */
1180 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1182 if (SUCCEEDED(hr)) /* initialized decoder */
1183 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1185 IWICBitmapDecoder_Release(decoder);
1189 IWICStream_Release(stream);
1192 if (SUCCEEDED(hr)) /* got framedecode */
1194 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1195 IWICBitmapFrameDecode_Release(framedecode);
1198 if (SUCCEEDED(initresult)) CoUninitialize();
1199 return hr;
1202 /*****************************************************
1203 * start of Icon-specific code
1206 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1208 HICON hicon;
1209 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1210 HDC hdcRef;
1211 int i;
1213 TRACE("(this %p, xbuf %p, xread %u)\n", This, xbuf, xread);
1216 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1217 FIXME("icon.idType=%d\n",cifd->idType);
1218 FIXME("icon.idCount=%d\n",cifd->idCount);
1220 for (i=0;i<cifd->idCount;i++) {
1221 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1222 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1223 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1224 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1225 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1226 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1227 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1228 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1232 /* Need at least one icon to do something. */
1233 if (!cifd->idCount)
1235 ERR("Invalid icon count of zero.\n");
1236 return E_FAIL;
1238 i=0;
1239 /* If we have more than one icon, try to find the best.
1240 * this currently means '32 pixel wide'.
1242 if (cifd->idCount!=1) {
1243 for (i=0;i<cifd->idCount;i++) {
1244 if (cifd->idEntries[i].bWidth == 32)
1245 break;
1247 if (i==cifd->idCount) i=0;
1249 if (xread < cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize)
1251 ERR("Icon data address %u is over %u bytes available.\n",
1252 cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize, xread);
1253 return E_FAIL;
1255 if (cifd->idType == 2)
1257 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, cifd->idEntries[i].dwDIBSize + 4);
1258 memcpy(buf, &cifd->idEntries[i].xHotspot, 4);
1259 memcpy(buf + 4, xbuf+cifd->idEntries[i].dwDIBOffset, cifd->idEntries[i].dwDIBSize);
1260 hicon = CreateIconFromResourceEx(
1261 buf,
1262 cifd->idEntries[i].dwDIBSize + 4,
1263 FALSE, /* is cursor */
1264 0x00030000,
1265 cifd->idEntries[i].bWidth,
1266 cifd->idEntries[i].bHeight,
1269 HeapFree(GetProcessHeap(), 0, buf);
1271 else
1273 hicon = CreateIconFromResourceEx(
1274 xbuf+cifd->idEntries[i].dwDIBOffset,
1275 cifd->idEntries[i].dwDIBSize,
1276 TRUE, /* is icon */
1277 0x00030000,
1278 cifd->idEntries[i].bWidth,
1279 cifd->idEntries[i].bHeight,
1283 if (!hicon) {
1284 ERR("CreateIcon failed.\n");
1285 return E_FAIL;
1286 } else {
1287 This->desc.picType = PICTYPE_ICON;
1288 This->desc.u.icon.hicon = hicon;
1289 This->origWidth = cifd->idEntries[i].bWidth;
1290 This->origHeight = cifd->idEntries[i].bHeight;
1291 hdcRef = CreateCompatibleDC(0);
1292 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1293 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1294 DeleteDC(hdcRef);
1295 return S_OK;
1299 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1300 const BYTE *data, ULONG size)
1302 HENHMETAFILE hemf;
1303 ENHMETAHEADER hdr;
1305 hemf = SetEnhMetaFileBits(size, data);
1306 if (!hemf) return E_FAIL;
1308 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1310 This->desc.picType = PICTYPE_ENHMETAFILE;
1311 This->desc.u.emf.hemf = hemf;
1313 This->origWidth = 0;
1314 This->origHeight = 0;
1315 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1316 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1318 return S_OK;
1321 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1322 const BYTE *data, ULONG size)
1324 const APM_HEADER *header = (const APM_HEADER *)data;
1325 HMETAFILE hmf;
1327 if (size < sizeof(APM_HEADER))
1328 return E_FAIL;
1329 if (header->key != 0x9ac6cdd7)
1330 return E_FAIL;
1332 /* SetMetaFileBitsEx performs data check on its own */
1333 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1334 if (!hmf) return E_FAIL;
1336 This->desc.picType = PICTYPE_METAFILE;
1337 This->desc.u.wmf.hmeta = hmf;
1338 This->desc.u.wmf.xExt = 0;
1339 This->desc.u.wmf.yExt = 0;
1341 This->origWidth = 0;
1342 This->origHeight = 0;
1343 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1344 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1345 return S_OK;
1348 /************************************************************************
1349 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1351 * Loads the binary data from the IStream. Starts at current position.
1352 * There appears to be an 2 DWORD header:
1353 * DWORD magic;
1354 * DWORD len;
1356 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1358 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1359 HRESULT hr;
1360 BOOL headerisdata;
1361 BOOL statfailed = FALSE;
1362 ULONG xread, toread;
1363 ULONG headerread;
1364 BYTE *xbuf;
1365 DWORD header[2];
1366 WORD magic;
1367 STATSTG statstg;
1368 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1370 TRACE("(%p,%p)\n",This,pStm);
1372 /****************************************************************************************
1373 * Part 1: Load the data
1375 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1376 * out whether we do.
1378 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1379 * compound file. This may explain most, if not all, of the cases of "no
1380 * header", and the header validation should take this into account.
1381 * At least in Visual Basic 6, resource streams, valid headers are
1382 * header[0] == "lt\0\0",
1383 * header[1] == length_of_stream.
1385 * Also handle streams where we do not have a working "Stat" method by
1386 * reading all data until the end of the stream.
1388 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1389 if (hr != S_OK) {
1390 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1391 statfailed = TRUE;
1392 /* we will read at least 8 byte ... just right below */
1393 statstg.cbSize.QuadPart = 8;
1396 toread = 0;
1397 headerread = 0;
1398 headerisdata = FALSE;
1399 do {
1400 hr = IStream_Read(pStm, header, 8, &xread);
1401 if (hr != S_OK || xread!=8) {
1402 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1403 return (hr?hr:E_FAIL);
1405 headerread += xread;
1406 xread = 0;
1408 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1409 if (toread != 0 && toread != header[1])
1410 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1411 toread, header[1]);
1412 toread = header[1];
1413 if (statfailed)
1415 statstg.cbSize.QuadPart = header[1] + 8;
1416 statfailed = FALSE;
1418 if (toread == 0) break;
1419 } else {
1420 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1421 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1422 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1423 (header[0] == EMR_HEADER) || /* EMF header */
1424 (header[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1425 (header[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1426 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1427 (header[1]==0)
1428 ) {/* Found start of bitmap data */
1429 headerisdata = TRUE;
1430 if (toread == 0)
1431 toread = statstg.cbSize.QuadPart-8;
1432 else toread -= 8;
1433 xread = 8;
1434 } else {
1435 FIXME("Unknown stream header magic: %08x\n", header[0]);
1436 toread = header[1];
1439 } while (!headerisdata);
1441 if (statfailed) { /* we don't know the size ... read all we get */
1442 unsigned int sizeinc = 4096;
1443 unsigned int origsize = sizeinc;
1444 ULONG nread = 42;
1446 TRACE("Reading all data from stream.\n");
1447 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1448 if (headerisdata)
1449 memcpy (xbuf, header, 8);
1450 while (1) {
1451 while (xread < origsize) {
1452 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1453 xread += nread;
1454 if (hr != S_OK || !nread)
1455 break;
1457 if (!nread || hr != S_OK) /* done, or error */
1458 break;
1459 if (xread == origsize) {
1460 origsize += sizeinc;
1461 sizeinc = 2*sizeinc; /* exponential increase */
1462 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1465 if (hr != S_OK)
1466 TRACE("hr in no-stat loader case is %08x\n", hr);
1467 TRACE("loaded %d bytes.\n", xread);
1468 This->datalen = xread;
1469 This->data = xbuf;
1470 } else {
1471 This->datalen = toread+(headerisdata?8:0);
1472 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1473 if (!xbuf)
1474 return E_OUTOFMEMORY;
1476 if (headerisdata)
1477 memcpy (xbuf, header, 8);
1479 while (xread < This->datalen) {
1480 ULONG nread;
1481 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1482 xread += nread;
1483 if (hr != S_OK || !nread)
1484 break;
1486 if (xread != This->datalen)
1487 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1489 if (This->datalen == 0) { /* Marks the "NONE" picture */
1490 This->desc.picType = PICTYPE_NONE;
1491 return S_OK;
1495 /****************************************************************************************
1496 * Part 2: Process the loaded data
1499 magic = xbuf[0] + (xbuf[1]<<8);
1500 This->loadtime_format = magic;
1502 switch (magic) {
1503 case BITMAP_FORMAT_GIF: /* GIF */
1504 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1505 break;
1506 case BITMAP_FORMAT_JPEG: /* JPEG */
1507 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1508 break;
1509 case BITMAP_FORMAT_BMP: /* Bitmap */
1510 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1511 break;
1512 case BITMAP_FORMAT_PNG: /* PNG */
1513 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1514 break;
1515 case BITMAP_FORMAT_APM: /* APM */
1516 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1517 break;
1518 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1519 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1520 break;
1522 default:
1524 unsigned int i;
1526 /* let's see if it's a EMF */
1527 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1528 if (hr == S_OK) break;
1530 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1531 hr=E_FAIL;
1532 for (i=0;i<xread+8;i++) {
1533 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1534 else MESSAGE("%02x ",xbuf[i-8]);
1535 if (i % 10 == 9) MESSAGE("\n");
1537 MESSAGE("\n");
1538 break;
1541 This->bIsDirty = FALSE;
1543 /* FIXME: this notify is not really documented */
1544 if (hr==S_OK)
1545 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1546 return hr;
1549 static BOOL serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1551 BOOL success = FALSE;
1552 HDC hDC;
1553 BITMAPINFO * pInfoBitmap;
1554 int iNumPaletteEntries;
1555 unsigned char * pPixelData;
1556 BITMAPFILEHEADER * pFileHeader;
1557 BITMAPINFO * pInfoHeader;
1559 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1560 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1562 /* Find out bitmap size and padded length */
1563 hDC = GetDC(0);
1564 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1565 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1567 /* Fetch bitmap palette & pixel data */
1569 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1570 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1572 /* Calculate the total length required for the BMP data */
1573 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1574 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1575 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1576 } else {
1577 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1578 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1579 else
1580 iNumPaletteEntries = 0;
1582 *pLength =
1583 sizeof(BITMAPFILEHEADER) +
1584 sizeof(BITMAPINFOHEADER) +
1585 iNumPaletteEntries * sizeof(RGBQUAD) +
1586 pInfoBitmap->bmiHeader.biSizeImage;
1587 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1589 /* Fill the BITMAPFILEHEADER */
1590 pFileHeader = *ppBuffer;
1591 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1592 pFileHeader->bfSize = *pLength;
1593 pFileHeader->bfOffBits =
1594 sizeof(BITMAPFILEHEADER) +
1595 sizeof(BITMAPINFOHEADER) +
1596 iNumPaletteEntries * sizeof(RGBQUAD);
1598 /* Fill the BITMAPINFOHEADER and the palette data */
1599 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1600 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1601 memcpy(
1602 (unsigned char *)(*ppBuffer) +
1603 sizeof(BITMAPFILEHEADER) +
1604 sizeof(BITMAPINFOHEADER) +
1605 iNumPaletteEntries * sizeof(RGBQUAD),
1606 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1607 success = TRUE;
1609 HeapFree(GetProcessHeap(), 0, pPixelData);
1610 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1611 return success;
1614 static BOOL serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1616 ICONINFO infoIcon;
1617 BOOL success = FALSE;
1619 *ppBuffer = NULL; *pLength = 0;
1620 if (GetIconInfo(hIcon, &infoIcon)) {
1621 HDC hDC;
1622 BITMAPINFO * pInfoBitmap;
1623 unsigned char * pIconData = NULL;
1624 unsigned int iDataSize = 0;
1626 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1628 /* Find out icon size */
1629 hDC = GetDC(0);
1630 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1631 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1632 if (1) {
1633 /* Auxiliary pointers */
1634 CURSORICONFILEDIR * pIconDir;
1635 CURSORICONFILEDIRENTRY * pIconEntry;
1636 BITMAPINFOHEADER * pIconBitmapHeader;
1637 unsigned int iOffsetPalette;
1638 unsigned int iOffsetColorData;
1639 unsigned int iOffsetMaskData;
1641 unsigned int iLengthScanLineMask;
1642 unsigned int iNumEntriesPalette;
1644 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1646 FIXME("DEBUG: bitmap size is %d x %d\n",
1647 pInfoBitmap->bmiHeader.biWidth,
1648 pInfoBitmap->bmiHeader.biHeight);
1649 FIXME("DEBUG: bitmap bpp is %d\n",
1650 pInfoBitmap->bmiHeader.biBitCount);
1651 FIXME("DEBUG: bitmap nplanes is %d\n",
1652 pInfoBitmap->bmiHeader.biPlanes);
1653 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1654 pInfoBitmap->bmiHeader.biSizeImage);
1656 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1657 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1658 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1660 /* Fill out the CURSORICONFILEDIR */
1661 pIconDir = (CURSORICONFILEDIR *)pIconData;
1662 pIconDir->idType = 1;
1663 pIconDir->idCount = 1;
1664 pIconDir->idReserved = 0;
1666 /* Fill out the CURSORICONFILEDIRENTRY */
1667 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1668 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1669 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1670 pIconEntry->bColorCount =
1671 (pInfoBitmap->bmiHeader.biBitCount < 8)
1672 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1673 : 0;
1674 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1675 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1676 pIconEntry->dwDIBSize = 0;
1677 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1679 /* Fill out the BITMAPINFOHEADER */
1680 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1681 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1683 /* Find out whether a palette exists for the bitmap */
1684 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1685 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1686 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1687 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1688 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1689 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1690 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1691 iNumEntriesPalette = 3;
1692 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1693 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1694 } else {
1695 iNumEntriesPalette = 0;
1698 /* Add bitmap size and header size to icon data size. */
1699 iOffsetPalette = iDataSize;
1700 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1701 iOffsetColorData = iDataSize;
1702 iDataSize += pIconBitmapHeader->biSizeImage;
1703 iOffsetMaskData = iDataSize;
1704 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1705 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1706 pIconBitmapHeader->biHeight *= 2;
1707 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1708 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1709 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1710 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1712 /* Get the actual bitmap data from the icon bitmap */
1713 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1714 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1715 if (iNumEntriesPalette > 0) {
1716 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1717 iNumEntriesPalette * sizeof(RGBQUAD));
1720 /* Reset all values so that GetDIBits call succeeds */
1721 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1722 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1723 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1725 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1726 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1727 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1729 printf("ERROR: unable to get bitmap mask (error %u)\n",
1730 GetLastError());
1734 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1735 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1737 /* Write out everything produced so far to the stream */
1738 *ppBuffer = pIconData; *pLength = iDataSize;
1739 success = TRUE;
1740 } else {
1742 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1743 GetLastError());
1747 Remarks (from MSDN entry on GetIconInfo):
1749 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1750 members of ICONINFO. The calling application must manage
1751 these bitmaps and delete them when they are no longer
1752 necessary.
1754 if (hDC) ReleaseDC(0, hDC);
1755 DeleteObject(infoIcon.hbmMask);
1756 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1757 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1758 } else {
1759 printf("ERROR: Unable to get icon information (error %u)\n",
1760 GetLastError());
1762 return success;
1765 static HRESULT WINAPI OLEPictureImpl_Save(
1766 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1768 HRESULT hResult = E_NOTIMPL;
1769 void * pIconData;
1770 unsigned int iDataSize;
1771 DWORD header[2];
1772 ULONG dummy;
1773 BOOL serializeResult = FALSE;
1774 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1776 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1778 switch (This->desc.picType) {
1779 case PICTYPE_NONE:
1780 header[0] = 0x0000746c;
1781 header[1] = 0;
1782 hResult = IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1783 break;
1785 case PICTYPE_ICON:
1786 if (This->bIsDirty || !This->data) {
1787 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1788 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1789 hResult = E_FAIL;
1790 break;
1792 HeapFree(GetProcessHeap(), 0, This->data);
1793 This->data = pIconData;
1794 This->datalen = iDataSize;
1797 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1798 header[1] = This->datalen;
1799 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1800 IStream_Write(pStm, This->data, This->datalen, &dummy);
1801 hResult = S_OK;
1802 break;
1803 case PICTYPE_BITMAP:
1804 if (This->bIsDirty || !This->data) {
1805 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1806 case BITMAP_FORMAT_BMP:
1807 serializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1808 break;
1809 case BITMAP_FORMAT_JPEG:
1810 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1811 break;
1812 case BITMAP_FORMAT_GIF:
1813 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1814 break;
1815 case BITMAP_FORMAT_PNG:
1816 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1817 break;
1818 default:
1819 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1820 break;
1823 if (!serializeResult)
1825 hResult = E_FAIL;
1826 break;
1829 HeapFree(GetProcessHeap(), 0, This->data);
1830 This->data = pIconData;
1831 This->datalen = iDataSize;
1834 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1835 header[1] = This->datalen;
1836 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1837 IStream_Write(pStm, This->data, This->datalen, &dummy);
1838 hResult = S_OK;
1839 break;
1840 case PICTYPE_METAFILE:
1841 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1842 break;
1843 case PICTYPE_ENHMETAFILE:
1844 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1845 break;
1846 default:
1847 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1848 break;
1850 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1851 return hResult;
1854 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1855 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1857 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1858 FIXME("(%p,%p),stub!\n",This,pcbSize);
1859 return E_NOTIMPL;
1863 /************************************************************************
1864 * IDispatch
1867 /************************************************************************
1868 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1870 * See Windows documentation for more details on IUnknown methods.
1872 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1873 IDispatch* iface,
1874 REFIID riid,
1875 VOID** ppvoid)
1877 OLEPictureImpl *This = impl_from_IDispatch(iface);
1879 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1882 /************************************************************************
1883 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1885 * See Windows documentation for more details on IUnknown methods.
1887 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1888 IDispatch* iface)
1890 OLEPictureImpl *This = impl_from_IDispatch(iface);
1892 return IPicture_AddRef(&This->IPicture_iface);
1895 /************************************************************************
1896 * OLEPictureImpl_IDispatch_Release (IUnknown)
1898 * See Windows documentation for more details on IUnknown methods.
1900 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1901 IDispatch* iface)
1903 OLEPictureImpl *This = impl_from_IDispatch(iface);
1905 return IPicture_Release(&This->IPicture_iface);
1908 /************************************************************************
1909 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1911 * See Windows documentation for more details on IDispatch methods.
1913 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1914 IDispatch* iface,
1915 unsigned int* pctinfo)
1917 TRACE("(%p)\n", pctinfo);
1919 *pctinfo = 1;
1921 return S_OK;
1924 /************************************************************************
1925 * OLEPictureImpl_GetTypeInfo (IDispatch)
1927 * See Windows documentation for more details on IDispatch methods.
1929 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1930 IDispatch* iface,
1931 UINT iTInfo,
1932 LCID lcid,
1933 ITypeInfo** ppTInfo)
1935 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1936 ITypeLib *tl;
1937 HRESULT hres;
1939 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1941 if (iTInfo != 0)
1942 return E_FAIL;
1944 hres = LoadTypeLib(stdole2tlb, &tl);
1945 if (FAILED(hres))
1947 ERR("Could not load stdole2.tlb\n");
1948 return hres;
1951 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1952 if (FAILED(hres))
1953 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1955 return hres;
1958 /************************************************************************
1959 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1961 * See Windows documentation for more details on IDispatch methods.
1963 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1964 IDispatch* iface,
1965 REFIID riid,
1966 LPOLESTR* rgszNames,
1967 UINT cNames,
1968 LCID lcid,
1969 DISPID* rgDispId)
1971 ITypeInfo * pTInfo;
1972 HRESULT hres;
1974 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1975 rgszNames, cNames, (int)lcid, rgDispId);
1977 if (cNames == 0)
1979 return E_INVALIDARG;
1981 else
1983 /* retrieve type information */
1984 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1986 if (FAILED(hres))
1988 ERR("GetTypeInfo failed.\n");
1989 return hres;
1992 /* convert names to DISPIDs */
1993 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1994 ITypeInfo_Release(pTInfo);
1996 return hres;
2000 /************************************************************************
2001 * OLEPictureImpl_Invoke (IDispatch)
2003 * See Windows documentation for more details on IDispatch methods.
2005 static HRESULT WINAPI OLEPictureImpl_Invoke(
2006 IDispatch* iface,
2007 DISPID dispIdMember,
2008 REFIID riid,
2009 LCID lcid,
2010 WORD wFlags,
2011 DISPPARAMS* pDispParams,
2012 VARIANT* pVarResult,
2013 EXCEPINFO* pExepInfo,
2014 UINT* puArgErr)
2016 OLEPictureImpl *This = impl_from_IDispatch(iface);
2017 HRESULT hr;
2019 /* validate parameters */
2021 if (!IsEqualIID(riid, &IID_NULL))
2023 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2024 return DISP_E_UNKNOWNNAME;
2027 if (!pDispParams)
2029 ERR("null pDispParams not allowed\n");
2030 return DISP_E_PARAMNOTOPTIONAL;
2033 if (wFlags & DISPATCH_PROPERTYGET)
2035 if (pDispParams->cArgs != 0)
2037 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2038 return DISP_E_BADPARAMCOUNT;
2040 if (!pVarResult)
2042 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2043 return DISP_E_PARAMNOTOPTIONAL;
2046 else if (wFlags & DISPATCH_PROPERTYPUT)
2048 if (pDispParams->cArgs != 1)
2050 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2051 return DISP_E_BADPARAMCOUNT;
2055 switch (dispIdMember)
2057 case DISPID_PICT_HANDLE:
2058 if (wFlags & DISPATCH_PROPERTYGET)
2060 TRACE("DISPID_PICT_HANDLE\n");
2061 V_VT(pVarResult) = VT_I4;
2062 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2064 break;
2065 case DISPID_PICT_HPAL:
2066 if (wFlags & DISPATCH_PROPERTYGET)
2068 TRACE("DISPID_PICT_HPAL\n");
2069 V_VT(pVarResult) = VT_I4;
2070 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2072 else if (wFlags & DISPATCH_PROPERTYPUT)
2074 VARIANTARG vararg;
2076 TRACE("DISPID_PICT_HPAL\n");
2078 VariantInit(&vararg);
2079 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2080 if (FAILED(hr))
2081 return hr;
2083 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2085 VariantClear(&vararg);
2086 return hr;
2088 break;
2089 case DISPID_PICT_TYPE:
2090 if (wFlags & DISPATCH_PROPERTYGET)
2092 TRACE("DISPID_PICT_TYPE\n");
2093 V_VT(pVarResult) = VT_I2;
2094 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2096 break;
2097 case DISPID_PICT_WIDTH:
2098 if (wFlags & DISPATCH_PROPERTYGET)
2100 TRACE("DISPID_PICT_WIDTH\n");
2101 V_VT(pVarResult) = VT_I4;
2102 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2104 break;
2105 case DISPID_PICT_HEIGHT:
2106 if (wFlags & DISPATCH_PROPERTYGET)
2108 TRACE("DISPID_PICT_HEIGHT\n");
2109 V_VT(pVarResult) = VT_I4;
2110 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2112 break;
2113 case DISPID_PICT_RENDER:
2114 if (wFlags & DISPATCH_METHOD)
2116 VARIANTARG *args = pDispParams->rgvarg;
2117 int i;
2119 TRACE("DISPID_PICT_RENDER\n");
2121 if (pDispParams->cArgs != 10)
2122 return DISP_E_BADPARAMCOUNT;
2124 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2125 for (i = 0; i < pDispParams->cArgs; i++)
2126 if (V_VT(&args[i]) != VT_I4)
2128 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i, V_VT(&args[i]));
2129 return DISP_E_TYPEMISMATCH;
2132 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2133 currently Render() doesn't use it at all so for now NULL is passed. */
2134 return IPicture_Render(&This->IPicture_iface,
2135 LongToHandle(V_I4(&args[9])),
2136 V_I4(&args[8]),
2137 V_I4(&args[7]),
2138 V_I4(&args[6]),
2139 V_I4(&args[5]),
2140 V_I4(&args[4]),
2141 V_I4(&args[3]),
2142 V_I4(&args[2]),
2143 V_I4(&args[1]),
2144 NULL);
2146 break;
2149 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2150 return DISP_E_MEMBERNOTFOUND;
2154 static const IPictureVtbl OLEPictureImpl_VTable =
2156 OLEPictureImpl_QueryInterface,
2157 OLEPictureImpl_AddRef,
2158 OLEPictureImpl_Release,
2159 OLEPictureImpl_get_Handle,
2160 OLEPictureImpl_get_hPal,
2161 OLEPictureImpl_get_Type,
2162 OLEPictureImpl_get_Width,
2163 OLEPictureImpl_get_Height,
2164 OLEPictureImpl_Render,
2165 OLEPictureImpl_set_hPal,
2166 OLEPictureImpl_get_CurDC,
2167 OLEPictureImpl_SelectPicture,
2168 OLEPictureImpl_get_KeepOriginalFormat,
2169 OLEPictureImpl_put_KeepOriginalFormat,
2170 OLEPictureImpl_PictureChanged,
2171 OLEPictureImpl_SaveAsFile,
2172 OLEPictureImpl_get_Attributes
2175 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2177 OLEPictureImpl_IDispatch_QueryInterface,
2178 OLEPictureImpl_IDispatch_AddRef,
2179 OLEPictureImpl_IDispatch_Release,
2180 OLEPictureImpl_GetTypeInfoCount,
2181 OLEPictureImpl_GetTypeInfo,
2182 OLEPictureImpl_GetIDsOfNames,
2183 OLEPictureImpl_Invoke
2186 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2188 OLEPictureImpl_IPersistStream_QueryInterface,
2189 OLEPictureImpl_IPersistStream_AddRef,
2190 OLEPictureImpl_IPersistStream_Release,
2191 OLEPictureImpl_GetClassID,
2192 OLEPictureImpl_IsDirty,
2193 OLEPictureImpl_Load,
2194 OLEPictureImpl_Save,
2195 OLEPictureImpl_GetSizeMax
2198 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2200 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2201 OLEPictureImpl_IConnectionPointContainer_AddRef,
2202 OLEPictureImpl_IConnectionPointContainer_Release,
2203 OLEPictureImpl_EnumConnectionPoints,
2204 OLEPictureImpl_FindConnectionPoint
2207 /***********************************************************************
2208 * OleCreatePictureIndirect (OLEAUT32.419)
2210 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2211 BOOL Own, void **ppvObj )
2213 OLEPictureImpl* newPict;
2214 HRESULT hr;
2216 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2218 *ppvObj = NULL;
2220 newPict = OLEPictureImpl_Construct(lpPictDesc, Own);
2222 if (newPict == NULL)
2223 return E_OUTOFMEMORY;
2226 * Make sure it supports the interface required by the caller.
2228 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2231 * Release the reference obtained in the constructor. If
2232 * the QueryInterface was unsuccessful, it will free the class.
2234 IPicture_Release(&newPict->IPicture_iface);
2236 return hr;
2240 /***********************************************************************
2241 * OleLoadPicture (OLEAUT32.418)
2243 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2244 REFIID riid, LPVOID *ppvObj )
2246 LPPERSISTSTREAM ps;
2247 IPicture *newpic;
2248 HRESULT hr;
2250 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2251 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2253 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2254 if (hr != S_OK)
2255 return hr;
2256 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2257 if (hr != S_OK) {
2258 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2259 IPicture_Release(newpic);
2260 *ppvObj = NULL;
2261 return hr;
2263 hr = IPersistStream_Load(ps,lpstream);
2264 IPersistStream_Release(ps);
2265 if (FAILED(hr))
2267 ERR("IPersistStream_Load failed\n");
2268 IPicture_Release(newpic);
2269 *ppvObj = NULL;
2270 return hr;
2272 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2273 if (hr != S_OK)
2274 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2275 IPicture_Release(newpic);
2276 return hr;
2279 /***********************************************************************
2280 * OleLoadPictureEx (OLEAUT32.401)
2282 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2283 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2285 LPPERSISTSTREAM ps;
2286 IPicture *newpic;
2287 HRESULT hr;
2289 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2290 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2292 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2293 if (hr != S_OK)
2294 return hr;
2295 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2296 if (hr != S_OK) {
2297 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2298 IPicture_Release(newpic);
2299 *ppvObj = NULL;
2300 return hr;
2302 hr = IPersistStream_Load(ps,lpstream);
2303 IPersistStream_Release(ps);
2304 if (FAILED(hr))
2306 ERR("IPersistStream_Load failed\n");
2307 IPicture_Release(newpic);
2308 *ppvObj = NULL;
2309 return hr;
2311 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2312 if (hr != S_OK)
2313 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2314 IPicture_Release(newpic);
2315 return hr;
2318 /***********************************************************************
2319 * OleLoadPictureFile (OLEAUT32.422)
2321 HRESULT WINAPI OleLoadPictureFile(VARIANT file, LPDISPATCH *picture)
2323 FIXME("(%s %p): stub\n", wine_dbgstr_variant(&file), picture);
2324 return E_NOTIMPL;
2327 /***********************************************************************
2328 * OleSavePictureFile (OLEAUT32.423)
2330 HRESULT WINAPI OleSavePictureFile(IDispatch *picture, BSTR filename)
2332 FIXME("(%p %s): stub\n", picture, debugstr_w(filename));
2333 return CTL_E_FILENOTFOUND;
2336 /***********************************************************************
2337 * OleLoadPicturePath (OLEAUT32.424)
2339 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2340 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2341 LPVOID *ppvRet )
2343 static const WCHAR file[] = { 'f','i','l','e',':',0 };
2344 IPicture *ipicture;
2345 HANDLE hFile;
2346 DWORD dwFileSize;
2347 HGLOBAL hGlobal = NULL;
2348 DWORD dwBytesRead;
2349 IStream *stream;
2350 BOOL bRead;
2351 IPersistStream *pStream;
2352 HRESULT hRes;
2353 HRESULT init_res;
2354 WCHAR *file_candidate;
2355 WCHAR path_buf[MAX_PATH];
2357 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2358 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2359 debugstr_guid(riid), ppvRet);
2361 if (!szURLorPath || !ppvRet)
2362 return E_INVALIDARG;
2364 *ppvRet = NULL;
2366 /* Convert file URLs to DOS paths. */
2367 if (strncmpW(szURLorPath, file, 5) == 0) {
2368 DWORD size;
2369 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2370 sizeof(path_buf)/sizeof(WCHAR), &size, 0);
2371 if (FAILED(hRes))
2372 return hRes;
2374 file_candidate = path_buf;
2376 else
2377 file_candidate = szURLorPath;
2379 /* Handle candidate DOS paths separately. */
2380 if (file_candidate[1] == ':') {
2381 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2382 0, NULL);
2383 if (hFile == INVALID_HANDLE_VALUE)
2384 return INET_E_RESOURCE_NOT_FOUND;
2386 dwFileSize = GetFileSize(hFile, NULL);
2387 if (dwFileSize != INVALID_FILE_SIZE )
2389 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2390 if ( hGlobal)
2392 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL) && dwBytesRead == dwFileSize;
2393 if (!bRead)
2395 GlobalFree(hGlobal);
2396 hGlobal = 0;
2400 CloseHandle(hFile);
2402 if (!hGlobal)
2403 return INET_E_RESOURCE_NOT_FOUND;
2405 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2406 if (FAILED(hRes))
2408 GlobalFree(hGlobal);
2409 return hRes;
2411 } else {
2412 IMoniker *pmnk;
2413 IBindCtx *pbc;
2415 hRes = CreateBindCtx(0, &pbc);
2416 if (SUCCEEDED(hRes))
2418 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2419 if (SUCCEEDED(hRes))
2421 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2422 IMoniker_Release(pmnk);
2424 IBindCtx_Release(pbc);
2426 if (FAILED(hRes))
2427 return hRes;
2430 init_res = CoInitialize(NULL);
2432 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2433 &IID_IPicture, (LPVOID*)&ipicture);
2434 if (SUCCEEDED(hRes)) {
2435 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2437 if (SUCCEEDED(hRes)) {
2438 hRes = IPersistStream_Load(pStream, stream);
2440 if (SUCCEEDED(hRes)) {
2441 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2443 if (FAILED(hRes))
2444 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2446 IPersistStream_Release(pStream);
2448 IPicture_Release(ipicture);
2451 IStream_Release(stream);
2453 if (SUCCEEDED(init_res))
2454 CoUninitialize();
2456 return hRes;
2459 /*******************************************************************************
2460 * StdPic ClassFactory
2462 typedef struct
2464 /* IUnknown fields */
2465 IClassFactory IClassFactory_iface;
2466 LONG ref;
2467 } IClassFactoryImpl;
2469 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2471 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2474 static HRESULT WINAPI
2475 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2476 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2478 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2479 return E_NOINTERFACE;
2482 static ULONG WINAPI
2483 SPCF_AddRef(LPCLASSFACTORY iface) {
2484 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2485 return InterlockedIncrement(&This->ref);
2488 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2489 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2490 /* static class, won't be freed */
2491 return InterlockedDecrement(&This->ref);
2494 static HRESULT WINAPI SPCF_CreateInstance(
2495 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2497 /* Creates an uninitialized picture */
2498 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2502 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2503 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2504 FIXME("(%p)->(%d),stub!\n",This,dolock);
2505 return S_OK;
2508 static const IClassFactoryVtbl SPCF_Vtbl = {
2509 SPCF_QueryInterface,
2510 SPCF_AddRef,
2511 SPCF_Release,
2512 SPCF_CreateInstance,
2513 SPCF_LockServer
2515 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2517 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }