libwine: Remove __wine_main_arg* from the public header.
[wine/zf.git] / dlls / oleaut32 / olepicture.c
blob43a92ca58f4be7e3b29745639e9ea8da10a5690e
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 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1951 ITypeLib *tl;
1952 HRESULT hres;
1954 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1956 if (iTInfo != 0)
1957 return E_FAIL;
1959 hres = LoadTypeLib(stdole2tlb, &tl);
1960 if (FAILED(hres))
1962 ERR("Could not load stdole2.tlb\n");
1963 return hres;
1966 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1967 if (FAILED(hres))
1968 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1970 return hres;
1973 /************************************************************************
1974 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1976 * See Windows documentation for more details on IDispatch methods.
1978 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1979 IDispatch* iface,
1980 REFIID riid,
1981 LPOLESTR* rgszNames,
1982 UINT cNames,
1983 LCID lcid,
1984 DISPID* rgDispId)
1986 ITypeInfo * pTInfo;
1987 HRESULT hres;
1989 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1990 rgszNames, cNames, (int)lcid, rgDispId);
1992 if (cNames == 0)
1994 return E_INVALIDARG;
1996 else
1998 /* retrieve type information */
1999 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2001 if (FAILED(hres))
2003 ERR("GetTypeInfo failed.\n");
2004 return hres;
2007 /* convert names to DISPIDs */
2008 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2009 ITypeInfo_Release(pTInfo);
2011 return hres;
2015 /************************************************************************
2016 * OLEPictureImpl_Invoke (IDispatch)
2018 * See Windows documentation for more details on IDispatch methods.
2020 static HRESULT WINAPI OLEPictureImpl_Invoke(
2021 IDispatch* iface,
2022 DISPID dispIdMember,
2023 REFIID riid,
2024 LCID lcid,
2025 WORD wFlags,
2026 DISPPARAMS* pDispParams,
2027 VARIANT* pVarResult,
2028 EXCEPINFO* pExepInfo,
2029 UINT* puArgErr)
2031 OLEPictureImpl *This = impl_from_IDispatch(iface);
2032 HRESULT hr;
2034 /* validate parameters */
2036 if (!IsEqualIID(riid, &IID_NULL))
2038 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2039 return DISP_E_UNKNOWNNAME;
2042 if (!pDispParams)
2044 ERR("null pDispParams not allowed\n");
2045 return DISP_E_PARAMNOTOPTIONAL;
2048 if (wFlags & DISPATCH_PROPERTYGET)
2050 if (pDispParams->cArgs != 0)
2052 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2053 return DISP_E_BADPARAMCOUNT;
2055 if (!pVarResult)
2057 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2058 return DISP_E_PARAMNOTOPTIONAL;
2061 else if (wFlags & DISPATCH_PROPERTYPUT)
2063 if (pDispParams->cArgs != 1)
2065 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2066 return DISP_E_BADPARAMCOUNT;
2070 switch (dispIdMember)
2072 case DISPID_PICT_HANDLE:
2073 if (wFlags & DISPATCH_PROPERTYGET)
2075 TRACE("DISPID_PICT_HANDLE\n");
2076 V_VT(pVarResult) = VT_I4;
2077 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2079 break;
2080 case DISPID_PICT_HPAL:
2081 if (wFlags & DISPATCH_PROPERTYGET)
2083 TRACE("DISPID_PICT_HPAL\n");
2084 V_VT(pVarResult) = VT_I4;
2085 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2087 else if (wFlags & DISPATCH_PROPERTYPUT)
2089 VARIANTARG vararg;
2091 TRACE("DISPID_PICT_HPAL\n");
2093 VariantInit(&vararg);
2094 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2095 if (FAILED(hr))
2096 return hr;
2098 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2100 VariantClear(&vararg);
2101 return hr;
2103 break;
2104 case DISPID_PICT_TYPE:
2105 if (wFlags & DISPATCH_PROPERTYGET)
2107 TRACE("DISPID_PICT_TYPE\n");
2108 V_VT(pVarResult) = VT_I2;
2109 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2111 break;
2112 case DISPID_PICT_WIDTH:
2113 if (wFlags & DISPATCH_PROPERTYGET)
2115 TRACE("DISPID_PICT_WIDTH\n");
2116 V_VT(pVarResult) = VT_I4;
2117 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2119 break;
2120 case DISPID_PICT_HEIGHT:
2121 if (wFlags & DISPATCH_PROPERTYGET)
2123 TRACE("DISPID_PICT_HEIGHT\n");
2124 V_VT(pVarResult) = VT_I4;
2125 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2127 break;
2128 case DISPID_PICT_RENDER:
2129 if (wFlags & DISPATCH_METHOD)
2131 VARIANTARG *args = pDispParams->rgvarg;
2132 int i;
2134 TRACE("DISPID_PICT_RENDER\n");
2136 if (pDispParams->cArgs != 10)
2137 return DISP_E_BADPARAMCOUNT;
2139 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2140 for (i = 0; i < pDispParams->cArgs; i++)
2141 if (V_VT(&args[i]) != VT_I4)
2143 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i, V_VT(&args[i]));
2144 return DISP_E_TYPEMISMATCH;
2147 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2148 currently Render() doesn't use it at all so for now NULL is passed. */
2149 return IPicture_Render(&This->IPicture_iface,
2150 LongToHandle(V_I4(&args[9])),
2151 V_I4(&args[8]),
2152 V_I4(&args[7]),
2153 V_I4(&args[6]),
2154 V_I4(&args[5]),
2155 V_I4(&args[4]),
2156 V_I4(&args[3]),
2157 V_I4(&args[2]),
2158 V_I4(&args[1]),
2159 NULL);
2161 break;
2164 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2165 return DISP_E_MEMBERNOTFOUND;
2169 static const IPictureVtbl OLEPictureImpl_VTable =
2171 OLEPictureImpl_QueryInterface,
2172 OLEPictureImpl_AddRef,
2173 OLEPictureImpl_Release,
2174 OLEPictureImpl_get_Handle,
2175 OLEPictureImpl_get_hPal,
2176 OLEPictureImpl_get_Type,
2177 OLEPictureImpl_get_Width,
2178 OLEPictureImpl_get_Height,
2179 OLEPictureImpl_Render,
2180 OLEPictureImpl_set_hPal,
2181 OLEPictureImpl_get_CurDC,
2182 OLEPictureImpl_SelectPicture,
2183 OLEPictureImpl_get_KeepOriginalFormat,
2184 OLEPictureImpl_put_KeepOriginalFormat,
2185 OLEPictureImpl_PictureChanged,
2186 OLEPictureImpl_SaveAsFile,
2187 OLEPictureImpl_get_Attributes
2190 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2192 OLEPictureImpl_IDispatch_QueryInterface,
2193 OLEPictureImpl_IDispatch_AddRef,
2194 OLEPictureImpl_IDispatch_Release,
2195 OLEPictureImpl_GetTypeInfoCount,
2196 OLEPictureImpl_GetTypeInfo,
2197 OLEPictureImpl_GetIDsOfNames,
2198 OLEPictureImpl_Invoke
2201 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2203 OLEPictureImpl_IPersistStream_QueryInterface,
2204 OLEPictureImpl_IPersistStream_AddRef,
2205 OLEPictureImpl_IPersistStream_Release,
2206 OLEPictureImpl_GetClassID,
2207 OLEPictureImpl_IsDirty,
2208 OLEPictureImpl_Load,
2209 OLEPictureImpl_Save,
2210 OLEPictureImpl_GetSizeMax
2213 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2215 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2216 OLEPictureImpl_IConnectionPointContainer_AddRef,
2217 OLEPictureImpl_IConnectionPointContainer_Release,
2218 OLEPictureImpl_EnumConnectionPoints,
2219 OLEPictureImpl_FindConnectionPoint
2222 /***********************************************************************
2223 * OleCreatePictureIndirect (OLEAUT32.419)
2225 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2226 BOOL Own, void **ppvObj )
2228 OLEPictureImpl* newPict;
2229 HRESULT hr;
2231 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2233 *ppvObj = NULL;
2235 hr = OLEPictureImpl_Construct(lpPictDesc, Own, &newPict);
2236 if (hr != S_OK) return hr;
2239 * Make sure it supports the interface required by the caller.
2241 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2244 * Release the reference obtained in the constructor. If
2245 * the QueryInterface was unsuccessful, it will free the class.
2247 IPicture_Release(&newPict->IPicture_iface);
2249 return hr;
2253 /***********************************************************************
2254 * OleLoadPicture (OLEAUT32.418)
2256 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2257 REFIID riid, LPVOID *ppvObj )
2259 LPPERSISTSTREAM ps;
2260 IPicture *newpic;
2261 HRESULT hr;
2263 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2264 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2266 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2267 if (hr != S_OK)
2268 return hr;
2269 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2270 if (hr != S_OK) {
2271 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2272 IPicture_Release(newpic);
2273 *ppvObj = NULL;
2274 return hr;
2276 hr = IPersistStream_Load(ps,lpstream);
2277 IPersistStream_Release(ps);
2278 if (FAILED(hr))
2280 ERR("IPersistStream_Load failed\n");
2281 IPicture_Release(newpic);
2282 *ppvObj = NULL;
2283 return hr;
2285 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2286 if (hr != S_OK)
2287 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2288 IPicture_Release(newpic);
2289 return hr;
2292 /***********************************************************************
2293 * OleLoadPictureEx (OLEAUT32.401)
2295 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2296 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2298 LPPERSISTSTREAM ps;
2299 IPicture *newpic;
2300 HRESULT hr;
2302 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2303 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2305 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2306 if (hr != S_OK)
2307 return hr;
2308 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2309 if (hr != S_OK) {
2310 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2311 IPicture_Release(newpic);
2312 *ppvObj = NULL;
2313 return hr;
2315 hr = IPersistStream_Load(ps,lpstream);
2316 IPersistStream_Release(ps);
2317 if (FAILED(hr))
2319 ERR("IPersistStream_Load failed\n");
2320 IPicture_Release(newpic);
2321 *ppvObj = NULL;
2322 return hr;
2324 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2325 if (hr != S_OK)
2326 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2327 IPicture_Release(newpic);
2328 return hr;
2331 /***********************************************************************
2332 * OleLoadPictureFile (OLEAUT32.422)
2334 HRESULT WINAPI OleLoadPictureFile(VARIANT file, LPDISPATCH *picture)
2336 FIXME("(%s %p): stub\n", wine_dbgstr_variant(&file), picture);
2337 return E_NOTIMPL;
2340 /***********************************************************************
2341 * OleSavePictureFile (OLEAUT32.423)
2343 HRESULT WINAPI OleSavePictureFile(IDispatch *picture, BSTR filename)
2345 FIXME("(%p %s): stub\n", picture, debugstr_w(filename));
2346 return CTL_E_FILENOTFOUND;
2349 /***********************************************************************
2350 * OleLoadPicturePath (OLEAUT32.424)
2352 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2353 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2354 LPVOID *ppvRet )
2356 static const WCHAR file[] = { 'f','i','l','e',':',0 };
2357 IPicture *ipicture;
2358 HANDLE hFile;
2359 DWORD dwFileSize;
2360 HGLOBAL hGlobal = NULL;
2361 DWORD dwBytesRead;
2362 IStream *stream;
2363 BOOL bRead;
2364 IPersistStream *pStream;
2365 HRESULT hRes;
2366 HRESULT init_res;
2367 WCHAR *file_candidate;
2368 WCHAR path_buf[MAX_PATH];
2370 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2371 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2372 debugstr_guid(riid), ppvRet);
2374 if (!szURLorPath || !ppvRet)
2375 return E_INVALIDARG;
2377 *ppvRet = NULL;
2379 /* Convert file URLs to DOS paths. */
2380 if (wcsncmp(szURLorPath, file, 5) == 0) {
2381 DWORD size;
2382 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2383 ARRAY_SIZE(path_buf), &size, 0);
2384 if (FAILED(hRes))
2385 return hRes;
2387 file_candidate = path_buf;
2389 else
2390 file_candidate = szURLorPath;
2392 /* Handle candidate DOS paths separately. */
2393 if (file_candidate[1] == ':') {
2394 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2395 0, NULL);
2396 if (hFile == INVALID_HANDLE_VALUE)
2397 return INET_E_RESOURCE_NOT_FOUND;
2399 dwFileSize = GetFileSize(hFile, NULL);
2400 if (dwFileSize != INVALID_FILE_SIZE )
2402 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2403 if ( hGlobal)
2405 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL) && dwBytesRead == dwFileSize;
2406 if (!bRead)
2408 GlobalFree(hGlobal);
2409 hGlobal = 0;
2413 CloseHandle(hFile);
2415 if (!hGlobal)
2416 return INET_E_RESOURCE_NOT_FOUND;
2418 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2419 if (FAILED(hRes))
2421 GlobalFree(hGlobal);
2422 return hRes;
2424 } else {
2425 IMoniker *pmnk;
2426 IBindCtx *pbc;
2428 hRes = CreateBindCtx(0, &pbc);
2429 if (SUCCEEDED(hRes))
2431 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2432 if (SUCCEEDED(hRes))
2434 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2435 IMoniker_Release(pmnk);
2437 IBindCtx_Release(pbc);
2439 if (FAILED(hRes))
2440 return hRes;
2443 init_res = CoInitialize(NULL);
2445 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2446 &IID_IPicture, (LPVOID*)&ipicture);
2447 if (SUCCEEDED(hRes)) {
2448 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2450 if (SUCCEEDED(hRes)) {
2451 hRes = IPersistStream_Load(pStream, stream);
2453 if (SUCCEEDED(hRes)) {
2454 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2456 if (FAILED(hRes))
2457 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2459 IPersistStream_Release(pStream);
2461 IPicture_Release(ipicture);
2464 IStream_Release(stream);
2466 if (SUCCEEDED(init_res))
2467 CoUninitialize();
2469 return hRes;
2472 /*******************************************************************************
2473 * StdPic ClassFactory
2475 typedef struct
2477 /* IUnknown fields */
2478 IClassFactory IClassFactory_iface;
2479 LONG ref;
2480 } IClassFactoryImpl;
2482 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2484 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2487 static HRESULT WINAPI
2488 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2489 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2491 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2492 return E_NOINTERFACE;
2495 static ULONG WINAPI
2496 SPCF_AddRef(LPCLASSFACTORY iface) {
2497 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2498 return InterlockedIncrement(&This->ref);
2501 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2502 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2503 /* static class, won't be freed */
2504 return InterlockedDecrement(&This->ref);
2507 static HRESULT WINAPI SPCF_CreateInstance(
2508 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2510 /* Creates an uninitialized picture */
2511 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2515 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2516 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2517 FIXME("(%p)->(%d),stub!\n",This,dolock);
2518 return S_OK;
2521 static const IClassFactoryVtbl SPCF_Vtbl = {
2522 SPCF_QueryInterface,
2523 SPCF_AddRef,
2524 SPCF_Release,
2525 SPCF_CreateInstance,
2526 SPCF_LockServer
2528 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2530 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }