kerberos: Add support for SECPKG_CRED_BOTH.
[wine.git] / dlls / oleaut32 / olepicture.c
blobe4bfafe6fd00c275e734f8712558926569dc7ef4
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 <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
43 #define COBJMACROS
44 #include "winerror.h"
45 #include "windef.h"
46 #include "winbase.h"
47 #include "wingdi.h"
48 #include "winuser.h"
49 #include "ole2.h"
50 #include "olectl.h"
51 #include "oleauto.h"
52 #include "connpt.h"
53 #include "urlmon.h"
54 #include "initguid.h"
55 #include "wincodec.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(olepicture);
60 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
61 #define BITMAP_FORMAT_JPEG 0xd8ff
62 #define BITMAP_FORMAT_GIF 0x4947
63 #define BITMAP_FORMAT_PNG 0x5089
64 #define BITMAP_FORMAT_APM 0xcdd7
66 #include "pshpack1.h"
68 /* Header for Aldus Placable Metafiles - a standard metafile follows */
69 typedef struct _APM_HEADER
71 DWORD key;
72 WORD handle;
73 SHORT left;
74 SHORT top;
75 SHORT right;
76 SHORT bottom;
77 WORD inch;
78 DWORD reserved;
79 WORD checksum;
80 } APM_HEADER;
82 typedef struct {
83 BYTE bWidth;
84 BYTE bHeight;
85 BYTE bColorCount;
86 BYTE bReserved;
87 WORD xHotspot;
88 WORD yHotspot;
89 DWORD dwDIBSize;
90 DWORD dwDIBOffset;
91 } CURSORICONFILEDIRENTRY;
93 typedef struct
95 WORD idReserved;
96 WORD idType;
97 WORD idCount;
98 CURSORICONFILEDIRENTRY idEntries[1];
99 } CURSORICONFILEDIR;
101 #include "poppack.h"
103 /*************************************************************************
104 * Declaration of implementation class
107 typedef struct OLEPictureImpl {
110 * IPicture handles IUnknown
113 IPicture IPicture_iface;
114 IDispatch IDispatch_iface;
115 IPersistStream IPersistStream_iface;
116 IConnectionPointContainer IConnectionPointContainer_iface;
118 /* Object reference count */
119 LONG ref;
121 /* We own the object and must destroy it ourselves */
122 BOOL fOwn;
124 /* Picture description */
125 PICTDESC desc;
127 /* These are the pixel size of a bitmap */
128 DWORD origWidth;
129 DWORD origHeight;
131 /* And these are the size of the picture converted into HIMETRIC units */
132 OLE_XSIZE_HIMETRIC himetricWidth;
133 OLE_YSIZE_HIMETRIC himetricHeight;
135 IConnectionPoint *pCP;
137 BOOL keepOrigFormat;
138 HDC hDCCur;
139 HBITMAP stock_bitmap;
141 /* Bitmap transparency mask */
142 HBITMAP hbmMask;
143 HBITMAP hbmXor;
144 COLORREF rgbTrans;
146 /* data */
147 void* data;
148 int datalen;
149 BOOL bIsDirty; /* Set to TRUE if picture has changed */
150 unsigned int loadtime_magic; /* If a length header was found, saves value */
151 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
152 } OLEPictureImpl;
154 static inline OLEPictureImpl *impl_from_IPicture(IPicture *iface)
156 return CONTAINING_RECORD(iface, OLEPictureImpl, IPicture_iface);
159 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
161 return CONTAINING_RECORD(iface, OLEPictureImpl, IDispatch_iface);
164 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
166 return CONTAINING_RECORD(iface, OLEPictureImpl, IPersistStream_iface);
169 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
171 return CONTAINING_RECORD(iface, OLEPictureImpl, IConnectionPointContainer_iface);
175 * Predeclare VTables. They get initialized at the end.
177 static const IPictureVtbl OLEPictureImpl_VTable;
178 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
179 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
180 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
182 /* pixels to HIMETRIC units conversion */
183 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
185 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
188 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
190 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
193 /***********************************************************************
194 * Implementation of the OLEPictureImpl class.
197 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
199 BITMAP bm;
200 HDC hdcRef;
202 TRACE("bitmap handle %p\n", This->desc.bmp.hbitmap);
203 if(GetObjectW(This->desc.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
204 ERR("GetObject fails\n");
205 return;
207 This->origWidth = bm.bmWidth;
208 This->origHeight = bm.bmHeight;
210 TRACE("width %d, height %d, bpp %d\n", bm.bmWidth, bm.bmHeight, bm.bmBitsPixel);
212 /* The width and height are stored in HIMETRIC units (0.01 mm),
213 so we take our pixel width divide by pixels per inch and
214 multiply by 25.4 * 100 */
215 /* Should we use GetBitmapDimension if available? */
216 hdcRef = CreateCompatibleDC(0);
218 This->himetricWidth = xpixels_to_himetric(bm.bmWidth, hdcRef);
219 This->himetricHeight = ypixels_to_himetric(bm.bmHeight, hdcRef);
220 This->stock_bitmap = GetCurrentObject( hdcRef, OBJ_BITMAP );
222 This->loadtime_format = BITMAP_FORMAT_BMP;
224 DeleteDC(hdcRef);
227 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
229 ICONINFO infoIcon;
231 TRACE("icon handle %p\n", This->desc.icon.hicon);
232 if (GetIconInfo(This->desc.icon.hicon, &infoIcon)) {
233 HDC hdcRef;
234 BITMAP bm;
236 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
237 if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
238 ERR("GetObject fails on icon bitmap\n");
239 return;
242 This->origWidth = bm.bmWidth;
243 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
244 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
245 hdcRef = GetDC(0);
247 This->himetricWidth = xpixels_to_himetric(This->origWidth, hdcRef);
248 This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
250 ReleaseDC(0, hdcRef);
252 DeleteObject(infoIcon.hbmMask);
253 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
254 } else {
255 ERR("GetIconInfo() fails on icon %p\n", This->desc.icon.hicon);
259 /************************************************************************
260 * OLEPictureImpl_Construct
262 * This method will construct a new instance of the OLEPictureImpl
263 * class.
265 * The caller of this method must release the object when it's
266 * done with it.
268 static HRESULT OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn, OLEPictureImpl **pict)
270 OLEPictureImpl *newObject;
271 HRESULT hr;
273 if (pictDesc)
274 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
277 * Allocate space for the object.
279 newObject = calloc(1, sizeof(OLEPictureImpl));
280 if (!newObject)
281 return E_OUTOFMEMORY;
284 * Initialize the virtual function table.
286 newObject->IPicture_iface.lpVtbl = &OLEPictureImpl_VTable;
287 newObject->IDispatch_iface.lpVtbl = &OLEPictureImpl_IDispatch_VTable;
288 newObject->IPersistStream_iface.lpVtbl = &OLEPictureImpl_IPersistStream_VTable;
289 newObject->IConnectionPointContainer_iface.lpVtbl = &OLEPictureImpl_IConnectionPointContainer_VTable;
291 newObject->pCP = NULL;
292 hr = CreateConnectionPoint((IUnknown*)&newObject->IPicture_iface, &IID_IPropertyNotifySink,
293 &newObject->pCP);
294 if (hr != S_OK)
296 free(newObject);
297 return hr;
301 * Start with one reference count. The caller of this function
302 * must release the interface pointer when it is done.
304 newObject->ref = 1;
305 newObject->hDCCur = 0;
307 newObject->fOwn = fOwn;
309 /* dunno about original value */
310 newObject->keepOrigFormat = TRUE;
312 newObject->hbmMask = NULL;
313 newObject->hbmXor = NULL;
314 newObject->loadtime_magic = 0xdeadbeef;
315 newObject->loadtime_format = 0;
316 newObject->bIsDirty = FALSE;
318 if (pictDesc) {
319 newObject->desc = *pictDesc;
321 switch(pictDesc->picType) {
322 case PICTYPE_BITMAP:
323 OLEPictureImpl_SetBitmap(newObject);
324 break;
326 case PICTYPE_METAFILE:
327 TRACE("metafile handle %p\n", pictDesc->wmf.hmeta);
328 newObject->himetricWidth = pictDesc->wmf.xExt;
329 newObject->himetricHeight = pictDesc->wmf.yExt;
330 break;
332 case PICTYPE_NONE:
333 /* not sure what to do here */
334 newObject->himetricWidth = newObject->himetricHeight = 0;
335 break;
337 case PICTYPE_ICON:
338 OLEPictureImpl_SetIcon(newObject);
339 break;
341 case PICTYPE_ENHMETAFILE:
342 FIXME("EMF is not supported\n");
343 newObject->himetricWidth = newObject->himetricHeight = 0;
344 break;
346 default:
347 WARN("Unsupported type %d\n", pictDesc->picType);
348 IPicture_Release(&newObject->IPicture_iface);
349 return E_UNEXPECTED;
351 } else {
352 newObject->desc.picType = PICTYPE_UNINITIALIZED;
355 TRACE("returning %p\n", newObject);
356 *pict = newObject;
357 return S_OK;
360 /************************************************************************
361 * OLEPictureImpl_Destroy
363 * This method is called by the Release method when the reference
364 * count goes down to 0. It will free all resources used by
365 * this object. */
366 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
368 TRACE("(%p)\n", Obj);
370 if (Obj->pCP)
371 IConnectionPoint_Release(Obj->pCP);
373 if(Obj->fOwn) { /* We need to destroy the picture */
374 switch(Obj->desc.picType) {
375 case PICTYPE_BITMAP:
376 DeleteObject(Obj->desc.bmp.hbitmap);
377 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
378 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
379 break;
380 case PICTYPE_METAFILE:
381 DeleteMetaFile(Obj->desc.wmf.hmeta);
382 break;
383 case PICTYPE_ICON:
384 DestroyIcon(Obj->desc.icon.hicon);
385 break;
386 case PICTYPE_ENHMETAFILE:
387 DeleteEnhMetaFile(Obj->desc.emf.hemf);
388 break;
389 case PICTYPE_NONE:
390 case PICTYPE_UNINITIALIZED:
391 /* Nothing to do */
392 break;
393 default:
394 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
395 break;
398 free(Obj->data);
399 free(Obj);
402 static ULONG WINAPI OLEPictureImpl_AddRef(
403 IPicture* iface)
405 OLEPictureImpl *This = impl_from_IPicture(iface);
406 ULONG refCount = InterlockedIncrement(&This->ref);
408 TRACE("%p, refcount %lu.\n", iface, refCount);
410 return refCount;
413 static ULONG WINAPI OLEPictureImpl_Release(
414 IPicture* iface)
416 OLEPictureImpl *This = impl_from_IPicture(iface);
417 ULONG refCount = InterlockedDecrement(&This->ref);
419 TRACE("%p, refcount %lu.\n", iface, refCount);
421 if (!refCount) OLEPictureImpl_Destroy(This);
423 return refCount;
426 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
427 IPicture* iface,
428 REFIID riid,
429 void** ppvObject)
431 OLEPictureImpl *This = impl_from_IPicture(iface);
433 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
435 if (!ppvObject)
436 return E_INVALIDARG;
438 *ppvObject = 0;
440 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
441 *ppvObject = &This->IPicture_iface;
442 else if (IsEqualIID(&IID_IDispatch, riid))
443 *ppvObject = &This->IDispatch_iface;
444 else if (IsEqualIID(&IID_IPictureDisp, riid))
445 *ppvObject = &This->IDispatch_iface;
446 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
447 *ppvObject = &This->IPersistStream_iface;
448 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
449 *ppvObject = &This->IConnectionPointContainer_iface;
451 if (!*ppvObject)
453 FIXME("() : asking for unsupported interface %s\n",debugstr_guid(riid));
454 return E_NOINTERFACE;
457 IPicture_AddRef(iface);
459 return S_OK;
462 /***********************************************************************
463 * OLEPicture_SendNotify (internal)
465 * Sends notification messages of changed properties to any interested
466 * connections.
468 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
470 IEnumConnections *pEnum;
471 CONNECTDATA CD;
473 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
474 return;
475 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
476 IPropertyNotifySink *sink;
478 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
479 IPropertyNotifySink_OnChanged(sink, dispID);
480 IPropertyNotifySink_Release(sink);
481 IUnknown_Release(CD.pUnk);
483 IEnumConnections_Release(pEnum);
486 /************************************************************************
487 * OLEPictureImpl_get_Handle
489 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
490 OLE_HANDLE *phandle)
492 OLEPictureImpl *This = impl_from_IPicture(iface);
493 TRACE("(%p)->(%p)\n", This, phandle);
495 if(!phandle)
496 return E_POINTER;
498 switch(This->desc.picType) {
499 case PICTYPE_NONE:
500 case PICTYPE_UNINITIALIZED:
501 *phandle = 0;
502 break;
503 case PICTYPE_BITMAP:
504 *phandle = HandleToUlong(This->desc.bmp.hbitmap);
505 break;
506 case PICTYPE_METAFILE:
507 *phandle = HandleToUlong(This->desc.wmf.hmeta);
508 break;
509 case PICTYPE_ICON:
510 *phandle = HandleToUlong(This->desc.icon.hicon);
511 break;
512 case PICTYPE_ENHMETAFILE:
513 *phandle = HandleToUlong(This->desc.emf.hemf);
514 break;
515 default:
516 FIXME("Unimplemented type %d\n", This->desc.picType);
517 return E_NOTIMPL;
519 TRACE("returning handle %08x\n", *phandle);
520 return S_OK;
523 /************************************************************************
524 * OLEPictureImpl_get_hPal
526 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
527 OLE_HANDLE *phandle)
529 OLEPictureImpl *This = impl_from_IPicture(iface);
531 TRACE("(%p)->(%p)\n", This, phandle);
533 if (!phandle) return E_POINTER;
535 if (This->desc.picType == PICTYPE_BITMAP)
537 *phandle = HandleToUlong(This->desc.bmp.hpal);
538 return S_OK;
541 return E_FAIL;
544 /************************************************************************
545 * OLEPictureImpl_get_Type
547 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
548 short *ptype)
550 OLEPictureImpl *This = impl_from_IPicture(iface);
551 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
553 if(!ptype)
554 return E_POINTER;
556 *ptype = This->desc.picType;
557 return S_OK;
560 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface, OLE_XSIZE_HIMETRIC *pwidth)
562 OLEPictureImpl *This = impl_from_IPicture(iface);
563 TRACE("%p, %p.\n", iface, pwidth);
564 *pwidth = This->himetricWidth;
565 return S_OK;
568 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface, OLE_YSIZE_HIMETRIC *pheight)
570 OLEPictureImpl *This = impl_from_IPicture(iface);
571 TRACE("%p, %p.\n", iface, pheight);
572 *pheight = This->himetricHeight;
573 return S_OK;
576 static void render_masked_bitmap(OLEPictureImpl *This, HDC hdc,
577 LONG x, LONG y, LONG cx, LONG cy, OLE_XPOS_HIMETRIC xSrc, OLE_YPOS_HIMETRIC ySrc,
578 OLE_XSIZE_HIMETRIC cxSrc, OLE_YSIZE_HIMETRIC cySrc, HBITMAP hbmMask, HBITMAP hbmXor)
580 HDC hdcBmp;
582 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
583 * NB y-axis gets flipped
586 hdcBmp = CreateCompatibleDC(0);
587 SetMapMode(hdcBmp, MM_ANISOTROPIC);
588 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
589 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
590 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
591 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
593 if (hbmMask)
595 SetBkColor(hdc, RGB(255, 255, 255));
596 SetTextColor(hdc, RGB(0, 0, 0));
598 SelectObject(hdcBmp, hbmMask);
599 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCAND);
601 if (hbmXor)
603 SelectObject(hdcBmp, hbmXor);
604 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
606 else StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc - This->himetricHeight,
607 cxSrc, cySrc, SRCPAINT);
609 else
611 SelectObject(hdcBmp, hbmXor);
612 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
615 DeleteDC(hdcBmp);
618 /************************************************************************
619 * OLEPictureImpl_Render
621 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
622 LONG x, LONG y, LONG cx, LONG cy,
623 OLE_XPOS_HIMETRIC xSrc,
624 OLE_YPOS_HIMETRIC ySrc,
625 OLE_XSIZE_HIMETRIC cxSrc,
626 OLE_YSIZE_HIMETRIC cySrc,
627 LPCRECT prcWBounds)
629 OLEPictureImpl *This = impl_from_IPicture(iface);
630 TRACE("%p, %p, (%ld,%ld), (%ld,%ld), (%ld,%ld), (%ld,%ld), %p)\n", iface, hdc, x, y, cx, cy, xSrc, ySrc,
631 cxSrc, cySrc, prcWBounds);
632 if(prcWBounds)
633 TRACE("prcWBounds %s\n", wine_dbgstr_rect(prcWBounds));
635 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
636 return CTL_E_INVALIDPROPERTYVALUE;
640 * While the documentation suggests this to be here (or after rendering?)
641 * it does cause an endless recursion in my sample app. -MM 20010804
642 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
645 switch(This->desc.picType) {
646 case PICTYPE_UNINITIALIZED:
647 case PICTYPE_NONE:
648 /* nothing to do */
649 return S_OK;
650 case PICTYPE_BITMAP:
652 HBITMAP hbmMask, hbmXor;
654 if (This->hbmMask)
656 hbmMask = This->hbmMask;
657 hbmXor = This->hbmXor;
659 else
661 hbmMask = 0;
662 hbmXor = This->desc.bmp.hbitmap;
665 render_masked_bitmap(This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, hbmMask, hbmXor);
666 break;
669 case PICTYPE_ICON:
671 ICONINFO info;
673 if (!GetIconInfo(This->desc.icon.hicon, &info))
674 return E_FAIL;
676 render_masked_bitmap(This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, info.hbmMask, info.hbmColor);
678 DeleteObject(info.hbmMask);
679 if (info.hbmColor) DeleteObject(info.hbmColor);
680 break;
683 case PICTYPE_METAFILE:
685 POINT prevOrg, prevWndOrg;
686 SIZE prevExt, prevWndExt;
687 int oldmode;
689 /* Render the WMF to the appropriate location by setting the
690 appropriate ratio between "device units" and "logical units" */
691 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
692 /* For the "source rectangle" the y-axis must be inverted */
693 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
694 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
695 /* For the "destination rectangle" no inversion is necessary */
696 SetViewportOrgEx(hdc, x, y, &prevOrg);
697 SetViewportExtEx(hdc, cx, cy, &prevExt);
699 if (!PlayMetaFile(hdc, This->desc.wmf.hmeta))
700 ERR("PlayMetaFile failed!\n");
702 /* We're done, restore the DC to the previous settings for converting
703 logical units to device units */
704 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
705 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
706 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
707 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
708 SetMapMode(hdc, oldmode);
709 break;
712 case PICTYPE_ENHMETAFILE:
714 RECT rc = { x, y, x + cx, y + cy };
715 PlayEnhMetaFile(hdc, This->desc.emf.hemf, &rc);
716 break;
719 default:
720 FIXME("type %d not implemented\n", This->desc.picType);
721 return E_NOTIMPL;
723 return S_OK;
726 /************************************************************************
727 * OLEPictureImpl_set_hPal
729 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
730 OLE_HANDLE hpal)
732 OLEPictureImpl *This = impl_from_IPicture(iface);
734 TRACE("(%p)->(%08x)\n", This, hpal);
736 if (This->desc.picType == PICTYPE_BITMAP)
738 This->desc.bmp.hpal = ULongToHandle(hpal);
739 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
740 return S_OK;
743 return E_FAIL;
746 /************************************************************************
747 * OLEPictureImpl_get_CurDC
749 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
750 HDC *phdc)
752 OLEPictureImpl *This = impl_from_IPicture(iface);
753 TRACE("(%p), returning %p\n", This, This->hDCCur);
754 if (phdc) *phdc = This->hDCCur;
755 return S_OK;
758 /************************************************************************
759 * OLEPictureImpl_SelectPicture
761 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
762 HDC hdcIn,
763 HDC *phdcOut,
764 OLE_HANDLE *phbmpOut)
766 OLEPictureImpl *This = impl_from_IPicture(iface);
767 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
768 if (This->desc.picType == PICTYPE_BITMAP) {
769 if (phdcOut)
770 *phdcOut = This->hDCCur;
771 if (This->hDCCur) SelectObject(This->hDCCur,This->stock_bitmap);
772 if (hdcIn) SelectObject(hdcIn,This->desc.bmp.hbitmap);
773 This->hDCCur = hdcIn;
774 if (phbmpOut)
775 *phbmpOut = HandleToUlong(This->desc.bmp.hbitmap);
776 return S_OK;
777 } else {
778 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
779 return E_FAIL;
783 /************************************************************************
784 * OLEPictureImpl_get_KeepOriginalFormat
786 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
787 BOOL *pfKeep)
789 OLEPictureImpl *This = impl_from_IPicture(iface);
790 TRACE("(%p)->(%p)\n", This, pfKeep);
791 if (!pfKeep)
792 return E_POINTER;
793 *pfKeep = This->keepOrigFormat;
794 return S_OK;
797 /************************************************************************
798 * OLEPictureImpl_put_KeepOriginalFormat
800 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
801 BOOL keep)
803 OLEPictureImpl *This = impl_from_IPicture(iface);
804 TRACE("(%p)->(%d)\n", This, keep);
805 This->keepOrigFormat = keep;
806 /* FIXME: what DISPID notification here? */
807 return S_OK;
810 /************************************************************************
811 * OLEPictureImpl_PictureChanged
813 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
815 OLEPictureImpl *This = impl_from_IPicture(iface);
816 TRACE("(%p)->()\n", This);
817 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
818 This->bIsDirty = TRUE;
819 return S_OK;
822 /************************************************************************
823 * OLEPictureImpl_SaveAsFile
825 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
826 IStream *pstream,
827 BOOL SaveMemCopy,
828 LONG *pcbSize)
830 OLEPictureImpl *This = impl_from_IPicture(iface);
831 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
832 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
835 /************************************************************************
836 * OLEPictureImpl_get_Attributes
838 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
839 DWORD *pdwAttr)
841 OLEPictureImpl *This = impl_from_IPicture(iface);
842 TRACE("(%p)->(%p).\n", This, pdwAttr);
844 if(!pdwAttr)
845 return E_POINTER;
847 *pdwAttr = 0;
848 switch (This->desc.picType) {
849 case PICTYPE_UNINITIALIZED:
850 case PICTYPE_NONE: break;
851 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
852 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
853 case PICTYPE_ENHMETAFILE: /* fall through */
854 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
855 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
857 return S_OK;
861 /************************************************************************
862 * IConnectionPointContainer
864 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
865 IConnectionPointContainer* iface,
866 REFIID riid,
867 VOID** ppvoid)
869 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
871 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
874 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
875 IConnectionPointContainer* iface)
877 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
879 return IPicture_AddRef(&This->IPicture_iface);
882 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
883 IConnectionPointContainer* iface)
885 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
887 return IPicture_Release(&This->IPicture_iface);
890 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
891 IConnectionPointContainer* iface,
892 IEnumConnectionPoints** ppEnum)
894 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
896 FIXME("(%p,%p), stub!\n",This,ppEnum);
897 return E_NOTIMPL;
900 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
901 IConnectionPointContainer* iface,
902 REFIID riid,
903 IConnectionPoint **ppCP)
905 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
906 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
907 if (!ppCP)
908 return E_POINTER;
909 *ppCP = NULL;
910 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
911 return IConnectionPoint_QueryInterface(This->pCP, &IID_IConnectionPoint, (void**)ppCP);
912 FIXME("no connection point for %s\n",debugstr_guid(riid));
913 return CONNECT_E_NOCONNECTION;
917 /************************************************************************
918 * IPersistStream
921 /************************************************************************
922 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
924 * See Windows documentation for more details on IUnknown methods.
926 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
927 IPersistStream* iface,
928 REFIID riid,
929 VOID** ppvoid)
931 OLEPictureImpl *This = impl_from_IPersistStream(iface);
933 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
936 /************************************************************************
937 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
939 * See Windows documentation for more details on IUnknown methods.
941 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
942 IPersistStream* iface)
944 OLEPictureImpl *This = impl_from_IPersistStream(iface);
946 return IPicture_AddRef(&This->IPicture_iface);
949 /************************************************************************
950 * OLEPictureImpl_IPersistStream_Release (IUnknown)
952 * See Windows documentation for more details on IUnknown methods.
954 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
955 IPersistStream* iface)
957 OLEPictureImpl *This = impl_from_IPersistStream(iface);
959 return IPicture_Release(&This->IPicture_iface);
962 /************************************************************************
963 * OLEPictureImpl_IPersistStream_GetClassID
965 static HRESULT WINAPI OLEPictureImpl_GetClassID(
966 IPersistStream* iface,CLSID* pClassID)
968 TRACE("(%p)\n", pClassID);
969 *pClassID = CLSID_StdPicture;
970 return S_OK;
973 /************************************************************************
974 * OLEPictureImpl_IPersistStream_IsDirty
976 static HRESULT WINAPI OLEPictureImpl_IsDirty(
977 IPersistStream* iface)
979 OLEPictureImpl *This = impl_from_IPersistStream(iface);
980 FIXME("(%p),stub!\n",This);
981 return E_NOTIMPL;
984 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
986 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
987 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
988 HDC hdcref;
990 /* Does not matter whether this is a coreheader or not, we only use
991 * components which are in both
993 hdcref = GetDC(0);
994 This->desc.bmp.hbitmap = CreateDIBitmap(
995 hdcref,
996 &(bi->bmiHeader),
997 CBM_INIT,
998 xbuf+bfh->bfOffBits,
1000 DIB_RGB_COLORS
1002 ReleaseDC(0, hdcref);
1003 if (This->desc.bmp.hbitmap == 0)
1004 return E_FAIL;
1005 This->desc.picType = PICTYPE_BITMAP;
1006 OLEPictureImpl_SetBitmap(This);
1007 return S_OK;
1010 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1012 HRESULT hr;
1013 BITMAPINFOHEADER bih;
1014 HDC hdcref;
1015 UINT width, height;
1016 UINT stride, buffersize;
1017 LPBYTE bits=NULL;
1018 WICRect rc;
1019 IWICBitmapSource *real_source;
1020 UINT x, y;
1021 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1022 BOOL has_alpha=FALSE;
1024 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1025 if (FAILED(hr)) return hr;
1027 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1028 if (FAILED(hr)) goto end;
1030 bih.biSize = sizeof(bih);
1031 bih.biWidth = width;
1032 bih.biHeight = -height;
1033 bih.biPlanes = 1;
1034 bih.biBitCount = 32;
1035 bih.biCompression = BI_RGB;
1036 bih.biSizeImage = 0;
1037 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1038 bih.biYPelsPerMeter = 4085;
1039 bih.biClrUsed = 0;
1040 bih.biClrImportant = 0;
1042 stride = 4 * width;
1043 buffersize = stride * height;
1045 bits = malloc(buffersize);
1046 if (!bits)
1048 hr = E_OUTOFMEMORY;
1049 goto end;
1052 rc.X = 0;
1053 rc.Y = 0;
1054 rc.Width = width;
1055 rc.Height = height;
1056 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1057 if (FAILED(hr))
1058 goto end;
1060 hdcref = GetDC(0);
1061 This->desc.bmp.hbitmap = CreateDIBitmap(
1062 hdcref,
1063 &bih,
1064 CBM_INIT,
1065 bits,
1066 (BITMAPINFO*)&bih,
1067 DIB_RGB_COLORS);
1069 if (This->desc.bmp.hbitmap == 0)
1071 hr = E_FAIL;
1072 ReleaseDC(0, hdcref);
1073 goto end;
1076 This->desc.picType = PICTYPE_BITMAP;
1077 OLEPictureImpl_SetBitmap(This);
1079 /* set transparent pixels to black, all others to white */
1080 for(y = 0; y < height; y++){
1081 for(x = 0; x < width; x++){
1082 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1083 if((*pixel & 0x80000000) == 0)
1085 has_alpha = TRUE;
1086 *pixel = black;
1088 else
1089 *pixel = white;
1093 if (has_alpha)
1095 HDC hdcBmp, hdcXor, hdcMask;
1096 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1098 This->hbmXor = CreateDIBitmap(
1099 hdcref,
1100 &bih,
1101 CBM_INIT,
1102 bits,
1103 (BITMAPINFO*)&bih,
1104 DIB_RGB_COLORS
1107 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1108 hdcBmp = CreateCompatibleDC(NULL);
1109 hdcXor = CreateCompatibleDC(NULL);
1110 hdcMask = CreateCompatibleDC(NULL);
1112 hbmoldBmp = SelectObject(hdcBmp,This->desc.bmp.hbitmap);
1113 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1114 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1116 SetBkColor(hdcXor,black);
1117 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1118 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1120 SelectObject(hdcBmp,hbmoldBmp);
1121 SelectObject(hdcXor,hbmoldXor);
1122 SelectObject(hdcMask,hbmoldMask);
1124 DeleteDC(hdcBmp);
1125 DeleteDC(hdcXor);
1126 DeleteDC(hdcMask);
1129 ReleaseDC(0, hdcref);
1131 end:
1132 free(bits);
1133 IWICBitmapSource_Release(real_source);
1134 return hr;
1137 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1139 HRESULT hr;
1140 IWICImagingFactory *factory;
1141 IWICBitmapDecoder *decoder;
1142 IWICBitmapFrameDecode *framedecode;
1143 HRESULT initresult;
1144 IWICStream *stream;
1146 initresult = CoInitialize(NULL);
1148 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1149 &IID_IWICImagingFactory, (void**)&factory);
1150 if (SUCCEEDED(hr)) /* created factory */
1152 hr = IWICImagingFactory_CreateStream(factory, &stream);
1153 IWICImagingFactory_Release(factory);
1156 if (SUCCEEDED(hr)) /* created stream */
1158 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1160 if (SUCCEEDED(hr)) /* initialized stream */
1162 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1163 &IID_IWICBitmapDecoder, (void**)&decoder);
1164 if (SUCCEEDED(hr)) /* created decoder */
1166 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1168 if (SUCCEEDED(hr)) /* initialized decoder */
1169 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1171 IWICBitmapDecoder_Release(decoder);
1175 IWICStream_Release(stream);
1178 if (SUCCEEDED(hr)) /* got framedecode */
1180 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1181 IWICBitmapFrameDecode_Release(framedecode);
1184 if (SUCCEEDED(initresult)) CoUninitialize();
1185 return hr;
1188 /*****************************************************
1189 * start of Icon-specific code
1192 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1194 HICON hicon;
1195 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1196 HDC hdcRef;
1197 int i;
1199 TRACE("(this %p, xbuf %p, xread %lu)\n", This, xbuf, xread);
1202 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1203 FIXME("icon.idType=%d\n",cifd->idType);
1204 FIXME("icon.idCount=%d\n",cifd->idCount);
1206 for (i=0;i<cifd->idCount;i++) {
1207 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1208 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1209 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1210 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1211 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1212 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1213 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1214 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1218 /* Need at least one icon to do something. */
1219 if (!cifd->idCount)
1221 ERR("Invalid icon count of zero.\n");
1222 return E_FAIL;
1224 i=0;
1225 /* If we have more than one icon, try to find the best.
1226 * this currently means '32 pixel wide'.
1228 if (cifd->idCount!=1) {
1229 for (i=0;i<cifd->idCount;i++) {
1230 if (cifd->idEntries[i].bWidth == 32)
1231 break;
1233 if (i==cifd->idCount) i=0;
1235 if (xread < cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize)
1237 ERR("Icon data address %lu is over %lu bytes available.\n",
1238 cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize, xread);
1239 return E_FAIL;
1241 if (cifd->idType == 2)
1243 BYTE *buf = malloc(cifd->idEntries[i].dwDIBSize + 4);
1244 memcpy(buf, &cifd->idEntries[i].xHotspot, 4);
1245 memcpy(buf + 4, xbuf+cifd->idEntries[i].dwDIBOffset, cifd->idEntries[i].dwDIBSize);
1246 hicon = CreateIconFromResourceEx(
1247 buf,
1248 cifd->idEntries[i].dwDIBSize + 4,
1249 FALSE, /* is cursor */
1250 0x00030000,
1251 cifd->idEntries[i].bWidth,
1252 cifd->idEntries[i].bHeight,
1255 free(buf);
1257 else
1259 hicon = CreateIconFromResourceEx(
1260 xbuf+cifd->idEntries[i].dwDIBOffset,
1261 cifd->idEntries[i].dwDIBSize,
1262 TRUE, /* is icon */
1263 0x00030000,
1264 cifd->idEntries[i].bWidth,
1265 cifd->idEntries[i].bHeight,
1269 if (!hicon) {
1270 ERR("CreateIcon failed.\n");
1271 return E_FAIL;
1272 } else {
1273 This->desc.picType = PICTYPE_ICON;
1274 This->desc.icon.hicon = hicon;
1275 This->origWidth = cifd->idEntries[i].bWidth;
1276 This->origHeight = cifd->idEntries[i].bHeight;
1277 hdcRef = CreateCompatibleDC(0);
1278 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1279 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1280 DeleteDC(hdcRef);
1281 return S_OK;
1285 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1286 const BYTE *data, ULONG size)
1288 HENHMETAFILE hemf;
1289 ENHMETAHEADER hdr;
1291 hemf = SetEnhMetaFileBits(size, data);
1292 if (!hemf) return E_FAIL;
1294 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1296 This->desc.picType = PICTYPE_ENHMETAFILE;
1297 This->desc.emf.hemf = hemf;
1299 This->origWidth = 0;
1300 This->origHeight = 0;
1301 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1302 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1304 return S_OK;
1307 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1308 const BYTE *data, ULONG size)
1310 const APM_HEADER *header = (const APM_HEADER *)data;
1311 HMETAFILE hmf;
1313 if (size < sizeof(APM_HEADER))
1314 return E_FAIL;
1315 if (header->key != 0x9ac6cdd7)
1316 return E_FAIL;
1318 /* SetMetaFileBitsEx performs data check on its own */
1319 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1320 if (!hmf) return E_FAIL;
1322 This->desc.picType = PICTYPE_METAFILE;
1323 This->desc.wmf.hmeta = hmf;
1324 This->desc.wmf.xExt = 0;
1325 This->desc.wmf.yExt = 0;
1327 This->origWidth = 0;
1328 This->origHeight = 0;
1329 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1330 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1331 return S_OK;
1334 /************************************************************************
1335 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1337 * Loads the binary data from the IStream. Starts at current position.
1338 * There appears to be an 2 DWORD header:
1339 * DWORD magic;
1340 * DWORD len;
1342 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1344 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1345 HRESULT hr;
1346 BOOL headerisdata;
1347 BOOL statfailed = FALSE;
1348 ULONG xread, toread;
1349 ULONG headerread;
1350 BYTE *xbuf;
1351 DWORD header[2];
1352 WORD magic;
1353 STATSTG statstg;
1354 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1356 TRACE("(%p,%p)\n",This,pStm);
1358 /****************************************************************************************
1359 * Part 1: Load the data
1361 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1362 * out whether we do.
1364 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1365 * compound file. This may explain most, if not all, of the cases of "no
1366 * header", and the header validation should take this into account.
1367 * At least in Visual Basic 6, resource streams, valid headers are
1368 * header[0] == "lt\0\0",
1369 * header[1] == length_of_stream.
1371 * Also handle streams where we do not have a working "Stat" method by
1372 * reading all data until the end of the stream.
1374 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1375 if (hr != S_OK) {
1376 TRACE("stat failed with hres %#lx, proceeding to read all data.\n",hr);
1377 statfailed = TRUE;
1378 /* we will read at least 8 byte ... just right below */
1379 statstg.cbSize.QuadPart = 8;
1382 toread = 0;
1383 headerread = 0;
1384 headerisdata = FALSE;
1385 do {
1386 hr = IStream_Read(pStm, header, 8, &xread);
1387 if (hr != S_OK || xread!=8) {
1388 ERR("Failure while reading picture header (hr is %#lx, nread is %ld).\n",hr,xread);
1389 return (hr?hr:E_FAIL);
1391 headerread += xread;
1392 xread = 0;
1394 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1395 if (toread != 0 && toread != header[1])
1396 FIXME("varying lengths of image data (prev=%lu curr=%lu), only last one will be used\n",
1397 toread, header[1]);
1398 toread = header[1];
1399 if (statfailed)
1401 statstg.cbSize.QuadPart = header[1] + 8;
1402 statfailed = FALSE;
1404 if (toread == 0) break;
1405 } else {
1406 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1407 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1408 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1409 (header[0] == EMR_HEADER) || /* EMF header */
1410 (header[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1411 (header[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1412 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1413 (header[1]==0)
1414 ) {/* Found start of bitmap data */
1415 headerisdata = TRUE;
1416 if (toread == 0)
1417 toread = statstg.cbSize.QuadPart-8;
1418 else toread -= 8;
1419 xread = 8;
1420 } else {
1421 FIXME("Unknown stream header magic: %#lx.\n", header[0]);
1422 toread = header[1];
1425 } while (!headerisdata);
1427 if (statfailed) { /* we don't know the size ... read all we get */
1428 unsigned int sizeinc = 4096;
1429 unsigned int origsize = sizeinc;
1430 ULONG nread = 42;
1432 TRACE("Reading all data from stream.\n");
1433 xbuf = calloc(1, origsize);
1434 if (headerisdata)
1435 memcpy (xbuf, header, 8);
1436 while (1) {
1437 while (xread < origsize) {
1438 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1439 xread += nread;
1440 if (hr != S_OK || !nread)
1441 break;
1443 if (!nread || hr != S_OK) /* done, or error */
1444 break;
1445 if (xread == origsize) {
1446 sizeinc = 2*sizeinc; /* exponential increase */
1447 xbuf = realloc(xbuf, origsize + sizeinc);
1448 memset(xbuf + origsize, 0, sizeinc);
1449 origsize += sizeinc;
1452 if (hr != S_OK)
1453 TRACE("hr in no-stat loader case is %#lx.\n", hr);
1454 TRACE("loaded %ld bytes.\n", xread);
1455 This->datalen = xread;
1456 This->data = xbuf;
1457 } else {
1458 This->datalen = toread+(headerisdata?8:0);
1459 xbuf = This->data = calloc(1, This->datalen);
1460 if (!xbuf)
1461 return E_OUTOFMEMORY;
1463 if (headerisdata)
1464 memcpy (xbuf, header, 8);
1466 while (xread < This->datalen) {
1467 ULONG nread;
1468 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1469 xread += nread;
1470 if (hr != S_OK || !nread)
1471 break;
1473 if (xread != This->datalen)
1474 ERR("Could only read %ld of %d bytes out of stream?\n", xread, This->datalen);
1476 if (This->datalen == 0) { /* Marks the "NONE" picture */
1477 This->desc.picType = PICTYPE_NONE;
1478 return S_OK;
1482 /****************************************************************************************
1483 * Part 2: Process the loaded data
1486 magic = xbuf[0] + (xbuf[1]<<8);
1487 This->loadtime_format = magic;
1489 switch (magic) {
1490 case BITMAP_FORMAT_GIF: /* GIF */
1491 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1492 break;
1493 case BITMAP_FORMAT_JPEG: /* JPEG */
1494 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1495 break;
1496 case BITMAP_FORMAT_BMP: /* Bitmap */
1497 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1498 break;
1499 case BITMAP_FORMAT_PNG: /* PNG */
1500 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1501 break;
1502 case BITMAP_FORMAT_APM: /* APM */
1503 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1504 break;
1505 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1506 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1507 break;
1509 default:
1511 unsigned int i;
1513 /* let's see if it's a EMF */
1514 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1515 if (hr == S_OK) break;
1517 FIXME("Unknown magic %04x, %ld read bytes:\n", magic, xread);
1518 hr=E_FAIL;
1519 for (i=0;i<xread+8;i++) {
1520 if (i<8) FIXME("%02x ",((unsigned char*)header)[i]);
1521 else FIXME("%02x ",xbuf[i-8]);
1522 if (i % 10 == 9) FIXME("\n");
1524 FIXME("\n");
1525 break;
1528 This->bIsDirty = FALSE;
1530 /* FIXME: this notify is not really documented */
1531 if (hr==S_OK)
1532 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1533 return hr;
1536 /* pass NULL buffer to fetch size */
1537 static HRESULT serializeBMP(HBITMAP hbmp, void **buffer, unsigned int *length)
1539 char infobuf[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)] = { 0 };
1540 BITMAPINFO *info = (BITMAPINFO *)infobuf;
1541 BITMAPINFO *bitmap;
1542 BITMAPFILEHEADER *filehdr;
1543 int numentries;
1544 HDC hdc;
1545 HRESULT hr = S_OK;
1546 unsigned char *data = NULL;
1548 /* Find out bitmap size and padded length */
1549 hdc = GetDC(0);
1550 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1551 if (!GetDIBits(hdc, hbmp, 0, 0, NULL, info, DIB_RGB_COLORS)) {
1552 hr = E_INVALIDARG;
1553 goto done;
1556 /* Calculate the total length required for the BMP data */
1557 if (info->bmiHeader.biClrUsed != 0) {
1558 numentries = info->bmiHeader.biClrUsed;
1559 if (numentries > 256)
1560 numentries = 256;
1561 } else {
1562 if (info->bmiHeader.biBitCount <= 8)
1563 numentries = 1 << info->bmiHeader.biBitCount;
1564 else
1565 numentries = 0;
1568 *length =
1569 sizeof(BITMAPFILEHEADER) +
1570 sizeof(BITMAPINFOHEADER) +
1571 numentries * sizeof(RGBQUAD) +
1572 info->bmiHeader.biSizeImage;
1574 if (!buffer)
1575 goto done;
1577 /* Fetch bitmap palette & pixel data */
1578 if (!(data = malloc(info->bmiHeader.biSizeImage))) {
1579 hr = E_OUTOFMEMORY;
1580 goto done;
1583 if (!GetDIBits(hdc, hbmp, 0, info->bmiHeader.biHeight, data, info, DIB_RGB_COLORS)) {
1584 hr = E_INVALIDARG;
1585 goto done;
1588 if (!(*buffer = malloc(*length))) {
1589 hr = E_OUTOFMEMORY;
1590 goto done;
1593 /* Fill the BITMAPFILEHEADER */
1594 filehdr = *buffer;
1595 filehdr->bfType = BITMAP_FORMAT_BMP;
1596 filehdr->bfSize = *length;
1597 filehdr->bfOffBits =
1598 sizeof(BITMAPFILEHEADER) +
1599 sizeof(BITMAPINFOHEADER) +
1600 numentries * sizeof(RGBQUAD);
1602 /* Fill the BITMAPINFOHEADER and the palette data */
1603 bitmap = (BITMAPINFO *)((unsigned char *)(*buffer) + sizeof(BITMAPFILEHEADER));
1604 memcpy(bitmap, info, sizeof(BITMAPINFOHEADER) + numentries * sizeof(RGBQUAD));
1605 memcpy((unsigned char *)(*buffer) + filehdr->bfOffBits, data, bitmap->bmiHeader.biSizeImage);
1607 done:
1608 free(data);
1609 ReleaseDC(0, hdc);
1610 return hr;
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 = calloc(1, 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 = calloc(1, 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 = realloc(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 free(pInfoBitmap);
1757 } else {
1758 ERR("Unable to get icon information (error %lu)\n", GetLastError());
1760 return success;
1763 static HRESULT WINAPI OLEPictureImpl_Save(
1764 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1766 HRESULT hResult = E_NOTIMPL;
1767 void * pIconData;
1768 unsigned int iDataSize;
1769 DWORD header[2];
1770 ULONG dummy;
1771 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1773 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1775 switch (This->desc.picType) {
1776 case PICTYPE_NONE:
1777 header[0] = 0x0000746c;
1778 header[1] = 0;
1779 hResult = IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1780 break;
1782 case PICTYPE_ICON:
1783 if (This->bIsDirty || !This->data) {
1784 if (!serializeIcon(This->desc.icon.hicon, &pIconData, &iDataSize)) {
1785 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1786 hResult = E_FAIL;
1787 break;
1789 free(This->data);
1790 This->data = pIconData;
1791 This->datalen = iDataSize;
1794 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1795 header[1] = This->datalen;
1796 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1797 IStream_Write(pStm, This->data, This->datalen, &dummy);
1798 hResult = S_OK;
1799 break;
1800 case PICTYPE_BITMAP:
1801 if (This->bIsDirty || !This->data) {
1802 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1803 case BITMAP_FORMAT_BMP:
1804 hResult = serializeBMP(This->desc.bmp.hbitmap, &pIconData, &iDataSize);
1805 break;
1806 case BITMAP_FORMAT_JPEG:
1807 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1808 break;
1809 case BITMAP_FORMAT_GIF:
1810 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1811 break;
1812 case BITMAP_FORMAT_PNG:
1813 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1814 break;
1815 default:
1816 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1817 break;
1820 if (hResult != S_OK)
1821 break;
1823 free(This->data);
1824 This->data = pIconData;
1825 This->datalen = iDataSize;
1828 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1829 header[1] = This->datalen;
1830 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1831 IStream_Write(pStm, This->data, This->datalen, &dummy);
1832 hResult = S_OK;
1833 break;
1834 case PICTYPE_METAFILE:
1835 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1836 break;
1837 case PICTYPE_ENHMETAFILE:
1838 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1839 break;
1840 default:
1841 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1842 break;
1844 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1845 return hResult;
1848 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *size)
1850 HRESULT hr = E_NOTIMPL;
1851 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1852 unsigned int datasize = This->datalen;
1854 FIXME("(%p,%p), partial stub!\n", This, size);
1856 if (!size)
1857 return E_INVALIDARG;
1859 switch (This->desc.picType) {
1860 case PICTYPE_NONE:
1861 hr = S_OK;
1862 break;
1863 case PICTYPE_ICON:
1864 FIXME("(%p), PICTYPE_ICON not implemented!\n",This);
1865 break;
1866 case PICTYPE_BITMAP:
1867 if (This->bIsDirty || !This->data) {
1868 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1869 case BITMAP_FORMAT_BMP:
1870 hr = serializeBMP(This->desc.bmp.hbitmap, NULL, &datasize);
1871 break;
1872 case BITMAP_FORMAT_JPEG:
1873 FIXME("(%p), PICTYPE_BITMAP (format JPEG) not implemented!\n",This);
1874 break;
1875 case BITMAP_FORMAT_GIF:
1876 FIXME("(%p), PICTYPE_BITMAP (format GIF) not implemented!\n",This);
1877 break;
1878 case BITMAP_FORMAT_PNG:
1879 FIXME("(%p), PICTYPE_BITMAP (format PNG) not implemented!\n",This);
1880 break;
1881 default:
1882 FIXME("(%p), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This);
1883 break;
1885 } else hr = S_OK;
1887 break;
1888 case PICTYPE_METAFILE:
1889 FIXME("(%p), PICTYPE_METAFILE not implemented!\n",This);
1890 break;
1891 case PICTYPE_ENHMETAFILE:
1892 FIXME("(%p), PICTYPE_ENHMETAFILE not implemented!\n",This);
1893 break;
1894 default:
1895 FIXME("(%p), [unknown type] not implemented!\n",This);
1896 break;
1899 size->HighPart = 0;
1900 size->LowPart = datasize + 8;
1901 return hr;
1905 /************************************************************************
1906 * IDispatch
1909 /************************************************************************
1910 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1912 * See Windows documentation for more details on IUnknown methods.
1914 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1915 IDispatch* iface,
1916 REFIID riid,
1917 VOID** ppvoid)
1919 OLEPictureImpl *This = impl_from_IDispatch(iface);
1921 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1924 /************************************************************************
1925 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1927 * See Windows documentation for more details on IUnknown methods.
1929 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1930 IDispatch* iface)
1932 OLEPictureImpl *This = impl_from_IDispatch(iface);
1934 return IPicture_AddRef(&This->IPicture_iface);
1937 /************************************************************************
1938 * OLEPictureImpl_IDispatch_Release (IUnknown)
1940 * See Windows documentation for more details on IUnknown methods.
1942 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1943 IDispatch* iface)
1945 OLEPictureImpl *This = impl_from_IDispatch(iface);
1947 return IPicture_Release(&This->IPicture_iface);
1950 /************************************************************************
1951 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1953 * See Windows documentation for more details on IDispatch methods.
1955 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1956 IDispatch* iface,
1957 unsigned int* pctinfo)
1959 TRACE("(%p)\n", pctinfo);
1961 *pctinfo = 1;
1963 return S_OK;
1966 /************************************************************************
1967 * OLEPictureImpl_GetTypeInfo (IDispatch)
1969 * See Windows documentation for more details on IDispatch methods.
1971 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1972 IDispatch* iface,
1973 UINT iTInfo,
1974 LCID lcid,
1975 ITypeInfo** ppTInfo)
1977 ITypeLib *tl;
1978 HRESULT hres;
1980 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1982 if (iTInfo != 0)
1983 return E_FAIL;
1985 hres = LoadTypeLib(L"stdole2.tlb", &tl);
1986 if (FAILED(hres))
1988 ERR("Could not load stdole2.tlb\n");
1989 return hres;
1992 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1993 if (FAILED(hres))
1994 ERR("Did not get IPictureDisp typeinfo from typelib, hres %#lx.\n", hres);
1996 return hres;
1999 /************************************************************************
2000 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2002 * See Windows documentation for more details on IDispatch methods.
2004 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2005 IDispatch* iface,
2006 REFIID riid,
2007 LPOLESTR* rgszNames,
2008 UINT cNames,
2009 LCID lcid,
2010 DISPID* rgDispId)
2012 ITypeInfo * pTInfo;
2013 HRESULT hres;
2015 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2016 rgszNames, cNames, (int)lcid, rgDispId);
2018 if (cNames == 0)
2020 return E_INVALIDARG;
2022 else
2024 /* retrieve type information */
2025 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2027 if (FAILED(hres))
2029 ERR("GetTypeInfo failed.\n");
2030 return hres;
2033 /* convert names to DISPIDs */
2034 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2035 ITypeInfo_Release(pTInfo);
2037 return hres;
2041 /************************************************************************
2042 * OLEPictureImpl_Invoke (IDispatch)
2044 * See Windows documentation for more details on IDispatch methods.
2046 static HRESULT WINAPI OLEPictureImpl_Invoke(
2047 IDispatch* iface,
2048 DISPID dispIdMember,
2049 REFIID riid,
2050 LCID lcid,
2051 WORD wFlags,
2052 DISPPARAMS* pDispParams,
2053 VARIANT* pVarResult,
2054 EXCEPINFO* pExepInfo,
2055 UINT* puArgErr)
2057 OLEPictureImpl *This = impl_from_IDispatch(iface);
2058 HRESULT hr;
2060 /* validate parameters */
2062 if (!IsEqualIID(riid, &IID_NULL))
2064 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2065 return DISP_E_UNKNOWNNAME;
2068 if (!pDispParams)
2070 ERR("null pDispParams not allowed\n");
2071 return DISP_E_PARAMNOTOPTIONAL;
2074 if (wFlags & DISPATCH_PROPERTYGET)
2076 if (pDispParams->cArgs != 0)
2078 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2079 return DISP_E_BADPARAMCOUNT;
2081 if (!pVarResult)
2083 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2084 return DISP_E_PARAMNOTOPTIONAL;
2087 else if (wFlags & DISPATCH_PROPERTYPUT)
2089 if (pDispParams->cArgs != 1)
2091 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2092 return DISP_E_BADPARAMCOUNT;
2096 switch (dispIdMember)
2098 case DISPID_PICT_HANDLE:
2099 if (wFlags & DISPATCH_PROPERTYGET)
2101 TRACE("DISPID_PICT_HANDLE\n");
2102 V_VT(pVarResult) = VT_I4;
2103 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2105 break;
2106 case DISPID_PICT_HPAL:
2107 if (wFlags & DISPATCH_PROPERTYGET)
2109 TRACE("DISPID_PICT_HPAL\n");
2110 V_VT(pVarResult) = VT_I4;
2111 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2113 else if (wFlags & DISPATCH_PROPERTYPUT)
2115 VARIANTARG vararg;
2117 TRACE("DISPID_PICT_HPAL\n");
2119 VariantInit(&vararg);
2120 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2121 if (FAILED(hr))
2122 return hr;
2124 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2126 VariantClear(&vararg);
2127 return hr;
2129 break;
2130 case DISPID_PICT_TYPE:
2131 if (wFlags & DISPATCH_PROPERTYGET)
2133 TRACE("DISPID_PICT_TYPE\n");
2134 V_VT(pVarResult) = VT_I2;
2135 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2137 break;
2138 case DISPID_PICT_WIDTH:
2139 if (wFlags & DISPATCH_PROPERTYGET)
2141 TRACE("DISPID_PICT_WIDTH\n");
2142 V_VT(pVarResult) = VT_I4;
2143 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2145 break;
2146 case DISPID_PICT_HEIGHT:
2147 if (wFlags & DISPATCH_PROPERTYGET)
2149 TRACE("DISPID_PICT_HEIGHT\n");
2150 V_VT(pVarResult) = VT_I4;
2151 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2153 break;
2154 case DISPID_PICT_RENDER:
2155 if (wFlags & DISPATCH_METHOD)
2157 VARIANTARG *args = pDispParams->rgvarg;
2158 int i;
2160 TRACE("DISPID_PICT_RENDER\n");
2162 if (pDispParams->cArgs != 10)
2163 return DISP_E_BADPARAMCOUNT;
2165 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2166 for (i = 0; i < pDispParams->cArgs; i++)
2167 if (V_VT(&args[i]) != VT_I4)
2169 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i, V_VT(&args[i]));
2170 return DISP_E_TYPEMISMATCH;
2173 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2174 currently Render() doesn't use it at all so for now NULL is passed. */
2175 return IPicture_Render(&This->IPicture_iface,
2176 LongToHandle(V_I4(&args[9])),
2177 V_I4(&args[8]),
2178 V_I4(&args[7]),
2179 V_I4(&args[6]),
2180 V_I4(&args[5]),
2181 V_I4(&args[4]),
2182 V_I4(&args[3]),
2183 V_I4(&args[2]),
2184 V_I4(&args[1]),
2185 NULL);
2187 break;
2190 ERR("invalid dispid %#lx or wFlags 0x%x\n", dispIdMember, wFlags);
2191 return DISP_E_MEMBERNOTFOUND;
2195 static const IPictureVtbl OLEPictureImpl_VTable =
2197 OLEPictureImpl_QueryInterface,
2198 OLEPictureImpl_AddRef,
2199 OLEPictureImpl_Release,
2200 OLEPictureImpl_get_Handle,
2201 OLEPictureImpl_get_hPal,
2202 OLEPictureImpl_get_Type,
2203 OLEPictureImpl_get_Width,
2204 OLEPictureImpl_get_Height,
2205 OLEPictureImpl_Render,
2206 OLEPictureImpl_set_hPal,
2207 OLEPictureImpl_get_CurDC,
2208 OLEPictureImpl_SelectPicture,
2209 OLEPictureImpl_get_KeepOriginalFormat,
2210 OLEPictureImpl_put_KeepOriginalFormat,
2211 OLEPictureImpl_PictureChanged,
2212 OLEPictureImpl_SaveAsFile,
2213 OLEPictureImpl_get_Attributes
2216 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2218 OLEPictureImpl_IDispatch_QueryInterface,
2219 OLEPictureImpl_IDispatch_AddRef,
2220 OLEPictureImpl_IDispatch_Release,
2221 OLEPictureImpl_GetTypeInfoCount,
2222 OLEPictureImpl_GetTypeInfo,
2223 OLEPictureImpl_GetIDsOfNames,
2224 OLEPictureImpl_Invoke
2227 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2229 OLEPictureImpl_IPersistStream_QueryInterface,
2230 OLEPictureImpl_IPersistStream_AddRef,
2231 OLEPictureImpl_IPersistStream_Release,
2232 OLEPictureImpl_GetClassID,
2233 OLEPictureImpl_IsDirty,
2234 OLEPictureImpl_Load,
2235 OLEPictureImpl_Save,
2236 OLEPictureImpl_GetSizeMax
2239 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2241 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2242 OLEPictureImpl_IConnectionPointContainer_AddRef,
2243 OLEPictureImpl_IConnectionPointContainer_Release,
2244 OLEPictureImpl_EnumConnectionPoints,
2245 OLEPictureImpl_FindConnectionPoint
2248 /***********************************************************************
2249 * OleCreatePictureIndirect (OLEAUT32.419)
2251 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2252 BOOL Own, void **ppvObj )
2254 OLEPictureImpl* newPict;
2255 HRESULT hr;
2257 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2259 *ppvObj = NULL;
2261 hr = OLEPictureImpl_Construct(lpPictDesc, Own, &newPict);
2262 if (hr != S_OK) return hr;
2265 * Make sure it supports the interface required by the caller.
2267 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2270 * Release the reference obtained in the constructor. If
2271 * the QueryInterface was unsuccessful, it will free the class.
2273 IPicture_Release(&newPict->IPicture_iface);
2275 return hr;
2279 /***********************************************************************
2280 * OleLoadPicture (OLEAUT32.418)
2282 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2283 REFIID riid, LPVOID *ppvObj )
2285 LPPERSISTSTREAM ps;
2286 IPicture *newpic;
2287 HRESULT hr;
2289 TRACE("%p, %ld, %d, %s, %p), partially implemented.\n",
2290 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2292 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2293 if (hr != S_OK)
2294 return hr;
2295 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2296 if (hr != S_OK) {
2297 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2298 IPicture_Release(newpic);
2299 *ppvObj = NULL;
2300 return hr;
2302 hr = IPersistStream_Load(ps,lpstream);
2303 IPersistStream_Release(ps);
2304 if (FAILED(hr))
2306 ERR("IPersistStream_Load failed\n");
2307 IPicture_Release(newpic);
2308 *ppvObj = NULL;
2309 return hr;
2311 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2312 if (hr != S_OK)
2313 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2314 IPicture_Release(newpic);
2315 return hr;
2318 /***********************************************************************
2319 * OleLoadPictureEx (OLEAUT32.401)
2321 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2322 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2324 LPPERSISTSTREAM ps;
2325 IPicture *newpic;
2326 HRESULT hr;
2328 FIXME("%p, %ld, %d, %s, %lu, %lu, %#lx, %p, partially implemented.\n",
2329 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2331 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2332 if (hr != S_OK)
2333 return hr;
2334 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2335 if (hr != S_OK) {
2336 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2337 IPicture_Release(newpic);
2338 *ppvObj = NULL;
2339 return hr;
2341 hr = IPersistStream_Load(ps,lpstream);
2342 IPersistStream_Release(ps);
2343 if (FAILED(hr))
2345 ERR("IPersistStream_Load failed\n");
2346 IPicture_Release(newpic);
2347 *ppvObj = NULL;
2348 return hr;
2350 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2351 if (hr != S_OK)
2352 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2353 IPicture_Release(newpic);
2354 return hr;
2357 static HRESULT create_stream(const WCHAR *filename, IStream **stream)
2359 HANDLE hFile;
2360 DWORD dwFileSize;
2361 HGLOBAL hGlobal = NULL;
2362 DWORD dwBytesRead;
2363 HRESULT hr = S_OK;
2365 hFile = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
2366 if (hFile == INVALID_HANDLE_VALUE)
2367 return HRESULT_FROM_WIN32(GetLastError());
2369 dwFileSize = GetFileSize(hFile, NULL);
2370 if (dwFileSize != INVALID_FILE_SIZE)
2372 hGlobal = GlobalAlloc(GMEM_FIXED, dwFileSize);
2373 if (!hGlobal)
2374 hr = E_OUTOFMEMORY;
2375 else
2377 if (!ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL))
2379 GlobalFree(hGlobal);
2380 hr = HRESULT_FROM_WIN32(GetLastError());
2385 CloseHandle(hFile);
2387 if (FAILED(hr)) return hr;
2389 hr = CreateStreamOnHGlobal(hGlobal, TRUE, stream);
2390 if (FAILED(hr))
2391 GlobalFree(hGlobal);
2393 return hr;
2396 /***********************************************************************
2397 * OleLoadPictureFile (OLEAUT32.422)
2399 HRESULT WINAPI OleLoadPictureFile(VARIANT filename, IDispatch **picture)
2401 IStream *stream;
2402 HRESULT hr;
2404 TRACE("(%s,%p)\n", wine_dbgstr_variant(&filename), picture);
2406 if (V_VT(&filename) != VT_BSTR)
2407 return CTL_E_FILENOTFOUND;
2409 hr = create_stream(V_BSTR(&filename), &stream);
2410 if (hr != S_OK)
2412 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
2413 return CTL_E_FILENOTFOUND;
2415 return CTL_E_PATHFILEACCESSERROR;
2418 hr = OleLoadPicture(stream, 0, FALSE, &IID_IDispatch, (void **)picture);
2419 IStream_Release(stream);
2420 return hr;
2423 /***********************************************************************
2424 * OleSavePictureFile (OLEAUT32.423)
2426 HRESULT WINAPI OleSavePictureFile(IDispatch *picture, BSTR filename)
2428 FIXME("(%p %s): stub\n", picture, debugstr_w(filename));
2429 return CTL_E_FILENOTFOUND;
2432 /***********************************************************************
2433 * OleLoadPicturePath (OLEAUT32.424)
2435 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2436 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2437 LPVOID *ppvRet )
2439 IStream *stream;
2440 HRESULT hRes;
2441 WCHAR *file_candidate;
2442 WCHAR path_buf[MAX_PATH];
2444 TRACE("%s, %p, %ld, %#lx, %s, %p.\n", debugstr_w(szURLorPath), punkCaller, dwReserved,
2445 clrReserved, debugstr_guid(riid), ppvRet);
2447 if (!szURLorPath || !ppvRet)
2448 return E_INVALIDARG;
2450 *ppvRet = NULL;
2452 /* Convert file URLs to DOS paths. */
2453 if (wcsncmp(szURLorPath, L"file:", 5) == 0) {
2454 DWORD size;
2455 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2456 ARRAY_SIZE(path_buf), &size, 0);
2457 if (FAILED(hRes))
2458 return hRes;
2460 file_candidate = path_buf;
2462 else
2463 file_candidate = szURLorPath;
2465 /* Handle candidate DOS paths separately. */
2466 if (file_candidate[1] == ':') {
2467 hRes = create_stream(file_candidate, &stream);
2468 if (FAILED(hRes))
2469 return INET_E_RESOURCE_NOT_FOUND;
2470 } else {
2471 IMoniker *pmnk;
2472 IBindCtx *pbc;
2474 hRes = CreateBindCtx(0, &pbc);
2475 if (SUCCEEDED(hRes))
2477 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2478 if (SUCCEEDED(hRes))
2480 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2481 IMoniker_Release(pmnk);
2483 IBindCtx_Release(pbc);
2485 if (FAILED(hRes))
2486 return hRes;
2489 hRes = OleLoadPicture(stream, 0, FALSE, riid, ppvRet);
2491 IStream_Release(stream);
2493 return hRes;
2496 /*******************************************************************************
2497 * StdPic ClassFactory
2499 typedef struct
2501 /* IUnknown fields */
2502 IClassFactory IClassFactory_iface;
2503 LONG ref;
2504 } IClassFactoryImpl;
2506 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2508 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2511 static HRESULT WINAPI
2512 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2513 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2515 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2516 return E_NOINTERFACE;
2519 static ULONG WINAPI
2520 SPCF_AddRef(LPCLASSFACTORY iface) {
2521 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2522 return InterlockedIncrement(&This->ref);
2525 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2526 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2527 /* static class, won't be freed */
2528 return InterlockedDecrement(&This->ref);
2531 static HRESULT WINAPI SPCF_CreateInstance(
2532 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2534 /* Creates an uninitialized picture */
2535 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2539 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2540 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2541 FIXME("(%p)->(%d),stub!\n",This,dolock);
2542 return S_OK;
2545 static const IClassFactoryVtbl SPCF_Vtbl = {
2546 SPCF_QueryInterface,
2547 SPCF_AddRef,
2548 SPCF_Release,
2549 SPCF_CreateInstance,
2550 SPCF_LockServer
2552 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2554 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }