ws2_32: Accept shouldn't fail when addrlen32 is NULL.
[wine.git] / dlls / oleaut32 / olepicture.c
blob96c109a557eb5f52c995cc82d75eea65972398a3
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 unsupported 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 %s\n", wine_dbgstr_rect(prcWBounds));
641 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
642 return CTL_E_INVALIDPROPERTYVALUE;
646 * While the documentation suggests this to be here (or after rendering?)
647 * it does cause an endless recursion in my sample app. -MM 20010804
648 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
651 switch(This->desc.picType) {
652 case PICTYPE_UNINITIALIZED:
653 case PICTYPE_NONE:
654 /* nothing to do */
655 return S_OK;
656 case PICTYPE_BITMAP:
658 HBITMAP hbmpOld;
659 HDC hdcBmp;
661 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
662 NB y-axis gets flipped */
664 hdcBmp = CreateCompatibleDC(0);
665 SetMapMode(hdcBmp, MM_ANISOTROPIC);
666 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
667 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
668 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
669 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
671 if (This->hbmMask) {
672 HDC hdcMask = CreateCompatibleDC(0);
673 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
675 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
677 SetMapMode(hdcMask, MM_ANISOTROPIC);
678 SetWindowOrgEx(hdcMask, 0, 0, NULL);
679 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
680 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
681 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
683 SetBkColor(hdc, RGB(255, 255, 255));
684 SetTextColor(hdc, RGB(0, 0, 0));
685 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
686 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
688 SelectObject(hdcMask, hOldbm);
689 DeleteDC(hdcMask);
690 } else {
691 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
692 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
695 SelectObject(hdcBmp, hbmpOld);
696 DeleteDC(hdcBmp);
698 break;
699 case PICTYPE_ICON:
700 FIXME("Not quite correct implementation of rendering icons...\n");
701 DrawIconEx(hdc, x, y, This->desc.u.icon.hicon, cx, cy, 0, NULL, DI_NORMAL);
702 break;
704 case PICTYPE_METAFILE:
706 POINT prevOrg, prevWndOrg;
707 SIZE prevExt, prevWndExt;
708 int oldmode;
710 /* Render the WMF to the appropriate location by setting the
711 appropriate ratio between "device units" and "logical units" */
712 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
713 /* For the "source rectangle" the y-axis must be inverted */
714 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
715 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
716 /* For the "destination rectangle" no inversion is necessary */
717 SetViewportOrgEx(hdc, x, y, &prevOrg);
718 SetViewportExtEx(hdc, cx, cy, &prevExt);
720 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
721 ERR("PlayMetaFile failed!\n");
723 /* We're done, restore the DC to the previous settings for converting
724 logical units to device units */
725 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
726 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
727 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
728 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
729 SetMapMode(hdc, oldmode);
730 break;
733 case PICTYPE_ENHMETAFILE:
735 RECT rc = { x, y, x + cx, y + cy };
736 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
737 break;
740 default:
741 FIXME("type %d not implemented\n", This->desc.picType);
742 return E_NOTIMPL;
744 return S_OK;
747 /************************************************************************
748 * OLEPictureImpl_set_hPal
750 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
751 OLE_HANDLE hpal)
753 OLEPictureImpl *This = impl_from_IPicture(iface);
754 FIXME("(%p)->(%08x): stub\n", This, hpal);
755 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
756 return E_NOTIMPL;
759 /************************************************************************
760 * OLEPictureImpl_get_CurDC
762 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
763 HDC *phdc)
765 OLEPictureImpl *This = impl_from_IPicture(iface);
766 TRACE("(%p), returning %p\n", This, This->hDCCur);
767 if (phdc) *phdc = This->hDCCur;
768 return S_OK;
771 /************************************************************************
772 * OLEPictureImpl_SelectPicture
774 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
775 HDC hdcIn,
776 HDC *phdcOut,
777 OLE_HANDLE *phbmpOut)
779 OLEPictureImpl *This = impl_from_IPicture(iface);
780 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
781 if (This->desc.picType == PICTYPE_BITMAP) {
782 if (phdcOut)
783 *phdcOut = This->hDCCur;
784 if (This->hDCCur) SelectObject(This->hDCCur,This->stock_bitmap);
785 if (hdcIn) SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
786 This->hDCCur = hdcIn;
787 if (phbmpOut)
788 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
789 return S_OK;
790 } else {
791 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
792 return E_FAIL;
796 /************************************************************************
797 * OLEPictureImpl_get_KeepOriginalFormat
799 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
800 BOOL *pfKeep)
802 OLEPictureImpl *This = impl_from_IPicture(iface);
803 TRACE("(%p)->(%p)\n", This, pfKeep);
804 if (!pfKeep)
805 return E_POINTER;
806 *pfKeep = This->keepOrigFormat;
807 return S_OK;
810 /************************************************************************
811 * OLEPictureImpl_put_KeepOriginalFormat
813 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
814 BOOL keep)
816 OLEPictureImpl *This = impl_from_IPicture(iface);
817 TRACE("(%p)->(%d)\n", This, keep);
818 This->keepOrigFormat = keep;
819 /* FIXME: what DISPID notification here? */
820 return S_OK;
823 /************************************************************************
824 * OLEPictureImpl_PictureChanged
826 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
828 OLEPictureImpl *This = impl_from_IPicture(iface);
829 TRACE("(%p)->()\n", This);
830 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
831 This->bIsDirty = TRUE;
832 return S_OK;
835 /************************************************************************
836 * OLEPictureImpl_SaveAsFile
838 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
839 IStream *pstream,
840 BOOL SaveMemCopy,
841 LONG *pcbSize)
843 OLEPictureImpl *This = impl_from_IPicture(iface);
844 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
845 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
848 /************************************************************************
849 * OLEPictureImpl_get_Attributes
851 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
852 DWORD *pdwAttr)
854 OLEPictureImpl *This = impl_from_IPicture(iface);
855 TRACE("(%p)->(%p).\n", This, pdwAttr);
857 if(!pdwAttr)
858 return E_POINTER;
860 *pdwAttr = 0;
861 switch (This->desc.picType) {
862 case PICTYPE_UNINITIALIZED:
863 case PICTYPE_NONE: break;
864 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
865 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
866 case PICTYPE_ENHMETAFILE: /* fall through */
867 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
868 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
870 return S_OK;
874 /************************************************************************
875 * IConnectionPointContainer
877 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
878 IConnectionPointContainer* iface,
879 REFIID riid,
880 VOID** ppvoid)
882 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
884 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
887 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
888 IConnectionPointContainer* iface)
890 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
892 return IPicture_AddRef(&This->IPicture_iface);
895 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
896 IConnectionPointContainer* iface)
898 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
900 return IPicture_Release(&This->IPicture_iface);
903 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
904 IConnectionPointContainer* iface,
905 IEnumConnectionPoints** ppEnum)
907 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
909 FIXME("(%p,%p), stub!\n",This,ppEnum);
910 return E_NOTIMPL;
913 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
914 IConnectionPointContainer* iface,
915 REFIID riid,
916 IConnectionPoint **ppCP)
918 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
919 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
920 if (!ppCP)
921 return E_POINTER;
922 *ppCP = NULL;
923 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
924 return IConnectionPoint_QueryInterface(This->pCP, &IID_IConnectionPoint, (void**)ppCP);
925 FIXME("no connection point for %s\n",debugstr_guid(riid));
926 return CONNECT_E_NOCONNECTION;
930 /************************************************************************
931 * IPersistStream
934 /************************************************************************
935 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
937 * See Windows documentation for more details on IUnknown methods.
939 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
940 IPersistStream* iface,
941 REFIID riid,
942 VOID** ppvoid)
944 OLEPictureImpl *This = impl_from_IPersistStream(iface);
946 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
949 /************************************************************************
950 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
952 * See Windows documentation for more details on IUnknown methods.
954 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
955 IPersistStream* iface)
957 OLEPictureImpl *This = impl_from_IPersistStream(iface);
959 return IPicture_AddRef(&This->IPicture_iface);
962 /************************************************************************
963 * OLEPictureImpl_IPersistStream_Release (IUnknown)
965 * See Windows documentation for more details on IUnknown methods.
967 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
968 IPersistStream* iface)
970 OLEPictureImpl *This = impl_from_IPersistStream(iface);
972 return IPicture_Release(&This->IPicture_iface);
975 /************************************************************************
976 * OLEPictureImpl_IPersistStream_GetClassID
978 static HRESULT WINAPI OLEPictureImpl_GetClassID(
979 IPersistStream* iface,CLSID* pClassID)
981 TRACE("(%p)\n", pClassID);
982 *pClassID = CLSID_StdPicture;
983 return S_OK;
986 /************************************************************************
987 * OLEPictureImpl_IPersistStream_IsDirty
989 static HRESULT WINAPI OLEPictureImpl_IsDirty(
990 IPersistStream* iface)
992 OLEPictureImpl *This = impl_from_IPersistStream(iface);
993 FIXME("(%p),stub!\n",This);
994 return E_NOTIMPL;
997 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
999 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1000 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1001 HDC hdcref;
1003 /* Does not matter whether this is a coreheader or not, we only use
1004 * components which are in both
1006 hdcref = GetDC(0);
1007 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1008 hdcref,
1009 &(bi->bmiHeader),
1010 CBM_INIT,
1011 xbuf+bfh->bfOffBits,
1013 DIB_RGB_COLORS
1015 ReleaseDC(0, hdcref);
1016 if (This->desc.u.bmp.hbitmap == 0)
1017 return E_FAIL;
1018 This->desc.picType = PICTYPE_BITMAP;
1019 OLEPictureImpl_SetBitmap(This);
1020 return S_OK;
1023 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1025 HRESULT hr;
1026 BITMAPINFOHEADER bih;
1027 HDC hdcref;
1028 UINT width, height;
1029 UINT stride, buffersize;
1030 LPBYTE bits=NULL;
1031 WICRect rc;
1032 IWICBitmapSource *real_source;
1033 UINT x, y;
1034 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1035 BOOL has_alpha=FALSE;
1037 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1038 if (FAILED(hr)) return hr;
1040 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1041 if (FAILED(hr)) goto end;
1043 bih.biSize = sizeof(bih);
1044 bih.biWidth = width;
1045 bih.biHeight = -height;
1046 bih.biPlanes = 1;
1047 bih.biBitCount = 32;
1048 bih.biCompression = BI_RGB;
1049 bih.biSizeImage = 0;
1050 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1051 bih.biYPelsPerMeter = 4085;
1052 bih.biClrUsed = 0;
1053 bih.biClrImportant = 0;
1055 stride = 4 * width;
1056 buffersize = stride * height;
1058 bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1059 if (!bits)
1061 hr = E_OUTOFMEMORY;
1062 goto end;
1065 rc.X = 0;
1066 rc.Y = 0;
1067 rc.Width = width;
1068 rc.Height = height;
1069 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1070 if (FAILED(hr))
1071 goto end;
1073 hdcref = GetDC(0);
1074 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1075 hdcref,
1076 &bih,
1077 CBM_INIT,
1078 bits,
1079 (BITMAPINFO*)&bih,
1080 DIB_RGB_COLORS);
1082 if (This->desc.u.bmp.hbitmap == 0)
1084 hr = E_FAIL;
1085 ReleaseDC(0, hdcref);
1086 goto end;
1089 This->desc.picType = PICTYPE_BITMAP;
1090 OLEPictureImpl_SetBitmap(This);
1092 /* set transparent pixels to black, all others to white */
1093 for(y = 0; y < height; y++){
1094 for(x = 0; x < width; x++){
1095 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1096 if((*pixel & 0x80000000) == 0)
1098 has_alpha = TRUE;
1099 *pixel = black;
1101 else
1102 *pixel = white;
1106 if (has_alpha)
1108 HDC hdcBmp, hdcXor, hdcMask;
1109 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1111 This->hbmXor = CreateDIBitmap(
1112 hdcref,
1113 &bih,
1114 CBM_INIT,
1115 bits,
1116 (BITMAPINFO*)&bih,
1117 DIB_RGB_COLORS
1120 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1121 hdcBmp = CreateCompatibleDC(NULL);
1122 hdcXor = CreateCompatibleDC(NULL);
1123 hdcMask = CreateCompatibleDC(NULL);
1125 hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1126 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1127 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1129 SetBkColor(hdcXor,black);
1130 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1131 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1133 SelectObject(hdcBmp,hbmoldBmp);
1134 SelectObject(hdcXor,hbmoldXor);
1135 SelectObject(hdcMask,hbmoldMask);
1137 DeleteDC(hdcBmp);
1138 DeleteDC(hdcXor);
1139 DeleteDC(hdcMask);
1142 ReleaseDC(0, hdcref);
1144 end:
1145 HeapFree(GetProcessHeap(), 0, bits);
1146 IWICBitmapSource_Release(real_source);
1147 return hr;
1150 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1152 HRESULT hr;
1153 IWICImagingFactory *factory;
1154 IWICBitmapDecoder *decoder;
1155 IWICBitmapFrameDecode *framedecode;
1156 HRESULT initresult;
1157 IWICStream *stream;
1159 initresult = CoInitialize(NULL);
1161 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1162 &IID_IWICImagingFactory, (void**)&factory);
1163 if (SUCCEEDED(hr)) /* created factory */
1165 hr = IWICImagingFactory_CreateStream(factory, &stream);
1166 IWICImagingFactory_Release(factory);
1169 if (SUCCEEDED(hr)) /* created stream */
1171 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1173 if (SUCCEEDED(hr)) /* initialized stream */
1175 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1176 &IID_IWICBitmapDecoder, (void**)&decoder);
1177 if (SUCCEEDED(hr)) /* created decoder */
1179 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1181 if (SUCCEEDED(hr)) /* initialized decoder */
1182 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1184 IWICBitmapDecoder_Release(decoder);
1188 IWICStream_Release(stream);
1191 if (SUCCEEDED(hr)) /* got framedecode */
1193 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1194 IWICBitmapFrameDecode_Release(framedecode);
1197 if (SUCCEEDED(initresult)) CoUninitialize();
1198 return hr;
1201 /*****************************************************
1202 * start of Icon-specific code
1205 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1207 HICON hicon;
1208 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1209 HDC hdcRef;
1210 int i;
1212 TRACE("(this %p, xbuf %p, xread %u)\n", This, xbuf, xread);
1215 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1216 FIXME("icon.idType=%d\n",cifd->idType);
1217 FIXME("icon.idCount=%d\n",cifd->idCount);
1219 for (i=0;i<cifd->idCount;i++) {
1220 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1221 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1222 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1223 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1224 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1225 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1226 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1227 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1231 /* Need at least one icon to do something. */
1232 if (!cifd->idCount)
1234 ERR("Invalid icon count of zero.\n");
1235 return E_FAIL;
1237 i=0;
1238 /* If we have more than one icon, try to find the best.
1239 * this currently means '32 pixel wide'.
1241 if (cifd->idCount!=1) {
1242 for (i=0;i<cifd->idCount;i++) {
1243 if (cifd->idEntries[i].bWidth == 32)
1244 break;
1246 if (i==cifd->idCount) i=0;
1248 if (xread < cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize)
1250 ERR("Icon data address %u is over %u bytes available.\n",
1251 cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize, xread);
1252 return E_FAIL;
1254 if (cifd->idType == 2)
1256 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, cifd->idEntries[i].dwDIBSize + 4);
1257 memcpy(buf, &cifd->idEntries[i].xHotspot, 4);
1258 memcpy(buf + 4, xbuf+cifd->idEntries[i].dwDIBOffset, cifd->idEntries[i].dwDIBSize);
1259 hicon = CreateIconFromResourceEx(
1260 buf,
1261 cifd->idEntries[i].dwDIBSize + 4,
1262 FALSE, /* is cursor */
1263 0x00030000,
1264 cifd->idEntries[i].bWidth,
1265 cifd->idEntries[i].bHeight,
1268 HeapFree(GetProcessHeap(), 0, buf);
1270 else
1272 hicon = CreateIconFromResourceEx(
1273 xbuf+cifd->idEntries[i].dwDIBOffset,
1274 cifd->idEntries[i].dwDIBSize,
1275 TRUE, /* is icon */
1276 0x00030000,
1277 cifd->idEntries[i].bWidth,
1278 cifd->idEntries[i].bHeight,
1282 if (!hicon) {
1283 ERR("CreateIcon failed.\n");
1284 return E_FAIL;
1285 } else {
1286 This->desc.picType = PICTYPE_ICON;
1287 This->desc.u.icon.hicon = hicon;
1288 This->origWidth = cifd->idEntries[i].bWidth;
1289 This->origHeight = cifd->idEntries[i].bHeight;
1290 hdcRef = CreateCompatibleDC(0);
1291 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1292 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1293 DeleteDC(hdcRef);
1294 return S_OK;
1298 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1299 const BYTE *data, ULONG size)
1301 HENHMETAFILE hemf;
1302 ENHMETAHEADER hdr;
1304 hemf = SetEnhMetaFileBits(size, data);
1305 if (!hemf) return E_FAIL;
1307 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1309 This->desc.picType = PICTYPE_ENHMETAFILE;
1310 This->desc.u.emf.hemf = hemf;
1312 This->origWidth = 0;
1313 This->origHeight = 0;
1314 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1315 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1317 return S_OK;
1320 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1321 const BYTE *data, ULONG size)
1323 const APM_HEADER *header = (const APM_HEADER *)data;
1324 HMETAFILE hmf;
1326 if (size < sizeof(APM_HEADER))
1327 return E_FAIL;
1328 if (header->key != 0x9ac6cdd7)
1329 return E_FAIL;
1331 /* SetMetaFileBitsEx performs data check on its own */
1332 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1333 if (!hmf) return E_FAIL;
1335 This->desc.picType = PICTYPE_METAFILE;
1336 This->desc.u.wmf.hmeta = hmf;
1337 This->desc.u.wmf.xExt = 0;
1338 This->desc.u.wmf.yExt = 0;
1340 This->origWidth = 0;
1341 This->origHeight = 0;
1342 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1343 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1344 return S_OK;
1347 /************************************************************************
1348 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1350 * Loads the binary data from the IStream. Starts at current position.
1351 * There appears to be an 2 DWORD header:
1352 * DWORD magic;
1353 * DWORD len;
1355 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1357 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1358 HRESULT hr;
1359 BOOL headerisdata;
1360 BOOL statfailed = FALSE;
1361 ULONG xread, toread;
1362 ULONG headerread;
1363 BYTE *xbuf;
1364 DWORD header[2];
1365 WORD magic;
1366 STATSTG statstg;
1367 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1369 TRACE("(%p,%p)\n",This,pStm);
1371 /****************************************************************************************
1372 * Part 1: Load the data
1374 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1375 * out whether we do.
1377 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1378 * compound file. This may explain most, if not all, of the cases of "no
1379 * header", and the header validation should take this into account.
1380 * At least in Visual Basic 6, resource streams, valid headers are
1381 * header[0] == "lt\0\0",
1382 * header[1] == length_of_stream.
1384 * Also handle streams where we do not have a working "Stat" method by
1385 * reading all data until the end of the stream.
1387 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1388 if (hr != S_OK) {
1389 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1390 statfailed = TRUE;
1391 /* we will read at least 8 byte ... just right below */
1392 statstg.cbSize.QuadPart = 8;
1395 toread = 0;
1396 headerread = 0;
1397 headerisdata = FALSE;
1398 do {
1399 hr = IStream_Read(pStm, header, 8, &xread);
1400 if (hr != S_OK || xread!=8) {
1401 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1402 return (hr?hr:E_FAIL);
1404 headerread += xread;
1405 xread = 0;
1407 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1408 if (toread != 0 && toread != header[1])
1409 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1410 toread, header[1]);
1411 toread = header[1];
1412 if (statfailed)
1414 statstg.cbSize.QuadPart = header[1] + 8;
1415 statfailed = FALSE;
1417 if (toread == 0) break;
1418 } else {
1419 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1420 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1421 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1422 (header[0] == EMR_HEADER) || /* EMF header */
1423 (header[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1424 (header[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1425 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1426 (header[1]==0)
1427 ) {/* Found start of bitmap data */
1428 headerisdata = TRUE;
1429 if (toread == 0)
1430 toread = statstg.cbSize.QuadPart-8;
1431 else toread -= 8;
1432 xread = 8;
1433 } else {
1434 FIXME("Unknown stream header magic: %08x\n", header[0]);
1435 toread = header[1];
1438 } while (!headerisdata);
1440 if (statfailed) { /* we don't know the size ... read all we get */
1441 unsigned int sizeinc = 4096;
1442 unsigned int origsize = sizeinc;
1443 ULONG nread = 42;
1445 TRACE("Reading all data from stream.\n");
1446 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1447 if (headerisdata)
1448 memcpy (xbuf, header, 8);
1449 while (1) {
1450 while (xread < origsize) {
1451 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1452 xread += nread;
1453 if (hr != S_OK || !nread)
1454 break;
1456 if (!nread || hr != S_OK) /* done, or error */
1457 break;
1458 if (xread == origsize) {
1459 origsize += sizeinc;
1460 sizeinc = 2*sizeinc; /* exponential increase */
1461 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1464 if (hr != S_OK)
1465 TRACE("hr in no-stat loader case is %08x\n", hr);
1466 TRACE("loaded %d bytes.\n", xread);
1467 This->datalen = xread;
1468 This->data = xbuf;
1469 } else {
1470 This->datalen = toread+(headerisdata?8:0);
1471 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1472 if (!xbuf)
1473 return E_OUTOFMEMORY;
1475 if (headerisdata)
1476 memcpy (xbuf, header, 8);
1478 while (xread < This->datalen) {
1479 ULONG nread;
1480 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1481 xread += nread;
1482 if (hr != S_OK || !nread)
1483 break;
1485 if (xread != This->datalen)
1486 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1488 if (This->datalen == 0) { /* Marks the "NONE" picture */
1489 This->desc.picType = PICTYPE_NONE;
1490 return S_OK;
1494 /****************************************************************************************
1495 * Part 2: Process the loaded data
1498 magic = xbuf[0] + (xbuf[1]<<8);
1499 This->loadtime_format = magic;
1501 switch (magic) {
1502 case BITMAP_FORMAT_GIF: /* GIF */
1503 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1504 break;
1505 case BITMAP_FORMAT_JPEG: /* JPEG */
1506 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1507 break;
1508 case BITMAP_FORMAT_BMP: /* Bitmap */
1509 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1510 break;
1511 case BITMAP_FORMAT_PNG: /* PNG */
1512 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1513 break;
1514 case BITMAP_FORMAT_APM: /* APM */
1515 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1516 break;
1517 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1518 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1519 break;
1521 default:
1523 unsigned int i;
1525 /* let's see if it's a EMF */
1526 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1527 if (hr == S_OK) break;
1529 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1530 hr=E_FAIL;
1531 for (i=0;i<xread+8;i++) {
1532 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1533 else MESSAGE("%02x ",xbuf[i-8]);
1534 if (i % 10 == 9) MESSAGE("\n");
1536 MESSAGE("\n");
1537 break;
1540 This->bIsDirty = FALSE;
1542 /* FIXME: this notify is not really documented */
1543 if (hr==S_OK)
1544 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1545 return hr;
1548 static BOOL serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1550 BOOL success = FALSE;
1551 HDC hDC;
1552 BITMAPINFO * pInfoBitmap;
1553 int iNumPaletteEntries;
1554 unsigned char * pPixelData;
1555 BITMAPFILEHEADER * pFileHeader;
1556 BITMAPINFO * pInfoHeader;
1558 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1559 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1561 /* Find out bitmap size and padded length */
1562 hDC = GetDC(0);
1563 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1564 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1566 /* Fetch bitmap palette & pixel data */
1568 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1569 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1571 /* Calculate the total length required for the BMP data */
1572 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1573 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1574 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1575 } else {
1576 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1577 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1578 else
1579 iNumPaletteEntries = 0;
1581 *pLength =
1582 sizeof(BITMAPFILEHEADER) +
1583 sizeof(BITMAPINFOHEADER) +
1584 iNumPaletteEntries * sizeof(RGBQUAD) +
1585 pInfoBitmap->bmiHeader.biSizeImage;
1586 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1588 /* Fill the BITMAPFILEHEADER */
1589 pFileHeader = *ppBuffer;
1590 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1591 pFileHeader->bfSize = *pLength;
1592 pFileHeader->bfOffBits =
1593 sizeof(BITMAPFILEHEADER) +
1594 sizeof(BITMAPINFOHEADER) +
1595 iNumPaletteEntries * sizeof(RGBQUAD);
1597 /* Fill the BITMAPINFOHEADER and the palette data */
1598 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1599 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1600 memcpy(
1601 (unsigned char *)(*ppBuffer) +
1602 sizeof(BITMAPFILEHEADER) +
1603 sizeof(BITMAPINFOHEADER) +
1604 iNumPaletteEntries * sizeof(RGBQUAD),
1605 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1606 success = TRUE;
1608 HeapFree(GetProcessHeap(), 0, pPixelData);
1609 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1610 return success;
1613 static BOOL serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1615 ICONINFO infoIcon;
1616 BOOL success = FALSE;
1618 *ppBuffer = NULL; *pLength = 0;
1619 if (GetIconInfo(hIcon, &infoIcon)) {
1620 HDC hDC;
1621 BITMAPINFO * pInfoBitmap;
1622 unsigned char * pIconData = NULL;
1623 unsigned int iDataSize = 0;
1625 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1627 /* Find out icon size */
1628 hDC = GetDC(0);
1629 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1630 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1631 if (1) {
1632 /* Auxiliary pointers */
1633 CURSORICONFILEDIR * pIconDir;
1634 CURSORICONFILEDIRENTRY * pIconEntry;
1635 BITMAPINFOHEADER * pIconBitmapHeader;
1636 unsigned int iOffsetPalette;
1637 unsigned int iOffsetColorData;
1638 unsigned int iOffsetMaskData;
1640 unsigned int iLengthScanLineMask;
1641 unsigned int iNumEntriesPalette;
1643 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1645 FIXME("DEBUG: bitmap size is %d x %d\n",
1646 pInfoBitmap->bmiHeader.biWidth,
1647 pInfoBitmap->bmiHeader.biHeight);
1648 FIXME("DEBUG: bitmap bpp is %d\n",
1649 pInfoBitmap->bmiHeader.biBitCount);
1650 FIXME("DEBUG: bitmap nplanes is %d\n",
1651 pInfoBitmap->bmiHeader.biPlanes);
1652 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1653 pInfoBitmap->bmiHeader.biSizeImage);
1655 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1656 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1657 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1659 /* Fill out the CURSORICONFILEDIR */
1660 pIconDir = (CURSORICONFILEDIR *)pIconData;
1661 pIconDir->idType = 1;
1662 pIconDir->idCount = 1;
1663 pIconDir->idReserved = 0;
1665 /* Fill out the CURSORICONFILEDIRENTRY */
1666 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1667 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1668 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1669 pIconEntry->bColorCount =
1670 (pInfoBitmap->bmiHeader.biBitCount < 8)
1671 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1672 : 0;
1673 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1674 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1675 pIconEntry->dwDIBSize = 0;
1676 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1678 /* Fill out the BITMAPINFOHEADER */
1679 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1680 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1682 /* Find out whether a palette exists for the bitmap */
1683 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1684 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1685 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1686 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1687 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1688 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1689 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1690 iNumEntriesPalette = 3;
1691 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1692 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1693 } else {
1694 iNumEntriesPalette = 0;
1697 /* Add bitmap size and header size to icon data size. */
1698 iOffsetPalette = iDataSize;
1699 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1700 iOffsetColorData = iDataSize;
1701 iDataSize += pIconBitmapHeader->biSizeImage;
1702 iOffsetMaskData = iDataSize;
1703 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1704 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1705 pIconBitmapHeader->biHeight *= 2;
1706 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1707 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1708 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1709 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1711 /* Get the actual bitmap data from the icon bitmap */
1712 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1713 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1714 if (iNumEntriesPalette > 0) {
1715 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1716 iNumEntriesPalette * sizeof(RGBQUAD));
1719 /* Reset all values so that GetDIBits call succeeds */
1720 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1721 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1722 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1724 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1725 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1726 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1728 printf("ERROR: unable to get bitmap mask (error %u)\n",
1729 GetLastError());
1733 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1734 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1736 /* Write out everything produced so far to the stream */
1737 *ppBuffer = pIconData; *pLength = iDataSize;
1738 success = TRUE;
1739 } else {
1741 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1742 GetLastError());
1746 Remarks (from MSDN entry on GetIconInfo):
1748 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1749 members of ICONINFO. The calling application must manage
1750 these bitmaps and delete them when they are no longer
1751 necessary.
1753 if (hDC) ReleaseDC(0, hDC);
1754 DeleteObject(infoIcon.hbmMask);
1755 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1756 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1757 } else {
1758 printf("ERROR: Unable to get icon information (error %u)\n",
1759 GetLastError());
1761 return success;
1764 static HRESULT WINAPI OLEPictureImpl_Save(
1765 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1767 HRESULT hResult = E_NOTIMPL;
1768 void * pIconData;
1769 unsigned int iDataSize;
1770 DWORD header[2];
1771 ULONG dummy;
1772 BOOL serializeResult = FALSE;
1773 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1775 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1777 switch (This->desc.picType) {
1778 case PICTYPE_NONE:
1779 header[0] = 0x0000746c;
1780 header[1] = 0;
1781 hResult = IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1782 break;
1784 case PICTYPE_ICON:
1785 if (This->bIsDirty || !This->data) {
1786 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1787 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1788 hResult = E_FAIL;
1789 break;
1791 HeapFree(GetProcessHeap(), 0, This->data);
1792 This->data = pIconData;
1793 This->datalen = iDataSize;
1796 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1797 header[1] = This->datalen;
1798 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1799 IStream_Write(pStm, This->data, This->datalen, &dummy);
1800 hResult = S_OK;
1801 break;
1802 case PICTYPE_BITMAP:
1803 if (This->bIsDirty || !This->data) {
1804 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1805 case BITMAP_FORMAT_BMP:
1806 serializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1807 break;
1808 case BITMAP_FORMAT_JPEG:
1809 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1810 break;
1811 case BITMAP_FORMAT_GIF:
1812 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1813 break;
1814 case BITMAP_FORMAT_PNG:
1815 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1816 break;
1817 default:
1818 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1819 break;
1822 if (!serializeResult)
1824 hResult = E_FAIL;
1825 break;
1828 HeapFree(GetProcessHeap(), 0, This->data);
1829 This->data = pIconData;
1830 This->datalen = iDataSize;
1833 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1834 header[1] = This->datalen;
1835 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1836 IStream_Write(pStm, This->data, This->datalen, &dummy);
1837 hResult = S_OK;
1838 break;
1839 case PICTYPE_METAFILE:
1840 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1841 break;
1842 case PICTYPE_ENHMETAFILE:
1843 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1844 break;
1845 default:
1846 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1847 break;
1849 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1850 return hResult;
1853 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1854 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1856 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1857 FIXME("(%p,%p),stub!\n",This,pcbSize);
1858 return E_NOTIMPL;
1862 /************************************************************************
1863 * IDispatch
1866 /************************************************************************
1867 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1869 * See Windows documentation for more details on IUnknown methods.
1871 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1872 IDispatch* iface,
1873 REFIID riid,
1874 VOID** ppvoid)
1876 OLEPictureImpl *This = impl_from_IDispatch(iface);
1878 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1881 /************************************************************************
1882 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1884 * See Windows documentation for more details on IUnknown methods.
1886 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1887 IDispatch* iface)
1889 OLEPictureImpl *This = impl_from_IDispatch(iface);
1891 return IPicture_AddRef(&This->IPicture_iface);
1894 /************************************************************************
1895 * OLEPictureImpl_IDispatch_Release (IUnknown)
1897 * See Windows documentation for more details on IUnknown methods.
1899 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1900 IDispatch* iface)
1902 OLEPictureImpl *This = impl_from_IDispatch(iface);
1904 return IPicture_Release(&This->IPicture_iface);
1907 /************************************************************************
1908 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1910 * See Windows documentation for more details on IDispatch methods.
1912 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1913 IDispatch* iface,
1914 unsigned int* pctinfo)
1916 TRACE("(%p)\n", pctinfo);
1918 *pctinfo = 1;
1920 return S_OK;
1923 /************************************************************************
1924 * OLEPictureImpl_GetTypeInfo (IDispatch)
1926 * See Windows documentation for more details on IDispatch methods.
1928 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1929 IDispatch* iface,
1930 UINT iTInfo,
1931 LCID lcid,
1932 ITypeInfo** ppTInfo)
1934 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1935 ITypeLib *tl;
1936 HRESULT hres;
1938 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1940 if (iTInfo != 0)
1941 return E_FAIL;
1943 hres = LoadTypeLib(stdole2tlb, &tl);
1944 if (FAILED(hres))
1946 ERR("Could not load stdole2.tlb\n");
1947 return hres;
1950 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1951 if (FAILED(hres))
1952 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1954 return hres;
1957 /************************************************************************
1958 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1960 * See Windows documentation for more details on IDispatch methods.
1962 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1963 IDispatch* iface,
1964 REFIID riid,
1965 LPOLESTR* rgszNames,
1966 UINT cNames,
1967 LCID lcid,
1968 DISPID* rgDispId)
1970 ITypeInfo * pTInfo;
1971 HRESULT hres;
1973 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1974 rgszNames, cNames, (int)lcid, rgDispId);
1976 if (cNames == 0)
1978 return E_INVALIDARG;
1980 else
1982 /* retrieve type information */
1983 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1985 if (FAILED(hres))
1987 ERR("GetTypeInfo failed.\n");
1988 return hres;
1991 /* convert names to DISPIDs */
1992 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1993 ITypeInfo_Release(pTInfo);
1995 return hres;
1999 /************************************************************************
2000 * OLEPictureImpl_Invoke (IDispatch)
2002 * See Windows documentation for more details on IDispatch methods.
2004 static HRESULT WINAPI OLEPictureImpl_Invoke(
2005 IDispatch* iface,
2006 DISPID dispIdMember,
2007 REFIID riid,
2008 LCID lcid,
2009 WORD wFlags,
2010 DISPPARAMS* pDispParams,
2011 VARIANT* pVarResult,
2012 EXCEPINFO* pExepInfo,
2013 UINT* puArgErr)
2015 OLEPictureImpl *This = impl_from_IDispatch(iface);
2016 HRESULT hr;
2018 /* validate parameters */
2020 if (!IsEqualIID(riid, &IID_NULL))
2022 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2023 return DISP_E_UNKNOWNNAME;
2026 if (!pDispParams)
2028 ERR("null pDispParams not allowed\n");
2029 return DISP_E_PARAMNOTOPTIONAL;
2032 if (wFlags & DISPATCH_PROPERTYGET)
2034 if (pDispParams->cArgs != 0)
2036 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2037 return DISP_E_BADPARAMCOUNT;
2039 if (!pVarResult)
2041 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2042 return DISP_E_PARAMNOTOPTIONAL;
2045 else if (wFlags & DISPATCH_PROPERTYPUT)
2047 if (pDispParams->cArgs != 1)
2049 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2050 return DISP_E_BADPARAMCOUNT;
2054 switch (dispIdMember)
2056 case DISPID_PICT_HANDLE:
2057 if (wFlags & DISPATCH_PROPERTYGET)
2059 TRACE("DISPID_PICT_HANDLE\n");
2060 V_VT(pVarResult) = VT_I4;
2061 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2063 break;
2064 case DISPID_PICT_HPAL:
2065 if (wFlags & DISPATCH_PROPERTYGET)
2067 TRACE("DISPID_PICT_HPAL\n");
2068 V_VT(pVarResult) = VT_I4;
2069 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2071 else if (wFlags & DISPATCH_PROPERTYPUT)
2073 VARIANTARG vararg;
2075 TRACE("DISPID_PICT_HPAL\n");
2077 VariantInit(&vararg);
2078 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2079 if (FAILED(hr))
2080 return hr;
2082 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2084 VariantClear(&vararg);
2085 return hr;
2087 break;
2088 case DISPID_PICT_TYPE:
2089 if (wFlags & DISPATCH_PROPERTYGET)
2091 TRACE("DISPID_PICT_TYPE\n");
2092 V_VT(pVarResult) = VT_I2;
2093 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2095 break;
2096 case DISPID_PICT_WIDTH:
2097 if (wFlags & DISPATCH_PROPERTYGET)
2099 TRACE("DISPID_PICT_WIDTH\n");
2100 V_VT(pVarResult) = VT_I4;
2101 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2103 break;
2104 case DISPID_PICT_HEIGHT:
2105 if (wFlags & DISPATCH_PROPERTYGET)
2107 TRACE("DISPID_PICT_HEIGHT\n");
2108 V_VT(pVarResult) = VT_I4;
2109 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2111 break;
2112 case DISPID_PICT_RENDER:
2113 if (wFlags & DISPATCH_METHOD)
2115 VARIANTARG *args = pDispParams->rgvarg;
2116 int i;
2118 TRACE("DISPID_PICT_RENDER\n");
2120 if (pDispParams->cArgs != 10)
2121 return DISP_E_BADPARAMCOUNT;
2123 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2124 for (i = 0; i < pDispParams->cArgs; i++)
2125 if (V_VT(&args[i]) != VT_I4)
2127 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i, V_VT(&args[i]));
2128 return DISP_E_TYPEMISMATCH;
2131 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2132 currently Render() doesn't use it at all so for now NULL is passed. */
2133 return IPicture_Render(&This->IPicture_iface,
2134 LongToHandle(V_I4(&args[9])),
2135 V_I4(&args[8]),
2136 V_I4(&args[7]),
2137 V_I4(&args[6]),
2138 V_I4(&args[5]),
2139 V_I4(&args[4]),
2140 V_I4(&args[3]),
2141 V_I4(&args[2]),
2142 V_I4(&args[1]),
2143 NULL);
2145 break;
2148 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2149 return DISP_E_MEMBERNOTFOUND;
2153 static const IPictureVtbl OLEPictureImpl_VTable =
2155 OLEPictureImpl_QueryInterface,
2156 OLEPictureImpl_AddRef,
2157 OLEPictureImpl_Release,
2158 OLEPictureImpl_get_Handle,
2159 OLEPictureImpl_get_hPal,
2160 OLEPictureImpl_get_Type,
2161 OLEPictureImpl_get_Width,
2162 OLEPictureImpl_get_Height,
2163 OLEPictureImpl_Render,
2164 OLEPictureImpl_set_hPal,
2165 OLEPictureImpl_get_CurDC,
2166 OLEPictureImpl_SelectPicture,
2167 OLEPictureImpl_get_KeepOriginalFormat,
2168 OLEPictureImpl_put_KeepOriginalFormat,
2169 OLEPictureImpl_PictureChanged,
2170 OLEPictureImpl_SaveAsFile,
2171 OLEPictureImpl_get_Attributes
2174 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2176 OLEPictureImpl_IDispatch_QueryInterface,
2177 OLEPictureImpl_IDispatch_AddRef,
2178 OLEPictureImpl_IDispatch_Release,
2179 OLEPictureImpl_GetTypeInfoCount,
2180 OLEPictureImpl_GetTypeInfo,
2181 OLEPictureImpl_GetIDsOfNames,
2182 OLEPictureImpl_Invoke
2185 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2187 OLEPictureImpl_IPersistStream_QueryInterface,
2188 OLEPictureImpl_IPersistStream_AddRef,
2189 OLEPictureImpl_IPersistStream_Release,
2190 OLEPictureImpl_GetClassID,
2191 OLEPictureImpl_IsDirty,
2192 OLEPictureImpl_Load,
2193 OLEPictureImpl_Save,
2194 OLEPictureImpl_GetSizeMax
2197 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2199 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2200 OLEPictureImpl_IConnectionPointContainer_AddRef,
2201 OLEPictureImpl_IConnectionPointContainer_Release,
2202 OLEPictureImpl_EnumConnectionPoints,
2203 OLEPictureImpl_FindConnectionPoint
2206 /***********************************************************************
2207 * OleCreatePictureIndirect (OLEAUT32.419)
2209 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2210 BOOL Own, void **ppvObj )
2212 OLEPictureImpl* newPict;
2213 HRESULT hr;
2215 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2217 *ppvObj = NULL;
2219 newPict = OLEPictureImpl_Construct(lpPictDesc, Own);
2221 if (newPict == NULL)
2222 return E_OUTOFMEMORY;
2225 * Make sure it supports the interface required by the caller.
2227 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2230 * Release the reference obtained in the constructor. If
2231 * the QueryInterface was unsuccessful, it will free the class.
2233 IPicture_Release(&newPict->IPicture_iface);
2235 return hr;
2239 /***********************************************************************
2240 * OleLoadPicture (OLEAUT32.418)
2242 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2243 REFIID riid, LPVOID *ppvObj )
2245 LPPERSISTSTREAM ps;
2246 IPicture *newpic;
2247 HRESULT hr;
2249 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2250 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2252 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2253 if (hr != S_OK)
2254 return hr;
2255 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2256 if (hr != S_OK) {
2257 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2258 IPicture_Release(newpic);
2259 *ppvObj = NULL;
2260 return hr;
2262 hr = IPersistStream_Load(ps,lpstream);
2263 IPersistStream_Release(ps);
2264 if (FAILED(hr))
2266 ERR("IPersistStream_Load failed\n");
2267 IPicture_Release(newpic);
2268 *ppvObj = NULL;
2269 return hr;
2271 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2272 if (hr != S_OK)
2273 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2274 IPicture_Release(newpic);
2275 return hr;
2278 /***********************************************************************
2279 * OleLoadPictureEx (OLEAUT32.401)
2281 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2282 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2284 LPPERSISTSTREAM ps;
2285 IPicture *newpic;
2286 HRESULT hr;
2288 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2289 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2291 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2292 if (hr != S_OK)
2293 return hr;
2294 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2295 if (hr != S_OK) {
2296 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2297 IPicture_Release(newpic);
2298 *ppvObj = NULL;
2299 return hr;
2301 hr = IPersistStream_Load(ps,lpstream);
2302 IPersistStream_Release(ps);
2303 if (FAILED(hr))
2305 ERR("IPersistStream_Load failed\n");
2306 IPicture_Release(newpic);
2307 *ppvObj = NULL;
2308 return hr;
2310 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2311 if (hr != S_OK)
2312 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2313 IPicture_Release(newpic);
2314 return hr;
2317 /***********************************************************************
2318 * OleLoadPictureFile (OLEAUT32.422)
2320 HRESULT WINAPI OleLoadPictureFile(VARIANT file, LPDISPATCH *picture)
2322 FIXME("(%s %p): stub\n", wine_dbgstr_variant(&file), picture);
2323 return E_NOTIMPL;
2326 /***********************************************************************
2327 * OleSavePictureFile (OLEAUT32.423)
2329 HRESULT WINAPI OleSavePictureFile(IDispatch *picture, BSTR filename)
2331 FIXME("(%p %s): stub\n", picture, debugstr_w(filename));
2332 return CTL_E_FILENOTFOUND;
2335 /***********************************************************************
2336 * OleLoadPicturePath (OLEAUT32.424)
2338 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2339 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2340 LPVOID *ppvRet )
2342 static const WCHAR file[] = { 'f','i','l','e',':',0 };
2343 IPicture *ipicture;
2344 HANDLE hFile;
2345 DWORD dwFileSize;
2346 HGLOBAL hGlobal = NULL;
2347 DWORD dwBytesRead;
2348 IStream *stream;
2349 BOOL bRead;
2350 IPersistStream *pStream;
2351 HRESULT hRes;
2352 HRESULT init_res;
2353 WCHAR *file_candidate;
2354 WCHAR path_buf[MAX_PATH];
2356 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2357 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2358 debugstr_guid(riid), ppvRet);
2360 if (!szURLorPath || !ppvRet)
2361 return E_INVALIDARG;
2363 *ppvRet = NULL;
2365 /* Convert file URLs to DOS paths. */
2366 if (strncmpW(szURLorPath, file, 5) == 0) {
2367 DWORD size;
2368 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2369 sizeof(path_buf)/sizeof(WCHAR), &size, 0);
2370 if (FAILED(hRes))
2371 return hRes;
2373 file_candidate = path_buf;
2375 else
2376 file_candidate = szURLorPath;
2378 /* Handle candidate DOS paths separately. */
2379 if (file_candidate[1] == ':') {
2380 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2381 0, NULL);
2382 if (hFile == INVALID_HANDLE_VALUE)
2383 return INET_E_RESOURCE_NOT_FOUND;
2385 dwFileSize = GetFileSize(hFile, NULL);
2386 if (dwFileSize != INVALID_FILE_SIZE )
2388 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2389 if ( hGlobal)
2391 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL) && dwBytesRead == dwFileSize;
2392 if (!bRead)
2394 GlobalFree(hGlobal);
2395 hGlobal = 0;
2399 CloseHandle(hFile);
2401 if (!hGlobal)
2402 return INET_E_RESOURCE_NOT_FOUND;
2404 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2405 if (FAILED(hRes))
2407 GlobalFree(hGlobal);
2408 return hRes;
2410 } else {
2411 IMoniker *pmnk;
2412 IBindCtx *pbc;
2414 hRes = CreateBindCtx(0, &pbc);
2415 if (SUCCEEDED(hRes))
2417 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2418 if (SUCCEEDED(hRes))
2420 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2421 IMoniker_Release(pmnk);
2423 IBindCtx_Release(pbc);
2425 if (FAILED(hRes))
2426 return hRes;
2429 init_res = CoInitialize(NULL);
2431 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2432 &IID_IPicture, (LPVOID*)&ipicture);
2433 if (SUCCEEDED(hRes)) {
2434 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2436 if (SUCCEEDED(hRes)) {
2437 hRes = IPersistStream_Load(pStream, stream);
2439 if (SUCCEEDED(hRes)) {
2440 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2442 if (FAILED(hRes))
2443 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2445 IPersistStream_Release(pStream);
2447 IPicture_Release(ipicture);
2450 IStream_Release(stream);
2452 if (SUCCEEDED(init_res))
2453 CoUninitialize();
2455 return hRes;
2458 /*******************************************************************************
2459 * StdPic ClassFactory
2461 typedef struct
2463 /* IUnknown fields */
2464 IClassFactory IClassFactory_iface;
2465 LONG ref;
2466 } IClassFactoryImpl;
2468 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2470 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2473 static HRESULT WINAPI
2474 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2475 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2477 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2478 return E_NOINTERFACE;
2481 static ULONG WINAPI
2482 SPCF_AddRef(LPCLASSFACTORY iface) {
2483 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2484 return InterlockedIncrement(&This->ref);
2487 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2488 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2489 /* static class, won't be freed */
2490 return InterlockedDecrement(&This->ref);
2493 static HRESULT WINAPI SPCF_CreateInstance(
2494 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2496 /* Creates an uninitialized picture */
2497 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2501 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2502 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2503 FIXME("(%p)->(%d),stub!\n",This,dolock);
2504 return S_OK;
2507 static const IClassFactoryVtbl SPCF_Vtbl = {
2508 SPCF_QueryInterface,
2509 SPCF_AddRef,
2510 SPCF_Release,
2511 SPCF_CreateInstance,
2512 SPCF_LockServer
2514 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2516 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }