riched20: Implement IsEqual() for ranges.
[wine.git] / dlls / oleaut32 / olepicture.c
blob5d0d801d39bd018214b2641dbe14465cb94af74b
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,&IID_IPropertyNotifySink,&newObject->pCP);
303 if (!newObject->pCP)
305 HeapFree(GetProcessHeap(), 0, newObject);
306 return NULL;
310 * Start with one reference count. The caller of this function
311 * must release the interface pointer when it is done.
313 newObject->ref = 1;
314 newObject->hDCCur = 0;
316 newObject->fOwn = fOwn;
318 /* dunno about original value */
319 newObject->keepOrigFormat = TRUE;
321 newObject->hbmMask = NULL;
322 newObject->hbmXor = NULL;
323 newObject->loadtime_magic = 0xdeadbeef;
324 newObject->loadtime_format = 0;
325 newObject->bIsDirty = FALSE;
327 if (pictDesc) {
328 newObject->desc = *pictDesc;
330 switch(pictDesc->picType) {
331 case PICTYPE_BITMAP:
332 OLEPictureImpl_SetBitmap(newObject);
333 break;
335 case PICTYPE_METAFILE:
336 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
337 newObject->himetricWidth = pictDesc->u.wmf.xExt;
338 newObject->himetricHeight = pictDesc->u.wmf.yExt;
339 break;
341 case PICTYPE_NONE:
342 /* not sure what to do here */
343 newObject->himetricWidth = newObject->himetricHeight = 0;
344 break;
346 case PICTYPE_ICON:
347 OLEPictureImpl_SetIcon(newObject);
348 break;
349 case PICTYPE_ENHMETAFILE:
350 default:
351 FIXME("Unsupported type %d\n", pictDesc->picType);
352 newObject->himetricWidth = newObject->himetricHeight = 0;
353 break;
355 } else {
356 newObject->desc.picType = PICTYPE_UNINITIALIZED;
359 TRACE("returning %p\n", newObject);
360 return newObject;
363 /************************************************************************
364 * OLEPictureImpl_Destroy
366 * This method is called by the Release method when the reference
367 * count goes down to 0. It will free all resources used by
368 * this object. */
369 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
371 TRACE("(%p)\n", Obj);
373 if (Obj->pCP)
374 IConnectionPoint_Release(Obj->pCP);
376 if(Obj->fOwn) { /* We need to destroy the picture */
377 switch(Obj->desc.picType) {
378 case PICTYPE_BITMAP:
379 DeleteObject(Obj->desc.u.bmp.hbitmap);
380 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
381 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
382 break;
383 case PICTYPE_METAFILE:
384 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
385 break;
386 case PICTYPE_ICON:
387 DestroyIcon(Obj->desc.u.icon.hicon);
388 break;
389 case PICTYPE_ENHMETAFILE:
390 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
391 break;
392 case PICTYPE_NONE:
393 case PICTYPE_UNINITIALIZED:
394 /* Nothing to do */
395 break;
396 default:
397 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
398 break;
401 HeapFree(GetProcessHeap(), 0, Obj->data);
402 HeapFree(GetProcessHeap(), 0, Obj);
406 /************************************************************************
407 * OLEPictureImpl_AddRef (IUnknown)
409 * See Windows documentation for more details on IUnknown methods.
411 static ULONG WINAPI OLEPictureImpl_AddRef(
412 IPicture* iface)
414 OLEPictureImpl *This = impl_from_IPicture(iface);
415 ULONG refCount = InterlockedIncrement(&This->ref);
417 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
419 return refCount;
422 /************************************************************************
423 * OLEPictureImpl_Release (IUnknown)
425 * See Windows documentation for more details on IUnknown methods.
427 static ULONG WINAPI OLEPictureImpl_Release(
428 IPicture* iface)
430 OLEPictureImpl *This = impl_from_IPicture(iface);
431 ULONG refCount = InterlockedDecrement(&This->ref);
433 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
436 * If the reference count goes down to 0, perform suicide.
438 if (!refCount) OLEPictureImpl_Destroy(This);
440 return refCount;
443 /************************************************************************
444 * OLEPictureImpl_QueryInterface (IUnknown)
446 * See Windows documentation for more details on IUnknown methods.
448 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
449 IPicture* iface,
450 REFIID riid,
451 void** ppvObject)
453 OLEPictureImpl *This = impl_from_IPicture(iface);
455 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
457 if (!ppvObject)
458 return E_INVALIDARG;
460 *ppvObject = 0;
462 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
463 *ppvObject = This;
464 else if (IsEqualIID(&IID_IDispatch, riid))
465 *ppvObject = &This->IDispatch_iface;
466 else if (IsEqualIID(&IID_IPictureDisp, riid))
467 *ppvObject = &This->IDispatch_iface;
468 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
469 *ppvObject = &This->IPersistStream_iface;
470 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
471 *ppvObject = &This->IConnectionPointContainer_iface;
473 if (!*ppvObject)
475 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
476 return E_NOINTERFACE;
479 IPicture_AddRef(iface);
481 return S_OK;
484 /***********************************************************************
485 * OLEPicture_SendNotify (internal)
487 * Sends notification messages of changed properties to any interested
488 * connections.
490 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
492 IEnumConnections *pEnum;
493 CONNECTDATA CD;
495 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
496 return;
497 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
498 IPropertyNotifySink *sink;
500 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
501 IPropertyNotifySink_OnChanged(sink, dispID);
502 IPropertyNotifySink_Release(sink);
503 IUnknown_Release(CD.pUnk);
505 IEnumConnections_Release(pEnum);
508 /************************************************************************
509 * OLEPictureImpl_get_Handle
511 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
512 OLE_HANDLE *phandle)
514 OLEPictureImpl *This = impl_from_IPicture(iface);
515 TRACE("(%p)->(%p)\n", This, phandle);
517 if(!phandle)
518 return E_POINTER;
520 switch(This->desc.picType) {
521 case PICTYPE_NONE:
522 case PICTYPE_UNINITIALIZED:
523 *phandle = 0;
524 break;
525 case PICTYPE_BITMAP:
526 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
527 break;
528 case PICTYPE_METAFILE:
529 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
530 break;
531 case PICTYPE_ICON:
532 *phandle = HandleToUlong(This->desc.u.icon.hicon);
533 break;
534 case PICTYPE_ENHMETAFILE:
535 *phandle = HandleToUlong(This->desc.u.emf.hemf);
536 break;
537 default:
538 FIXME("Unimplemented type %d\n", This->desc.picType);
539 return E_NOTIMPL;
541 TRACE("returning handle %08x\n", *phandle);
542 return S_OK;
545 /************************************************************************
546 * OLEPictureImpl_get_hPal
548 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
549 OLE_HANDLE *phandle)
551 OLEPictureImpl *This = impl_from_IPicture(iface);
552 HRESULT hres;
553 TRACE("(%p)->(%p)\n", This, phandle);
555 if (!phandle)
556 return E_POINTER;
558 switch (This->desc.picType) {
559 case (UINT)PICTYPE_UNINITIALIZED:
560 case PICTYPE_NONE:
561 *phandle = 0;
562 hres = S_FALSE;
563 break;
564 case PICTYPE_BITMAP:
565 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
566 hres = S_OK;
567 break;
568 case PICTYPE_METAFILE:
569 hres = E_FAIL;
570 break;
571 case PICTYPE_ICON:
572 case PICTYPE_ENHMETAFILE:
573 default:
574 FIXME("unimplemented for type %d. Returning 0 palette.\n",
575 This->desc.picType);
576 *phandle = 0;
577 hres = S_OK;
580 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
581 return hres;
584 /************************************************************************
585 * OLEPictureImpl_get_Type
587 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
588 short *ptype)
590 OLEPictureImpl *This = impl_from_IPicture(iface);
591 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
593 if(!ptype)
594 return E_POINTER;
596 *ptype = This->desc.picType;
597 return S_OK;
600 /************************************************************************
601 * OLEPictureImpl_get_Width
603 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
604 OLE_XSIZE_HIMETRIC *pwidth)
606 OLEPictureImpl *This = impl_from_IPicture(iface);
607 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
608 *pwidth = This->himetricWidth;
609 return S_OK;
612 /************************************************************************
613 * OLEPictureImpl_get_Height
615 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
616 OLE_YSIZE_HIMETRIC *pheight)
618 OLEPictureImpl *This = impl_from_IPicture(iface);
619 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
620 *pheight = This->himetricHeight;
621 return S_OK;
624 /************************************************************************
625 * OLEPictureImpl_Render
627 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
628 LONG x, LONG y, LONG cx, LONG cy,
629 OLE_XPOS_HIMETRIC xSrc,
630 OLE_YPOS_HIMETRIC ySrc,
631 OLE_XSIZE_HIMETRIC cxSrc,
632 OLE_YSIZE_HIMETRIC cySrc,
633 LPCRECT prcWBounds)
635 OLEPictureImpl *This = impl_from_IPicture(iface);
636 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
637 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
638 if(prcWBounds)
639 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
640 prcWBounds->right, prcWBounds->bottom);
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;
1214 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1215 FIXME("icon.idType=%d\n",cifd->idType);
1216 FIXME("icon.idCount=%d\n",cifd->idCount);
1218 for (i=0;i<cifd->idCount;i++) {
1219 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1220 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1221 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1222 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1223 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1224 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1225 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1226 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1229 i=0;
1230 /* If we have more than one icon, try to find the best.
1231 * this currently means '32 pixel wide'.
1233 if (cifd->idCount!=1) {
1234 for (i=0;i<cifd->idCount;i++) {
1235 if (cifd->idEntries[i].bWidth == 32)
1236 break;
1238 if (i==cifd->idCount) i=0;
1240 if (cifd->idType == 2)
1242 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, cifd->idEntries[i].dwDIBSize + 4);
1243 memcpy(buf, &cifd->idEntries[i].xHotspot, 4);
1244 memcpy(buf + 4, xbuf+cifd->idEntries[i].dwDIBOffset, cifd->idEntries[i].dwDIBSize);
1245 hicon = CreateIconFromResourceEx(
1246 buf,
1247 cifd->idEntries[i].dwDIBSize + 4,
1248 FALSE, /* is cursor */
1249 0x00030000,
1250 cifd->idEntries[i].bWidth,
1251 cifd->idEntries[i].bHeight,
1254 HeapFree(GetProcessHeap(), 0, buf);
1256 else
1258 hicon = CreateIconFromResourceEx(
1259 xbuf+cifd->idEntries[i].dwDIBOffset,
1260 cifd->idEntries[i].dwDIBSize,
1261 TRUE, /* is icon */
1262 0x00030000,
1263 cifd->idEntries[i].bWidth,
1264 cifd->idEntries[i].bHeight,
1268 if (!hicon) {
1269 ERR("CreateIcon failed.\n");
1270 return E_FAIL;
1271 } else {
1272 This->desc.picType = PICTYPE_ICON;
1273 This->desc.u.icon.hicon = hicon;
1274 This->origWidth = cifd->idEntries[i].bWidth;
1275 This->origHeight = cifd->idEntries[i].bHeight;
1276 hdcRef = CreateCompatibleDC(0);
1277 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1278 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1279 DeleteDC(hdcRef);
1280 return S_OK;
1284 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1285 const BYTE *data, ULONG size)
1287 HENHMETAFILE hemf;
1288 ENHMETAHEADER hdr;
1290 hemf = SetEnhMetaFileBits(size, data);
1291 if (!hemf) return E_FAIL;
1293 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1295 This->desc.picType = PICTYPE_ENHMETAFILE;
1296 This->desc.u.emf.hemf = hemf;
1298 This->origWidth = 0;
1299 This->origHeight = 0;
1300 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1301 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1303 return S_OK;
1306 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1307 const BYTE *data, ULONG size)
1309 const APM_HEADER *header = (const APM_HEADER *)data;
1310 HMETAFILE hmf;
1312 if (size < sizeof(APM_HEADER))
1313 return E_FAIL;
1314 if (header->key != 0x9ac6cdd7)
1315 return E_FAIL;
1317 /* SetMetaFileBitsEx performs data check on its own */
1318 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1319 if (!hmf) return E_FAIL;
1321 This->desc.picType = PICTYPE_METAFILE;
1322 This->desc.u.wmf.hmeta = hmf;
1323 This->desc.u.wmf.xExt = 0;
1324 This->desc.u.wmf.yExt = 0;
1326 This->origWidth = 0;
1327 This->origHeight = 0;
1328 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1329 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1330 return S_OK;
1333 /************************************************************************
1334 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1336 * Loads the binary data from the IStream. Starts at current position.
1337 * There appears to be an 2 DWORD header:
1338 * DWORD magic;
1339 * DWORD len;
1341 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1343 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1344 HRESULT hr;
1345 BOOL headerisdata;
1346 BOOL statfailed = FALSE;
1347 ULONG xread, toread;
1348 ULONG headerread;
1349 BYTE *xbuf;
1350 DWORD header[2];
1351 WORD magic;
1352 STATSTG statstg;
1353 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1355 TRACE("(%p,%p)\n",This,pStm);
1357 /****************************************************************************************
1358 * Part 1: Load the data
1360 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1361 * out whether we do.
1363 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1364 * compound file. This may explain most, if not all, of the cases of "no
1365 * header", and the header validation should take this into account.
1366 * At least in Visual Basic 6, resource streams, valid headers are
1367 * header[0] == "lt\0\0",
1368 * header[1] == length_of_stream.
1370 * Also handle streams where we do not have a working "Stat" method by
1371 * reading all data until the end of the stream.
1373 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1374 if (hr != S_OK) {
1375 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1376 statfailed = TRUE;
1377 /* we will read at least 8 byte ... just right below */
1378 statstg.cbSize.QuadPart = 8;
1381 toread = 0;
1382 headerread = 0;
1383 headerisdata = FALSE;
1384 do {
1385 hr = IStream_Read(pStm, header, 8, &xread);
1386 if (hr != S_OK || xread!=8) {
1387 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1388 return (hr?hr:E_FAIL);
1390 headerread += xread;
1391 xread = 0;
1393 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1394 if (toread != 0 && toread != header[1])
1395 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1396 toread, header[1]);
1397 toread = header[1];
1398 if (statfailed)
1400 statstg.cbSize.QuadPart = header[1] + 8;
1401 statfailed = FALSE;
1403 if (toread == 0) break;
1404 } else {
1405 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1406 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1407 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1408 (header[0] == EMR_HEADER) || /* EMF header */
1409 (header[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1410 (header[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1411 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1412 (header[1]==0)
1413 ) {/* Found start of bitmap data */
1414 headerisdata = TRUE;
1415 if (toread == 0)
1416 toread = statstg.cbSize.QuadPart-8;
1417 else toread -= 8;
1418 xread = 8;
1419 } else {
1420 FIXME("Unknown stream header magic: %08x\n", header[0]);
1421 toread = header[1];
1424 } while (!headerisdata);
1426 if (statfailed) { /* we don't know the size ... read all we get */
1427 unsigned int sizeinc = 4096;
1428 unsigned int origsize = sizeinc;
1429 ULONG nread = 42;
1431 TRACE("Reading all data from stream.\n");
1432 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1433 if (headerisdata)
1434 memcpy (xbuf, header, 8);
1435 while (1) {
1436 while (xread < origsize) {
1437 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1438 xread += nread;
1439 if (hr != S_OK || !nread)
1440 break;
1442 if (!nread || hr != S_OK) /* done, or error */
1443 break;
1444 if (xread == origsize) {
1445 origsize += sizeinc;
1446 sizeinc = 2*sizeinc; /* exponential increase */
1447 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1450 if (hr != S_OK)
1451 TRACE("hr in no-stat loader case is %08x\n", hr);
1452 TRACE("loaded %d bytes.\n", xread);
1453 This->datalen = xread;
1454 This->data = xbuf;
1455 } else {
1456 This->datalen = toread+(headerisdata?8:0);
1457 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1458 if (!xbuf)
1459 return E_OUTOFMEMORY;
1461 if (headerisdata)
1462 memcpy (xbuf, header, 8);
1464 while (xread < This->datalen) {
1465 ULONG nread;
1466 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1467 xread += nread;
1468 if (hr != S_OK || !nread)
1469 break;
1471 if (xread != This->datalen)
1472 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1474 if (This->datalen == 0) { /* Marks the "NONE" picture */
1475 This->desc.picType = PICTYPE_NONE;
1476 return S_OK;
1480 /****************************************************************************************
1481 * Part 2: Process the loaded data
1484 magic = xbuf[0] + (xbuf[1]<<8);
1485 This->loadtime_format = magic;
1487 switch (magic) {
1488 case BITMAP_FORMAT_GIF: /* GIF */
1489 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1490 break;
1491 case BITMAP_FORMAT_JPEG: /* JPEG */
1492 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1493 break;
1494 case BITMAP_FORMAT_BMP: /* Bitmap */
1495 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1496 break;
1497 case BITMAP_FORMAT_PNG: /* PNG */
1498 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1499 break;
1500 case BITMAP_FORMAT_APM: /* APM */
1501 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1502 break;
1503 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1504 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1505 break;
1507 default:
1509 unsigned int i;
1511 /* let's see if it's a EMF */
1512 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1513 if (hr == S_OK) break;
1515 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1516 hr=E_FAIL;
1517 for (i=0;i<xread+8;i++) {
1518 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1519 else MESSAGE("%02x ",xbuf[i-8]);
1520 if (i % 10 == 9) MESSAGE("\n");
1522 MESSAGE("\n");
1523 break;
1526 This->bIsDirty = FALSE;
1528 /* FIXME: this notify is not really documented */
1529 if (hr==S_OK)
1530 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1531 return hr;
1534 static BOOL serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1536 BOOL success = FALSE;
1537 HDC hDC;
1538 BITMAPINFO * pInfoBitmap;
1539 int iNumPaletteEntries;
1540 unsigned char * pPixelData;
1541 BITMAPFILEHEADER * pFileHeader;
1542 BITMAPINFO * pInfoHeader;
1544 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1545 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1547 /* Find out bitmap size and padded length */
1548 hDC = GetDC(0);
1549 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1550 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1552 /* Fetch bitmap palette & pixel data */
1554 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1555 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1557 /* Calculate the total length required for the BMP data */
1558 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1559 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1560 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1561 } else {
1562 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1563 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1564 else
1565 iNumPaletteEntries = 0;
1567 *pLength =
1568 sizeof(BITMAPFILEHEADER) +
1569 sizeof(BITMAPINFOHEADER) +
1570 iNumPaletteEntries * sizeof(RGBQUAD) +
1571 pInfoBitmap->bmiHeader.biSizeImage;
1572 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1574 /* Fill the BITMAPFILEHEADER */
1575 pFileHeader = *ppBuffer;
1576 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1577 pFileHeader->bfSize = *pLength;
1578 pFileHeader->bfOffBits =
1579 sizeof(BITMAPFILEHEADER) +
1580 sizeof(BITMAPINFOHEADER) +
1581 iNumPaletteEntries * sizeof(RGBQUAD);
1583 /* Fill the BITMAPINFOHEADER and the palette data */
1584 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1585 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1586 memcpy(
1587 (unsigned char *)(*ppBuffer) +
1588 sizeof(BITMAPFILEHEADER) +
1589 sizeof(BITMAPINFOHEADER) +
1590 iNumPaletteEntries * sizeof(RGBQUAD),
1591 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1592 success = TRUE;
1594 HeapFree(GetProcessHeap(), 0, pPixelData);
1595 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1596 return success;
1599 static BOOL serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1601 ICONINFO infoIcon;
1602 BOOL success = FALSE;
1604 *ppBuffer = NULL; *pLength = 0;
1605 if (GetIconInfo(hIcon, &infoIcon)) {
1606 HDC hDC;
1607 BITMAPINFO * pInfoBitmap;
1608 unsigned char * pIconData = NULL;
1609 unsigned int iDataSize = 0;
1611 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1613 /* Find out icon size */
1614 hDC = GetDC(0);
1615 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1616 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1617 if (1) {
1618 /* Auxiliary pointers */
1619 CURSORICONFILEDIR * pIconDir;
1620 CURSORICONFILEDIRENTRY * pIconEntry;
1621 BITMAPINFOHEADER * pIconBitmapHeader;
1622 unsigned int iOffsetPalette;
1623 unsigned int iOffsetColorData;
1624 unsigned int iOffsetMaskData;
1626 unsigned int iLengthScanLineMask;
1627 unsigned int iNumEntriesPalette;
1629 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1631 FIXME("DEBUG: bitmap size is %d x %d\n",
1632 pInfoBitmap->bmiHeader.biWidth,
1633 pInfoBitmap->bmiHeader.biHeight);
1634 FIXME("DEBUG: bitmap bpp is %d\n",
1635 pInfoBitmap->bmiHeader.biBitCount);
1636 FIXME("DEBUG: bitmap nplanes is %d\n",
1637 pInfoBitmap->bmiHeader.biPlanes);
1638 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1639 pInfoBitmap->bmiHeader.biSizeImage);
1641 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1642 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1643 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1645 /* Fill out the CURSORICONFILEDIR */
1646 pIconDir = (CURSORICONFILEDIR *)pIconData;
1647 pIconDir->idType = 1;
1648 pIconDir->idCount = 1;
1649 pIconDir->idReserved = 0;
1651 /* Fill out the CURSORICONFILEDIRENTRY */
1652 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1653 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1654 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1655 pIconEntry->bColorCount =
1656 (pInfoBitmap->bmiHeader.biBitCount < 8)
1657 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1658 : 0;
1659 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1660 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1661 pIconEntry->dwDIBSize = 0;
1662 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1664 /* Fill out the BITMAPINFOHEADER */
1665 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1666 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1668 /* Find out whether a palette exists for the bitmap */
1669 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1670 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1671 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1672 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1673 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1674 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1675 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1676 iNumEntriesPalette = 3;
1677 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1678 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1679 } else {
1680 iNumEntriesPalette = 0;
1683 /* Add bitmap size and header size to icon data size. */
1684 iOffsetPalette = iDataSize;
1685 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1686 iOffsetColorData = iDataSize;
1687 iDataSize += pIconBitmapHeader->biSizeImage;
1688 iOffsetMaskData = iDataSize;
1689 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1690 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1691 pIconBitmapHeader->biHeight *= 2;
1692 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1693 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1694 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1695 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1697 /* Get the actual bitmap data from the icon bitmap */
1698 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1699 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1700 if (iNumEntriesPalette > 0) {
1701 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1702 iNumEntriesPalette * sizeof(RGBQUAD));
1705 /* Reset all values so that GetDIBits call succeeds */
1706 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1707 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1708 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1710 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1711 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1712 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1714 printf("ERROR: unable to get bitmap mask (error %u)\n",
1715 GetLastError());
1719 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1720 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1722 /* Write out everything produced so far to the stream */
1723 *ppBuffer = pIconData; *pLength = iDataSize;
1724 success = TRUE;
1725 } else {
1727 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1728 GetLastError());
1732 Remarks (from MSDN entry on GetIconInfo):
1734 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1735 members of ICONINFO. The calling application must manage
1736 these bitmaps and delete them when they are no longer
1737 necessary.
1739 if (hDC) ReleaseDC(0, hDC);
1740 DeleteObject(infoIcon.hbmMask);
1741 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1742 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1743 } else {
1744 printf("ERROR: Unable to get icon information (error %u)\n",
1745 GetLastError());
1747 return success;
1750 static HRESULT WINAPI OLEPictureImpl_Save(
1751 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1753 HRESULT hResult = E_NOTIMPL;
1754 void * pIconData;
1755 unsigned int iDataSize;
1756 DWORD header[2];
1757 ULONG dummy;
1758 BOOL serializeResult = FALSE;
1759 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1761 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1763 switch (This->desc.picType) {
1764 case PICTYPE_NONE:
1765 header[0] = 0x0000746c;
1766 header[1] = 0;
1767 hResult = IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1768 break;
1770 case PICTYPE_ICON:
1771 if (This->bIsDirty || !This->data) {
1772 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1773 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1774 hResult = E_FAIL;
1775 break;
1777 HeapFree(GetProcessHeap(), 0, This->data);
1778 This->data = pIconData;
1779 This->datalen = iDataSize;
1782 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1783 header[1] = This->datalen;
1784 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1785 IStream_Write(pStm, This->data, This->datalen, &dummy);
1786 hResult = S_OK;
1787 break;
1788 case PICTYPE_BITMAP:
1789 if (This->bIsDirty || !This->data) {
1790 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1791 case BITMAP_FORMAT_BMP:
1792 serializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1793 break;
1794 case BITMAP_FORMAT_JPEG:
1795 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1796 break;
1797 case BITMAP_FORMAT_GIF:
1798 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1799 break;
1800 case BITMAP_FORMAT_PNG:
1801 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1802 break;
1803 default:
1804 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1805 break;
1808 if (!serializeResult)
1810 hResult = E_FAIL;
1811 break;
1814 HeapFree(GetProcessHeap(), 0, This->data);
1815 This->data = pIconData;
1816 This->datalen = iDataSize;
1819 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1820 header[1] = This->datalen;
1821 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1822 IStream_Write(pStm, This->data, This->datalen, &dummy);
1823 hResult = S_OK;
1824 break;
1825 case PICTYPE_METAFILE:
1826 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1827 break;
1828 case PICTYPE_ENHMETAFILE:
1829 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1830 break;
1831 default:
1832 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1833 break;
1835 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1836 return hResult;
1839 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1840 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1842 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1843 FIXME("(%p,%p),stub!\n",This,pcbSize);
1844 return E_NOTIMPL;
1848 /************************************************************************
1849 * IDispatch
1852 /************************************************************************
1853 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1855 * See Windows documentation for more details on IUnknown methods.
1857 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1858 IDispatch* iface,
1859 REFIID riid,
1860 VOID** ppvoid)
1862 OLEPictureImpl *This = impl_from_IDispatch(iface);
1864 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1867 /************************************************************************
1868 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1870 * See Windows documentation for more details on IUnknown methods.
1872 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1873 IDispatch* iface)
1875 OLEPictureImpl *This = impl_from_IDispatch(iface);
1877 return IPicture_AddRef(&This->IPicture_iface);
1880 /************************************************************************
1881 * OLEPictureImpl_IDispatch_Release (IUnknown)
1883 * See Windows documentation for more details on IUnknown methods.
1885 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1886 IDispatch* iface)
1888 OLEPictureImpl *This = impl_from_IDispatch(iface);
1890 return IPicture_Release(&This->IPicture_iface);
1893 /************************************************************************
1894 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1896 * See Windows documentation for more details on IDispatch methods.
1898 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1899 IDispatch* iface,
1900 unsigned int* pctinfo)
1902 TRACE("(%p)\n", pctinfo);
1904 *pctinfo = 1;
1906 return S_OK;
1909 /************************************************************************
1910 * OLEPictureImpl_GetTypeInfo (IDispatch)
1912 * See Windows documentation for more details on IDispatch methods.
1914 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1915 IDispatch* iface,
1916 UINT iTInfo,
1917 LCID lcid,
1918 ITypeInfo** ppTInfo)
1920 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1921 ITypeLib *tl;
1922 HRESULT hres;
1924 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1926 if (iTInfo != 0)
1927 return E_FAIL;
1929 hres = LoadTypeLib(stdole2tlb, &tl);
1930 if (FAILED(hres))
1932 ERR("Could not load stdole2.tlb\n");
1933 return hres;
1936 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1937 if (FAILED(hres))
1938 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1940 return hres;
1943 /************************************************************************
1944 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1946 * See Windows documentation for more details on IDispatch methods.
1948 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1949 IDispatch* iface,
1950 REFIID riid,
1951 LPOLESTR* rgszNames,
1952 UINT cNames,
1953 LCID lcid,
1954 DISPID* rgDispId)
1956 ITypeInfo * pTInfo;
1957 HRESULT hres;
1959 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1960 rgszNames, cNames, (int)lcid, rgDispId);
1962 if (cNames == 0)
1964 return E_INVALIDARG;
1966 else
1968 /* retrieve type information */
1969 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1971 if (FAILED(hres))
1973 ERR("GetTypeInfo failed.\n");
1974 return hres;
1977 /* convert names to DISPIDs */
1978 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1979 ITypeInfo_Release(pTInfo);
1981 return hres;
1985 /************************************************************************
1986 * OLEPictureImpl_Invoke (IDispatch)
1988 * See Windows documentation for more details on IDispatch methods.
1990 static HRESULT WINAPI OLEPictureImpl_Invoke(
1991 IDispatch* iface,
1992 DISPID dispIdMember,
1993 REFIID riid,
1994 LCID lcid,
1995 WORD wFlags,
1996 DISPPARAMS* pDispParams,
1997 VARIANT* pVarResult,
1998 EXCEPINFO* pExepInfo,
1999 UINT* puArgErr)
2001 OLEPictureImpl *This = impl_from_IDispatch(iface);
2002 HRESULT hr;
2004 /* validate parameters */
2006 if (!IsEqualIID(riid, &IID_NULL))
2008 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2009 return DISP_E_UNKNOWNNAME;
2012 if (!pDispParams)
2014 ERR("null pDispParams not allowed\n");
2015 return DISP_E_PARAMNOTOPTIONAL;
2018 if (wFlags & DISPATCH_PROPERTYGET)
2020 if (pDispParams->cArgs != 0)
2022 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2023 return DISP_E_BADPARAMCOUNT;
2025 if (!pVarResult)
2027 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2028 return DISP_E_PARAMNOTOPTIONAL;
2031 else if (wFlags & DISPATCH_PROPERTYPUT)
2033 if (pDispParams->cArgs != 1)
2035 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2036 return DISP_E_BADPARAMCOUNT;
2040 switch (dispIdMember)
2042 case DISPID_PICT_HANDLE:
2043 if (wFlags & DISPATCH_PROPERTYGET)
2045 TRACE("DISPID_PICT_HANDLE\n");
2046 V_VT(pVarResult) = VT_I4;
2047 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2049 break;
2050 case DISPID_PICT_HPAL:
2051 if (wFlags & DISPATCH_PROPERTYGET)
2053 TRACE("DISPID_PICT_HPAL\n");
2054 V_VT(pVarResult) = VT_I4;
2055 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2057 else if (wFlags & DISPATCH_PROPERTYPUT)
2059 VARIANTARG vararg;
2061 TRACE("DISPID_PICT_HPAL\n");
2063 VariantInit(&vararg);
2064 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2065 if (FAILED(hr))
2066 return hr;
2068 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2070 VariantClear(&vararg);
2071 return hr;
2073 break;
2074 case DISPID_PICT_TYPE:
2075 if (wFlags & DISPATCH_PROPERTYGET)
2077 TRACE("DISPID_PICT_TYPE\n");
2078 V_VT(pVarResult) = VT_I2;
2079 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2081 break;
2082 case DISPID_PICT_WIDTH:
2083 if (wFlags & DISPATCH_PROPERTYGET)
2085 TRACE("DISPID_PICT_WIDTH\n");
2086 V_VT(pVarResult) = VT_I4;
2087 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2089 break;
2090 case DISPID_PICT_HEIGHT:
2091 if (wFlags & DISPATCH_PROPERTYGET)
2093 TRACE("DISPID_PICT_HEIGHT\n");
2094 V_VT(pVarResult) = VT_I4;
2095 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2097 break;
2098 case DISPID_PICT_RENDER:
2099 if (wFlags & DISPATCH_METHOD)
2101 VARIANTARG *args = pDispParams->rgvarg;
2102 int i;
2104 TRACE("DISPID_PICT_RENDER\n");
2106 if (pDispParams->cArgs != 10)
2107 return DISP_E_BADPARAMCOUNT;
2109 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2110 for (i = 0; i < pDispParams->cArgs; i++)
2111 if (V_VT(&args[i]) != VT_I4)
2113 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i, V_VT(&args[i]));
2114 return DISP_E_TYPEMISMATCH;
2117 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2118 currently Render() doesn't use it at all so for now NULL is passed. */
2119 return IPicture_Render(&This->IPicture_iface,
2120 LongToHandle(V_I4(&args[9])),
2121 V_I4(&args[8]),
2122 V_I4(&args[7]),
2123 V_I4(&args[6]),
2124 V_I4(&args[5]),
2125 V_I4(&args[4]),
2126 V_I4(&args[3]),
2127 V_I4(&args[2]),
2128 V_I4(&args[1]),
2129 NULL);
2131 break;
2134 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2135 return DISP_E_MEMBERNOTFOUND;
2139 static const IPictureVtbl OLEPictureImpl_VTable =
2141 OLEPictureImpl_QueryInterface,
2142 OLEPictureImpl_AddRef,
2143 OLEPictureImpl_Release,
2144 OLEPictureImpl_get_Handle,
2145 OLEPictureImpl_get_hPal,
2146 OLEPictureImpl_get_Type,
2147 OLEPictureImpl_get_Width,
2148 OLEPictureImpl_get_Height,
2149 OLEPictureImpl_Render,
2150 OLEPictureImpl_set_hPal,
2151 OLEPictureImpl_get_CurDC,
2152 OLEPictureImpl_SelectPicture,
2153 OLEPictureImpl_get_KeepOriginalFormat,
2154 OLEPictureImpl_put_KeepOriginalFormat,
2155 OLEPictureImpl_PictureChanged,
2156 OLEPictureImpl_SaveAsFile,
2157 OLEPictureImpl_get_Attributes
2160 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2162 OLEPictureImpl_IDispatch_QueryInterface,
2163 OLEPictureImpl_IDispatch_AddRef,
2164 OLEPictureImpl_IDispatch_Release,
2165 OLEPictureImpl_GetTypeInfoCount,
2166 OLEPictureImpl_GetTypeInfo,
2167 OLEPictureImpl_GetIDsOfNames,
2168 OLEPictureImpl_Invoke
2171 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2173 OLEPictureImpl_IPersistStream_QueryInterface,
2174 OLEPictureImpl_IPersistStream_AddRef,
2175 OLEPictureImpl_IPersistStream_Release,
2176 OLEPictureImpl_GetClassID,
2177 OLEPictureImpl_IsDirty,
2178 OLEPictureImpl_Load,
2179 OLEPictureImpl_Save,
2180 OLEPictureImpl_GetSizeMax
2183 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2185 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2186 OLEPictureImpl_IConnectionPointContainer_AddRef,
2187 OLEPictureImpl_IConnectionPointContainer_Release,
2188 OLEPictureImpl_EnumConnectionPoints,
2189 OLEPictureImpl_FindConnectionPoint
2192 /***********************************************************************
2193 * OleCreatePictureIndirect (OLEAUT32.419)
2195 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2196 BOOL Own, void **ppvObj )
2198 OLEPictureImpl* newPict;
2199 HRESULT hr;
2201 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2203 *ppvObj = NULL;
2205 newPict = OLEPictureImpl_Construct(lpPictDesc, Own);
2207 if (newPict == NULL)
2208 return E_OUTOFMEMORY;
2211 * Make sure it supports the interface required by the caller.
2213 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2216 * Release the reference obtained in the constructor. If
2217 * the QueryInterface was unsuccessful, it will free the class.
2219 IPicture_Release(&newPict->IPicture_iface);
2221 return hr;
2225 /***********************************************************************
2226 * OleLoadPicture (OLEAUT32.418)
2228 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2229 REFIID riid, LPVOID *ppvObj )
2231 LPPERSISTSTREAM ps;
2232 IPicture *newpic;
2233 HRESULT hr;
2235 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2236 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2238 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2239 if (hr != S_OK)
2240 return hr;
2241 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2242 if (hr != S_OK) {
2243 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2244 IPicture_Release(newpic);
2245 *ppvObj = NULL;
2246 return hr;
2248 hr = IPersistStream_Load(ps,lpstream);
2249 IPersistStream_Release(ps);
2250 if (FAILED(hr))
2252 ERR("IPersistStream_Load failed\n");
2253 IPicture_Release(newpic);
2254 *ppvObj = NULL;
2255 return hr;
2257 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2258 if (hr != S_OK)
2259 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2260 IPicture_Release(newpic);
2261 return hr;
2264 /***********************************************************************
2265 * OleLoadPictureEx (OLEAUT32.401)
2267 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2268 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2270 LPPERSISTSTREAM ps;
2271 IPicture *newpic;
2272 HRESULT hr;
2274 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2275 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2277 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2278 if (hr != S_OK)
2279 return hr;
2280 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2281 if (hr != S_OK) {
2282 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2283 IPicture_Release(newpic);
2284 *ppvObj = NULL;
2285 return hr;
2287 hr = IPersistStream_Load(ps,lpstream);
2288 IPersistStream_Release(ps);
2289 if (FAILED(hr))
2291 ERR("IPersistStream_Load failed\n");
2292 IPicture_Release(newpic);
2293 *ppvObj = NULL;
2294 return hr;
2296 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2297 if (hr != S_OK)
2298 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2299 IPicture_Release(newpic);
2300 return hr;
2303 /***********************************************************************
2304 * OleSavePictureFile (OLEAUT32.423)
2306 HRESULT WINAPI OleSavePictureFile(IDispatch *picture, BSTR filename)
2308 FIXME("(%p %s): stub\n", picture, debugstr_w(filename));
2309 return CTL_E_FILENOTFOUND;
2312 /***********************************************************************
2313 * OleLoadPicturePath (OLEAUT32.424)
2315 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2316 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2317 LPVOID *ppvRet )
2319 static const WCHAR file[] = { 'f','i','l','e',':',0 };
2320 IPicture *ipicture;
2321 HANDLE hFile;
2322 DWORD dwFileSize;
2323 HGLOBAL hGlobal = NULL;
2324 DWORD dwBytesRead;
2325 IStream *stream;
2326 BOOL bRead;
2327 IPersistStream *pStream;
2328 HRESULT hRes;
2329 HRESULT init_res;
2330 WCHAR *file_candidate;
2331 WCHAR path_buf[MAX_PATH];
2333 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2334 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2335 debugstr_guid(riid), ppvRet);
2337 if (!szURLorPath || !ppvRet)
2338 return E_INVALIDARG;
2340 *ppvRet = NULL;
2342 /* Convert file URLs to DOS paths. */
2343 if (strncmpW(szURLorPath, file, 5) == 0) {
2344 DWORD size;
2345 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2346 sizeof(path_buf)/sizeof(WCHAR), &size, 0);
2347 if (FAILED(hRes))
2348 return hRes;
2350 file_candidate = path_buf;
2352 else
2353 file_candidate = szURLorPath;
2355 /* Handle candidate DOS paths separately. */
2356 if (file_candidate[1] == ':') {
2357 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2358 0, NULL);
2359 if (hFile == INVALID_HANDLE_VALUE)
2360 return INET_E_RESOURCE_NOT_FOUND;
2362 dwFileSize = GetFileSize(hFile, NULL);
2363 if (dwFileSize != INVALID_FILE_SIZE )
2365 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2366 if ( hGlobal)
2368 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL) && dwBytesRead == dwFileSize;
2369 if (!bRead)
2371 GlobalFree(hGlobal);
2372 hGlobal = 0;
2376 CloseHandle(hFile);
2378 if (!hGlobal)
2379 return INET_E_RESOURCE_NOT_FOUND;
2381 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2382 if (FAILED(hRes))
2384 GlobalFree(hGlobal);
2385 return hRes;
2387 } else {
2388 IMoniker *pmnk;
2389 IBindCtx *pbc;
2391 hRes = CreateBindCtx(0, &pbc);
2392 if (SUCCEEDED(hRes))
2394 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2395 if (SUCCEEDED(hRes))
2397 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2398 IMoniker_Release(pmnk);
2400 IBindCtx_Release(pbc);
2402 if (FAILED(hRes))
2403 return hRes;
2406 init_res = CoInitialize(NULL);
2408 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2409 &IID_IPicture, (LPVOID*)&ipicture);
2410 if (SUCCEEDED(hRes)) {
2411 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2413 if (SUCCEEDED(hRes)) {
2414 hRes = IPersistStream_Load(pStream, stream);
2416 if (SUCCEEDED(hRes)) {
2417 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2419 if (FAILED(hRes))
2420 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2422 IPersistStream_Release(pStream);
2424 IPicture_Release(ipicture);
2427 IStream_Release(stream);
2429 if (SUCCEEDED(init_res))
2430 CoUninitialize();
2432 return hRes;
2435 /*******************************************************************************
2436 * StdPic ClassFactory
2438 typedef struct
2440 /* IUnknown fields */
2441 IClassFactory IClassFactory_iface;
2442 LONG ref;
2443 } IClassFactoryImpl;
2445 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2447 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2450 static HRESULT WINAPI
2451 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2452 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2454 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2455 return E_NOINTERFACE;
2458 static ULONG WINAPI
2459 SPCF_AddRef(LPCLASSFACTORY iface) {
2460 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2461 return InterlockedIncrement(&This->ref);
2464 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2465 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2466 /* static class, won't be freed */
2467 return InterlockedDecrement(&This->ref);
2470 static HRESULT WINAPI SPCF_CreateInstance(
2471 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2473 /* Creates an uninitialized picture */
2474 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2478 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2479 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2480 FIXME("(%p)->(%d),stub!\n",This,dolock);
2481 return S_OK;
2484 static const IClassFactoryVtbl SPCF_Vtbl = {
2485 SPCF_QueryInterface,
2486 SPCF_AddRef,
2487 SPCF_Release,
2488 SPCF_CreateInstance,
2489 SPCF_LockServer
2491 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2493 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }