netapi32: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / oleaut32 / olepicture.c
blobb2ad6cb473aee84d3473994ae8eb5adbe728b74e
1 /*
2 * OLE Picture object
4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
8 * Copyright 2008 Kirill K. Smirnov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * BUGS
26 * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
27 * Lots of methods are just stubs.
30 * NOTES (or things that msdn doesn't tell you)
32 * The width and height properties are returned in HIMETRIC units (0.01mm)
33 * IPicture::Render also uses these to select a region of the src picture.
34 * A bitmap's size is converted into these units by using the screen resolution
35 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
43 #define COBJMACROS
44 #include "winerror.h"
45 #include "windef.h"
46 #include "winbase.h"
47 #include "wingdi.h"
48 #include "winuser.h"
49 #include "ole2.h"
50 #include "olectl.h"
51 #include "oleauto.h"
52 #include "connpt.h"
53 #include "urlmon.h"
54 #include "initguid.h"
55 #include "wincodec.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(olepicture);
60 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
61 #define BITMAP_FORMAT_JPEG 0xd8ff
62 #define BITMAP_FORMAT_GIF 0x4947
63 #define BITMAP_FORMAT_PNG 0x5089
64 #define BITMAP_FORMAT_APM 0xcdd7
66 #include "pshpack1.h"
68 /* Header for Aldus Placable Metafiles - a standard metafile follows */
69 typedef struct _APM_HEADER
71 DWORD key;
72 WORD handle;
73 SHORT left;
74 SHORT top;
75 SHORT right;
76 SHORT bottom;
77 WORD inch;
78 DWORD reserved;
79 WORD checksum;
80 } APM_HEADER;
82 typedef struct {
83 BYTE bWidth;
84 BYTE bHeight;
85 BYTE bColorCount;
86 BYTE bReserved;
87 WORD xHotspot;
88 WORD yHotspot;
89 DWORD dwDIBSize;
90 DWORD dwDIBOffset;
91 } CURSORICONFILEDIRENTRY;
93 typedef struct
95 WORD idReserved;
96 WORD idType;
97 WORD idCount;
98 CURSORICONFILEDIRENTRY idEntries[1];
99 } CURSORICONFILEDIR;
101 #include "poppack.h"
103 /*************************************************************************
104 * Declaration of implementation class
107 typedef struct OLEPictureImpl {
110 * IPicture handles IUnknown
113 IPicture IPicture_iface;
114 IDispatch IDispatch_iface;
115 IPersistStream IPersistStream_iface;
116 IConnectionPointContainer IConnectionPointContainer_iface;
118 /* Object reference count */
119 LONG ref;
121 /* We own the object and must destroy it ourselves */
122 BOOL fOwn;
124 /* Picture description */
125 PICTDESC desc;
127 /* These are the pixel size of a bitmap */
128 DWORD origWidth;
129 DWORD origHeight;
131 /* And these are the size of the picture converted into HIMETRIC units */
132 OLE_XSIZE_HIMETRIC himetricWidth;
133 OLE_YSIZE_HIMETRIC himetricHeight;
135 IConnectionPoint *pCP;
137 BOOL keepOrigFormat;
138 HDC hDCCur;
139 HBITMAP stock_bitmap;
141 /* Bitmap transparency mask */
142 HBITMAP hbmMask;
143 HBITMAP hbmXor;
144 COLORREF rgbTrans;
146 /* data */
147 void* data;
148 int datalen;
149 BOOL bIsDirty; /* Set to TRUE if picture has changed */
150 unsigned int loadtime_magic; /* If a length header was found, saves value */
151 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
152 } OLEPictureImpl;
154 static inline OLEPictureImpl *impl_from_IPicture(IPicture *iface)
156 return CONTAINING_RECORD(iface, OLEPictureImpl, IPicture_iface);
159 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
161 return CONTAINING_RECORD(iface, OLEPictureImpl, IDispatch_iface);
164 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
166 return CONTAINING_RECORD(iface, OLEPictureImpl, IPersistStream_iface);
169 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
171 return CONTAINING_RECORD(iface, OLEPictureImpl, IConnectionPointContainer_iface);
175 * Predeclare VTables. They get initialized at the end.
177 static const IPictureVtbl OLEPictureImpl_VTable;
178 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
179 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
180 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
182 /* pixels to HIMETRIC units conversion */
183 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
185 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
188 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
190 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
193 /***********************************************************************
194 * Implementation of the OLEPictureImpl class.
197 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
199 BITMAP bm;
200 HDC hdcRef;
202 TRACE("bitmap handle %p\n", This->desc.bmp.hbitmap);
203 if(GetObjectW(This->desc.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
204 ERR("GetObject fails\n");
205 return;
207 This->origWidth = bm.bmWidth;
208 This->origHeight = bm.bmHeight;
210 TRACE("width %d, height %d, bpp %d\n", bm.bmWidth, bm.bmHeight, bm.bmBitsPixel);
212 /* The width and height are stored in HIMETRIC units (0.01 mm),
213 so we take our pixel width divide by pixels per inch and
214 multiply by 25.4 * 100 */
215 /* Should we use GetBitmapDimension if available? */
216 hdcRef = CreateCompatibleDC(0);
218 This->himetricWidth = xpixels_to_himetric(bm.bmWidth, hdcRef);
219 This->himetricHeight = ypixels_to_himetric(bm.bmHeight, hdcRef);
220 This->stock_bitmap = GetCurrentObject( hdcRef, OBJ_BITMAP );
222 This->loadtime_format = BITMAP_FORMAT_BMP;
224 DeleteDC(hdcRef);
227 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
229 ICONINFO infoIcon;
231 TRACE("icon handle %p\n", This->desc.icon.hicon);
232 if (GetIconInfo(This->desc.icon.hicon, &infoIcon)) {
233 HDC hdcRef;
234 BITMAP bm;
236 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
237 if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
238 ERR("GetObject fails on icon bitmap\n");
239 return;
242 This->origWidth = bm.bmWidth;
243 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
244 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
245 hdcRef = GetDC(0);
247 This->himetricWidth = xpixels_to_himetric(This->origWidth, hdcRef);
248 This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
250 ReleaseDC(0, hdcRef);
252 DeleteObject(infoIcon.hbmMask);
253 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
254 } else {
255 ERR("GetIconInfo() fails on icon %p\n", This->desc.icon.hicon);
259 /************************************************************************
260 * OLEPictureImpl_Construct
262 * This method will construct a new instance of the OLEPictureImpl
263 * class.
265 * The caller of this method must release the object when it's
266 * done with it.
268 static HRESULT OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn, OLEPictureImpl **pict)
270 OLEPictureImpl *newObject;
271 HRESULT hr;
273 if (pictDesc)
274 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
277 * Allocate space for the object.
279 newObject = calloc(1, sizeof(OLEPictureImpl));
280 if (!newObject)
281 return E_OUTOFMEMORY;
284 * Initialize the virtual function table.
286 newObject->IPicture_iface.lpVtbl = &OLEPictureImpl_VTable;
287 newObject->IDispatch_iface.lpVtbl = &OLEPictureImpl_IDispatch_VTable;
288 newObject->IPersistStream_iface.lpVtbl = &OLEPictureImpl_IPersistStream_VTable;
289 newObject->IConnectionPointContainer_iface.lpVtbl = &OLEPictureImpl_IConnectionPointContainer_VTable;
291 newObject->pCP = NULL;
292 hr = CreateConnectionPoint((IUnknown*)&newObject->IPicture_iface, &IID_IPropertyNotifySink,
293 &newObject->pCP);
294 if (hr != S_OK)
296 free(newObject);
297 return hr;
301 * Start with one reference count. The caller of this function
302 * must release the interface pointer when it is done.
304 newObject->ref = 1;
305 newObject->hDCCur = 0;
307 newObject->fOwn = fOwn;
309 /* dunno about original value */
310 newObject->keepOrigFormat = TRUE;
312 newObject->hbmMask = NULL;
313 newObject->hbmXor = NULL;
314 newObject->loadtime_magic = 0xdeadbeef;
315 newObject->loadtime_format = 0;
316 newObject->bIsDirty = FALSE;
318 if (pictDesc) {
319 newObject->desc = *pictDesc;
321 switch(pictDesc->picType) {
322 case PICTYPE_BITMAP:
323 OLEPictureImpl_SetBitmap(newObject);
324 break;
326 case PICTYPE_METAFILE:
327 TRACE("metafile handle %p\n", pictDesc->wmf.hmeta);
328 newObject->himetricWidth = pictDesc->wmf.xExt;
329 newObject->himetricHeight = pictDesc->wmf.yExt;
330 break;
332 case PICTYPE_NONE:
333 /* not sure what to do here */
334 newObject->himetricWidth = newObject->himetricHeight = 0;
335 break;
337 case PICTYPE_ICON:
338 OLEPictureImpl_SetIcon(newObject);
339 break;
341 case PICTYPE_ENHMETAFILE:
342 FIXME("EMF is not supported\n");
343 newObject->himetricWidth = newObject->himetricHeight = 0;
344 break;
346 default:
347 WARN("Unsupported type %d\n", pictDesc->picType);
348 IPicture_Release(&newObject->IPicture_iface);
349 return E_UNEXPECTED;
351 } else {
352 newObject->desc.picType = PICTYPE_UNINITIALIZED;
355 TRACE("returning %p\n", newObject);
356 *pict = newObject;
357 return S_OK;
360 /************************************************************************
361 * OLEPictureImpl_Destroy
363 * This method is called by the Release method when the reference
364 * count goes down to 0. It will free all resources used by
365 * this object. */
366 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
368 TRACE("(%p)\n", Obj);
370 if (Obj->pCP)
371 IConnectionPoint_Release(Obj->pCP);
373 if(Obj->fOwn) { /* We need to destroy the picture */
374 switch(Obj->desc.picType) {
375 case PICTYPE_BITMAP:
376 DeleteObject(Obj->desc.bmp.hbitmap);
377 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
378 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
379 break;
380 case PICTYPE_METAFILE:
381 DeleteMetaFile(Obj->desc.wmf.hmeta);
382 break;
383 case PICTYPE_ICON:
384 DestroyIcon(Obj->desc.icon.hicon);
385 break;
386 case PICTYPE_ENHMETAFILE:
387 DeleteEnhMetaFile(Obj->desc.emf.hemf);
388 break;
389 case PICTYPE_NONE:
390 case PICTYPE_UNINITIALIZED:
391 /* Nothing to do */
392 break;
393 default:
394 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
395 break;
398 free(Obj->data);
399 free(Obj);
402 static ULONG WINAPI OLEPictureImpl_AddRef(
403 IPicture* iface)
405 OLEPictureImpl *This = impl_from_IPicture(iface);
406 ULONG refCount = InterlockedIncrement(&This->ref);
408 TRACE("%p, refcount %lu.\n", iface, refCount);
410 return refCount;
413 static ULONG WINAPI OLEPictureImpl_Release(
414 IPicture* iface)
416 OLEPictureImpl *This = impl_from_IPicture(iface);
417 ULONG refCount = InterlockedDecrement(&This->ref);
419 TRACE("%p, refcount %lu.\n", iface, refCount);
421 if (!refCount) OLEPictureImpl_Destroy(This);
423 return refCount;
426 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
427 IPicture* iface,
428 REFIID riid,
429 void** ppvObject)
431 OLEPictureImpl *This = impl_from_IPicture(iface);
433 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
435 if (!ppvObject)
436 return E_INVALIDARG;
438 *ppvObject = 0;
440 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
441 *ppvObject = &This->IPicture_iface;
442 else if (IsEqualIID(&IID_IDispatch, riid))
443 *ppvObject = &This->IDispatch_iface;
444 else if (IsEqualIID(&IID_IPictureDisp, riid))
445 *ppvObject = &This->IDispatch_iface;
446 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
447 *ppvObject = &This->IPersistStream_iface;
448 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
449 *ppvObject = &This->IConnectionPointContainer_iface;
451 if (!*ppvObject)
453 FIXME("() : asking for unsupported interface %s\n",debugstr_guid(riid));
454 return E_NOINTERFACE;
457 IPicture_AddRef(iface);
459 return S_OK;
462 /***********************************************************************
463 * OLEPicture_SendNotify (internal)
465 * Sends notification messages of changed properties to any interested
466 * connections.
468 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
470 IEnumConnections *pEnum;
471 CONNECTDATA CD;
473 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
474 return;
475 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
476 IPropertyNotifySink *sink;
478 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
479 IPropertyNotifySink_OnChanged(sink, dispID);
480 IPropertyNotifySink_Release(sink);
481 IUnknown_Release(CD.pUnk);
483 IEnumConnections_Release(pEnum);
486 /************************************************************************
487 * OLEPictureImpl_get_Handle
489 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
490 OLE_HANDLE *phandle)
492 OLEPictureImpl *This = impl_from_IPicture(iface);
493 TRACE("(%p)->(%p)\n", This, phandle);
495 if(!phandle)
496 return E_POINTER;
498 switch(This->desc.picType) {
499 case PICTYPE_NONE:
500 case PICTYPE_UNINITIALIZED:
501 *phandle = 0;
502 break;
503 case PICTYPE_BITMAP:
504 *phandle = HandleToUlong(This->desc.bmp.hbitmap);
505 break;
506 case PICTYPE_METAFILE:
507 *phandle = HandleToUlong(This->desc.wmf.hmeta);
508 break;
509 case PICTYPE_ICON:
510 *phandle = HandleToUlong(This->desc.icon.hicon);
511 break;
512 case PICTYPE_ENHMETAFILE:
513 *phandle = HandleToUlong(This->desc.emf.hemf);
514 break;
515 default:
516 FIXME("Unimplemented type %d\n", This->desc.picType);
517 return E_NOTIMPL;
519 TRACE("returning handle %08x\n", *phandle);
520 return S_OK;
523 /************************************************************************
524 * OLEPictureImpl_get_hPal
526 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
527 OLE_HANDLE *phandle)
529 OLEPictureImpl *This = impl_from_IPicture(iface);
531 TRACE("(%p)->(%p)\n", This, phandle);
533 if (!phandle) return E_POINTER;
535 if (This->desc.picType == PICTYPE_BITMAP)
537 *phandle = HandleToUlong(This->desc.bmp.hpal);
538 return S_OK;
541 return E_FAIL;
544 /************************************************************************
545 * OLEPictureImpl_get_Type
547 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
548 short *ptype)
550 OLEPictureImpl *This = impl_from_IPicture(iface);
551 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
553 if(!ptype)
554 return E_POINTER;
556 *ptype = This->desc.picType;
557 return S_OK;
560 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface, OLE_XSIZE_HIMETRIC *pwidth)
562 OLEPictureImpl *This = impl_from_IPicture(iface);
563 TRACE("%p, %p.\n", iface, pwidth);
564 *pwidth = This->himetricWidth;
565 return S_OK;
568 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface, OLE_YSIZE_HIMETRIC *pheight)
570 OLEPictureImpl *This = impl_from_IPicture(iface);
571 TRACE("%p, %p.\n", iface, pheight);
572 *pheight = This->himetricHeight;
573 return S_OK;
576 static void render_masked_bitmap(OLEPictureImpl *This, HDC hdc,
577 LONG x, LONG y, LONG cx, LONG cy, OLE_XPOS_HIMETRIC xSrc, OLE_YPOS_HIMETRIC ySrc,
578 OLE_XSIZE_HIMETRIC cxSrc, OLE_YSIZE_HIMETRIC cySrc, HBITMAP hbmMask, HBITMAP hbmXor)
580 HDC hdcBmp;
582 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
583 * NB y-axis gets flipped
586 hdcBmp = CreateCompatibleDC(0);
587 SetMapMode(hdcBmp, MM_ANISOTROPIC);
588 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
589 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
590 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
591 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
593 if (hbmMask)
595 SetBkColor(hdc, RGB(255, 255, 255));
596 SetTextColor(hdc, RGB(0, 0, 0));
598 SelectObject(hdcBmp, hbmMask);
599 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCAND);
601 if (hbmXor)
603 SelectObject(hdcBmp, hbmXor);
604 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
606 else StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc - This->himetricHeight,
607 cxSrc, cySrc, SRCPAINT);
609 else
611 SelectObject(hdcBmp, hbmXor);
612 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
615 DeleteDC(hdcBmp);
618 /************************************************************************
619 * OLEPictureImpl_Render
621 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
622 LONG x, LONG y, LONG cx, LONG cy,
623 OLE_XPOS_HIMETRIC xSrc,
624 OLE_YPOS_HIMETRIC ySrc,
625 OLE_XSIZE_HIMETRIC cxSrc,
626 OLE_YSIZE_HIMETRIC cySrc,
627 LPCRECT prcWBounds)
629 OLEPictureImpl *This = impl_from_IPicture(iface);
630 TRACE("%p, %p, (%ld,%ld), (%ld,%ld), (%ld,%ld), (%ld,%ld), %p)\n", iface, hdc, x, y, cx, cy, xSrc, ySrc,
631 cxSrc, cySrc, prcWBounds);
632 if(prcWBounds)
633 TRACE("prcWBounds %s\n", wine_dbgstr_rect(prcWBounds));
635 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
636 return CTL_E_INVALIDPROPERTYVALUE;
640 * While the documentation suggests this to be here (or after rendering?)
641 * it does cause an endless recursion in my sample app. -MM 20010804
642 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
645 switch(This->desc.picType) {
646 case PICTYPE_UNINITIALIZED:
647 case PICTYPE_NONE:
648 /* nothing to do */
649 return S_OK;
650 case PICTYPE_BITMAP:
652 HBITMAP hbmMask, hbmXor;
654 if (This->hbmMask)
656 hbmMask = This->hbmMask;
657 hbmXor = This->hbmXor;
659 else
661 hbmMask = 0;
662 hbmXor = This->desc.bmp.hbitmap;
665 render_masked_bitmap(This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, hbmMask, hbmXor);
666 break;
669 case PICTYPE_ICON:
671 ICONINFO info;
673 if (!GetIconInfo(This->desc.icon.hicon, &info))
674 return E_FAIL;
676 render_masked_bitmap(This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, info.hbmMask, info.hbmColor);
678 DeleteObject(info.hbmMask);
679 if (info.hbmColor) DeleteObject(info.hbmColor);
680 break;
683 case PICTYPE_METAFILE:
685 POINT prevOrg, prevWndOrg;
686 SIZE prevExt, prevWndExt;
687 int oldmode;
689 /* Render the WMF to the appropriate location by setting the
690 appropriate ratio between "device units" and "logical units" */
691 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
692 /* For the "source rectangle" the y-axis must be inverted */
693 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
694 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
695 /* For the "destination rectangle" no inversion is necessary */
696 SetViewportOrgEx(hdc, x, y, &prevOrg);
697 SetViewportExtEx(hdc, cx, cy, &prevExt);
699 if (!PlayMetaFile(hdc, This->desc.wmf.hmeta))
700 ERR("PlayMetaFile failed!\n");
702 /* We're done, restore the DC to the previous settings for converting
703 logical units to device units */
704 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
705 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
706 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
707 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
708 SetMapMode(hdc, oldmode);
709 break;
712 case PICTYPE_ENHMETAFILE:
714 RECT rc = { x, y, x + cx, y + cy };
715 PlayEnhMetaFile(hdc, This->desc.emf.hemf, &rc);
716 break;
719 default:
720 FIXME("type %d not implemented\n", This->desc.picType);
721 return E_NOTIMPL;
723 return S_OK;
726 /************************************************************************
727 * OLEPictureImpl_set_hPal
729 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
730 OLE_HANDLE hpal)
732 OLEPictureImpl *This = impl_from_IPicture(iface);
734 TRACE("(%p)->(%08x)\n", This, hpal);
736 if (This->desc.picType == PICTYPE_BITMAP)
738 This->desc.bmp.hpal = ULongToHandle(hpal);
739 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
740 return S_OK;
743 return E_FAIL;
746 /************************************************************************
747 * OLEPictureImpl_get_CurDC
749 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
750 HDC *phdc)
752 OLEPictureImpl *This = impl_from_IPicture(iface);
753 TRACE("(%p), returning %p\n", This, This->hDCCur);
754 if (phdc) *phdc = This->hDCCur;
755 return S_OK;
758 /************************************************************************
759 * OLEPictureImpl_SelectPicture
761 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
762 HDC hdcIn,
763 HDC *phdcOut,
764 OLE_HANDLE *phbmpOut)
766 OLEPictureImpl *This = impl_from_IPicture(iface);
767 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
768 if (This->desc.picType == PICTYPE_BITMAP) {
769 if (phdcOut)
770 *phdcOut = This->hDCCur;
771 if (This->hDCCur) SelectObject(This->hDCCur,This->stock_bitmap);
772 if (hdcIn) SelectObject(hdcIn,This->desc.bmp.hbitmap);
773 This->hDCCur = hdcIn;
774 if (phbmpOut)
775 *phbmpOut = HandleToUlong(This->desc.bmp.hbitmap);
776 return S_OK;
777 } else {
778 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
779 return E_FAIL;
783 /************************************************************************
784 * OLEPictureImpl_get_KeepOriginalFormat
786 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
787 BOOL *pfKeep)
789 OLEPictureImpl *This = impl_from_IPicture(iface);
790 TRACE("(%p)->(%p)\n", This, pfKeep);
791 if (!pfKeep)
792 return E_POINTER;
793 *pfKeep = This->keepOrigFormat;
794 return S_OK;
797 /************************************************************************
798 * OLEPictureImpl_put_KeepOriginalFormat
800 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
801 BOOL keep)
803 OLEPictureImpl *This = impl_from_IPicture(iface);
804 TRACE("(%p)->(%d)\n", This, keep);
805 This->keepOrigFormat = keep;
806 /* FIXME: what DISPID notification here? */
807 return S_OK;
810 /************************************************************************
811 * OLEPictureImpl_PictureChanged
813 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
815 OLEPictureImpl *This = impl_from_IPicture(iface);
816 TRACE("(%p)->()\n", This);
817 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
818 This->bIsDirty = TRUE;
819 return S_OK;
822 /************************************************************************
823 * OLEPictureImpl_SaveAsFile
825 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
826 IStream *pstream,
827 BOOL SaveMemCopy,
828 LONG *pcbSize)
830 OLEPictureImpl *This = impl_from_IPicture(iface);
831 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
832 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
835 /************************************************************************
836 * OLEPictureImpl_get_Attributes
838 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
839 DWORD *pdwAttr)
841 OLEPictureImpl *This = impl_from_IPicture(iface);
842 TRACE("(%p)->(%p).\n", This, pdwAttr);
844 if(!pdwAttr)
845 return E_POINTER;
847 *pdwAttr = 0;
848 switch (This->desc.picType) {
849 case PICTYPE_UNINITIALIZED:
850 case PICTYPE_NONE: break;
851 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
852 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
853 case PICTYPE_ENHMETAFILE: /* fall through */
854 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
855 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
857 return S_OK;
861 /************************************************************************
862 * IConnectionPointContainer
864 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
865 IConnectionPointContainer* iface,
866 REFIID riid,
867 VOID** ppvoid)
869 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
871 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
874 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
875 IConnectionPointContainer* iface)
877 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
879 return IPicture_AddRef(&This->IPicture_iface);
882 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
883 IConnectionPointContainer* iface)
885 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
887 return IPicture_Release(&This->IPicture_iface);
890 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
891 IConnectionPointContainer* iface,
892 IEnumConnectionPoints** ppEnum)
894 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
896 FIXME("(%p,%p), stub!\n",This,ppEnum);
897 return E_NOTIMPL;
900 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
901 IConnectionPointContainer* iface,
902 REFIID riid,
903 IConnectionPoint **ppCP)
905 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
906 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
907 if (!ppCP)
908 return E_POINTER;
909 *ppCP = NULL;
910 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
911 return IConnectionPoint_QueryInterface(This->pCP, &IID_IConnectionPoint, (void**)ppCP);
912 FIXME("no connection point for %s\n",debugstr_guid(riid));
913 return CONNECT_E_NOCONNECTION;
917 /************************************************************************
918 * IPersistStream
921 /************************************************************************
922 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
924 * See Windows documentation for more details on IUnknown methods.
926 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
927 IPersistStream* iface,
928 REFIID riid,
929 VOID** ppvoid)
931 OLEPictureImpl *This = impl_from_IPersistStream(iface);
933 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
936 /************************************************************************
937 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
939 * See Windows documentation for more details on IUnknown methods.
941 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
942 IPersistStream* iface)
944 OLEPictureImpl *This = impl_from_IPersistStream(iface);
946 return IPicture_AddRef(&This->IPicture_iface);
949 /************************************************************************
950 * OLEPictureImpl_IPersistStream_Release (IUnknown)
952 * See Windows documentation for more details on IUnknown methods.
954 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
955 IPersistStream* iface)
957 OLEPictureImpl *This = impl_from_IPersistStream(iface);
959 return IPicture_Release(&This->IPicture_iface);
962 /************************************************************************
963 * OLEPictureImpl_IPersistStream_GetClassID
965 static HRESULT WINAPI OLEPictureImpl_GetClassID(
966 IPersistStream* iface,CLSID* pClassID)
968 TRACE("(%p)\n", pClassID);
969 *pClassID = CLSID_StdPicture;
970 return S_OK;
973 /************************************************************************
974 * OLEPictureImpl_IPersistStream_IsDirty
976 static HRESULT WINAPI OLEPictureImpl_IsDirty(
977 IPersistStream* iface)
979 OLEPictureImpl *This = impl_from_IPersistStream(iface);
980 FIXME("(%p),stub!\n",This);
981 return E_NOTIMPL;
984 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
986 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
987 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
988 HDC hdcref;
990 /* Does not matter whether this is a coreheader or not, we only use
991 * components which are in both
993 hdcref = GetDC(0);
994 This->desc.bmp.hbitmap = CreateDIBitmap(
995 hdcref,
996 &(bi->bmiHeader),
997 CBM_INIT,
998 xbuf+bfh->bfOffBits,
1000 DIB_RGB_COLORS
1002 ReleaseDC(0, hdcref);
1003 if (This->desc.bmp.hbitmap == 0)
1004 return E_FAIL;
1005 This->desc.picType = PICTYPE_BITMAP;
1006 OLEPictureImpl_SetBitmap(This);
1007 return S_OK;
1010 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1012 HRESULT hr;
1013 BITMAPINFOHEADER bih;
1014 HDC hdcref;
1015 UINT width, height;
1016 UINT stride, buffersize;
1017 LPBYTE bits=NULL;
1018 WICRect rc;
1019 IWICBitmapSource *real_source;
1020 UINT x, y;
1021 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1022 BOOL has_alpha=FALSE;
1024 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1025 if (FAILED(hr)) return hr;
1027 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1028 if (FAILED(hr)) goto end;
1030 bih.biSize = sizeof(bih);
1031 bih.biWidth = width;
1032 bih.biHeight = -height;
1033 bih.biPlanes = 1;
1034 bih.biBitCount = 32;
1035 bih.biCompression = BI_RGB;
1036 bih.biSizeImage = 0;
1037 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1038 bih.biYPelsPerMeter = 4085;
1039 bih.biClrUsed = 0;
1040 bih.biClrImportant = 0;
1042 stride = 4 * width;
1043 buffersize = stride * height;
1045 bits = malloc(buffersize);
1046 if (!bits)
1048 hr = E_OUTOFMEMORY;
1049 goto end;
1052 rc.X = 0;
1053 rc.Y = 0;
1054 rc.Width = width;
1055 rc.Height = height;
1056 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1057 if (FAILED(hr))
1058 goto end;
1060 hdcref = GetDC(0);
1061 This->desc.bmp.hbitmap = CreateDIBitmap(
1062 hdcref,
1063 &bih,
1064 CBM_INIT,
1065 bits,
1066 (BITMAPINFO*)&bih,
1067 DIB_RGB_COLORS);
1069 if (This->desc.bmp.hbitmap == 0)
1071 hr = E_FAIL;
1072 ReleaseDC(0, hdcref);
1073 goto end;
1076 This->desc.picType = PICTYPE_BITMAP;
1077 OLEPictureImpl_SetBitmap(This);
1079 /* set transparent pixels to black, all others to white */
1080 for(y = 0; y < height; y++){
1081 for(x = 0; x < width; x++){
1082 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1083 if((*pixel & 0x80000000) == 0)
1085 has_alpha = TRUE;
1086 *pixel = black;
1088 else
1089 *pixel = white;
1093 if (has_alpha)
1095 HDC hdcBmp, hdcXor, hdcMask;
1096 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1098 This->hbmXor = CreateDIBitmap(
1099 hdcref,
1100 &bih,
1101 CBM_INIT,
1102 bits,
1103 (BITMAPINFO*)&bih,
1104 DIB_RGB_COLORS
1107 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1108 hdcBmp = CreateCompatibleDC(NULL);
1109 hdcXor = CreateCompatibleDC(NULL);
1110 hdcMask = CreateCompatibleDC(NULL);
1112 hbmoldBmp = SelectObject(hdcBmp,This->desc.bmp.hbitmap);
1113 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1114 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1116 SetBkColor(hdcXor,black);
1117 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1118 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1120 SelectObject(hdcBmp,hbmoldBmp);
1121 SelectObject(hdcXor,hbmoldXor);
1122 SelectObject(hdcMask,hbmoldMask);
1124 DeleteDC(hdcBmp);
1125 DeleteDC(hdcXor);
1126 DeleteDC(hdcMask);
1129 ReleaseDC(0, hdcref);
1131 end:
1132 free(bits);
1133 IWICBitmapSource_Release(real_source);
1134 return hr;
1137 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1139 HRESULT hr;
1140 IWICImagingFactory *factory;
1141 IWICBitmapDecoder *decoder;
1142 IWICBitmapFrameDecode *framedecode;
1143 HRESULT initresult;
1144 IWICStream *stream;
1146 initresult = CoInitialize(NULL);
1148 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1149 &IID_IWICImagingFactory, (void**)&factory);
1150 if (SUCCEEDED(hr)) /* created factory */
1152 hr = IWICImagingFactory_CreateStream(factory, &stream);
1153 IWICImagingFactory_Release(factory);
1156 if (SUCCEEDED(hr)) /* created stream */
1158 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1160 if (SUCCEEDED(hr)) /* initialized stream */
1162 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1163 &IID_IWICBitmapDecoder, (void**)&decoder);
1164 if (SUCCEEDED(hr)) /* created decoder */
1166 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1168 if (SUCCEEDED(hr)) /* initialized decoder */
1169 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1171 IWICBitmapDecoder_Release(decoder);
1175 IWICStream_Release(stream);
1178 if (SUCCEEDED(hr)) /* got framedecode */
1180 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1181 IWICBitmapFrameDecode_Release(framedecode);
1184 if (SUCCEEDED(initresult)) CoUninitialize();
1185 return hr;
1188 /*****************************************************
1189 * start of Icon-specific code
1192 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1194 HICON hicon;
1195 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1196 HDC hdcRef;
1197 int i;
1199 TRACE("(this %p, xbuf %p, xread %lu)\n", This, xbuf, xread);
1202 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1203 FIXME("icon.idType=%d\n",cifd->idType);
1204 FIXME("icon.idCount=%d\n",cifd->idCount);
1206 for (i=0;i<cifd->idCount;i++) {
1207 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1208 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1209 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1210 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1211 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1212 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1213 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1214 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1218 /* Need at least one icon to do something. */
1219 if (!cifd->idCount)
1221 ERR("Invalid icon count of zero.\n");
1222 return E_FAIL;
1224 i=0;
1225 /* If we have more than one icon, try to find the best.
1226 * this currently means '32 pixel wide'.
1228 if (cifd->idCount!=1) {
1229 for (i=0;i<cifd->idCount;i++) {
1230 if (cifd->idEntries[i].bWidth == 32)
1231 break;
1233 if (i==cifd->idCount) i=0;
1235 if (xread < cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize)
1237 ERR("Icon data address %lu is over %lu bytes available.\n",
1238 cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize, xread);
1239 return E_FAIL;
1241 if (cifd->idType == 2)
1243 BYTE *buf = malloc(cifd->idEntries[i].dwDIBSize + 4);
1244 memcpy(buf, &cifd->idEntries[i].xHotspot, 4);
1245 memcpy(buf + 4, xbuf+cifd->idEntries[i].dwDIBOffset, cifd->idEntries[i].dwDIBSize);
1246 hicon = CreateIconFromResourceEx(
1247 buf,
1248 cifd->idEntries[i].dwDIBSize + 4,
1249 FALSE, /* is cursor */
1250 0x00030000,
1251 cifd->idEntries[i].bWidth,
1252 cifd->idEntries[i].bHeight,
1255 free(buf);
1257 else
1259 hicon = CreateIconFromResourceEx(
1260 xbuf+cifd->idEntries[i].dwDIBOffset,
1261 cifd->idEntries[i].dwDIBSize,
1262 TRUE, /* is icon */
1263 0x00030000,
1264 cifd->idEntries[i].bWidth,
1265 cifd->idEntries[i].bHeight,
1269 if (!hicon) {
1270 ERR("CreateIcon failed.\n");
1271 return E_FAIL;
1272 } else {
1273 This->desc.picType = PICTYPE_ICON;
1274 This->desc.icon.hicon = hicon;
1275 This->origWidth = cifd->idEntries[i].bWidth;
1276 This->origHeight = cifd->idEntries[i].bHeight;
1277 hdcRef = CreateCompatibleDC(0);
1278 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1279 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1280 DeleteDC(hdcRef);
1281 return S_OK;
1285 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1286 const BYTE *data, ULONG size)
1288 HENHMETAFILE hemf;
1289 ENHMETAHEADER hdr;
1291 hemf = SetEnhMetaFileBits(size, data);
1292 if (!hemf) return E_FAIL;
1294 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1296 This->desc.picType = PICTYPE_ENHMETAFILE;
1297 This->desc.emf.hemf = hemf;
1299 This->origWidth = 0;
1300 This->origHeight = 0;
1301 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1302 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1304 return S_OK;
1307 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1308 const BYTE *data, ULONG size)
1310 const APM_HEADER *header = (const APM_HEADER *)data;
1311 HMETAFILE hmf;
1313 if (size < sizeof(APM_HEADER))
1314 return E_FAIL;
1315 if (header->key != 0x9ac6cdd7)
1316 return E_FAIL;
1318 /* SetMetaFileBitsEx performs data check on its own */
1319 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1320 if (!hmf) return E_FAIL;
1322 This->desc.picType = PICTYPE_METAFILE;
1323 This->desc.wmf.hmeta = hmf;
1324 This->desc.wmf.xExt = 0;
1325 This->desc.wmf.yExt = 0;
1327 This->origWidth = 0;
1328 This->origHeight = 0;
1329 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1330 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1331 return S_OK;
1334 /************************************************************************
1335 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1337 * Loads the binary data from the IStream. Starts at current position.
1338 * There appears to be an 2 DWORD header:
1339 * DWORD magic;
1340 * DWORD len;
1342 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1344 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1345 HRESULT hr;
1346 BOOL headerisdata;
1347 BOOL statfailed = FALSE;
1348 ULONG xread, toread;
1349 ULONG headerread;
1350 BYTE *xbuf;
1351 DWORD header[2];
1352 WORD magic;
1353 STATSTG statstg;
1354 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1356 TRACE("(%p,%p)\n",This,pStm);
1358 /****************************************************************************************
1359 * Part 1: Load the data
1361 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1362 * out whether we do.
1364 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1365 * compound file. This may explain most, if not all, of the cases of "no
1366 * header", and the header validation should take this into account.
1367 * At least in Visual Basic 6, resource streams, valid headers are
1368 * header[0] == "lt\0\0",
1369 * header[1] == length_of_stream.
1371 * Also handle streams where we do not have a working "Stat" method by
1372 * reading all data until the end of the stream.
1374 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1375 if (hr != S_OK) {
1376 TRACE("stat failed with hres %#lx, proceeding to read all data.\n",hr);
1377 statfailed = TRUE;
1378 /* we will read at least 8 byte ... just right below */
1379 statstg.cbSize.QuadPart = 8;
1382 toread = 0;
1383 headerread = 0;
1384 headerisdata = FALSE;
1385 do {
1386 hr = IStream_Read(pStm, header, 8, &xread);
1387 if (hr != S_OK || xread!=8) {
1388 ERR("Failure while reading picture header (hr is %#lx, nread is %ld).\n",hr,xread);
1389 return (hr?hr:E_FAIL);
1391 headerread += xread;
1392 xread = 0;
1394 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1395 if (toread != 0 && toread != header[1])
1396 FIXME("varying lengths of image data (prev=%lu curr=%lu), only last one will be used\n",
1397 toread, header[1]);
1398 toread = header[1];
1399 if (statfailed)
1401 statstg.cbSize.QuadPart = header[1] + 8;
1402 statfailed = FALSE;
1404 if (toread == 0) break;
1405 } else {
1406 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1407 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1408 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1409 (header[0] == EMR_HEADER) || /* EMF header */
1410 (header[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1411 (header[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1412 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1413 (header[1]==0)
1414 ) {/* Found start of bitmap data */
1415 headerisdata = TRUE;
1416 if (toread == 0)
1417 toread = statstg.cbSize.QuadPart-8;
1418 else toread -= 8;
1419 xread = 8;
1420 } else {
1421 FIXME("Unknown stream header magic: %#lx.\n", header[0]);
1422 toread = header[1];
1425 } while (!headerisdata);
1427 if (statfailed) { /* we don't know the size ... read all we get */
1428 unsigned int sizeinc = 4096;
1429 unsigned int origsize = sizeinc;
1430 ULONG nread = 42;
1432 TRACE("Reading all data from stream.\n");
1433 xbuf = calloc(1, origsize);
1434 if (headerisdata)
1435 memcpy (xbuf, header, 8);
1436 while (1) {
1437 while (xread < origsize) {
1438 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1439 xread += nread;
1440 if (hr != S_OK || !nread)
1441 break;
1443 if (!nread || hr != S_OK) /* done, or error */
1444 break;
1445 if (xread == origsize) {
1446 sizeinc = 2*sizeinc; /* exponential increase */
1447 xbuf = realloc(xbuf, origsize + sizeinc);
1448 memset(xbuf + origsize, 0, sizeinc);
1449 origsize += sizeinc;
1452 if (hr != S_OK)
1453 TRACE("hr in no-stat loader case is %#lx.\n", hr);
1454 TRACE("loaded %ld bytes.\n", xread);
1455 This->datalen = xread;
1456 This->data = xbuf;
1457 } else {
1458 This->datalen = toread+(headerisdata?8:0);
1459 xbuf = This->data = calloc(1, This->datalen);
1460 if (!xbuf)
1461 return E_OUTOFMEMORY;
1463 if (headerisdata)
1464 memcpy (xbuf, header, 8);
1466 while (xread < This->datalen) {
1467 ULONG nread;
1468 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1469 xread += nread;
1470 if (hr != S_OK || !nread)
1471 break;
1473 if (xread != This->datalen)
1474 ERR("Could only read %ld of %d bytes out of stream?\n", xread, This->datalen);
1476 if (This->datalen == 0) { /* Marks the "NONE" picture */
1477 This->desc.picType = PICTYPE_NONE;
1478 return S_OK;
1482 /****************************************************************************************
1483 * Part 2: Process the loaded data
1486 magic = xbuf[0] + (xbuf[1]<<8);
1487 This->loadtime_format = magic;
1489 switch (magic) {
1490 case BITMAP_FORMAT_GIF: /* GIF */
1491 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1492 break;
1493 case BITMAP_FORMAT_JPEG: /* JPEG */
1494 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1495 break;
1496 case BITMAP_FORMAT_BMP: /* Bitmap */
1497 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1498 break;
1499 case BITMAP_FORMAT_PNG: /* PNG */
1500 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1501 break;
1502 case BITMAP_FORMAT_APM: /* APM */
1503 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1504 break;
1505 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1506 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1507 break;
1509 default:
1511 unsigned int i;
1513 /* let's see if it's a EMF */
1514 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1515 if (hr == S_OK) break;
1517 FIXME("Unknown magic %04x, %ld read bytes:\n", magic, xread);
1518 hr=E_FAIL;
1519 for (i=0;i<xread+8;i++) {
1520 if (i<8) FIXME("%02x ",((unsigned char*)header)[i]);
1521 else FIXME("%02x ",xbuf[i-8]);
1522 if (i % 10 == 9) FIXME("\n");
1524 FIXME("\n");
1525 break;
1528 This->bIsDirty = FALSE;
1530 /* FIXME: this notify is not really documented */
1531 if (hr==S_OK)
1532 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1533 return hr;
1536 static BOOL serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1538 BOOL success = FALSE;
1539 HDC hDC;
1540 BITMAPINFO * pInfoBitmap;
1541 int iNumPaletteEntries;
1542 unsigned char * pPixelData;
1543 BITMAPFILEHEADER * pFileHeader;
1544 BITMAPINFO * pInfoHeader;
1546 pInfoBitmap = calloc(1, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1548 /* Find out bitmap size and padded length */
1549 hDC = GetDC(0);
1550 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1551 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1553 /* Fetch bitmap palette & pixel data */
1555 pPixelData = calloc(1, pInfoBitmap->bmiHeader.biSizeImage);
1556 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1558 /* Calculate the total length required for the BMP data */
1559 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1560 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1561 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1562 } else {
1563 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1564 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1565 else
1566 iNumPaletteEntries = 0;
1568 *pLength =
1569 sizeof(BITMAPFILEHEADER) +
1570 sizeof(BITMAPINFOHEADER) +
1571 iNumPaletteEntries * sizeof(RGBQUAD) +
1572 pInfoBitmap->bmiHeader.biSizeImage;
1573 *ppBuffer = calloc(1, *pLength);
1575 /* Fill the BITMAPFILEHEADER */
1576 pFileHeader = *ppBuffer;
1577 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1578 pFileHeader->bfSize = *pLength;
1579 pFileHeader->bfOffBits =
1580 sizeof(BITMAPFILEHEADER) +
1581 sizeof(BITMAPINFOHEADER) +
1582 iNumPaletteEntries * sizeof(RGBQUAD);
1584 /* Fill the BITMAPINFOHEADER and the palette data */
1585 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1586 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1587 memcpy(
1588 (unsigned char *)(*ppBuffer) +
1589 sizeof(BITMAPFILEHEADER) +
1590 sizeof(BITMAPINFOHEADER) +
1591 iNumPaletteEntries * sizeof(RGBQUAD),
1592 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1593 success = TRUE;
1595 free(pPixelData);
1596 free(pInfoBitmap);
1597 return success;
1600 static BOOL serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1602 ICONINFO infoIcon;
1603 BOOL success = FALSE;
1605 *ppBuffer = NULL; *pLength = 0;
1606 if (GetIconInfo(hIcon, &infoIcon)) {
1607 HDC hDC;
1608 BITMAPINFO * pInfoBitmap;
1609 unsigned char * pIconData = NULL;
1610 unsigned int iDataSize = 0;
1612 pInfoBitmap = calloc(1, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1614 /* Find out icon size */
1615 hDC = GetDC(0);
1616 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1617 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1618 if (1) {
1619 /* Auxiliary pointers */
1620 CURSORICONFILEDIR * pIconDir;
1621 CURSORICONFILEDIRENTRY * pIconEntry;
1622 BITMAPINFOHEADER * pIconBitmapHeader;
1623 unsigned int iOffsetPalette;
1624 unsigned int iOffsetColorData;
1625 unsigned int iOffsetMaskData;
1627 unsigned int iLengthScanLineMask;
1628 unsigned int iNumEntriesPalette;
1630 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1632 FIXME("DEBUG: bitmap size is %d x %d\n",
1633 pInfoBitmap->bmiHeader.biWidth,
1634 pInfoBitmap->bmiHeader.biHeight);
1635 FIXME("DEBUG: bitmap bpp is %d\n",
1636 pInfoBitmap->bmiHeader.biBitCount);
1637 FIXME("DEBUG: bitmap nplanes is %d\n",
1638 pInfoBitmap->bmiHeader.biPlanes);
1639 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1640 pInfoBitmap->bmiHeader.biSizeImage);
1642 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1643 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1644 pIconData = calloc(1, iDataSize);
1646 /* Fill out the CURSORICONFILEDIR */
1647 pIconDir = (CURSORICONFILEDIR *)pIconData;
1648 pIconDir->idType = 1;
1649 pIconDir->idCount = 1;
1650 pIconDir->idReserved = 0;
1652 /* Fill out the CURSORICONFILEDIRENTRY */
1653 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1654 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1655 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1656 pIconEntry->bColorCount =
1657 (pInfoBitmap->bmiHeader.biBitCount < 8)
1658 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1659 : 0;
1660 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1661 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1662 pIconEntry->dwDIBSize = 0;
1663 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1665 /* Fill out the BITMAPINFOHEADER */
1666 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1667 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1669 /* Find out whether a palette exists for the bitmap */
1670 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1671 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1672 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1673 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1674 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1675 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1676 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1677 iNumEntriesPalette = 3;
1678 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1679 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1680 } else {
1681 iNumEntriesPalette = 0;
1684 /* Add bitmap size and header size to icon data size. */
1685 iOffsetPalette = iDataSize;
1686 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1687 iOffsetColorData = iDataSize;
1688 iDataSize += pIconBitmapHeader->biSizeImage;
1689 iOffsetMaskData = iDataSize;
1690 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1691 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1692 pIconBitmapHeader->biHeight *= 2;
1693 pIconData = realloc(pIconData, iDataSize);
1694 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1695 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1696 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1698 /* Get the actual bitmap data from the icon bitmap */
1699 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1700 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1701 if (iNumEntriesPalette > 0) {
1702 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1703 iNumEntriesPalette * sizeof(RGBQUAD));
1706 /* Reset all values so that GetDIBits call succeeds */
1707 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1708 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1709 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1711 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1712 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1713 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1715 printf("ERROR: unable to get bitmap mask (error %u)\n",
1716 GetLastError());
1720 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1721 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1723 /* Write out everything produced so far to the stream */
1724 *ppBuffer = pIconData; *pLength = iDataSize;
1725 success = TRUE;
1726 } else {
1728 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1729 GetLastError());
1733 Remarks (from MSDN entry on GetIconInfo):
1735 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1736 members of ICONINFO. The calling application must manage
1737 these bitmaps and delete them when they are no longer
1738 necessary.
1740 if (hDC) ReleaseDC(0, hDC);
1741 DeleteObject(infoIcon.hbmMask);
1742 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1743 free(pInfoBitmap);
1744 } else {
1745 ERR("Unable to get icon information (error %lu)\n", GetLastError());
1747 return success;
1750 static HRESULT WINAPI OLEPictureImpl_Save(
1751 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1753 HRESULT hResult = E_NOTIMPL;
1754 void * pIconData;
1755 unsigned int iDataSize;
1756 DWORD header[2];
1757 ULONG dummy;
1758 BOOL serializeResult = FALSE;
1759 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1761 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1763 switch (This->desc.picType) {
1764 case PICTYPE_NONE:
1765 header[0] = 0x0000746c;
1766 header[1] = 0;
1767 hResult = IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1768 break;
1770 case PICTYPE_ICON:
1771 if (This->bIsDirty || !This->data) {
1772 if (!serializeIcon(This->desc.icon.hicon, &pIconData, &iDataSize)) {
1773 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1774 hResult = E_FAIL;
1775 break;
1777 free(This->data);
1778 This->data = pIconData;
1779 This->datalen = iDataSize;
1782 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1783 header[1] = This->datalen;
1784 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1785 IStream_Write(pStm, This->data, This->datalen, &dummy);
1786 hResult = S_OK;
1787 break;
1788 case PICTYPE_BITMAP:
1789 if (This->bIsDirty || !This->data) {
1790 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1791 case BITMAP_FORMAT_BMP:
1792 serializeResult = serializeBMP(This->desc.bmp.hbitmap, &pIconData, &iDataSize);
1793 break;
1794 case BITMAP_FORMAT_JPEG:
1795 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1796 break;
1797 case BITMAP_FORMAT_GIF:
1798 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1799 break;
1800 case BITMAP_FORMAT_PNG:
1801 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1802 break;
1803 default:
1804 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1805 break;
1808 if (!serializeResult)
1810 hResult = E_FAIL;
1811 break;
1814 free(This->data);
1815 This->data = pIconData;
1816 This->datalen = iDataSize;
1819 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1820 header[1] = This->datalen;
1821 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1822 IStream_Write(pStm, This->data, This->datalen, &dummy);
1823 hResult = S_OK;
1824 break;
1825 case PICTYPE_METAFILE:
1826 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1827 break;
1828 case PICTYPE_ENHMETAFILE:
1829 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1830 break;
1831 default:
1832 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1833 break;
1835 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1836 return hResult;
1839 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1840 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1842 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1843 FIXME("(%p,%p),stub!\n",This,pcbSize);
1844 return E_NOTIMPL;
1848 /************************************************************************
1849 * IDispatch
1852 /************************************************************************
1853 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1855 * See Windows documentation for more details on IUnknown methods.
1857 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1858 IDispatch* iface,
1859 REFIID riid,
1860 VOID** ppvoid)
1862 OLEPictureImpl *This = impl_from_IDispatch(iface);
1864 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1867 /************************************************************************
1868 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1870 * See Windows documentation for more details on IUnknown methods.
1872 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1873 IDispatch* iface)
1875 OLEPictureImpl *This = impl_from_IDispatch(iface);
1877 return IPicture_AddRef(&This->IPicture_iface);
1880 /************************************************************************
1881 * OLEPictureImpl_IDispatch_Release (IUnknown)
1883 * See Windows documentation for more details on IUnknown methods.
1885 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1886 IDispatch* iface)
1888 OLEPictureImpl *This = impl_from_IDispatch(iface);
1890 return IPicture_Release(&This->IPicture_iface);
1893 /************************************************************************
1894 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1896 * See Windows documentation for more details on IDispatch methods.
1898 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1899 IDispatch* iface,
1900 unsigned int* pctinfo)
1902 TRACE("(%p)\n", pctinfo);
1904 *pctinfo = 1;
1906 return S_OK;
1909 /************************************************************************
1910 * OLEPictureImpl_GetTypeInfo (IDispatch)
1912 * See Windows documentation for more details on IDispatch methods.
1914 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1915 IDispatch* iface,
1916 UINT iTInfo,
1917 LCID lcid,
1918 ITypeInfo** ppTInfo)
1920 ITypeLib *tl;
1921 HRESULT hres;
1923 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1925 if (iTInfo != 0)
1926 return E_FAIL;
1928 hres = LoadTypeLib(L"stdole2.tlb", &tl);
1929 if (FAILED(hres))
1931 ERR("Could not load stdole2.tlb\n");
1932 return hres;
1935 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1936 if (FAILED(hres))
1937 ERR("Did not get IPictureDisp typeinfo from typelib, hres %#lx.\n", hres);
1939 return hres;
1942 /************************************************************************
1943 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1945 * See Windows documentation for more details on IDispatch methods.
1947 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1948 IDispatch* iface,
1949 REFIID riid,
1950 LPOLESTR* rgszNames,
1951 UINT cNames,
1952 LCID lcid,
1953 DISPID* rgDispId)
1955 ITypeInfo * pTInfo;
1956 HRESULT hres;
1958 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1959 rgszNames, cNames, (int)lcid, rgDispId);
1961 if (cNames == 0)
1963 return E_INVALIDARG;
1965 else
1967 /* retrieve type information */
1968 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1970 if (FAILED(hres))
1972 ERR("GetTypeInfo failed.\n");
1973 return hres;
1976 /* convert names to DISPIDs */
1977 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1978 ITypeInfo_Release(pTInfo);
1980 return hres;
1984 /************************************************************************
1985 * OLEPictureImpl_Invoke (IDispatch)
1987 * See Windows documentation for more details on IDispatch methods.
1989 static HRESULT WINAPI OLEPictureImpl_Invoke(
1990 IDispatch* iface,
1991 DISPID dispIdMember,
1992 REFIID riid,
1993 LCID lcid,
1994 WORD wFlags,
1995 DISPPARAMS* pDispParams,
1996 VARIANT* pVarResult,
1997 EXCEPINFO* pExepInfo,
1998 UINT* puArgErr)
2000 OLEPictureImpl *This = impl_from_IDispatch(iface);
2001 HRESULT hr;
2003 /* validate parameters */
2005 if (!IsEqualIID(riid, &IID_NULL))
2007 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2008 return DISP_E_UNKNOWNNAME;
2011 if (!pDispParams)
2013 ERR("null pDispParams not allowed\n");
2014 return DISP_E_PARAMNOTOPTIONAL;
2017 if (wFlags & DISPATCH_PROPERTYGET)
2019 if (pDispParams->cArgs != 0)
2021 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2022 return DISP_E_BADPARAMCOUNT;
2024 if (!pVarResult)
2026 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2027 return DISP_E_PARAMNOTOPTIONAL;
2030 else if (wFlags & DISPATCH_PROPERTYPUT)
2032 if (pDispParams->cArgs != 1)
2034 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2035 return DISP_E_BADPARAMCOUNT;
2039 switch (dispIdMember)
2041 case DISPID_PICT_HANDLE:
2042 if (wFlags & DISPATCH_PROPERTYGET)
2044 TRACE("DISPID_PICT_HANDLE\n");
2045 V_VT(pVarResult) = VT_I4;
2046 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2048 break;
2049 case DISPID_PICT_HPAL:
2050 if (wFlags & DISPATCH_PROPERTYGET)
2052 TRACE("DISPID_PICT_HPAL\n");
2053 V_VT(pVarResult) = VT_I4;
2054 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2056 else if (wFlags & DISPATCH_PROPERTYPUT)
2058 VARIANTARG vararg;
2060 TRACE("DISPID_PICT_HPAL\n");
2062 VariantInit(&vararg);
2063 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2064 if (FAILED(hr))
2065 return hr;
2067 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2069 VariantClear(&vararg);
2070 return hr;
2072 break;
2073 case DISPID_PICT_TYPE:
2074 if (wFlags & DISPATCH_PROPERTYGET)
2076 TRACE("DISPID_PICT_TYPE\n");
2077 V_VT(pVarResult) = VT_I2;
2078 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2080 break;
2081 case DISPID_PICT_WIDTH:
2082 if (wFlags & DISPATCH_PROPERTYGET)
2084 TRACE("DISPID_PICT_WIDTH\n");
2085 V_VT(pVarResult) = VT_I4;
2086 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2088 break;
2089 case DISPID_PICT_HEIGHT:
2090 if (wFlags & DISPATCH_PROPERTYGET)
2092 TRACE("DISPID_PICT_HEIGHT\n");
2093 V_VT(pVarResult) = VT_I4;
2094 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2096 break;
2097 case DISPID_PICT_RENDER:
2098 if (wFlags & DISPATCH_METHOD)
2100 VARIANTARG *args = pDispParams->rgvarg;
2101 int i;
2103 TRACE("DISPID_PICT_RENDER\n");
2105 if (pDispParams->cArgs != 10)
2106 return DISP_E_BADPARAMCOUNT;
2108 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2109 for (i = 0; i < pDispParams->cArgs; i++)
2110 if (V_VT(&args[i]) != VT_I4)
2112 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i, V_VT(&args[i]));
2113 return DISP_E_TYPEMISMATCH;
2116 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2117 currently Render() doesn't use it at all so for now NULL is passed. */
2118 return IPicture_Render(&This->IPicture_iface,
2119 LongToHandle(V_I4(&args[9])),
2120 V_I4(&args[8]),
2121 V_I4(&args[7]),
2122 V_I4(&args[6]),
2123 V_I4(&args[5]),
2124 V_I4(&args[4]),
2125 V_I4(&args[3]),
2126 V_I4(&args[2]),
2127 V_I4(&args[1]),
2128 NULL);
2130 break;
2133 ERR("invalid dispid %#lx or wFlags 0x%x\n", dispIdMember, wFlags);
2134 return DISP_E_MEMBERNOTFOUND;
2138 static const IPictureVtbl OLEPictureImpl_VTable =
2140 OLEPictureImpl_QueryInterface,
2141 OLEPictureImpl_AddRef,
2142 OLEPictureImpl_Release,
2143 OLEPictureImpl_get_Handle,
2144 OLEPictureImpl_get_hPal,
2145 OLEPictureImpl_get_Type,
2146 OLEPictureImpl_get_Width,
2147 OLEPictureImpl_get_Height,
2148 OLEPictureImpl_Render,
2149 OLEPictureImpl_set_hPal,
2150 OLEPictureImpl_get_CurDC,
2151 OLEPictureImpl_SelectPicture,
2152 OLEPictureImpl_get_KeepOriginalFormat,
2153 OLEPictureImpl_put_KeepOriginalFormat,
2154 OLEPictureImpl_PictureChanged,
2155 OLEPictureImpl_SaveAsFile,
2156 OLEPictureImpl_get_Attributes
2159 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2161 OLEPictureImpl_IDispatch_QueryInterface,
2162 OLEPictureImpl_IDispatch_AddRef,
2163 OLEPictureImpl_IDispatch_Release,
2164 OLEPictureImpl_GetTypeInfoCount,
2165 OLEPictureImpl_GetTypeInfo,
2166 OLEPictureImpl_GetIDsOfNames,
2167 OLEPictureImpl_Invoke
2170 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2172 OLEPictureImpl_IPersistStream_QueryInterface,
2173 OLEPictureImpl_IPersistStream_AddRef,
2174 OLEPictureImpl_IPersistStream_Release,
2175 OLEPictureImpl_GetClassID,
2176 OLEPictureImpl_IsDirty,
2177 OLEPictureImpl_Load,
2178 OLEPictureImpl_Save,
2179 OLEPictureImpl_GetSizeMax
2182 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2184 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2185 OLEPictureImpl_IConnectionPointContainer_AddRef,
2186 OLEPictureImpl_IConnectionPointContainer_Release,
2187 OLEPictureImpl_EnumConnectionPoints,
2188 OLEPictureImpl_FindConnectionPoint
2191 /***********************************************************************
2192 * OleCreatePictureIndirect (OLEAUT32.419)
2194 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2195 BOOL Own, void **ppvObj )
2197 OLEPictureImpl* newPict;
2198 HRESULT hr;
2200 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2202 *ppvObj = NULL;
2204 hr = OLEPictureImpl_Construct(lpPictDesc, Own, &newPict);
2205 if (hr != S_OK) return hr;
2208 * Make sure it supports the interface required by the caller.
2210 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2213 * Release the reference obtained in the constructor. If
2214 * the QueryInterface was unsuccessful, it will free the class.
2216 IPicture_Release(&newPict->IPicture_iface);
2218 return hr;
2222 /***********************************************************************
2223 * OleLoadPicture (OLEAUT32.418)
2225 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2226 REFIID riid, LPVOID *ppvObj )
2228 LPPERSISTSTREAM ps;
2229 IPicture *newpic;
2230 HRESULT hr;
2232 TRACE("%p, %ld, %d, %s, %p), partially implemented.\n",
2233 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2235 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2236 if (hr != S_OK)
2237 return hr;
2238 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2239 if (hr != S_OK) {
2240 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2241 IPicture_Release(newpic);
2242 *ppvObj = NULL;
2243 return hr;
2245 hr = IPersistStream_Load(ps,lpstream);
2246 IPersistStream_Release(ps);
2247 if (FAILED(hr))
2249 ERR("IPersistStream_Load failed\n");
2250 IPicture_Release(newpic);
2251 *ppvObj = NULL;
2252 return hr;
2254 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2255 if (hr != S_OK)
2256 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2257 IPicture_Release(newpic);
2258 return hr;
2261 /***********************************************************************
2262 * OleLoadPictureEx (OLEAUT32.401)
2264 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2265 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2267 LPPERSISTSTREAM ps;
2268 IPicture *newpic;
2269 HRESULT hr;
2271 FIXME("%p, %ld, %d, %s, %lu, %lu, %#lx, %p, partially implemented.\n",
2272 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2274 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2275 if (hr != S_OK)
2276 return hr;
2277 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2278 if (hr != S_OK) {
2279 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2280 IPicture_Release(newpic);
2281 *ppvObj = NULL;
2282 return hr;
2284 hr = IPersistStream_Load(ps,lpstream);
2285 IPersistStream_Release(ps);
2286 if (FAILED(hr))
2288 ERR("IPersistStream_Load failed\n");
2289 IPicture_Release(newpic);
2290 *ppvObj = NULL;
2291 return hr;
2293 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2294 if (hr != S_OK)
2295 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2296 IPicture_Release(newpic);
2297 return hr;
2300 /***********************************************************************
2301 * OleLoadPictureFile (OLEAUT32.422)
2303 HRESULT WINAPI OleLoadPictureFile(VARIANT file, LPDISPATCH *picture)
2305 FIXME("(%s %p): stub\n", wine_dbgstr_variant(&file), picture);
2306 return E_NOTIMPL;
2309 /***********************************************************************
2310 * OleSavePictureFile (OLEAUT32.423)
2312 HRESULT WINAPI OleSavePictureFile(IDispatch *picture, BSTR filename)
2314 FIXME("(%p %s): stub\n", picture, debugstr_w(filename));
2315 return CTL_E_FILENOTFOUND;
2318 /***********************************************************************
2319 * OleLoadPicturePath (OLEAUT32.424)
2321 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2322 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2323 LPVOID *ppvRet )
2325 IPicture *ipicture;
2326 HANDLE hFile;
2327 DWORD dwFileSize;
2328 HGLOBAL hGlobal = NULL;
2329 DWORD dwBytesRead;
2330 IStream *stream;
2331 BOOL bRead;
2332 IPersistStream *pStream;
2333 HRESULT hRes;
2334 HRESULT init_res;
2335 WCHAR *file_candidate;
2336 WCHAR path_buf[MAX_PATH];
2338 TRACE("%s, %p, %ld, %#lx, %s, %p.\n", debugstr_w(szURLorPath), punkCaller, dwReserved,
2339 clrReserved, debugstr_guid(riid), ppvRet);
2341 if (!szURLorPath || !ppvRet)
2342 return E_INVALIDARG;
2344 *ppvRet = NULL;
2346 /* Convert file URLs to DOS paths. */
2347 if (wcsncmp(szURLorPath, L"file:", 5) == 0) {
2348 DWORD size;
2349 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2350 ARRAY_SIZE(path_buf), &size, 0);
2351 if (FAILED(hRes))
2352 return hRes;
2354 file_candidate = path_buf;
2356 else
2357 file_candidate = szURLorPath;
2359 /* Handle candidate DOS paths separately. */
2360 if (file_candidate[1] == ':') {
2361 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2362 0, NULL);
2363 if (hFile == INVALID_HANDLE_VALUE)
2364 return INET_E_RESOURCE_NOT_FOUND;
2366 dwFileSize = GetFileSize(hFile, NULL);
2367 if (dwFileSize != INVALID_FILE_SIZE )
2369 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2370 if ( hGlobal)
2372 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL) && dwBytesRead == dwFileSize;
2373 if (!bRead)
2375 GlobalFree(hGlobal);
2376 hGlobal = 0;
2380 CloseHandle(hFile);
2382 if (!hGlobal)
2383 return INET_E_RESOURCE_NOT_FOUND;
2385 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2386 if (FAILED(hRes))
2388 GlobalFree(hGlobal);
2389 return hRes;
2391 } else {
2392 IMoniker *pmnk;
2393 IBindCtx *pbc;
2395 hRes = CreateBindCtx(0, &pbc);
2396 if (SUCCEEDED(hRes))
2398 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2399 if (SUCCEEDED(hRes))
2401 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2402 IMoniker_Release(pmnk);
2404 IBindCtx_Release(pbc);
2406 if (FAILED(hRes))
2407 return hRes;
2410 init_res = CoInitialize(NULL);
2412 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2413 &IID_IPicture, (LPVOID*)&ipicture);
2414 if (SUCCEEDED(hRes)) {
2415 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2417 if (SUCCEEDED(hRes)) {
2418 hRes = IPersistStream_Load(pStream, stream);
2420 if (SUCCEEDED(hRes)) {
2421 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2423 if (FAILED(hRes))
2424 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2426 IPersistStream_Release(pStream);
2428 IPicture_Release(ipicture);
2431 IStream_Release(stream);
2433 if (SUCCEEDED(init_res))
2434 CoUninitialize();
2436 return hRes;
2439 /*******************************************************************************
2440 * StdPic ClassFactory
2442 typedef struct
2444 /* IUnknown fields */
2445 IClassFactory IClassFactory_iface;
2446 LONG ref;
2447 } IClassFactoryImpl;
2449 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2451 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2454 static HRESULT WINAPI
2455 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2456 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2458 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2459 return E_NOINTERFACE;
2462 static ULONG WINAPI
2463 SPCF_AddRef(LPCLASSFACTORY iface) {
2464 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2465 return InterlockedIncrement(&This->ref);
2468 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2469 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2470 /* static class, won't be freed */
2471 return InterlockedDecrement(&This->ref);
2474 static HRESULT WINAPI SPCF_CreateInstance(
2475 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2477 /* Creates an uninitialized picture */
2478 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2482 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2483 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2484 FIXME("(%p)->(%d),stub!\n",This,dolock);
2485 return S_OK;
2488 static const IClassFactoryVtbl SPCF_Vtbl = {
2489 SPCF_QueryInterface,
2490 SPCF_AddRef,
2491 SPCF_Release,
2492 SPCF_CreateInstance,
2493 SPCF_LockServer
2495 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2497 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }