user32: Move unpack_message call to User32CallWindowProc.
[wine.git] / dlls / oleaut32 / olepicture.c
blob2f9e27042d9ecb00799b2f72ab99482337adfbcc
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 #define NONAMELESSUNION
46 #include "winerror.h"
47 #include "windef.h"
48 #include "winbase.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #include "ole2.h"
52 #include "olectl.h"
53 #include "oleauto.h"
54 #include "connpt.h"
55 #include "urlmon.h"
56 #include "initguid.h"
57 #include "wincodec.h"
58 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(olepicture);
62 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
63 #define BITMAP_FORMAT_JPEG 0xd8ff
64 #define BITMAP_FORMAT_GIF 0x4947
65 #define BITMAP_FORMAT_PNG 0x5089
66 #define BITMAP_FORMAT_APM 0xcdd7
68 #include "pshpack1.h"
70 /* Header for Aldus Placable Metafiles - a standard metafile follows */
71 typedef struct _APM_HEADER
73 DWORD key;
74 WORD handle;
75 SHORT left;
76 SHORT top;
77 SHORT right;
78 SHORT bottom;
79 WORD inch;
80 DWORD reserved;
81 WORD checksum;
82 } APM_HEADER;
84 typedef struct {
85 BYTE bWidth;
86 BYTE bHeight;
87 BYTE bColorCount;
88 BYTE bReserved;
89 WORD xHotspot;
90 WORD yHotspot;
91 DWORD dwDIBSize;
92 DWORD dwDIBOffset;
93 } CURSORICONFILEDIRENTRY;
95 typedef struct
97 WORD idReserved;
98 WORD idType;
99 WORD idCount;
100 CURSORICONFILEDIRENTRY idEntries[1];
101 } CURSORICONFILEDIR;
103 #include "poppack.h"
105 /*************************************************************************
106 * Declaration of implementation class
109 typedef struct OLEPictureImpl {
112 * IPicture handles IUnknown
115 IPicture IPicture_iface;
116 IDispatch IDispatch_iface;
117 IPersistStream IPersistStream_iface;
118 IConnectionPointContainer IConnectionPointContainer_iface;
120 /* Object reference count */
121 LONG ref;
123 /* We own the object and must destroy it ourselves */
124 BOOL fOwn;
126 /* Picture description */
127 PICTDESC desc;
129 /* These are the pixel size of a bitmap */
130 DWORD origWidth;
131 DWORD origHeight;
133 /* And these are the size of the picture converted into HIMETRIC units */
134 OLE_XSIZE_HIMETRIC himetricWidth;
135 OLE_YSIZE_HIMETRIC himetricHeight;
137 IConnectionPoint *pCP;
139 BOOL keepOrigFormat;
140 HDC hDCCur;
141 HBITMAP stock_bitmap;
143 /* Bitmap transparency mask */
144 HBITMAP hbmMask;
145 HBITMAP hbmXor;
146 COLORREF rgbTrans;
148 /* data */
149 void* data;
150 int datalen;
151 BOOL bIsDirty; /* Set to TRUE if picture has changed */
152 unsigned int loadtime_magic; /* If a length header was found, saves value */
153 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
154 } OLEPictureImpl;
156 static inline OLEPictureImpl *impl_from_IPicture(IPicture *iface)
158 return CONTAINING_RECORD(iface, OLEPictureImpl, IPicture_iface);
161 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
163 return CONTAINING_RECORD(iface, OLEPictureImpl, IDispatch_iface);
166 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
168 return CONTAINING_RECORD(iface, OLEPictureImpl, IPersistStream_iface);
171 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
173 return CONTAINING_RECORD(iface, OLEPictureImpl, IConnectionPointContainer_iface);
177 * Predeclare VTables. They get initialized at the end.
179 static const IPictureVtbl OLEPictureImpl_VTable;
180 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
181 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
182 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
184 /* pixels to HIMETRIC units conversion */
185 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
187 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
190 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
192 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
195 /***********************************************************************
196 * Implementation of the OLEPictureImpl class.
199 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
201 BITMAP bm;
202 HDC hdcRef;
204 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
205 if(GetObjectW(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
206 ERR("GetObject fails\n");
207 return;
209 This->origWidth = bm.bmWidth;
210 This->origHeight = bm.bmHeight;
212 TRACE("width %d, height %d, bpp %d\n", bm.bmWidth, bm.bmHeight, bm.bmBitsPixel);
214 /* The width and height are stored in HIMETRIC units (0.01 mm),
215 so we take our pixel width divide by pixels per inch and
216 multiply by 25.4 * 100 */
217 /* Should we use GetBitmapDimension if available? */
218 hdcRef = CreateCompatibleDC(0);
220 This->himetricWidth = xpixels_to_himetric(bm.bmWidth, hdcRef);
221 This->himetricHeight = ypixels_to_himetric(bm.bmHeight, hdcRef);
222 This->stock_bitmap = GetCurrentObject( hdcRef, OBJ_BITMAP );
224 This->loadtime_format = BITMAP_FORMAT_BMP;
226 DeleteDC(hdcRef);
229 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
231 ICONINFO infoIcon;
233 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
234 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
235 HDC hdcRef;
236 BITMAP bm;
238 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
239 if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
240 ERR("GetObject fails on icon bitmap\n");
241 return;
244 This->origWidth = bm.bmWidth;
245 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
246 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
247 hdcRef = GetDC(0);
249 This->himetricWidth = xpixels_to_himetric(This->origWidth, hdcRef);
250 This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
252 ReleaseDC(0, hdcRef);
254 DeleteObject(infoIcon.hbmMask);
255 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
256 } else {
257 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
261 /************************************************************************
262 * OLEPictureImpl_Construct
264 * This method will construct a new instance of the OLEPictureImpl
265 * class.
267 * The caller of this method must release the object when it's
268 * done with it.
270 static HRESULT OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn, OLEPictureImpl **pict)
272 OLEPictureImpl *newObject;
273 HRESULT hr;
275 if (pictDesc)
276 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
279 * Allocate space for the object.
281 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
282 if (!newObject)
283 return E_OUTOFMEMORY;
286 * Initialize the virtual function table.
288 newObject->IPicture_iface.lpVtbl = &OLEPictureImpl_VTable;
289 newObject->IDispatch_iface.lpVtbl = &OLEPictureImpl_IDispatch_VTable;
290 newObject->IPersistStream_iface.lpVtbl = &OLEPictureImpl_IPersistStream_VTable;
291 newObject->IConnectionPointContainer_iface.lpVtbl = &OLEPictureImpl_IConnectionPointContainer_VTable;
293 newObject->pCP = NULL;
294 hr = CreateConnectionPoint((IUnknown*)&newObject->IPicture_iface, &IID_IPropertyNotifySink,
295 &newObject->pCP);
296 if (hr != S_OK)
298 HeapFree(GetProcessHeap(), 0, newObject);
299 return hr;
303 * Start with one reference count. The caller of this function
304 * must release the interface pointer when it is done.
306 newObject->ref = 1;
307 newObject->hDCCur = 0;
309 newObject->fOwn = fOwn;
311 /* dunno about original value */
312 newObject->keepOrigFormat = TRUE;
314 newObject->hbmMask = NULL;
315 newObject->hbmXor = NULL;
316 newObject->loadtime_magic = 0xdeadbeef;
317 newObject->loadtime_format = 0;
318 newObject->bIsDirty = FALSE;
320 if (pictDesc) {
321 newObject->desc = *pictDesc;
323 switch(pictDesc->picType) {
324 case PICTYPE_BITMAP:
325 OLEPictureImpl_SetBitmap(newObject);
326 break;
328 case PICTYPE_METAFILE:
329 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
330 newObject->himetricWidth = pictDesc->u.wmf.xExt;
331 newObject->himetricHeight = pictDesc->u.wmf.yExt;
332 break;
334 case PICTYPE_NONE:
335 /* not sure what to do here */
336 newObject->himetricWidth = newObject->himetricHeight = 0;
337 break;
339 case PICTYPE_ICON:
340 OLEPictureImpl_SetIcon(newObject);
341 break;
343 case PICTYPE_ENHMETAFILE:
344 FIXME("EMF is not supported\n");
345 newObject->himetricWidth = newObject->himetricHeight = 0;
346 break;
348 default:
349 WARN("Unsupported type %d\n", pictDesc->picType);
350 IPicture_Release(&newObject->IPicture_iface);
351 return E_UNEXPECTED;
353 } else {
354 newObject->desc.picType = PICTYPE_UNINITIALIZED;
357 TRACE("returning %p\n", newObject);
358 *pict = newObject;
359 return S_OK;
362 /************************************************************************
363 * OLEPictureImpl_Destroy
365 * This method is called by the Release method when the reference
366 * count goes down to 0. It will free all resources used by
367 * this object. */
368 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
370 TRACE("(%p)\n", Obj);
372 if (Obj->pCP)
373 IConnectionPoint_Release(Obj->pCP);
375 if(Obj->fOwn) { /* We need to destroy the picture */
376 switch(Obj->desc.picType) {
377 case PICTYPE_BITMAP:
378 DeleteObject(Obj->desc.u.bmp.hbitmap);
379 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
380 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
381 break;
382 case PICTYPE_METAFILE:
383 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
384 break;
385 case PICTYPE_ICON:
386 DestroyIcon(Obj->desc.u.icon.hicon);
387 break;
388 case PICTYPE_ENHMETAFILE:
389 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
390 break;
391 case PICTYPE_NONE:
392 case PICTYPE_UNINITIALIZED:
393 /* Nothing to do */
394 break;
395 default:
396 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
397 break;
400 HeapFree(GetProcessHeap(), 0, Obj->data);
401 HeapFree(GetProcessHeap(), 0, Obj);
404 static ULONG WINAPI OLEPictureImpl_AddRef(
405 IPicture* iface)
407 OLEPictureImpl *This = impl_from_IPicture(iface);
408 ULONG refCount = InterlockedIncrement(&This->ref);
410 TRACE("%p, refcount %lu.\n", iface, refCount);
412 return refCount;
415 static ULONG WINAPI OLEPictureImpl_Release(
416 IPicture* iface)
418 OLEPictureImpl *This = impl_from_IPicture(iface);
419 ULONG refCount = InterlockedDecrement(&This->ref);
421 TRACE("%p, refcount %lu.\n", iface, refCount);
423 if (!refCount) OLEPictureImpl_Destroy(This);
425 return refCount;
428 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
429 IPicture* iface,
430 REFIID riid,
431 void** ppvObject)
433 OLEPictureImpl *This = impl_from_IPicture(iface);
435 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
437 if (!ppvObject)
438 return E_INVALIDARG;
440 *ppvObject = 0;
442 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
443 *ppvObject = &This->IPicture_iface;
444 else if (IsEqualIID(&IID_IDispatch, riid))
445 *ppvObject = &This->IDispatch_iface;
446 else if (IsEqualIID(&IID_IPictureDisp, riid))
447 *ppvObject = &This->IDispatch_iface;
448 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
449 *ppvObject = &This->IPersistStream_iface;
450 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
451 *ppvObject = &This->IConnectionPointContainer_iface;
453 if (!*ppvObject)
455 FIXME("() : asking for unsupported interface %s\n",debugstr_guid(riid));
456 return E_NOINTERFACE;
459 IPicture_AddRef(iface);
461 return S_OK;
464 /***********************************************************************
465 * OLEPicture_SendNotify (internal)
467 * Sends notification messages of changed properties to any interested
468 * connections.
470 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
472 IEnumConnections *pEnum;
473 CONNECTDATA CD;
475 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
476 return;
477 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
478 IPropertyNotifySink *sink;
480 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
481 IPropertyNotifySink_OnChanged(sink, dispID);
482 IPropertyNotifySink_Release(sink);
483 IUnknown_Release(CD.pUnk);
485 IEnumConnections_Release(pEnum);
488 /************************************************************************
489 * OLEPictureImpl_get_Handle
491 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
492 OLE_HANDLE *phandle)
494 OLEPictureImpl *This = impl_from_IPicture(iface);
495 TRACE("(%p)->(%p)\n", This, phandle);
497 if(!phandle)
498 return E_POINTER;
500 switch(This->desc.picType) {
501 case PICTYPE_NONE:
502 case PICTYPE_UNINITIALIZED:
503 *phandle = 0;
504 break;
505 case PICTYPE_BITMAP:
506 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
507 break;
508 case PICTYPE_METAFILE:
509 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
510 break;
511 case PICTYPE_ICON:
512 *phandle = HandleToUlong(This->desc.u.icon.hicon);
513 break;
514 case PICTYPE_ENHMETAFILE:
515 *phandle = HandleToUlong(This->desc.u.emf.hemf);
516 break;
517 default:
518 FIXME("Unimplemented type %d\n", This->desc.picType);
519 return E_NOTIMPL;
521 TRACE("returning handle %08x\n", *phandle);
522 return S_OK;
525 /************************************************************************
526 * OLEPictureImpl_get_hPal
528 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
529 OLE_HANDLE *phandle)
531 OLEPictureImpl *This = impl_from_IPicture(iface);
533 TRACE("(%p)->(%p)\n", This, phandle);
535 if (!phandle) return E_POINTER;
537 if (This->desc.picType == PICTYPE_BITMAP)
539 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
540 return S_OK;
543 return E_FAIL;
546 /************************************************************************
547 * OLEPictureImpl_get_Type
549 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
550 short *ptype)
552 OLEPictureImpl *This = impl_from_IPicture(iface);
553 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
555 if(!ptype)
556 return E_POINTER;
558 *ptype = This->desc.picType;
559 return S_OK;
562 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface, OLE_XSIZE_HIMETRIC *pwidth)
564 OLEPictureImpl *This = impl_from_IPicture(iface);
565 TRACE("%p, %p.\n", iface, pwidth);
566 *pwidth = This->himetricWidth;
567 return S_OK;
570 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface, OLE_YSIZE_HIMETRIC *pheight)
572 OLEPictureImpl *This = impl_from_IPicture(iface);
573 TRACE("%p, %p.\n", iface, pheight);
574 *pheight = This->himetricHeight;
575 return S_OK;
578 static void render_masked_bitmap(OLEPictureImpl *This, HDC hdc,
579 LONG x, LONG y, LONG cx, LONG cy, OLE_XPOS_HIMETRIC xSrc, OLE_YPOS_HIMETRIC ySrc,
580 OLE_XSIZE_HIMETRIC cxSrc, OLE_YSIZE_HIMETRIC cySrc, HBITMAP hbmMask, HBITMAP hbmXor)
582 HDC hdcBmp;
584 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
585 * NB y-axis gets flipped
588 hdcBmp = CreateCompatibleDC(0);
589 SetMapMode(hdcBmp, MM_ANISOTROPIC);
590 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
591 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
592 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
593 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
595 if (hbmMask)
597 SetBkColor(hdc, RGB(255, 255, 255));
598 SetTextColor(hdc, RGB(0, 0, 0));
600 SelectObject(hdcBmp, hbmMask);
601 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCAND);
603 if (hbmXor)
605 SelectObject(hdcBmp, hbmXor);
606 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
608 else StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc - This->himetricHeight,
609 cxSrc, cySrc, SRCPAINT);
611 else
613 SelectObject(hdcBmp, hbmXor);
614 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
617 DeleteDC(hdcBmp);
620 /************************************************************************
621 * OLEPictureImpl_Render
623 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
624 LONG x, LONG y, LONG cx, LONG cy,
625 OLE_XPOS_HIMETRIC xSrc,
626 OLE_YPOS_HIMETRIC ySrc,
627 OLE_XSIZE_HIMETRIC cxSrc,
628 OLE_YSIZE_HIMETRIC cySrc,
629 LPCRECT prcWBounds)
631 OLEPictureImpl *This = impl_from_IPicture(iface);
632 TRACE("%p, %p, (%ld,%ld), (%ld,%ld), (%ld,%ld), (%ld,%ld), %p)\n", iface, hdc, x, y, cx, cy, xSrc, ySrc,
633 cxSrc, cySrc, prcWBounds);
634 if(prcWBounds)
635 TRACE("prcWBounds %s\n", wine_dbgstr_rect(prcWBounds));
637 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
638 return CTL_E_INVALIDPROPERTYVALUE;
642 * While the documentation suggests this to be here (or after rendering?)
643 * it does cause an endless recursion in my sample app. -MM 20010804
644 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
647 switch(This->desc.picType) {
648 case PICTYPE_UNINITIALIZED:
649 case PICTYPE_NONE:
650 /* nothing to do */
651 return S_OK;
652 case PICTYPE_BITMAP:
654 HBITMAP hbmMask, hbmXor;
656 if (This->hbmMask)
658 hbmMask = This->hbmMask;
659 hbmXor = This->hbmXor;
661 else
663 hbmMask = 0;
664 hbmXor = This->desc.u.bmp.hbitmap;
667 render_masked_bitmap(This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, hbmMask, hbmXor);
668 break;
671 case PICTYPE_ICON:
673 ICONINFO info;
675 if (!GetIconInfo(This->desc.u.icon.hicon, &info))
676 return E_FAIL;
678 render_masked_bitmap(This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, info.hbmMask, info.hbmColor);
680 DeleteObject(info.hbmMask);
681 if (info.hbmColor) DeleteObject(info.hbmColor);
682 break;
685 case PICTYPE_METAFILE:
687 POINT prevOrg, prevWndOrg;
688 SIZE prevExt, prevWndExt;
689 int oldmode;
691 /* Render the WMF to the appropriate location by setting the
692 appropriate ratio between "device units" and "logical units" */
693 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
694 /* For the "source rectangle" the y-axis must be inverted */
695 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
696 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
697 /* For the "destination rectangle" no inversion is necessary */
698 SetViewportOrgEx(hdc, x, y, &prevOrg);
699 SetViewportExtEx(hdc, cx, cy, &prevExt);
701 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
702 ERR("PlayMetaFile failed!\n");
704 /* We're done, restore the DC to the previous settings for converting
705 logical units to device units */
706 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
707 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
708 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
709 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
710 SetMapMode(hdc, oldmode);
711 break;
714 case PICTYPE_ENHMETAFILE:
716 RECT rc = { x, y, x + cx, y + cy };
717 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
718 break;
721 default:
722 FIXME("type %d not implemented\n", This->desc.picType);
723 return E_NOTIMPL;
725 return S_OK;
728 /************************************************************************
729 * OLEPictureImpl_set_hPal
731 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
732 OLE_HANDLE hpal)
734 OLEPictureImpl *This = impl_from_IPicture(iface);
736 TRACE("(%p)->(%08x)\n", This, hpal);
738 if (This->desc.picType == PICTYPE_BITMAP)
740 This->desc.u.bmp.hpal = ULongToHandle(hpal);
741 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
742 return S_OK;
745 return E_FAIL;
748 /************************************************************************
749 * OLEPictureImpl_get_CurDC
751 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
752 HDC *phdc)
754 OLEPictureImpl *This = impl_from_IPicture(iface);
755 TRACE("(%p), returning %p\n", This, This->hDCCur);
756 if (phdc) *phdc = This->hDCCur;
757 return S_OK;
760 /************************************************************************
761 * OLEPictureImpl_SelectPicture
763 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
764 HDC hdcIn,
765 HDC *phdcOut,
766 OLE_HANDLE *phbmpOut)
768 OLEPictureImpl *This = impl_from_IPicture(iface);
769 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
770 if (This->desc.picType == PICTYPE_BITMAP) {
771 if (phdcOut)
772 *phdcOut = This->hDCCur;
773 if (This->hDCCur) SelectObject(This->hDCCur,This->stock_bitmap);
774 if (hdcIn) SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
775 This->hDCCur = hdcIn;
776 if (phbmpOut)
777 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
778 return S_OK;
779 } else {
780 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
781 return E_FAIL;
785 /************************************************************************
786 * OLEPictureImpl_get_KeepOriginalFormat
788 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
789 BOOL *pfKeep)
791 OLEPictureImpl *This = impl_from_IPicture(iface);
792 TRACE("(%p)->(%p)\n", This, pfKeep);
793 if (!pfKeep)
794 return E_POINTER;
795 *pfKeep = This->keepOrigFormat;
796 return S_OK;
799 /************************************************************************
800 * OLEPictureImpl_put_KeepOriginalFormat
802 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
803 BOOL keep)
805 OLEPictureImpl *This = impl_from_IPicture(iface);
806 TRACE("(%p)->(%d)\n", This, keep);
807 This->keepOrigFormat = keep;
808 /* FIXME: what DISPID notification here? */
809 return S_OK;
812 /************************************************************************
813 * OLEPictureImpl_PictureChanged
815 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
817 OLEPictureImpl *This = impl_from_IPicture(iface);
818 TRACE("(%p)->()\n", This);
819 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
820 This->bIsDirty = TRUE;
821 return S_OK;
824 /************************************************************************
825 * OLEPictureImpl_SaveAsFile
827 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
828 IStream *pstream,
829 BOOL SaveMemCopy,
830 LONG *pcbSize)
832 OLEPictureImpl *This = impl_from_IPicture(iface);
833 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
834 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
837 /************************************************************************
838 * OLEPictureImpl_get_Attributes
840 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
841 DWORD *pdwAttr)
843 OLEPictureImpl *This = impl_from_IPicture(iface);
844 TRACE("(%p)->(%p).\n", This, pdwAttr);
846 if(!pdwAttr)
847 return E_POINTER;
849 *pdwAttr = 0;
850 switch (This->desc.picType) {
851 case PICTYPE_UNINITIALIZED:
852 case PICTYPE_NONE: break;
853 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
854 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
855 case PICTYPE_ENHMETAFILE: /* fall through */
856 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
857 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
859 return S_OK;
863 /************************************************************************
864 * IConnectionPointContainer
866 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
867 IConnectionPointContainer* iface,
868 REFIID riid,
869 VOID** ppvoid)
871 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
873 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
876 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
877 IConnectionPointContainer* iface)
879 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
881 return IPicture_AddRef(&This->IPicture_iface);
884 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
885 IConnectionPointContainer* iface)
887 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
889 return IPicture_Release(&This->IPicture_iface);
892 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
893 IConnectionPointContainer* iface,
894 IEnumConnectionPoints** ppEnum)
896 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
898 FIXME("(%p,%p), stub!\n",This,ppEnum);
899 return E_NOTIMPL;
902 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
903 IConnectionPointContainer* iface,
904 REFIID riid,
905 IConnectionPoint **ppCP)
907 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
908 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
909 if (!ppCP)
910 return E_POINTER;
911 *ppCP = NULL;
912 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
913 return IConnectionPoint_QueryInterface(This->pCP, &IID_IConnectionPoint, (void**)ppCP);
914 FIXME("no connection point for %s\n",debugstr_guid(riid));
915 return CONNECT_E_NOCONNECTION;
919 /************************************************************************
920 * IPersistStream
923 /************************************************************************
924 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
926 * See Windows documentation for more details on IUnknown methods.
928 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
929 IPersistStream* iface,
930 REFIID riid,
931 VOID** ppvoid)
933 OLEPictureImpl *This = impl_from_IPersistStream(iface);
935 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
938 /************************************************************************
939 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
941 * See Windows documentation for more details on IUnknown methods.
943 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
944 IPersistStream* iface)
946 OLEPictureImpl *This = impl_from_IPersistStream(iface);
948 return IPicture_AddRef(&This->IPicture_iface);
951 /************************************************************************
952 * OLEPictureImpl_IPersistStream_Release (IUnknown)
954 * See Windows documentation for more details on IUnknown methods.
956 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
957 IPersistStream* iface)
959 OLEPictureImpl *This = impl_from_IPersistStream(iface);
961 return IPicture_Release(&This->IPicture_iface);
964 /************************************************************************
965 * OLEPictureImpl_IPersistStream_GetClassID
967 static HRESULT WINAPI OLEPictureImpl_GetClassID(
968 IPersistStream* iface,CLSID* pClassID)
970 TRACE("(%p)\n", pClassID);
971 *pClassID = CLSID_StdPicture;
972 return S_OK;
975 /************************************************************************
976 * OLEPictureImpl_IPersistStream_IsDirty
978 static HRESULT WINAPI OLEPictureImpl_IsDirty(
979 IPersistStream* iface)
981 OLEPictureImpl *This = impl_from_IPersistStream(iface);
982 FIXME("(%p),stub!\n",This);
983 return E_NOTIMPL;
986 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
988 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
989 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
990 HDC hdcref;
992 /* Does not matter whether this is a coreheader or not, we only use
993 * components which are in both
995 hdcref = GetDC(0);
996 This->desc.u.bmp.hbitmap = CreateDIBitmap(
997 hdcref,
998 &(bi->bmiHeader),
999 CBM_INIT,
1000 xbuf+bfh->bfOffBits,
1002 DIB_RGB_COLORS
1004 ReleaseDC(0, hdcref);
1005 if (This->desc.u.bmp.hbitmap == 0)
1006 return E_FAIL;
1007 This->desc.picType = PICTYPE_BITMAP;
1008 OLEPictureImpl_SetBitmap(This);
1009 return S_OK;
1012 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1014 HRESULT hr;
1015 BITMAPINFOHEADER bih;
1016 HDC hdcref;
1017 UINT width, height;
1018 UINT stride, buffersize;
1019 LPBYTE bits=NULL;
1020 WICRect rc;
1021 IWICBitmapSource *real_source;
1022 UINT x, y;
1023 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1024 BOOL has_alpha=FALSE;
1026 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1027 if (FAILED(hr)) return hr;
1029 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1030 if (FAILED(hr)) goto end;
1032 bih.biSize = sizeof(bih);
1033 bih.biWidth = width;
1034 bih.biHeight = -height;
1035 bih.biPlanes = 1;
1036 bih.biBitCount = 32;
1037 bih.biCompression = BI_RGB;
1038 bih.biSizeImage = 0;
1039 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1040 bih.biYPelsPerMeter = 4085;
1041 bih.biClrUsed = 0;
1042 bih.biClrImportant = 0;
1044 stride = 4 * width;
1045 buffersize = stride * height;
1047 bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1048 if (!bits)
1050 hr = E_OUTOFMEMORY;
1051 goto end;
1054 rc.X = 0;
1055 rc.Y = 0;
1056 rc.Width = width;
1057 rc.Height = height;
1058 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1059 if (FAILED(hr))
1060 goto end;
1062 hdcref = GetDC(0);
1063 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1064 hdcref,
1065 &bih,
1066 CBM_INIT,
1067 bits,
1068 (BITMAPINFO*)&bih,
1069 DIB_RGB_COLORS);
1071 if (This->desc.u.bmp.hbitmap == 0)
1073 hr = E_FAIL;
1074 ReleaseDC(0, hdcref);
1075 goto end;
1078 This->desc.picType = PICTYPE_BITMAP;
1079 OLEPictureImpl_SetBitmap(This);
1081 /* set transparent pixels to black, all others to white */
1082 for(y = 0; y < height; y++){
1083 for(x = 0; x < width; x++){
1084 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1085 if((*pixel & 0x80000000) == 0)
1087 has_alpha = TRUE;
1088 *pixel = black;
1090 else
1091 *pixel = white;
1095 if (has_alpha)
1097 HDC hdcBmp, hdcXor, hdcMask;
1098 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1100 This->hbmXor = CreateDIBitmap(
1101 hdcref,
1102 &bih,
1103 CBM_INIT,
1104 bits,
1105 (BITMAPINFO*)&bih,
1106 DIB_RGB_COLORS
1109 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1110 hdcBmp = CreateCompatibleDC(NULL);
1111 hdcXor = CreateCompatibleDC(NULL);
1112 hdcMask = CreateCompatibleDC(NULL);
1114 hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1115 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1116 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1118 SetBkColor(hdcXor,black);
1119 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1120 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1122 SelectObject(hdcBmp,hbmoldBmp);
1123 SelectObject(hdcXor,hbmoldXor);
1124 SelectObject(hdcMask,hbmoldMask);
1126 DeleteDC(hdcBmp);
1127 DeleteDC(hdcXor);
1128 DeleteDC(hdcMask);
1131 ReleaseDC(0, hdcref);
1133 end:
1134 HeapFree(GetProcessHeap(), 0, bits);
1135 IWICBitmapSource_Release(real_source);
1136 return hr;
1139 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1141 HRESULT hr;
1142 IWICImagingFactory *factory;
1143 IWICBitmapDecoder *decoder;
1144 IWICBitmapFrameDecode *framedecode;
1145 HRESULT initresult;
1146 IWICStream *stream;
1148 initresult = CoInitialize(NULL);
1150 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1151 &IID_IWICImagingFactory, (void**)&factory);
1152 if (SUCCEEDED(hr)) /* created factory */
1154 hr = IWICImagingFactory_CreateStream(factory, &stream);
1155 IWICImagingFactory_Release(factory);
1158 if (SUCCEEDED(hr)) /* created stream */
1160 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1162 if (SUCCEEDED(hr)) /* initialized stream */
1164 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1165 &IID_IWICBitmapDecoder, (void**)&decoder);
1166 if (SUCCEEDED(hr)) /* created decoder */
1168 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1170 if (SUCCEEDED(hr)) /* initialized decoder */
1171 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1173 IWICBitmapDecoder_Release(decoder);
1177 IWICStream_Release(stream);
1180 if (SUCCEEDED(hr)) /* got framedecode */
1182 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1183 IWICBitmapFrameDecode_Release(framedecode);
1186 if (SUCCEEDED(initresult)) CoUninitialize();
1187 return hr;
1190 /*****************************************************
1191 * start of Icon-specific code
1194 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1196 HICON hicon;
1197 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1198 HDC hdcRef;
1199 int i;
1201 TRACE("(this %p, xbuf %p, xread %lu)\n", This, xbuf, xread);
1204 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1205 FIXME("icon.idType=%d\n",cifd->idType);
1206 FIXME("icon.idCount=%d\n",cifd->idCount);
1208 for (i=0;i<cifd->idCount;i++) {
1209 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1210 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1211 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1212 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1213 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1214 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1215 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1216 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1220 /* Need at least one icon to do something. */
1221 if (!cifd->idCount)
1223 ERR("Invalid icon count of zero.\n");
1224 return E_FAIL;
1226 i=0;
1227 /* If we have more than one icon, try to find the best.
1228 * this currently means '32 pixel wide'.
1230 if (cifd->idCount!=1) {
1231 for (i=0;i<cifd->idCount;i++) {
1232 if (cifd->idEntries[i].bWidth == 32)
1233 break;
1235 if (i==cifd->idCount) i=0;
1237 if (xread < cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize)
1239 ERR("Icon data address %lu is over %lu bytes available.\n",
1240 cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize, xread);
1241 return E_FAIL;
1243 if (cifd->idType == 2)
1245 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, cifd->idEntries[i].dwDIBSize + 4);
1246 memcpy(buf, &cifd->idEntries[i].xHotspot, 4);
1247 memcpy(buf + 4, xbuf+cifd->idEntries[i].dwDIBOffset, cifd->idEntries[i].dwDIBSize);
1248 hicon = CreateIconFromResourceEx(
1249 buf,
1250 cifd->idEntries[i].dwDIBSize + 4,
1251 FALSE, /* is cursor */
1252 0x00030000,
1253 cifd->idEntries[i].bWidth,
1254 cifd->idEntries[i].bHeight,
1257 HeapFree(GetProcessHeap(), 0, buf);
1259 else
1261 hicon = CreateIconFromResourceEx(
1262 xbuf+cifd->idEntries[i].dwDIBOffset,
1263 cifd->idEntries[i].dwDIBSize,
1264 TRUE, /* is icon */
1265 0x00030000,
1266 cifd->idEntries[i].bWidth,
1267 cifd->idEntries[i].bHeight,
1271 if (!hicon) {
1272 ERR("CreateIcon failed.\n");
1273 return E_FAIL;
1274 } else {
1275 This->desc.picType = PICTYPE_ICON;
1276 This->desc.u.icon.hicon = hicon;
1277 This->origWidth = cifd->idEntries[i].bWidth;
1278 This->origHeight = cifd->idEntries[i].bHeight;
1279 hdcRef = CreateCompatibleDC(0);
1280 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1281 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1282 DeleteDC(hdcRef);
1283 return S_OK;
1287 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1288 const BYTE *data, ULONG size)
1290 HENHMETAFILE hemf;
1291 ENHMETAHEADER hdr;
1293 hemf = SetEnhMetaFileBits(size, data);
1294 if (!hemf) return E_FAIL;
1296 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1298 This->desc.picType = PICTYPE_ENHMETAFILE;
1299 This->desc.u.emf.hemf = hemf;
1301 This->origWidth = 0;
1302 This->origHeight = 0;
1303 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1304 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1306 return S_OK;
1309 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1310 const BYTE *data, ULONG size)
1312 const APM_HEADER *header = (const APM_HEADER *)data;
1313 HMETAFILE hmf;
1315 if (size < sizeof(APM_HEADER))
1316 return E_FAIL;
1317 if (header->key != 0x9ac6cdd7)
1318 return E_FAIL;
1320 /* SetMetaFileBitsEx performs data check on its own */
1321 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1322 if (!hmf) return E_FAIL;
1324 This->desc.picType = PICTYPE_METAFILE;
1325 This->desc.u.wmf.hmeta = hmf;
1326 This->desc.u.wmf.xExt = 0;
1327 This->desc.u.wmf.yExt = 0;
1329 This->origWidth = 0;
1330 This->origHeight = 0;
1331 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1332 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1333 return S_OK;
1336 /************************************************************************
1337 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1339 * Loads the binary data from the IStream. Starts at current position.
1340 * There appears to be an 2 DWORD header:
1341 * DWORD magic;
1342 * DWORD len;
1344 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1346 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1347 HRESULT hr;
1348 BOOL headerisdata;
1349 BOOL statfailed = FALSE;
1350 ULONG xread, toread;
1351 ULONG headerread;
1352 BYTE *xbuf;
1353 DWORD header[2];
1354 WORD magic;
1355 STATSTG statstg;
1356 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1358 TRACE("(%p,%p)\n",This,pStm);
1360 /****************************************************************************************
1361 * Part 1: Load the data
1363 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1364 * out whether we do.
1366 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1367 * compound file. This may explain most, if not all, of the cases of "no
1368 * header", and the header validation should take this into account.
1369 * At least in Visual Basic 6, resource streams, valid headers are
1370 * header[0] == "lt\0\0",
1371 * header[1] == length_of_stream.
1373 * Also handle streams where we do not have a working "Stat" method by
1374 * reading all data until the end of the stream.
1376 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1377 if (hr != S_OK) {
1378 TRACE("stat failed with hres %#lx, proceeding to read all data.\n",hr);
1379 statfailed = TRUE;
1380 /* we will read at least 8 byte ... just right below */
1381 statstg.cbSize.QuadPart = 8;
1384 toread = 0;
1385 headerread = 0;
1386 headerisdata = FALSE;
1387 do {
1388 hr = IStream_Read(pStm, header, 8, &xread);
1389 if (hr != S_OK || xread!=8) {
1390 ERR("Failure while reading picture header (hr is %#lx, nread is %ld).\n",hr,xread);
1391 return (hr?hr:E_FAIL);
1393 headerread += xread;
1394 xread = 0;
1396 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1397 if (toread != 0 && toread != header[1])
1398 FIXME("varying lengths of image data (prev=%lu curr=%lu), only last one will be used\n",
1399 toread, header[1]);
1400 toread = header[1];
1401 if (statfailed)
1403 statstg.cbSize.QuadPart = header[1] + 8;
1404 statfailed = FALSE;
1406 if (toread == 0) break;
1407 } else {
1408 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1409 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1410 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1411 (header[0] == EMR_HEADER) || /* EMF header */
1412 (header[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1413 (header[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1414 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1415 (header[1]==0)
1416 ) {/* Found start of bitmap data */
1417 headerisdata = TRUE;
1418 if (toread == 0)
1419 toread = statstg.cbSize.QuadPart-8;
1420 else toread -= 8;
1421 xread = 8;
1422 } else {
1423 FIXME("Unknown stream header magic: %#lx.\n", header[0]);
1424 toread = header[1];
1427 } while (!headerisdata);
1429 if (statfailed) { /* we don't know the size ... read all we get */
1430 unsigned int sizeinc = 4096;
1431 unsigned int origsize = sizeinc;
1432 ULONG nread = 42;
1434 TRACE("Reading all data from stream.\n");
1435 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1436 if (headerisdata)
1437 memcpy (xbuf, header, 8);
1438 while (1) {
1439 while (xread < origsize) {
1440 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1441 xread += nread;
1442 if (hr != S_OK || !nread)
1443 break;
1445 if (!nread || hr != S_OK) /* done, or error */
1446 break;
1447 if (xread == origsize) {
1448 origsize += sizeinc;
1449 sizeinc = 2*sizeinc; /* exponential increase */
1450 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1453 if (hr != S_OK)
1454 TRACE("hr in no-stat loader case is %#lx.\n", hr);
1455 TRACE("loaded %ld bytes.\n", xread);
1456 This->datalen = xread;
1457 This->data = xbuf;
1458 } else {
1459 This->datalen = toread+(headerisdata?8:0);
1460 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1461 if (!xbuf)
1462 return E_OUTOFMEMORY;
1464 if (headerisdata)
1465 memcpy (xbuf, header, 8);
1467 while (xread < This->datalen) {
1468 ULONG nread;
1469 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1470 xread += nread;
1471 if (hr != S_OK || !nread)
1472 break;
1474 if (xread != This->datalen)
1475 ERR("Could only read %ld of %d bytes out of stream?\n", xread, This->datalen);
1477 if (This->datalen == 0) { /* Marks the "NONE" picture */
1478 This->desc.picType = PICTYPE_NONE;
1479 return S_OK;
1483 /****************************************************************************************
1484 * Part 2: Process the loaded data
1487 magic = xbuf[0] + (xbuf[1]<<8);
1488 This->loadtime_format = magic;
1490 switch (magic) {
1491 case BITMAP_FORMAT_GIF: /* GIF */
1492 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1493 break;
1494 case BITMAP_FORMAT_JPEG: /* JPEG */
1495 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1496 break;
1497 case BITMAP_FORMAT_BMP: /* Bitmap */
1498 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1499 break;
1500 case BITMAP_FORMAT_PNG: /* PNG */
1501 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1502 break;
1503 case BITMAP_FORMAT_APM: /* APM */
1504 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1505 break;
1506 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1507 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1508 break;
1510 default:
1512 unsigned int i;
1514 /* let's see if it's a EMF */
1515 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1516 if (hr == S_OK) break;
1518 FIXME("Unknown magic %04x, %ld read bytes:\n", magic, xread);
1519 hr=E_FAIL;
1520 for (i=0;i<xread+8;i++) {
1521 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1522 else MESSAGE("%02x ",xbuf[i-8]);
1523 if (i % 10 == 9) MESSAGE("\n");
1525 MESSAGE("\n");
1526 break;
1529 This->bIsDirty = FALSE;
1531 /* FIXME: this notify is not really documented */
1532 if (hr==S_OK)
1533 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1534 return hr;
1537 static BOOL serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1539 BOOL success = FALSE;
1540 HDC hDC;
1541 BITMAPINFO * pInfoBitmap;
1542 int iNumPaletteEntries;
1543 unsigned char * pPixelData;
1544 BITMAPFILEHEADER * pFileHeader;
1545 BITMAPINFO * pInfoHeader;
1547 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1548 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1550 /* Find out bitmap size and padded length */
1551 hDC = GetDC(0);
1552 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1553 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1555 /* Fetch bitmap palette & pixel data */
1557 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1558 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1560 /* Calculate the total length required for the BMP data */
1561 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1562 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1563 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1564 } else {
1565 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1566 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1567 else
1568 iNumPaletteEntries = 0;
1570 *pLength =
1571 sizeof(BITMAPFILEHEADER) +
1572 sizeof(BITMAPINFOHEADER) +
1573 iNumPaletteEntries * sizeof(RGBQUAD) +
1574 pInfoBitmap->bmiHeader.biSizeImage;
1575 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1577 /* Fill the BITMAPFILEHEADER */
1578 pFileHeader = *ppBuffer;
1579 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1580 pFileHeader->bfSize = *pLength;
1581 pFileHeader->bfOffBits =
1582 sizeof(BITMAPFILEHEADER) +
1583 sizeof(BITMAPINFOHEADER) +
1584 iNumPaletteEntries * sizeof(RGBQUAD);
1586 /* Fill the BITMAPINFOHEADER and the palette data */
1587 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1588 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1589 memcpy(
1590 (unsigned char *)(*ppBuffer) +
1591 sizeof(BITMAPFILEHEADER) +
1592 sizeof(BITMAPINFOHEADER) +
1593 iNumPaletteEntries * sizeof(RGBQUAD),
1594 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1595 success = TRUE;
1597 HeapFree(GetProcessHeap(), 0, pPixelData);
1598 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1599 return success;
1602 static BOOL serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1604 ICONINFO infoIcon;
1605 BOOL success = FALSE;
1607 *ppBuffer = NULL; *pLength = 0;
1608 if (GetIconInfo(hIcon, &infoIcon)) {
1609 HDC hDC;
1610 BITMAPINFO * pInfoBitmap;
1611 unsigned char * pIconData = NULL;
1612 unsigned int iDataSize = 0;
1614 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1616 /* Find out icon size */
1617 hDC = GetDC(0);
1618 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1619 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1620 if (1) {
1621 /* Auxiliary pointers */
1622 CURSORICONFILEDIR * pIconDir;
1623 CURSORICONFILEDIRENTRY * pIconEntry;
1624 BITMAPINFOHEADER * pIconBitmapHeader;
1625 unsigned int iOffsetPalette;
1626 unsigned int iOffsetColorData;
1627 unsigned int iOffsetMaskData;
1629 unsigned int iLengthScanLineMask;
1630 unsigned int iNumEntriesPalette;
1632 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1634 FIXME("DEBUG: bitmap size is %d x %d\n",
1635 pInfoBitmap->bmiHeader.biWidth,
1636 pInfoBitmap->bmiHeader.biHeight);
1637 FIXME("DEBUG: bitmap bpp is %d\n",
1638 pInfoBitmap->bmiHeader.biBitCount);
1639 FIXME("DEBUG: bitmap nplanes is %d\n",
1640 pInfoBitmap->bmiHeader.biPlanes);
1641 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1642 pInfoBitmap->bmiHeader.biSizeImage);
1644 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1645 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1646 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1648 /* Fill out the CURSORICONFILEDIR */
1649 pIconDir = (CURSORICONFILEDIR *)pIconData;
1650 pIconDir->idType = 1;
1651 pIconDir->idCount = 1;
1652 pIconDir->idReserved = 0;
1654 /* Fill out the CURSORICONFILEDIRENTRY */
1655 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1656 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1657 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1658 pIconEntry->bColorCount =
1659 (pInfoBitmap->bmiHeader.biBitCount < 8)
1660 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1661 : 0;
1662 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1663 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1664 pIconEntry->dwDIBSize = 0;
1665 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1667 /* Fill out the BITMAPINFOHEADER */
1668 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1669 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1671 /* Find out whether a palette exists for the bitmap */
1672 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1673 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1674 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1675 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1676 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1677 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1678 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1679 iNumEntriesPalette = 3;
1680 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1681 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1682 } else {
1683 iNumEntriesPalette = 0;
1686 /* Add bitmap size and header size to icon data size. */
1687 iOffsetPalette = iDataSize;
1688 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1689 iOffsetColorData = iDataSize;
1690 iDataSize += pIconBitmapHeader->biSizeImage;
1691 iOffsetMaskData = iDataSize;
1692 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1693 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1694 pIconBitmapHeader->biHeight *= 2;
1695 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1696 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1697 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1698 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1700 /* Get the actual bitmap data from the icon bitmap */
1701 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1702 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1703 if (iNumEntriesPalette > 0) {
1704 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1705 iNumEntriesPalette * sizeof(RGBQUAD));
1708 /* Reset all values so that GetDIBits call succeeds */
1709 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1710 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1711 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1713 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1714 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1715 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1717 printf("ERROR: unable to get bitmap mask (error %u)\n",
1718 GetLastError());
1722 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1723 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1725 /* Write out everything produced so far to the stream */
1726 *ppBuffer = pIconData; *pLength = iDataSize;
1727 success = TRUE;
1728 } else {
1730 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1731 GetLastError());
1735 Remarks (from MSDN entry on GetIconInfo):
1737 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1738 members of ICONINFO. The calling application must manage
1739 these bitmaps and delete them when they are no longer
1740 necessary.
1742 if (hDC) ReleaseDC(0, hDC);
1743 DeleteObject(infoIcon.hbmMask);
1744 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1745 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1746 } else {
1747 ERR("Unable to get icon information (error %lu)\n", GetLastError());
1749 return success;
1752 static HRESULT WINAPI OLEPictureImpl_Save(
1753 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1755 HRESULT hResult = E_NOTIMPL;
1756 void * pIconData;
1757 unsigned int iDataSize;
1758 DWORD header[2];
1759 ULONG dummy;
1760 BOOL serializeResult = FALSE;
1761 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1763 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1765 switch (This->desc.picType) {
1766 case PICTYPE_NONE:
1767 header[0] = 0x0000746c;
1768 header[1] = 0;
1769 hResult = IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1770 break;
1772 case PICTYPE_ICON:
1773 if (This->bIsDirty || !This->data) {
1774 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1775 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1776 hResult = E_FAIL;
1777 break;
1779 HeapFree(GetProcessHeap(), 0, This->data);
1780 This->data = pIconData;
1781 This->datalen = iDataSize;
1784 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1785 header[1] = This->datalen;
1786 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1787 IStream_Write(pStm, This->data, This->datalen, &dummy);
1788 hResult = S_OK;
1789 break;
1790 case PICTYPE_BITMAP:
1791 if (This->bIsDirty || !This->data) {
1792 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1793 case BITMAP_FORMAT_BMP:
1794 serializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1795 break;
1796 case BITMAP_FORMAT_JPEG:
1797 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1798 break;
1799 case BITMAP_FORMAT_GIF:
1800 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1801 break;
1802 case BITMAP_FORMAT_PNG:
1803 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1804 break;
1805 default:
1806 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1807 break;
1810 if (!serializeResult)
1812 hResult = E_FAIL;
1813 break;
1816 HeapFree(GetProcessHeap(), 0, This->data);
1817 This->data = pIconData;
1818 This->datalen = iDataSize;
1821 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1822 header[1] = This->datalen;
1823 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1824 IStream_Write(pStm, This->data, This->datalen, &dummy);
1825 hResult = S_OK;
1826 break;
1827 case PICTYPE_METAFILE:
1828 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1829 break;
1830 case PICTYPE_ENHMETAFILE:
1831 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1832 break;
1833 default:
1834 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1835 break;
1837 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1838 return hResult;
1841 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1842 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1844 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1845 FIXME("(%p,%p),stub!\n",This,pcbSize);
1846 return E_NOTIMPL;
1850 /************************************************************************
1851 * IDispatch
1854 /************************************************************************
1855 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1857 * See Windows documentation for more details on IUnknown methods.
1859 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1860 IDispatch* iface,
1861 REFIID riid,
1862 VOID** ppvoid)
1864 OLEPictureImpl *This = impl_from_IDispatch(iface);
1866 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1869 /************************************************************************
1870 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1872 * See Windows documentation for more details on IUnknown methods.
1874 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1875 IDispatch* iface)
1877 OLEPictureImpl *This = impl_from_IDispatch(iface);
1879 return IPicture_AddRef(&This->IPicture_iface);
1882 /************************************************************************
1883 * OLEPictureImpl_IDispatch_Release (IUnknown)
1885 * See Windows documentation for more details on IUnknown methods.
1887 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1888 IDispatch* iface)
1890 OLEPictureImpl *This = impl_from_IDispatch(iface);
1892 return IPicture_Release(&This->IPicture_iface);
1895 /************************************************************************
1896 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1898 * See Windows documentation for more details on IDispatch methods.
1900 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1901 IDispatch* iface,
1902 unsigned int* pctinfo)
1904 TRACE("(%p)\n", pctinfo);
1906 *pctinfo = 1;
1908 return S_OK;
1911 /************************************************************************
1912 * OLEPictureImpl_GetTypeInfo (IDispatch)
1914 * See Windows documentation for more details on IDispatch methods.
1916 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1917 IDispatch* iface,
1918 UINT iTInfo,
1919 LCID lcid,
1920 ITypeInfo** ppTInfo)
1922 ITypeLib *tl;
1923 HRESULT hres;
1925 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1927 if (iTInfo != 0)
1928 return E_FAIL;
1930 hres = LoadTypeLib(L"stdole2.tlb", &tl);
1931 if (FAILED(hres))
1933 ERR("Could not load stdole2.tlb\n");
1934 return hres;
1937 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1938 if (FAILED(hres))
1939 ERR("Did not get IPictureDisp typeinfo from typelib, hres %#lx.\n", hres);
1941 return hres;
1944 /************************************************************************
1945 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1947 * See Windows documentation for more details on IDispatch methods.
1949 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1950 IDispatch* iface,
1951 REFIID riid,
1952 LPOLESTR* rgszNames,
1953 UINT cNames,
1954 LCID lcid,
1955 DISPID* rgDispId)
1957 ITypeInfo * pTInfo;
1958 HRESULT hres;
1960 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1961 rgszNames, cNames, (int)lcid, rgDispId);
1963 if (cNames == 0)
1965 return E_INVALIDARG;
1967 else
1969 /* retrieve type information */
1970 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1972 if (FAILED(hres))
1974 ERR("GetTypeInfo failed.\n");
1975 return hres;
1978 /* convert names to DISPIDs */
1979 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1980 ITypeInfo_Release(pTInfo);
1982 return hres;
1986 /************************************************************************
1987 * OLEPictureImpl_Invoke (IDispatch)
1989 * See Windows documentation for more details on IDispatch methods.
1991 static HRESULT WINAPI OLEPictureImpl_Invoke(
1992 IDispatch* iface,
1993 DISPID dispIdMember,
1994 REFIID riid,
1995 LCID lcid,
1996 WORD wFlags,
1997 DISPPARAMS* pDispParams,
1998 VARIANT* pVarResult,
1999 EXCEPINFO* pExepInfo,
2000 UINT* puArgErr)
2002 OLEPictureImpl *This = impl_from_IDispatch(iface);
2003 HRESULT hr;
2005 /* validate parameters */
2007 if (!IsEqualIID(riid, &IID_NULL))
2009 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2010 return DISP_E_UNKNOWNNAME;
2013 if (!pDispParams)
2015 ERR("null pDispParams not allowed\n");
2016 return DISP_E_PARAMNOTOPTIONAL;
2019 if (wFlags & DISPATCH_PROPERTYGET)
2021 if (pDispParams->cArgs != 0)
2023 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2024 return DISP_E_BADPARAMCOUNT;
2026 if (!pVarResult)
2028 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2029 return DISP_E_PARAMNOTOPTIONAL;
2032 else if (wFlags & DISPATCH_PROPERTYPUT)
2034 if (pDispParams->cArgs != 1)
2036 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2037 return DISP_E_BADPARAMCOUNT;
2041 switch (dispIdMember)
2043 case DISPID_PICT_HANDLE:
2044 if (wFlags & DISPATCH_PROPERTYGET)
2046 TRACE("DISPID_PICT_HANDLE\n");
2047 V_VT(pVarResult) = VT_I4;
2048 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2050 break;
2051 case DISPID_PICT_HPAL:
2052 if (wFlags & DISPATCH_PROPERTYGET)
2054 TRACE("DISPID_PICT_HPAL\n");
2055 V_VT(pVarResult) = VT_I4;
2056 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2058 else if (wFlags & DISPATCH_PROPERTYPUT)
2060 VARIANTARG vararg;
2062 TRACE("DISPID_PICT_HPAL\n");
2064 VariantInit(&vararg);
2065 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2066 if (FAILED(hr))
2067 return hr;
2069 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2071 VariantClear(&vararg);
2072 return hr;
2074 break;
2075 case DISPID_PICT_TYPE:
2076 if (wFlags & DISPATCH_PROPERTYGET)
2078 TRACE("DISPID_PICT_TYPE\n");
2079 V_VT(pVarResult) = VT_I2;
2080 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2082 break;
2083 case DISPID_PICT_WIDTH:
2084 if (wFlags & DISPATCH_PROPERTYGET)
2086 TRACE("DISPID_PICT_WIDTH\n");
2087 V_VT(pVarResult) = VT_I4;
2088 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2090 break;
2091 case DISPID_PICT_HEIGHT:
2092 if (wFlags & DISPATCH_PROPERTYGET)
2094 TRACE("DISPID_PICT_HEIGHT\n");
2095 V_VT(pVarResult) = VT_I4;
2096 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2098 break;
2099 case DISPID_PICT_RENDER:
2100 if (wFlags & DISPATCH_METHOD)
2102 VARIANTARG *args = pDispParams->rgvarg;
2103 int i;
2105 TRACE("DISPID_PICT_RENDER\n");
2107 if (pDispParams->cArgs != 10)
2108 return DISP_E_BADPARAMCOUNT;
2110 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2111 for (i = 0; i < pDispParams->cArgs; i++)
2112 if (V_VT(&args[i]) != VT_I4)
2114 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i, V_VT(&args[i]));
2115 return DISP_E_TYPEMISMATCH;
2118 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2119 currently Render() doesn't use it at all so for now NULL is passed. */
2120 return IPicture_Render(&This->IPicture_iface,
2121 LongToHandle(V_I4(&args[9])),
2122 V_I4(&args[8]),
2123 V_I4(&args[7]),
2124 V_I4(&args[6]),
2125 V_I4(&args[5]),
2126 V_I4(&args[4]),
2127 V_I4(&args[3]),
2128 V_I4(&args[2]),
2129 V_I4(&args[1]),
2130 NULL);
2132 break;
2135 ERR("invalid dispid %#lx or wFlags 0x%x\n", dispIdMember, wFlags);
2136 return DISP_E_MEMBERNOTFOUND;
2140 static const IPictureVtbl OLEPictureImpl_VTable =
2142 OLEPictureImpl_QueryInterface,
2143 OLEPictureImpl_AddRef,
2144 OLEPictureImpl_Release,
2145 OLEPictureImpl_get_Handle,
2146 OLEPictureImpl_get_hPal,
2147 OLEPictureImpl_get_Type,
2148 OLEPictureImpl_get_Width,
2149 OLEPictureImpl_get_Height,
2150 OLEPictureImpl_Render,
2151 OLEPictureImpl_set_hPal,
2152 OLEPictureImpl_get_CurDC,
2153 OLEPictureImpl_SelectPicture,
2154 OLEPictureImpl_get_KeepOriginalFormat,
2155 OLEPictureImpl_put_KeepOriginalFormat,
2156 OLEPictureImpl_PictureChanged,
2157 OLEPictureImpl_SaveAsFile,
2158 OLEPictureImpl_get_Attributes
2161 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2163 OLEPictureImpl_IDispatch_QueryInterface,
2164 OLEPictureImpl_IDispatch_AddRef,
2165 OLEPictureImpl_IDispatch_Release,
2166 OLEPictureImpl_GetTypeInfoCount,
2167 OLEPictureImpl_GetTypeInfo,
2168 OLEPictureImpl_GetIDsOfNames,
2169 OLEPictureImpl_Invoke
2172 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2174 OLEPictureImpl_IPersistStream_QueryInterface,
2175 OLEPictureImpl_IPersistStream_AddRef,
2176 OLEPictureImpl_IPersistStream_Release,
2177 OLEPictureImpl_GetClassID,
2178 OLEPictureImpl_IsDirty,
2179 OLEPictureImpl_Load,
2180 OLEPictureImpl_Save,
2181 OLEPictureImpl_GetSizeMax
2184 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2186 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2187 OLEPictureImpl_IConnectionPointContainer_AddRef,
2188 OLEPictureImpl_IConnectionPointContainer_Release,
2189 OLEPictureImpl_EnumConnectionPoints,
2190 OLEPictureImpl_FindConnectionPoint
2193 /***********************************************************************
2194 * OleCreatePictureIndirect (OLEAUT32.419)
2196 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2197 BOOL Own, void **ppvObj )
2199 OLEPictureImpl* newPict;
2200 HRESULT hr;
2202 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2204 *ppvObj = NULL;
2206 hr = OLEPictureImpl_Construct(lpPictDesc, Own, &newPict);
2207 if (hr != S_OK) return hr;
2210 * Make sure it supports the interface required by the caller.
2212 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2215 * Release the reference obtained in the constructor. If
2216 * the QueryInterface was unsuccessful, it will free the class.
2218 IPicture_Release(&newPict->IPicture_iface);
2220 return hr;
2224 /***********************************************************************
2225 * OleLoadPicture (OLEAUT32.418)
2227 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2228 REFIID riid, LPVOID *ppvObj )
2230 LPPERSISTSTREAM ps;
2231 IPicture *newpic;
2232 HRESULT hr;
2234 TRACE("%p, %ld, %d, %s, %p), partially implemented.\n",
2235 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2237 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2238 if (hr != S_OK)
2239 return hr;
2240 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2241 if (hr != S_OK) {
2242 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2243 IPicture_Release(newpic);
2244 *ppvObj = NULL;
2245 return hr;
2247 hr = IPersistStream_Load(ps,lpstream);
2248 IPersistStream_Release(ps);
2249 if (FAILED(hr))
2251 ERR("IPersistStream_Load failed\n");
2252 IPicture_Release(newpic);
2253 *ppvObj = NULL;
2254 return hr;
2256 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2257 if (hr != S_OK)
2258 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2259 IPicture_Release(newpic);
2260 return hr;
2263 /***********************************************************************
2264 * OleLoadPictureEx (OLEAUT32.401)
2266 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2267 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2269 LPPERSISTSTREAM ps;
2270 IPicture *newpic;
2271 HRESULT hr;
2273 FIXME("%p, %ld, %d, %s, %lu, %lu, %#lx, %p, partially implemented.\n",
2274 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2276 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2277 if (hr != S_OK)
2278 return hr;
2279 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2280 if (hr != S_OK) {
2281 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2282 IPicture_Release(newpic);
2283 *ppvObj = NULL;
2284 return hr;
2286 hr = IPersistStream_Load(ps,lpstream);
2287 IPersistStream_Release(ps);
2288 if (FAILED(hr))
2290 ERR("IPersistStream_Load failed\n");
2291 IPicture_Release(newpic);
2292 *ppvObj = NULL;
2293 return hr;
2295 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2296 if (hr != S_OK)
2297 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2298 IPicture_Release(newpic);
2299 return hr;
2302 /***********************************************************************
2303 * OleLoadPictureFile (OLEAUT32.422)
2305 HRESULT WINAPI OleLoadPictureFile(VARIANT file, LPDISPATCH *picture)
2307 FIXME("(%s %p): stub\n", wine_dbgstr_variant(&file), picture);
2308 return E_NOTIMPL;
2311 /***********************************************************************
2312 * OleSavePictureFile (OLEAUT32.423)
2314 HRESULT WINAPI OleSavePictureFile(IDispatch *picture, BSTR filename)
2316 FIXME("(%p %s): stub\n", picture, debugstr_w(filename));
2317 return CTL_E_FILENOTFOUND;
2320 /***********************************************************************
2321 * OleLoadPicturePath (OLEAUT32.424)
2323 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2324 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2325 LPVOID *ppvRet )
2327 IPicture *ipicture;
2328 HANDLE hFile;
2329 DWORD dwFileSize;
2330 HGLOBAL hGlobal = NULL;
2331 DWORD dwBytesRead;
2332 IStream *stream;
2333 BOOL bRead;
2334 IPersistStream *pStream;
2335 HRESULT hRes;
2336 HRESULT init_res;
2337 WCHAR *file_candidate;
2338 WCHAR path_buf[MAX_PATH];
2340 TRACE("%s, %p, %ld, %#lx, %s, %p.\n", debugstr_w(szURLorPath), punkCaller, dwReserved,
2341 clrReserved, debugstr_guid(riid), ppvRet);
2343 if (!szURLorPath || !ppvRet)
2344 return E_INVALIDARG;
2346 *ppvRet = NULL;
2348 /* Convert file URLs to DOS paths. */
2349 if (wcsncmp(szURLorPath, L"file:", 5) == 0) {
2350 DWORD size;
2351 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2352 ARRAY_SIZE(path_buf), &size, 0);
2353 if (FAILED(hRes))
2354 return hRes;
2356 file_candidate = path_buf;
2358 else
2359 file_candidate = szURLorPath;
2361 /* Handle candidate DOS paths separately. */
2362 if (file_candidate[1] == ':') {
2363 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2364 0, NULL);
2365 if (hFile == INVALID_HANDLE_VALUE)
2366 return INET_E_RESOURCE_NOT_FOUND;
2368 dwFileSize = GetFileSize(hFile, NULL);
2369 if (dwFileSize != INVALID_FILE_SIZE )
2371 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2372 if ( hGlobal)
2374 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL) && dwBytesRead == dwFileSize;
2375 if (!bRead)
2377 GlobalFree(hGlobal);
2378 hGlobal = 0;
2382 CloseHandle(hFile);
2384 if (!hGlobal)
2385 return INET_E_RESOURCE_NOT_FOUND;
2387 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2388 if (FAILED(hRes))
2390 GlobalFree(hGlobal);
2391 return hRes;
2393 } else {
2394 IMoniker *pmnk;
2395 IBindCtx *pbc;
2397 hRes = CreateBindCtx(0, &pbc);
2398 if (SUCCEEDED(hRes))
2400 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2401 if (SUCCEEDED(hRes))
2403 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2404 IMoniker_Release(pmnk);
2406 IBindCtx_Release(pbc);
2408 if (FAILED(hRes))
2409 return hRes;
2412 init_res = CoInitialize(NULL);
2414 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2415 &IID_IPicture, (LPVOID*)&ipicture);
2416 if (SUCCEEDED(hRes)) {
2417 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2419 if (SUCCEEDED(hRes)) {
2420 hRes = IPersistStream_Load(pStream, stream);
2422 if (SUCCEEDED(hRes)) {
2423 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2425 if (FAILED(hRes))
2426 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2428 IPersistStream_Release(pStream);
2430 IPicture_Release(ipicture);
2433 IStream_Release(stream);
2435 if (SUCCEEDED(init_res))
2436 CoUninitialize();
2438 return hRes;
2441 /*******************************************************************************
2442 * StdPic ClassFactory
2444 typedef struct
2446 /* IUnknown fields */
2447 IClassFactory IClassFactory_iface;
2448 LONG ref;
2449 } IClassFactoryImpl;
2451 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2453 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2456 static HRESULT WINAPI
2457 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2458 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2460 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2461 return E_NOINTERFACE;
2464 static ULONG WINAPI
2465 SPCF_AddRef(LPCLASSFACTORY iface) {
2466 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2467 return InterlockedIncrement(&This->ref);
2470 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2471 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2472 /* static class, won't be freed */
2473 return InterlockedDecrement(&This->ref);
2476 static HRESULT WINAPI SPCF_CreateInstance(
2477 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2479 /* Creates an uninitialized picture */
2480 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2484 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2485 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2486 FIXME("(%p)->(%d),stub!\n",This,dolock);
2487 return S_OK;
2490 static const IClassFactoryVtbl SPCF_Vtbl = {
2491 SPCF_QueryInterface,
2492 SPCF_AddRef,
2493 SPCF_Release,
2494 SPCF_CreateInstance,
2495 SPCF_LockServer
2497 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2499 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }