winspool/tests: Add tests for GetFormA().
[wine.git] / dlls / oleaut32 / olepicture.c
blob5dac8e4ee610125ab97f6a38f8f5f5f0dfc324e4
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);
405 /************************************************************************
406 * OLEPictureImpl_AddRef (IUnknown)
408 * See Windows documentation for more details on IUnknown methods.
410 static ULONG WINAPI OLEPictureImpl_AddRef(
411 IPicture* iface)
413 OLEPictureImpl *This = impl_from_IPicture(iface);
414 ULONG refCount = InterlockedIncrement(&This->ref);
416 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
418 return refCount;
421 /************************************************************************
422 * OLEPictureImpl_Release (IUnknown)
424 * See Windows documentation for more details on IUnknown methods.
426 static ULONG WINAPI OLEPictureImpl_Release(
427 IPicture* iface)
429 OLEPictureImpl *This = impl_from_IPicture(iface);
430 ULONG refCount = InterlockedDecrement(&This->ref);
432 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
435 * If the reference count goes down to 0, perform suicide.
437 if (!refCount) OLEPictureImpl_Destroy(This);
439 return refCount;
442 /************************************************************************
443 * OLEPictureImpl_QueryInterface (IUnknown)
445 * See Windows documentation for more details on IUnknown methods.
447 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
448 IPicture* iface,
449 REFIID riid,
450 void** ppvObject)
452 OLEPictureImpl *This = impl_from_IPicture(iface);
454 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
456 if (!ppvObject)
457 return E_INVALIDARG;
459 *ppvObject = 0;
461 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
462 *ppvObject = &This->IPicture_iface;
463 else if (IsEqualIID(&IID_IDispatch, riid))
464 *ppvObject = &This->IDispatch_iface;
465 else if (IsEqualIID(&IID_IPictureDisp, riid))
466 *ppvObject = &This->IDispatch_iface;
467 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
468 *ppvObject = &This->IPersistStream_iface;
469 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
470 *ppvObject = &This->IConnectionPointContainer_iface;
472 if (!*ppvObject)
474 FIXME("() : asking for unsupported interface %s\n",debugstr_guid(riid));
475 return E_NOINTERFACE;
478 IPicture_AddRef(iface);
480 return S_OK;
483 /***********************************************************************
484 * OLEPicture_SendNotify (internal)
486 * Sends notification messages of changed properties to any interested
487 * connections.
489 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
491 IEnumConnections *pEnum;
492 CONNECTDATA CD;
494 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
495 return;
496 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
497 IPropertyNotifySink *sink;
499 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
500 IPropertyNotifySink_OnChanged(sink, dispID);
501 IPropertyNotifySink_Release(sink);
502 IUnknown_Release(CD.pUnk);
504 IEnumConnections_Release(pEnum);
507 /************************************************************************
508 * OLEPictureImpl_get_Handle
510 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
511 OLE_HANDLE *phandle)
513 OLEPictureImpl *This = impl_from_IPicture(iface);
514 TRACE("(%p)->(%p)\n", This, phandle);
516 if(!phandle)
517 return E_POINTER;
519 switch(This->desc.picType) {
520 case PICTYPE_NONE:
521 case PICTYPE_UNINITIALIZED:
522 *phandle = 0;
523 break;
524 case PICTYPE_BITMAP:
525 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
526 break;
527 case PICTYPE_METAFILE:
528 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
529 break;
530 case PICTYPE_ICON:
531 *phandle = HandleToUlong(This->desc.u.icon.hicon);
532 break;
533 case PICTYPE_ENHMETAFILE:
534 *phandle = HandleToUlong(This->desc.u.emf.hemf);
535 break;
536 default:
537 FIXME("Unimplemented type %d\n", This->desc.picType);
538 return E_NOTIMPL;
540 TRACE("returning handle %08x\n", *phandle);
541 return S_OK;
544 /************************************************************************
545 * OLEPictureImpl_get_hPal
547 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
548 OLE_HANDLE *phandle)
550 OLEPictureImpl *This = impl_from_IPicture(iface);
552 TRACE("(%p)->(%p)\n", This, phandle);
554 if (!phandle) return E_POINTER;
556 if (This->desc.picType == PICTYPE_BITMAP)
558 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
559 return S_OK;
562 return E_FAIL;
565 /************************************************************************
566 * OLEPictureImpl_get_Type
568 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
569 short *ptype)
571 OLEPictureImpl *This = impl_from_IPicture(iface);
572 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
574 if(!ptype)
575 return E_POINTER;
577 *ptype = This->desc.picType;
578 return S_OK;
581 /************************************************************************
582 * OLEPictureImpl_get_Width
584 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
585 OLE_XSIZE_HIMETRIC *pwidth)
587 OLEPictureImpl *This = impl_from_IPicture(iface);
588 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
589 *pwidth = This->himetricWidth;
590 return S_OK;
593 /************************************************************************
594 * OLEPictureImpl_get_Height
596 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
597 OLE_YSIZE_HIMETRIC *pheight)
599 OLEPictureImpl *This = impl_from_IPicture(iface);
600 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
601 *pheight = This->himetricHeight;
602 return S_OK;
605 static void render_masked_bitmap(OLEPictureImpl *This, HDC hdc,
606 LONG x, LONG y, LONG cx, LONG cy, OLE_XPOS_HIMETRIC xSrc, OLE_YPOS_HIMETRIC ySrc,
607 OLE_XSIZE_HIMETRIC cxSrc, OLE_YSIZE_HIMETRIC cySrc, HBITMAP hbmMask, HBITMAP hbmXor)
609 HDC hdcBmp;
611 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
612 * NB y-axis gets flipped
615 hdcBmp = CreateCompatibleDC(0);
616 SetMapMode(hdcBmp, MM_ANISOTROPIC);
617 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
618 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
619 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
620 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
622 if (hbmMask)
624 SetBkColor(hdc, RGB(255, 255, 255));
625 SetTextColor(hdc, RGB(0, 0, 0));
627 SelectObject(hdcBmp, hbmMask);
628 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCAND);
630 if (hbmXor)
632 SelectObject(hdcBmp, hbmXor);
633 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
635 else StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc - This->himetricHeight,
636 cxSrc, cySrc, SRCPAINT);
638 else
640 SelectObject(hdcBmp, hbmXor);
641 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
644 DeleteDC(hdcBmp);
647 /************************************************************************
648 * OLEPictureImpl_Render
650 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
651 LONG x, LONG y, LONG cx, LONG cy,
652 OLE_XPOS_HIMETRIC xSrc,
653 OLE_YPOS_HIMETRIC ySrc,
654 OLE_XSIZE_HIMETRIC cxSrc,
655 OLE_YSIZE_HIMETRIC cySrc,
656 LPCRECT prcWBounds)
658 OLEPictureImpl *This = impl_from_IPicture(iface);
659 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
660 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
661 if(prcWBounds)
662 TRACE("prcWBounds %s\n", wine_dbgstr_rect(prcWBounds));
664 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
665 return CTL_E_INVALIDPROPERTYVALUE;
669 * While the documentation suggests this to be here (or after rendering?)
670 * it does cause an endless recursion in my sample app. -MM 20010804
671 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
674 switch(This->desc.picType) {
675 case PICTYPE_UNINITIALIZED:
676 case PICTYPE_NONE:
677 /* nothing to do */
678 return S_OK;
679 case PICTYPE_BITMAP:
681 HBITMAP hbmMask, hbmXor;
683 if (This->hbmMask)
685 hbmMask = This->hbmMask;
686 hbmXor = This->hbmXor;
688 else
690 hbmMask = 0;
691 hbmXor = This->desc.u.bmp.hbitmap;
694 render_masked_bitmap(This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, hbmMask, hbmXor);
695 break;
698 case PICTYPE_ICON:
700 ICONINFO info;
702 if (!GetIconInfo(This->desc.u.icon.hicon, &info))
703 return E_FAIL;
705 render_masked_bitmap(This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, info.hbmMask, info.hbmColor);
707 DeleteObject(info.hbmMask);
708 if (info.hbmColor) DeleteObject(info.hbmColor);
709 break;
712 case PICTYPE_METAFILE:
714 POINT prevOrg, prevWndOrg;
715 SIZE prevExt, prevWndExt;
716 int oldmode;
718 /* Render the WMF to the appropriate location by setting the
719 appropriate ratio between "device units" and "logical units" */
720 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
721 /* For the "source rectangle" the y-axis must be inverted */
722 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
723 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
724 /* For the "destination rectangle" no inversion is necessary */
725 SetViewportOrgEx(hdc, x, y, &prevOrg);
726 SetViewportExtEx(hdc, cx, cy, &prevExt);
728 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
729 ERR("PlayMetaFile failed!\n");
731 /* We're done, restore the DC to the previous settings for converting
732 logical units to device units */
733 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
734 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
735 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
736 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
737 SetMapMode(hdc, oldmode);
738 break;
741 case PICTYPE_ENHMETAFILE:
743 RECT rc = { x, y, x + cx, y + cy };
744 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
745 break;
748 default:
749 FIXME("type %d not implemented\n", This->desc.picType);
750 return E_NOTIMPL;
752 return S_OK;
755 /************************************************************************
756 * OLEPictureImpl_set_hPal
758 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
759 OLE_HANDLE hpal)
761 OLEPictureImpl *This = impl_from_IPicture(iface);
763 TRACE("(%p)->(%08x)\n", This, hpal);
765 if (This->desc.picType == PICTYPE_BITMAP)
767 This->desc.u.bmp.hpal = ULongToHandle(hpal);
768 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
769 return S_OK;
772 return E_FAIL;
775 /************************************************************************
776 * OLEPictureImpl_get_CurDC
778 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
779 HDC *phdc)
781 OLEPictureImpl *This = impl_from_IPicture(iface);
782 TRACE("(%p), returning %p\n", This, This->hDCCur);
783 if (phdc) *phdc = This->hDCCur;
784 return S_OK;
787 /************************************************************************
788 * OLEPictureImpl_SelectPicture
790 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
791 HDC hdcIn,
792 HDC *phdcOut,
793 OLE_HANDLE *phbmpOut)
795 OLEPictureImpl *This = impl_from_IPicture(iface);
796 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
797 if (This->desc.picType == PICTYPE_BITMAP) {
798 if (phdcOut)
799 *phdcOut = This->hDCCur;
800 if (This->hDCCur) SelectObject(This->hDCCur,This->stock_bitmap);
801 if (hdcIn) SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
802 This->hDCCur = hdcIn;
803 if (phbmpOut)
804 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
805 return S_OK;
806 } else {
807 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
808 return E_FAIL;
812 /************************************************************************
813 * OLEPictureImpl_get_KeepOriginalFormat
815 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
816 BOOL *pfKeep)
818 OLEPictureImpl *This = impl_from_IPicture(iface);
819 TRACE("(%p)->(%p)\n", This, pfKeep);
820 if (!pfKeep)
821 return E_POINTER;
822 *pfKeep = This->keepOrigFormat;
823 return S_OK;
826 /************************************************************************
827 * OLEPictureImpl_put_KeepOriginalFormat
829 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
830 BOOL keep)
832 OLEPictureImpl *This = impl_from_IPicture(iface);
833 TRACE("(%p)->(%d)\n", This, keep);
834 This->keepOrigFormat = keep;
835 /* FIXME: what DISPID notification here? */
836 return S_OK;
839 /************************************************************************
840 * OLEPictureImpl_PictureChanged
842 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
844 OLEPictureImpl *This = impl_from_IPicture(iface);
845 TRACE("(%p)->()\n", This);
846 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
847 This->bIsDirty = TRUE;
848 return S_OK;
851 /************************************************************************
852 * OLEPictureImpl_SaveAsFile
854 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
855 IStream *pstream,
856 BOOL SaveMemCopy,
857 LONG *pcbSize)
859 OLEPictureImpl *This = impl_from_IPicture(iface);
860 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
861 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
864 /************************************************************************
865 * OLEPictureImpl_get_Attributes
867 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
868 DWORD *pdwAttr)
870 OLEPictureImpl *This = impl_from_IPicture(iface);
871 TRACE("(%p)->(%p).\n", This, pdwAttr);
873 if(!pdwAttr)
874 return E_POINTER;
876 *pdwAttr = 0;
877 switch (This->desc.picType) {
878 case PICTYPE_UNINITIALIZED:
879 case PICTYPE_NONE: break;
880 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
881 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
882 case PICTYPE_ENHMETAFILE: /* fall through */
883 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
884 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
886 return S_OK;
890 /************************************************************************
891 * IConnectionPointContainer
893 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
894 IConnectionPointContainer* iface,
895 REFIID riid,
896 VOID** ppvoid)
898 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
900 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
903 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
904 IConnectionPointContainer* iface)
906 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
908 return IPicture_AddRef(&This->IPicture_iface);
911 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
912 IConnectionPointContainer* iface)
914 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
916 return IPicture_Release(&This->IPicture_iface);
919 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
920 IConnectionPointContainer* iface,
921 IEnumConnectionPoints** ppEnum)
923 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
925 FIXME("(%p,%p), stub!\n",This,ppEnum);
926 return E_NOTIMPL;
929 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
930 IConnectionPointContainer* iface,
931 REFIID riid,
932 IConnectionPoint **ppCP)
934 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
935 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
936 if (!ppCP)
937 return E_POINTER;
938 *ppCP = NULL;
939 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
940 return IConnectionPoint_QueryInterface(This->pCP, &IID_IConnectionPoint, (void**)ppCP);
941 FIXME("no connection point for %s\n",debugstr_guid(riid));
942 return CONNECT_E_NOCONNECTION;
946 /************************************************************************
947 * IPersistStream
950 /************************************************************************
951 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
953 * See Windows documentation for more details on IUnknown methods.
955 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
956 IPersistStream* iface,
957 REFIID riid,
958 VOID** ppvoid)
960 OLEPictureImpl *This = impl_from_IPersistStream(iface);
962 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
965 /************************************************************************
966 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
968 * See Windows documentation for more details on IUnknown methods.
970 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
971 IPersistStream* iface)
973 OLEPictureImpl *This = impl_from_IPersistStream(iface);
975 return IPicture_AddRef(&This->IPicture_iface);
978 /************************************************************************
979 * OLEPictureImpl_IPersistStream_Release (IUnknown)
981 * See Windows documentation for more details on IUnknown methods.
983 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
984 IPersistStream* iface)
986 OLEPictureImpl *This = impl_from_IPersistStream(iface);
988 return IPicture_Release(&This->IPicture_iface);
991 /************************************************************************
992 * OLEPictureImpl_IPersistStream_GetClassID
994 static HRESULT WINAPI OLEPictureImpl_GetClassID(
995 IPersistStream* iface,CLSID* pClassID)
997 TRACE("(%p)\n", pClassID);
998 *pClassID = CLSID_StdPicture;
999 return S_OK;
1002 /************************************************************************
1003 * OLEPictureImpl_IPersistStream_IsDirty
1005 static HRESULT WINAPI OLEPictureImpl_IsDirty(
1006 IPersistStream* iface)
1008 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1009 FIXME("(%p),stub!\n",This);
1010 return E_NOTIMPL;
1013 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1015 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1016 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1017 HDC hdcref;
1019 /* Does not matter whether this is a coreheader or not, we only use
1020 * components which are in both
1022 hdcref = GetDC(0);
1023 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1024 hdcref,
1025 &(bi->bmiHeader),
1026 CBM_INIT,
1027 xbuf+bfh->bfOffBits,
1029 DIB_RGB_COLORS
1031 ReleaseDC(0, hdcref);
1032 if (This->desc.u.bmp.hbitmap == 0)
1033 return E_FAIL;
1034 This->desc.picType = PICTYPE_BITMAP;
1035 OLEPictureImpl_SetBitmap(This);
1036 return S_OK;
1039 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1041 HRESULT hr;
1042 BITMAPINFOHEADER bih;
1043 HDC hdcref;
1044 UINT width, height;
1045 UINT stride, buffersize;
1046 LPBYTE bits=NULL;
1047 WICRect rc;
1048 IWICBitmapSource *real_source;
1049 UINT x, y;
1050 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1051 BOOL has_alpha=FALSE;
1053 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1054 if (FAILED(hr)) return hr;
1056 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1057 if (FAILED(hr)) goto end;
1059 bih.biSize = sizeof(bih);
1060 bih.biWidth = width;
1061 bih.biHeight = -height;
1062 bih.biPlanes = 1;
1063 bih.biBitCount = 32;
1064 bih.biCompression = BI_RGB;
1065 bih.biSizeImage = 0;
1066 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1067 bih.biYPelsPerMeter = 4085;
1068 bih.biClrUsed = 0;
1069 bih.biClrImportant = 0;
1071 stride = 4 * width;
1072 buffersize = stride * height;
1074 bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1075 if (!bits)
1077 hr = E_OUTOFMEMORY;
1078 goto end;
1081 rc.X = 0;
1082 rc.Y = 0;
1083 rc.Width = width;
1084 rc.Height = height;
1085 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1086 if (FAILED(hr))
1087 goto end;
1089 hdcref = GetDC(0);
1090 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1091 hdcref,
1092 &bih,
1093 CBM_INIT,
1094 bits,
1095 (BITMAPINFO*)&bih,
1096 DIB_RGB_COLORS);
1098 if (This->desc.u.bmp.hbitmap == 0)
1100 hr = E_FAIL;
1101 ReleaseDC(0, hdcref);
1102 goto end;
1105 This->desc.picType = PICTYPE_BITMAP;
1106 OLEPictureImpl_SetBitmap(This);
1108 /* set transparent pixels to black, all others to white */
1109 for(y = 0; y < height; y++){
1110 for(x = 0; x < width; x++){
1111 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1112 if((*pixel & 0x80000000) == 0)
1114 has_alpha = TRUE;
1115 *pixel = black;
1117 else
1118 *pixel = white;
1122 if (has_alpha)
1124 HDC hdcBmp, hdcXor, hdcMask;
1125 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1127 This->hbmXor = CreateDIBitmap(
1128 hdcref,
1129 &bih,
1130 CBM_INIT,
1131 bits,
1132 (BITMAPINFO*)&bih,
1133 DIB_RGB_COLORS
1136 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1137 hdcBmp = CreateCompatibleDC(NULL);
1138 hdcXor = CreateCompatibleDC(NULL);
1139 hdcMask = CreateCompatibleDC(NULL);
1141 hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1142 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1143 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1145 SetBkColor(hdcXor,black);
1146 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1147 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1149 SelectObject(hdcBmp,hbmoldBmp);
1150 SelectObject(hdcXor,hbmoldXor);
1151 SelectObject(hdcMask,hbmoldMask);
1153 DeleteDC(hdcBmp);
1154 DeleteDC(hdcXor);
1155 DeleteDC(hdcMask);
1158 ReleaseDC(0, hdcref);
1160 end:
1161 HeapFree(GetProcessHeap(), 0, bits);
1162 IWICBitmapSource_Release(real_source);
1163 return hr;
1166 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1168 HRESULT hr;
1169 IWICImagingFactory *factory;
1170 IWICBitmapDecoder *decoder;
1171 IWICBitmapFrameDecode *framedecode;
1172 HRESULT initresult;
1173 IWICStream *stream;
1175 initresult = CoInitialize(NULL);
1177 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1178 &IID_IWICImagingFactory, (void**)&factory);
1179 if (SUCCEEDED(hr)) /* created factory */
1181 hr = IWICImagingFactory_CreateStream(factory, &stream);
1182 IWICImagingFactory_Release(factory);
1185 if (SUCCEEDED(hr)) /* created stream */
1187 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1189 if (SUCCEEDED(hr)) /* initialized stream */
1191 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1192 &IID_IWICBitmapDecoder, (void**)&decoder);
1193 if (SUCCEEDED(hr)) /* created decoder */
1195 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1197 if (SUCCEEDED(hr)) /* initialized decoder */
1198 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1200 IWICBitmapDecoder_Release(decoder);
1204 IWICStream_Release(stream);
1207 if (SUCCEEDED(hr)) /* got framedecode */
1209 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1210 IWICBitmapFrameDecode_Release(framedecode);
1213 if (SUCCEEDED(initresult)) CoUninitialize();
1214 return hr;
1217 /*****************************************************
1218 * start of Icon-specific code
1221 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1223 HICON hicon;
1224 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1225 HDC hdcRef;
1226 int i;
1228 TRACE("(this %p, xbuf %p, xread %u)\n", This, xbuf, xread);
1231 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1232 FIXME("icon.idType=%d\n",cifd->idType);
1233 FIXME("icon.idCount=%d\n",cifd->idCount);
1235 for (i=0;i<cifd->idCount;i++) {
1236 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1237 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1238 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1239 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1240 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1241 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1242 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1243 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1247 /* Need at least one icon to do something. */
1248 if (!cifd->idCount)
1250 ERR("Invalid icon count of zero.\n");
1251 return E_FAIL;
1253 i=0;
1254 /* If we have more than one icon, try to find the best.
1255 * this currently means '32 pixel wide'.
1257 if (cifd->idCount!=1) {
1258 for (i=0;i<cifd->idCount;i++) {
1259 if (cifd->idEntries[i].bWidth == 32)
1260 break;
1262 if (i==cifd->idCount) i=0;
1264 if (xread < cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize)
1266 ERR("Icon data address %u is over %u bytes available.\n",
1267 cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize, xread);
1268 return E_FAIL;
1270 if (cifd->idType == 2)
1272 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, cifd->idEntries[i].dwDIBSize + 4);
1273 memcpy(buf, &cifd->idEntries[i].xHotspot, 4);
1274 memcpy(buf + 4, xbuf+cifd->idEntries[i].dwDIBOffset, cifd->idEntries[i].dwDIBSize);
1275 hicon = CreateIconFromResourceEx(
1276 buf,
1277 cifd->idEntries[i].dwDIBSize + 4,
1278 FALSE, /* is cursor */
1279 0x00030000,
1280 cifd->idEntries[i].bWidth,
1281 cifd->idEntries[i].bHeight,
1284 HeapFree(GetProcessHeap(), 0, buf);
1286 else
1288 hicon = CreateIconFromResourceEx(
1289 xbuf+cifd->idEntries[i].dwDIBOffset,
1290 cifd->idEntries[i].dwDIBSize,
1291 TRUE, /* is icon */
1292 0x00030000,
1293 cifd->idEntries[i].bWidth,
1294 cifd->idEntries[i].bHeight,
1298 if (!hicon) {
1299 ERR("CreateIcon failed.\n");
1300 return E_FAIL;
1301 } else {
1302 This->desc.picType = PICTYPE_ICON;
1303 This->desc.u.icon.hicon = hicon;
1304 This->origWidth = cifd->idEntries[i].bWidth;
1305 This->origHeight = cifd->idEntries[i].bHeight;
1306 hdcRef = CreateCompatibleDC(0);
1307 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1308 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1309 DeleteDC(hdcRef);
1310 return S_OK;
1314 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1315 const BYTE *data, ULONG size)
1317 HENHMETAFILE hemf;
1318 ENHMETAHEADER hdr;
1320 hemf = SetEnhMetaFileBits(size, data);
1321 if (!hemf) return E_FAIL;
1323 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1325 This->desc.picType = PICTYPE_ENHMETAFILE;
1326 This->desc.u.emf.hemf = hemf;
1328 This->origWidth = 0;
1329 This->origHeight = 0;
1330 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1331 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1333 return S_OK;
1336 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1337 const BYTE *data, ULONG size)
1339 const APM_HEADER *header = (const APM_HEADER *)data;
1340 HMETAFILE hmf;
1342 if (size < sizeof(APM_HEADER))
1343 return E_FAIL;
1344 if (header->key != 0x9ac6cdd7)
1345 return E_FAIL;
1347 /* SetMetaFileBitsEx performs data check on its own */
1348 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1349 if (!hmf) return E_FAIL;
1351 This->desc.picType = PICTYPE_METAFILE;
1352 This->desc.u.wmf.hmeta = hmf;
1353 This->desc.u.wmf.xExt = 0;
1354 This->desc.u.wmf.yExt = 0;
1356 This->origWidth = 0;
1357 This->origHeight = 0;
1358 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1359 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1360 return S_OK;
1363 /************************************************************************
1364 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1366 * Loads the binary data from the IStream. Starts at current position.
1367 * There appears to be an 2 DWORD header:
1368 * DWORD magic;
1369 * DWORD len;
1371 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1373 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1374 HRESULT hr;
1375 BOOL headerisdata;
1376 BOOL statfailed = FALSE;
1377 ULONG xread, toread;
1378 ULONG headerread;
1379 BYTE *xbuf;
1380 DWORD header[2];
1381 WORD magic;
1382 STATSTG statstg;
1383 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1385 TRACE("(%p,%p)\n",This,pStm);
1387 /****************************************************************************************
1388 * Part 1: Load the data
1390 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1391 * out whether we do.
1393 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1394 * compound file. This may explain most, if not all, of the cases of "no
1395 * header", and the header validation should take this into account.
1396 * At least in Visual Basic 6, resource streams, valid headers are
1397 * header[0] == "lt\0\0",
1398 * header[1] == length_of_stream.
1400 * Also handle streams where we do not have a working "Stat" method by
1401 * reading all data until the end of the stream.
1403 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1404 if (hr != S_OK) {
1405 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1406 statfailed = TRUE;
1407 /* we will read at least 8 byte ... just right below */
1408 statstg.cbSize.QuadPart = 8;
1411 toread = 0;
1412 headerread = 0;
1413 headerisdata = FALSE;
1414 do {
1415 hr = IStream_Read(pStm, header, 8, &xread);
1416 if (hr != S_OK || xread!=8) {
1417 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1418 return (hr?hr:E_FAIL);
1420 headerread += xread;
1421 xread = 0;
1423 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1424 if (toread != 0 && toread != header[1])
1425 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1426 toread, header[1]);
1427 toread = header[1];
1428 if (statfailed)
1430 statstg.cbSize.QuadPart = header[1] + 8;
1431 statfailed = FALSE;
1433 if (toread == 0) break;
1434 } else {
1435 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1436 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1437 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1438 (header[0] == EMR_HEADER) || /* EMF header */
1439 (header[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1440 (header[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1441 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1442 (header[1]==0)
1443 ) {/* Found start of bitmap data */
1444 headerisdata = TRUE;
1445 if (toread == 0)
1446 toread = statstg.cbSize.QuadPart-8;
1447 else toread -= 8;
1448 xread = 8;
1449 } else {
1450 FIXME("Unknown stream header magic: %08x\n", header[0]);
1451 toread = header[1];
1454 } while (!headerisdata);
1456 if (statfailed) { /* we don't know the size ... read all we get */
1457 unsigned int sizeinc = 4096;
1458 unsigned int origsize = sizeinc;
1459 ULONG nread = 42;
1461 TRACE("Reading all data from stream.\n");
1462 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1463 if (headerisdata)
1464 memcpy (xbuf, header, 8);
1465 while (1) {
1466 while (xread < origsize) {
1467 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1468 xread += nread;
1469 if (hr != S_OK || !nread)
1470 break;
1472 if (!nread || hr != S_OK) /* done, or error */
1473 break;
1474 if (xread == origsize) {
1475 origsize += sizeinc;
1476 sizeinc = 2*sizeinc; /* exponential increase */
1477 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1480 if (hr != S_OK)
1481 TRACE("hr in no-stat loader case is %08x\n", hr);
1482 TRACE("loaded %d bytes.\n", xread);
1483 This->datalen = xread;
1484 This->data = xbuf;
1485 } else {
1486 This->datalen = toread+(headerisdata?8:0);
1487 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1488 if (!xbuf)
1489 return E_OUTOFMEMORY;
1491 if (headerisdata)
1492 memcpy (xbuf, header, 8);
1494 while (xread < This->datalen) {
1495 ULONG nread;
1496 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1497 xread += nread;
1498 if (hr != S_OK || !nread)
1499 break;
1501 if (xread != This->datalen)
1502 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1504 if (This->datalen == 0) { /* Marks the "NONE" picture */
1505 This->desc.picType = PICTYPE_NONE;
1506 return S_OK;
1510 /****************************************************************************************
1511 * Part 2: Process the loaded data
1514 magic = xbuf[0] + (xbuf[1]<<8);
1515 This->loadtime_format = magic;
1517 switch (magic) {
1518 case BITMAP_FORMAT_GIF: /* GIF */
1519 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1520 break;
1521 case BITMAP_FORMAT_JPEG: /* JPEG */
1522 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1523 break;
1524 case BITMAP_FORMAT_BMP: /* Bitmap */
1525 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1526 break;
1527 case BITMAP_FORMAT_PNG: /* PNG */
1528 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1529 break;
1530 case BITMAP_FORMAT_APM: /* APM */
1531 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1532 break;
1533 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1534 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1535 break;
1537 default:
1539 unsigned int i;
1541 /* let's see if it's a EMF */
1542 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1543 if (hr == S_OK) break;
1545 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1546 hr=E_FAIL;
1547 for (i=0;i<xread+8;i++) {
1548 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1549 else MESSAGE("%02x ",xbuf[i-8]);
1550 if (i % 10 == 9) MESSAGE("\n");
1552 MESSAGE("\n");
1553 break;
1556 This->bIsDirty = FALSE;
1558 /* FIXME: this notify is not really documented */
1559 if (hr==S_OK)
1560 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1561 return hr;
1564 static BOOL serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1566 BOOL success = FALSE;
1567 HDC hDC;
1568 BITMAPINFO * pInfoBitmap;
1569 int iNumPaletteEntries;
1570 unsigned char * pPixelData;
1571 BITMAPFILEHEADER * pFileHeader;
1572 BITMAPINFO * pInfoHeader;
1574 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1575 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1577 /* Find out bitmap size and padded length */
1578 hDC = GetDC(0);
1579 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1580 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1582 /* Fetch bitmap palette & pixel data */
1584 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1585 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1587 /* Calculate the total length required for the BMP data */
1588 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1589 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1590 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1591 } else {
1592 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1593 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1594 else
1595 iNumPaletteEntries = 0;
1597 *pLength =
1598 sizeof(BITMAPFILEHEADER) +
1599 sizeof(BITMAPINFOHEADER) +
1600 iNumPaletteEntries * sizeof(RGBQUAD) +
1601 pInfoBitmap->bmiHeader.biSizeImage;
1602 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1604 /* Fill the BITMAPFILEHEADER */
1605 pFileHeader = *ppBuffer;
1606 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1607 pFileHeader->bfSize = *pLength;
1608 pFileHeader->bfOffBits =
1609 sizeof(BITMAPFILEHEADER) +
1610 sizeof(BITMAPINFOHEADER) +
1611 iNumPaletteEntries * sizeof(RGBQUAD);
1613 /* Fill the BITMAPINFOHEADER and the palette data */
1614 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1615 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1616 memcpy(
1617 (unsigned char *)(*ppBuffer) +
1618 sizeof(BITMAPFILEHEADER) +
1619 sizeof(BITMAPINFOHEADER) +
1620 iNumPaletteEntries * sizeof(RGBQUAD),
1621 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1622 success = TRUE;
1624 HeapFree(GetProcessHeap(), 0, pPixelData);
1625 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1626 return success;
1629 static BOOL serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1631 ICONINFO infoIcon;
1632 BOOL success = FALSE;
1634 *ppBuffer = NULL; *pLength = 0;
1635 if (GetIconInfo(hIcon, &infoIcon)) {
1636 HDC hDC;
1637 BITMAPINFO * pInfoBitmap;
1638 unsigned char * pIconData = NULL;
1639 unsigned int iDataSize = 0;
1641 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1643 /* Find out icon size */
1644 hDC = GetDC(0);
1645 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1646 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1647 if (1) {
1648 /* Auxiliary pointers */
1649 CURSORICONFILEDIR * pIconDir;
1650 CURSORICONFILEDIRENTRY * pIconEntry;
1651 BITMAPINFOHEADER * pIconBitmapHeader;
1652 unsigned int iOffsetPalette;
1653 unsigned int iOffsetColorData;
1654 unsigned int iOffsetMaskData;
1656 unsigned int iLengthScanLineMask;
1657 unsigned int iNumEntriesPalette;
1659 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1661 FIXME("DEBUG: bitmap size is %d x %d\n",
1662 pInfoBitmap->bmiHeader.biWidth,
1663 pInfoBitmap->bmiHeader.biHeight);
1664 FIXME("DEBUG: bitmap bpp is %d\n",
1665 pInfoBitmap->bmiHeader.biBitCount);
1666 FIXME("DEBUG: bitmap nplanes is %d\n",
1667 pInfoBitmap->bmiHeader.biPlanes);
1668 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1669 pInfoBitmap->bmiHeader.biSizeImage);
1671 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1672 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1673 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1675 /* Fill out the CURSORICONFILEDIR */
1676 pIconDir = (CURSORICONFILEDIR *)pIconData;
1677 pIconDir->idType = 1;
1678 pIconDir->idCount = 1;
1679 pIconDir->idReserved = 0;
1681 /* Fill out the CURSORICONFILEDIRENTRY */
1682 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1683 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1684 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1685 pIconEntry->bColorCount =
1686 (pInfoBitmap->bmiHeader.biBitCount < 8)
1687 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1688 : 0;
1689 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1690 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1691 pIconEntry->dwDIBSize = 0;
1692 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1694 /* Fill out the BITMAPINFOHEADER */
1695 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1696 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1698 /* Find out whether a palette exists for the bitmap */
1699 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1700 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1701 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1702 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1703 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1704 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1705 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1706 iNumEntriesPalette = 3;
1707 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1708 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1709 } else {
1710 iNumEntriesPalette = 0;
1713 /* Add bitmap size and header size to icon data size. */
1714 iOffsetPalette = iDataSize;
1715 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1716 iOffsetColorData = iDataSize;
1717 iDataSize += pIconBitmapHeader->biSizeImage;
1718 iOffsetMaskData = iDataSize;
1719 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1720 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1721 pIconBitmapHeader->biHeight *= 2;
1722 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1723 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1724 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1725 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1727 /* Get the actual bitmap data from the icon bitmap */
1728 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1729 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1730 if (iNumEntriesPalette > 0) {
1731 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1732 iNumEntriesPalette * sizeof(RGBQUAD));
1735 /* Reset all values so that GetDIBits call succeeds */
1736 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1737 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1738 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1740 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1741 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1742 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1744 printf("ERROR: unable to get bitmap mask (error %u)\n",
1745 GetLastError());
1749 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1750 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1752 /* Write out everything produced so far to the stream */
1753 *ppBuffer = pIconData; *pLength = iDataSize;
1754 success = TRUE;
1755 } else {
1757 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1758 GetLastError());
1762 Remarks (from MSDN entry on GetIconInfo):
1764 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1765 members of ICONINFO. The calling application must manage
1766 these bitmaps and delete them when they are no longer
1767 necessary.
1769 if (hDC) ReleaseDC(0, hDC);
1770 DeleteObject(infoIcon.hbmMask);
1771 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1772 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1773 } else {
1774 printf("ERROR: Unable to get icon information (error %u)\n",
1775 GetLastError());
1777 return success;
1780 static HRESULT WINAPI OLEPictureImpl_Save(
1781 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1783 HRESULT hResult = E_NOTIMPL;
1784 void * pIconData;
1785 unsigned int iDataSize;
1786 DWORD header[2];
1787 ULONG dummy;
1788 BOOL serializeResult = FALSE;
1789 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1791 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1793 switch (This->desc.picType) {
1794 case PICTYPE_NONE:
1795 header[0] = 0x0000746c;
1796 header[1] = 0;
1797 hResult = IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1798 break;
1800 case PICTYPE_ICON:
1801 if (This->bIsDirty || !This->data) {
1802 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1803 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1804 hResult = E_FAIL;
1805 break;
1807 HeapFree(GetProcessHeap(), 0, This->data);
1808 This->data = pIconData;
1809 This->datalen = iDataSize;
1812 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1813 header[1] = This->datalen;
1814 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1815 IStream_Write(pStm, This->data, This->datalen, &dummy);
1816 hResult = S_OK;
1817 break;
1818 case PICTYPE_BITMAP:
1819 if (This->bIsDirty || !This->data) {
1820 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1821 case BITMAP_FORMAT_BMP:
1822 serializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1823 break;
1824 case BITMAP_FORMAT_JPEG:
1825 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1826 break;
1827 case BITMAP_FORMAT_GIF:
1828 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1829 break;
1830 case BITMAP_FORMAT_PNG:
1831 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1832 break;
1833 default:
1834 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1835 break;
1838 if (!serializeResult)
1840 hResult = E_FAIL;
1841 break;
1844 HeapFree(GetProcessHeap(), 0, This->data);
1845 This->data = pIconData;
1846 This->datalen = iDataSize;
1849 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1850 header[1] = This->datalen;
1851 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1852 IStream_Write(pStm, This->data, This->datalen, &dummy);
1853 hResult = S_OK;
1854 break;
1855 case PICTYPE_METAFILE:
1856 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1857 break;
1858 case PICTYPE_ENHMETAFILE:
1859 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1860 break;
1861 default:
1862 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1863 break;
1865 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1866 return hResult;
1869 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1870 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1872 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1873 FIXME("(%p,%p),stub!\n",This,pcbSize);
1874 return E_NOTIMPL;
1878 /************************************************************************
1879 * IDispatch
1882 /************************************************************************
1883 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1885 * See Windows documentation for more details on IUnknown methods.
1887 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1888 IDispatch* iface,
1889 REFIID riid,
1890 VOID** ppvoid)
1892 OLEPictureImpl *This = impl_from_IDispatch(iface);
1894 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1897 /************************************************************************
1898 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1900 * See Windows documentation for more details on IUnknown methods.
1902 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1903 IDispatch* iface)
1905 OLEPictureImpl *This = impl_from_IDispatch(iface);
1907 return IPicture_AddRef(&This->IPicture_iface);
1910 /************************************************************************
1911 * OLEPictureImpl_IDispatch_Release (IUnknown)
1913 * See Windows documentation for more details on IUnknown methods.
1915 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1916 IDispatch* iface)
1918 OLEPictureImpl *This = impl_from_IDispatch(iface);
1920 return IPicture_Release(&This->IPicture_iface);
1923 /************************************************************************
1924 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1926 * See Windows documentation for more details on IDispatch methods.
1928 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1929 IDispatch* iface,
1930 unsigned int* pctinfo)
1932 TRACE("(%p)\n", pctinfo);
1934 *pctinfo = 1;
1936 return S_OK;
1939 /************************************************************************
1940 * OLEPictureImpl_GetTypeInfo (IDispatch)
1942 * See Windows documentation for more details on IDispatch methods.
1944 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1945 IDispatch* iface,
1946 UINT iTInfo,
1947 LCID lcid,
1948 ITypeInfo** ppTInfo)
1950 ITypeLib *tl;
1951 HRESULT hres;
1953 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1955 if (iTInfo != 0)
1956 return E_FAIL;
1958 hres = LoadTypeLib(L"stdole2.tlb", &tl);
1959 if (FAILED(hres))
1961 ERR("Could not load stdole2.tlb\n");
1962 return hres;
1965 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1966 if (FAILED(hres))
1967 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1969 return hres;
1972 /************************************************************************
1973 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1975 * See Windows documentation for more details on IDispatch methods.
1977 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1978 IDispatch* iface,
1979 REFIID riid,
1980 LPOLESTR* rgszNames,
1981 UINT cNames,
1982 LCID lcid,
1983 DISPID* rgDispId)
1985 ITypeInfo * pTInfo;
1986 HRESULT hres;
1988 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1989 rgszNames, cNames, (int)lcid, rgDispId);
1991 if (cNames == 0)
1993 return E_INVALIDARG;
1995 else
1997 /* retrieve type information */
1998 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2000 if (FAILED(hres))
2002 ERR("GetTypeInfo failed.\n");
2003 return hres;
2006 /* convert names to DISPIDs */
2007 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2008 ITypeInfo_Release(pTInfo);
2010 return hres;
2014 /************************************************************************
2015 * OLEPictureImpl_Invoke (IDispatch)
2017 * See Windows documentation for more details on IDispatch methods.
2019 static HRESULT WINAPI OLEPictureImpl_Invoke(
2020 IDispatch* iface,
2021 DISPID dispIdMember,
2022 REFIID riid,
2023 LCID lcid,
2024 WORD wFlags,
2025 DISPPARAMS* pDispParams,
2026 VARIANT* pVarResult,
2027 EXCEPINFO* pExepInfo,
2028 UINT* puArgErr)
2030 OLEPictureImpl *This = impl_from_IDispatch(iface);
2031 HRESULT hr;
2033 /* validate parameters */
2035 if (!IsEqualIID(riid, &IID_NULL))
2037 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2038 return DISP_E_UNKNOWNNAME;
2041 if (!pDispParams)
2043 ERR("null pDispParams not allowed\n");
2044 return DISP_E_PARAMNOTOPTIONAL;
2047 if (wFlags & DISPATCH_PROPERTYGET)
2049 if (pDispParams->cArgs != 0)
2051 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2052 return DISP_E_BADPARAMCOUNT;
2054 if (!pVarResult)
2056 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2057 return DISP_E_PARAMNOTOPTIONAL;
2060 else if (wFlags & DISPATCH_PROPERTYPUT)
2062 if (pDispParams->cArgs != 1)
2064 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2065 return DISP_E_BADPARAMCOUNT;
2069 switch (dispIdMember)
2071 case DISPID_PICT_HANDLE:
2072 if (wFlags & DISPATCH_PROPERTYGET)
2074 TRACE("DISPID_PICT_HANDLE\n");
2075 V_VT(pVarResult) = VT_I4;
2076 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2078 break;
2079 case DISPID_PICT_HPAL:
2080 if (wFlags & DISPATCH_PROPERTYGET)
2082 TRACE("DISPID_PICT_HPAL\n");
2083 V_VT(pVarResult) = VT_I4;
2084 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2086 else if (wFlags & DISPATCH_PROPERTYPUT)
2088 VARIANTARG vararg;
2090 TRACE("DISPID_PICT_HPAL\n");
2092 VariantInit(&vararg);
2093 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2094 if (FAILED(hr))
2095 return hr;
2097 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2099 VariantClear(&vararg);
2100 return hr;
2102 break;
2103 case DISPID_PICT_TYPE:
2104 if (wFlags & DISPATCH_PROPERTYGET)
2106 TRACE("DISPID_PICT_TYPE\n");
2107 V_VT(pVarResult) = VT_I2;
2108 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2110 break;
2111 case DISPID_PICT_WIDTH:
2112 if (wFlags & DISPATCH_PROPERTYGET)
2114 TRACE("DISPID_PICT_WIDTH\n");
2115 V_VT(pVarResult) = VT_I4;
2116 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2118 break;
2119 case DISPID_PICT_HEIGHT:
2120 if (wFlags & DISPATCH_PROPERTYGET)
2122 TRACE("DISPID_PICT_HEIGHT\n");
2123 V_VT(pVarResult) = VT_I4;
2124 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2126 break;
2127 case DISPID_PICT_RENDER:
2128 if (wFlags & DISPATCH_METHOD)
2130 VARIANTARG *args = pDispParams->rgvarg;
2131 int i;
2133 TRACE("DISPID_PICT_RENDER\n");
2135 if (pDispParams->cArgs != 10)
2136 return DISP_E_BADPARAMCOUNT;
2138 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2139 for (i = 0; i < pDispParams->cArgs; i++)
2140 if (V_VT(&args[i]) != VT_I4)
2142 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i, V_VT(&args[i]));
2143 return DISP_E_TYPEMISMATCH;
2146 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2147 currently Render() doesn't use it at all so for now NULL is passed. */
2148 return IPicture_Render(&This->IPicture_iface,
2149 LongToHandle(V_I4(&args[9])),
2150 V_I4(&args[8]),
2151 V_I4(&args[7]),
2152 V_I4(&args[6]),
2153 V_I4(&args[5]),
2154 V_I4(&args[4]),
2155 V_I4(&args[3]),
2156 V_I4(&args[2]),
2157 V_I4(&args[1]),
2158 NULL);
2160 break;
2163 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2164 return DISP_E_MEMBERNOTFOUND;
2168 static const IPictureVtbl OLEPictureImpl_VTable =
2170 OLEPictureImpl_QueryInterface,
2171 OLEPictureImpl_AddRef,
2172 OLEPictureImpl_Release,
2173 OLEPictureImpl_get_Handle,
2174 OLEPictureImpl_get_hPal,
2175 OLEPictureImpl_get_Type,
2176 OLEPictureImpl_get_Width,
2177 OLEPictureImpl_get_Height,
2178 OLEPictureImpl_Render,
2179 OLEPictureImpl_set_hPal,
2180 OLEPictureImpl_get_CurDC,
2181 OLEPictureImpl_SelectPicture,
2182 OLEPictureImpl_get_KeepOriginalFormat,
2183 OLEPictureImpl_put_KeepOriginalFormat,
2184 OLEPictureImpl_PictureChanged,
2185 OLEPictureImpl_SaveAsFile,
2186 OLEPictureImpl_get_Attributes
2189 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2191 OLEPictureImpl_IDispatch_QueryInterface,
2192 OLEPictureImpl_IDispatch_AddRef,
2193 OLEPictureImpl_IDispatch_Release,
2194 OLEPictureImpl_GetTypeInfoCount,
2195 OLEPictureImpl_GetTypeInfo,
2196 OLEPictureImpl_GetIDsOfNames,
2197 OLEPictureImpl_Invoke
2200 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2202 OLEPictureImpl_IPersistStream_QueryInterface,
2203 OLEPictureImpl_IPersistStream_AddRef,
2204 OLEPictureImpl_IPersistStream_Release,
2205 OLEPictureImpl_GetClassID,
2206 OLEPictureImpl_IsDirty,
2207 OLEPictureImpl_Load,
2208 OLEPictureImpl_Save,
2209 OLEPictureImpl_GetSizeMax
2212 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2214 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2215 OLEPictureImpl_IConnectionPointContainer_AddRef,
2216 OLEPictureImpl_IConnectionPointContainer_Release,
2217 OLEPictureImpl_EnumConnectionPoints,
2218 OLEPictureImpl_FindConnectionPoint
2221 /***********************************************************************
2222 * OleCreatePictureIndirect (OLEAUT32.419)
2224 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2225 BOOL Own, void **ppvObj )
2227 OLEPictureImpl* newPict;
2228 HRESULT hr;
2230 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2232 *ppvObj = NULL;
2234 hr = OLEPictureImpl_Construct(lpPictDesc, Own, &newPict);
2235 if (hr != S_OK) return hr;
2238 * Make sure it supports the interface required by the caller.
2240 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2243 * Release the reference obtained in the constructor. If
2244 * the QueryInterface was unsuccessful, it will free the class.
2246 IPicture_Release(&newPict->IPicture_iface);
2248 return hr;
2252 /***********************************************************************
2253 * OleLoadPicture (OLEAUT32.418)
2255 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2256 REFIID riid, LPVOID *ppvObj )
2258 LPPERSISTSTREAM ps;
2259 IPicture *newpic;
2260 HRESULT hr;
2262 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2263 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2265 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2266 if (hr != S_OK)
2267 return hr;
2268 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2269 if (hr != S_OK) {
2270 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2271 IPicture_Release(newpic);
2272 *ppvObj = NULL;
2273 return hr;
2275 hr = IPersistStream_Load(ps,lpstream);
2276 IPersistStream_Release(ps);
2277 if (FAILED(hr))
2279 ERR("IPersistStream_Load failed\n");
2280 IPicture_Release(newpic);
2281 *ppvObj = NULL;
2282 return hr;
2284 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2285 if (hr != S_OK)
2286 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2287 IPicture_Release(newpic);
2288 return hr;
2291 /***********************************************************************
2292 * OleLoadPictureEx (OLEAUT32.401)
2294 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2295 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2297 LPPERSISTSTREAM ps;
2298 IPicture *newpic;
2299 HRESULT hr;
2301 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2302 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2304 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2305 if (hr != S_OK)
2306 return hr;
2307 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2308 if (hr != S_OK) {
2309 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2310 IPicture_Release(newpic);
2311 *ppvObj = NULL;
2312 return hr;
2314 hr = IPersistStream_Load(ps,lpstream);
2315 IPersistStream_Release(ps);
2316 if (FAILED(hr))
2318 ERR("IPersistStream_Load failed\n");
2319 IPicture_Release(newpic);
2320 *ppvObj = NULL;
2321 return hr;
2323 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2324 if (hr != S_OK)
2325 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2326 IPicture_Release(newpic);
2327 return hr;
2330 /***********************************************************************
2331 * OleLoadPictureFile (OLEAUT32.422)
2333 HRESULT WINAPI OleLoadPictureFile(VARIANT file, LPDISPATCH *picture)
2335 FIXME("(%s %p): stub\n", wine_dbgstr_variant(&file), picture);
2336 return E_NOTIMPL;
2339 /***********************************************************************
2340 * OleSavePictureFile (OLEAUT32.423)
2342 HRESULT WINAPI OleSavePictureFile(IDispatch *picture, BSTR filename)
2344 FIXME("(%p %s): stub\n", picture, debugstr_w(filename));
2345 return CTL_E_FILENOTFOUND;
2348 /***********************************************************************
2349 * OleLoadPicturePath (OLEAUT32.424)
2351 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2352 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2353 LPVOID *ppvRet )
2355 IPicture *ipicture;
2356 HANDLE hFile;
2357 DWORD dwFileSize;
2358 HGLOBAL hGlobal = NULL;
2359 DWORD dwBytesRead;
2360 IStream *stream;
2361 BOOL bRead;
2362 IPersistStream *pStream;
2363 HRESULT hRes;
2364 HRESULT init_res;
2365 WCHAR *file_candidate;
2366 WCHAR path_buf[MAX_PATH];
2368 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2369 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2370 debugstr_guid(riid), ppvRet);
2372 if (!szURLorPath || !ppvRet)
2373 return E_INVALIDARG;
2375 *ppvRet = NULL;
2377 /* Convert file URLs to DOS paths. */
2378 if (wcsncmp(szURLorPath, L"file:", 5) == 0) {
2379 DWORD size;
2380 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2381 ARRAY_SIZE(path_buf), &size, 0);
2382 if (FAILED(hRes))
2383 return hRes;
2385 file_candidate = path_buf;
2387 else
2388 file_candidate = szURLorPath;
2390 /* Handle candidate DOS paths separately. */
2391 if (file_candidate[1] == ':') {
2392 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2393 0, NULL);
2394 if (hFile == INVALID_HANDLE_VALUE)
2395 return INET_E_RESOURCE_NOT_FOUND;
2397 dwFileSize = GetFileSize(hFile, NULL);
2398 if (dwFileSize != INVALID_FILE_SIZE )
2400 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2401 if ( hGlobal)
2403 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL) && dwBytesRead == dwFileSize;
2404 if (!bRead)
2406 GlobalFree(hGlobal);
2407 hGlobal = 0;
2411 CloseHandle(hFile);
2413 if (!hGlobal)
2414 return INET_E_RESOURCE_NOT_FOUND;
2416 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2417 if (FAILED(hRes))
2419 GlobalFree(hGlobal);
2420 return hRes;
2422 } else {
2423 IMoniker *pmnk;
2424 IBindCtx *pbc;
2426 hRes = CreateBindCtx(0, &pbc);
2427 if (SUCCEEDED(hRes))
2429 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2430 if (SUCCEEDED(hRes))
2432 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2433 IMoniker_Release(pmnk);
2435 IBindCtx_Release(pbc);
2437 if (FAILED(hRes))
2438 return hRes;
2441 init_res = CoInitialize(NULL);
2443 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2444 &IID_IPicture, (LPVOID*)&ipicture);
2445 if (SUCCEEDED(hRes)) {
2446 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2448 if (SUCCEEDED(hRes)) {
2449 hRes = IPersistStream_Load(pStream, stream);
2451 if (SUCCEEDED(hRes)) {
2452 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2454 if (FAILED(hRes))
2455 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2457 IPersistStream_Release(pStream);
2459 IPicture_Release(ipicture);
2462 IStream_Release(stream);
2464 if (SUCCEEDED(init_res))
2465 CoUninitialize();
2467 return hRes;
2470 /*******************************************************************************
2471 * StdPic ClassFactory
2473 typedef struct
2475 /* IUnknown fields */
2476 IClassFactory IClassFactory_iface;
2477 LONG ref;
2478 } IClassFactoryImpl;
2480 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2482 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2485 static HRESULT WINAPI
2486 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2487 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2489 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2490 return E_NOINTERFACE;
2493 static ULONG WINAPI
2494 SPCF_AddRef(LPCLASSFACTORY iface) {
2495 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2496 return InterlockedIncrement(&This->ref);
2499 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2500 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2501 /* static class, won't be freed */
2502 return InterlockedDecrement(&This->ref);
2505 static HRESULT WINAPI SPCF_CreateInstance(
2506 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2508 /* Creates an uninitialized picture */
2509 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2513 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2514 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2515 FIXME("(%p)->(%d),stub!\n",This,dolock);
2516 return S_OK;
2519 static const IClassFactoryVtbl SPCF_Vtbl = {
2520 SPCF_QueryInterface,
2521 SPCF_AddRef,
2522 SPCF_Release,
2523 SPCF_CreateInstance,
2524 SPCF_LockServer
2526 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2528 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }