ntdll: Use list_empty() instead of list_count() == 0.
[wine/multimedia.git] / dlls / oleaut32 / olepicture.c
blob80817858cbf758948f43713286f007b22c4d6ddb
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 "config.h"
40 #include "wine/port.h"
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <string.h>
49 #define COBJMACROS
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
53 #include "winerror.h"
54 #include "windef.h"
55 #include "winbase.h"
56 #include "wingdi.h"
57 #include "winuser.h"
58 #include "ole2.h"
59 #include "olectl.h"
60 #include "oleauto.h"
61 #include "connpt.h"
62 #include "urlmon.h"
63 #include "initguid.h"
64 #include "wincodec.h"
65 #include "wine/debug.h"
66 #include "wine/unicode.h"
67 #include "wine/library.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(ole);
71 #include "pshpack1.h"
73 /* Header for Aldus Placable Metafiles - a standard metafile follows */
74 typedef struct _APM_HEADER
76 DWORD key;
77 WORD handle;
78 SHORT left;
79 SHORT top;
80 SHORT right;
81 SHORT bottom;
82 WORD inch;
83 DWORD reserved;
84 WORD checksum;
85 } APM_HEADER;
87 typedef struct {
88 BYTE bWidth;
89 BYTE bHeight;
90 BYTE bColorCount;
91 BYTE bReserved;
92 WORD xHotspot;
93 WORD yHotspot;
94 DWORD dwDIBSize;
95 DWORD dwDIBOffset;
96 } CURSORICONFILEDIRENTRY;
98 typedef struct
100 WORD idReserved;
101 WORD idType;
102 WORD idCount;
103 CURSORICONFILEDIRENTRY idEntries[1];
104 } CURSORICONFILEDIR;
106 #include "poppack.h"
108 /*************************************************************************
109 * Declaration of implementation class
112 typedef struct OLEPictureImpl {
115 * IPicture handles IUnknown
118 IPicture IPicture_iface;
119 IDispatch IDispatch_iface;
120 IPersistStream IPersistStream_iface;
121 IConnectionPointContainer IConnectionPointContainer_iface;
123 /* Object reference count */
124 LONG ref;
126 /* We own the object and must destroy it ourselves */
127 BOOL fOwn;
129 /* Picture description */
130 PICTDESC desc;
132 /* These are the pixel size of a bitmap */
133 DWORD origWidth;
134 DWORD origHeight;
136 /* And these are the size of the picture converted into HIMETRIC units */
137 OLE_XSIZE_HIMETRIC himetricWidth;
138 OLE_YSIZE_HIMETRIC himetricHeight;
140 IConnectionPoint *pCP;
142 BOOL keepOrigFormat;
143 HDC hDCCur;
145 /* Bitmap transparency mask */
146 HBITMAP hbmMask;
147 HBITMAP hbmXor;
148 COLORREF rgbTrans;
150 /* data */
151 void* data;
152 int datalen;
153 BOOL bIsDirty; /* Set to TRUE if picture has changed */
154 unsigned int loadtime_magic; /* If a length header was found, saves value */
155 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
156 } OLEPictureImpl;
158 static inline OLEPictureImpl *impl_from_IPicture(IPicture *iface)
160 return CONTAINING_RECORD(iface, OLEPictureImpl, IPicture_iface);
163 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
165 return CONTAINING_RECORD(iface, OLEPictureImpl, IDispatch_iface);
168 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
170 return CONTAINING_RECORD(iface, OLEPictureImpl, IPersistStream_iface);
173 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
175 return CONTAINING_RECORD(iface, OLEPictureImpl, IConnectionPointContainer_iface);
179 * Predeclare VTables. They get initialized at the end.
181 static const IPictureVtbl OLEPictureImpl_VTable;
182 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
183 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
184 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
186 /* pixels to HIMETRIC units conversion */
187 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
189 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
192 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
194 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
197 /***********************************************************************
198 * Implementation of the OLEPictureImpl class.
201 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
203 BITMAP bm;
204 HDC hdcRef;
206 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
207 if(GetObjectW(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
208 ERR("GetObject fails\n");
209 return;
211 This->origWidth = bm.bmWidth;
212 This->origHeight = bm.bmHeight;
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);
223 DeleteDC(hdcRef);
226 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
228 ICONINFO infoIcon;
230 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
231 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
232 HDC hdcRef;
233 BITMAP bm;
235 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
236 if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
237 ERR("GetObject fails on icon bitmap\n");
238 return;
241 This->origWidth = bm.bmWidth;
242 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
243 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
244 hdcRef = GetDC(0);
246 This->himetricWidth = xpixels_to_himetric(This->origWidth, hdcRef);
247 This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
249 ReleaseDC(0, hdcRef);
251 DeleteObject(infoIcon.hbmMask);
252 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
253 } else {
254 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
258 /************************************************************************
259 * OLEPictureImpl_Construct
261 * This method will construct a new instance of the OLEPictureImpl
262 * class.
264 * The caller of this method must release the object when it's
265 * done with it.
267 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
269 OLEPictureImpl* newObject = 0;
271 if (pictDesc)
272 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
275 * Allocate space for the object.
277 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
279 if (newObject==0)
280 return newObject;
283 * Initialize the virtual function table.
285 newObject->IPicture_iface.lpVtbl = &OLEPictureImpl_VTable;
286 newObject->IDispatch_iface.lpVtbl = &OLEPictureImpl_IDispatch_VTable;
287 newObject->IPersistStream_iface.lpVtbl = &OLEPictureImpl_IPersistStream_VTable;
288 newObject->IConnectionPointContainer_iface.lpVtbl = &OLEPictureImpl_IConnectionPointContainer_VTable;
290 newObject->pCP = NULL;
291 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
292 if (!newObject->pCP)
294 HeapFree(GetProcessHeap(), 0, newObject);
295 return NULL;
299 * Start with one reference count. The caller of this function
300 * must release the interface pointer when it is done.
302 newObject->ref = 1;
303 newObject->hDCCur = 0;
305 newObject->fOwn = fOwn;
307 /* dunno about original value */
308 newObject->keepOrigFormat = TRUE;
310 newObject->hbmMask = NULL;
311 newObject->hbmXor = NULL;
312 newObject->loadtime_magic = 0xdeadbeef;
313 newObject->loadtime_format = 0;
314 newObject->bIsDirty = FALSE;
316 if (pictDesc) {
317 newObject->desc = *pictDesc;
319 switch(pictDesc->picType) {
320 case PICTYPE_BITMAP:
321 OLEPictureImpl_SetBitmap(newObject);
322 break;
324 case PICTYPE_METAFILE:
325 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
326 newObject->himetricWidth = pictDesc->u.wmf.xExt;
327 newObject->himetricHeight = pictDesc->u.wmf.yExt;
328 break;
330 case PICTYPE_NONE:
331 /* not sure what to do here */
332 newObject->himetricWidth = newObject->himetricHeight = 0;
333 break;
335 case PICTYPE_ICON:
336 OLEPictureImpl_SetIcon(newObject);
337 break;
338 case PICTYPE_ENHMETAFILE:
339 default:
340 FIXME("Unsupported type %d\n", pictDesc->picType);
341 newObject->himetricWidth = newObject->himetricHeight = 0;
342 break;
344 } else {
345 newObject->desc.picType = PICTYPE_UNINITIALIZED;
348 TRACE("returning %p\n", newObject);
349 return newObject;
352 /************************************************************************
353 * OLEPictureImpl_Destroy
355 * This method is called by the Release method when the reference
356 * count goes down to 0. It will free all resources used by
357 * this object. */
358 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
360 TRACE("(%p)\n", Obj);
362 if (Obj->pCP)
363 IConnectionPoint_Release(Obj->pCP);
365 if(Obj->fOwn) { /* We need to destroy the picture */
366 switch(Obj->desc.picType) {
367 case PICTYPE_BITMAP:
368 DeleteObject(Obj->desc.u.bmp.hbitmap);
369 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
370 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
371 break;
372 case PICTYPE_METAFILE:
373 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
374 break;
375 case PICTYPE_ICON:
376 DestroyIcon(Obj->desc.u.icon.hicon);
377 break;
378 case PICTYPE_ENHMETAFILE:
379 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
380 break;
381 case PICTYPE_NONE:
382 case PICTYPE_UNINITIALIZED:
383 /* Nothing to do */
384 break;
385 default:
386 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
387 break;
390 HeapFree(GetProcessHeap(), 0, Obj->data);
391 HeapFree(GetProcessHeap(), 0, Obj);
395 /************************************************************************
396 * OLEPictureImpl_AddRef (IUnknown)
398 * See Windows documentation for more details on IUnknown methods.
400 static ULONG WINAPI OLEPictureImpl_AddRef(
401 IPicture* iface)
403 OLEPictureImpl *This = impl_from_IPicture(iface);
404 ULONG refCount = InterlockedIncrement(&This->ref);
406 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
408 return refCount;
411 /************************************************************************
412 * OLEPictureImpl_Release (IUnknown)
414 * See Windows documentation for more details on IUnknown methods.
416 static ULONG WINAPI OLEPictureImpl_Release(
417 IPicture* iface)
419 OLEPictureImpl *This = impl_from_IPicture(iface);
420 ULONG refCount = InterlockedDecrement(&This->ref);
422 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
425 * If the reference count goes down to 0, perform suicide.
427 if (!refCount) OLEPictureImpl_Destroy(This);
429 return refCount;
432 /************************************************************************
433 * OLEPictureImpl_QueryInterface (IUnknown)
435 * See Windows documentation for more details on IUnknown methods.
437 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
438 IPicture* iface,
439 REFIID riid,
440 void** ppvObject)
442 OLEPictureImpl *This = impl_from_IPicture(iface);
444 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
446 if (!ppvObject)
447 return E_INVALIDARG;
449 *ppvObject = 0;
451 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
452 *ppvObject = This;
453 else if (IsEqualIID(&IID_IDispatch, riid))
454 *ppvObject = &This->IDispatch_iface;
455 else if (IsEqualIID(&IID_IPictureDisp, riid))
456 *ppvObject = &This->IDispatch_iface;
457 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
458 *ppvObject = &This->IPersistStream_iface;
459 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
460 *ppvObject = &This->IConnectionPointContainer_iface;
462 if (!*ppvObject)
464 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
465 return E_NOINTERFACE;
468 IPicture_AddRef(iface);
470 return S_OK;
473 /***********************************************************************
474 * OLEPicture_SendNotify (internal)
476 * Sends notification messages of changed properties to any interested
477 * connections.
479 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
481 IEnumConnections *pEnum;
482 CONNECTDATA CD;
484 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
485 return;
486 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
487 IPropertyNotifySink *sink;
489 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
490 IPropertyNotifySink_OnChanged(sink, dispID);
491 IPropertyNotifySink_Release(sink);
492 IUnknown_Release(CD.pUnk);
494 IEnumConnections_Release(pEnum);
497 /************************************************************************
498 * OLEPictureImpl_get_Handle
500 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
501 OLE_HANDLE *phandle)
503 OLEPictureImpl *This = impl_from_IPicture(iface);
504 TRACE("(%p)->(%p)\n", This, phandle);
506 if(!phandle)
507 return E_POINTER;
509 switch(This->desc.picType) {
510 case PICTYPE_NONE:
511 case PICTYPE_UNINITIALIZED:
512 *phandle = 0;
513 break;
514 case PICTYPE_BITMAP:
515 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
516 break;
517 case PICTYPE_METAFILE:
518 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
519 break;
520 case PICTYPE_ICON:
521 *phandle = HandleToUlong(This->desc.u.icon.hicon);
522 break;
523 case PICTYPE_ENHMETAFILE:
524 *phandle = HandleToUlong(This->desc.u.emf.hemf);
525 break;
526 default:
527 FIXME("Unimplemented type %d\n", This->desc.picType);
528 return E_NOTIMPL;
530 TRACE("returning handle %08x\n", *phandle);
531 return S_OK;
534 /************************************************************************
535 * OLEPictureImpl_get_hPal
537 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
538 OLE_HANDLE *phandle)
540 OLEPictureImpl *This = impl_from_IPicture(iface);
541 HRESULT hres;
542 TRACE("(%p)->(%p)\n", This, phandle);
544 if (!phandle)
545 return E_POINTER;
547 switch (This->desc.picType) {
548 case (UINT)PICTYPE_UNINITIALIZED:
549 case PICTYPE_NONE:
550 *phandle = 0;
551 hres = S_FALSE;
552 break;
553 case PICTYPE_BITMAP:
554 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
555 hres = S_OK;
556 break;
557 case PICTYPE_METAFILE:
558 hres = E_FAIL;
559 break;
560 case PICTYPE_ICON:
561 case PICTYPE_ENHMETAFILE:
562 default:
563 FIXME("unimplemented for type %d. Returning 0 palette.\n",
564 This->desc.picType);
565 *phandle = 0;
566 hres = S_OK;
569 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
570 return hres;
573 /************************************************************************
574 * OLEPictureImpl_get_Type
576 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
577 short *ptype)
579 OLEPictureImpl *This = impl_from_IPicture(iface);
580 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
582 if(!ptype)
583 return E_POINTER;
585 *ptype = This->desc.picType;
586 return S_OK;
589 /************************************************************************
590 * OLEPictureImpl_get_Width
592 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
593 OLE_XSIZE_HIMETRIC *pwidth)
595 OLEPictureImpl *This = impl_from_IPicture(iface);
596 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
597 *pwidth = This->himetricWidth;
598 return S_OK;
601 /************************************************************************
602 * OLEPictureImpl_get_Height
604 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
605 OLE_YSIZE_HIMETRIC *pheight)
607 OLEPictureImpl *This = impl_from_IPicture(iface);
608 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
609 *pheight = This->himetricHeight;
610 return S_OK;
613 /************************************************************************
614 * OLEPictureImpl_Render
616 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
617 LONG x, LONG y, LONG cx, LONG cy,
618 OLE_XPOS_HIMETRIC xSrc,
619 OLE_YPOS_HIMETRIC ySrc,
620 OLE_XSIZE_HIMETRIC cxSrc,
621 OLE_YSIZE_HIMETRIC cySrc,
622 LPCRECT prcWBounds)
624 OLEPictureImpl *This = impl_from_IPicture(iface);
625 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
626 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
627 if(prcWBounds)
628 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
629 prcWBounds->right, prcWBounds->bottom);
631 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
632 return CTL_E_INVALIDPROPERTYVALUE;
636 * While the documentation suggests this to be here (or after rendering?)
637 * it does cause an endless recursion in my sample app. -MM 20010804
638 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
641 switch(This->desc.picType) {
642 case PICTYPE_UNINITIALIZED:
643 case PICTYPE_NONE:
644 /* nothing to do */
645 return S_OK;
646 case PICTYPE_BITMAP:
648 HBITMAP hbmpOld;
649 HDC hdcBmp;
651 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
652 NB y-axis gets flipped */
654 hdcBmp = CreateCompatibleDC(0);
655 SetMapMode(hdcBmp, MM_ANISOTROPIC);
656 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
657 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
658 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
659 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
661 if (This->hbmMask) {
662 HDC hdcMask = CreateCompatibleDC(0);
663 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
665 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
667 SetMapMode(hdcMask, MM_ANISOTROPIC);
668 SetWindowOrgEx(hdcMask, 0, 0, NULL);
669 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
670 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
671 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
673 SetBkColor(hdc, RGB(255, 255, 255));
674 SetTextColor(hdc, RGB(0, 0, 0));
675 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
676 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
678 SelectObject(hdcMask, hOldbm);
679 DeleteDC(hdcMask);
680 } else {
681 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
682 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
685 SelectObject(hdcBmp, hbmpOld);
686 DeleteDC(hdcBmp);
688 break;
689 case PICTYPE_ICON:
690 FIXME("Not quite correct implementation of rendering icons...\n");
691 DrawIconEx(hdc, x, y, This->desc.u.icon.hicon, cx, cy, 0, NULL, DI_NORMAL);
692 break;
694 case PICTYPE_METAFILE:
696 POINT prevOrg, prevWndOrg;
697 SIZE prevExt, prevWndExt;
698 int oldmode;
700 /* Render the WMF to the appropriate location by setting the
701 appropriate ratio between "device units" and "logical units" */
702 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
703 /* For the "source rectangle" the y-axis must be inverted */
704 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
705 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
706 /* For the "destination rectangle" no inversion is necessary */
707 SetViewportOrgEx(hdc, x, y, &prevOrg);
708 SetViewportExtEx(hdc, cx, cy, &prevExt);
710 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
711 ERR("PlayMetaFile failed!\n");
713 /* We're done, restore the DC to the previous settings for converting
714 logical units to device units */
715 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
716 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
717 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
718 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
719 SetMapMode(hdc, oldmode);
720 break;
723 case PICTYPE_ENHMETAFILE:
725 RECT rc = { x, y, x + cx, y + cy };
726 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
727 break;
730 default:
731 FIXME("type %d not implemented\n", This->desc.picType);
732 return E_NOTIMPL;
734 return S_OK;
737 /************************************************************************
738 * OLEPictureImpl_set_hPal
740 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
741 OLE_HANDLE hpal)
743 OLEPictureImpl *This = impl_from_IPicture(iface);
744 FIXME("(%p)->(%08x): stub\n", This, hpal);
745 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
746 return E_NOTIMPL;
749 /************************************************************************
750 * OLEPictureImpl_get_CurDC
752 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
753 HDC *phdc)
755 OLEPictureImpl *This = impl_from_IPicture(iface);
756 TRACE("(%p), returning %p\n", This, This->hDCCur);
757 if (phdc) *phdc = This->hDCCur;
758 return S_OK;
761 /************************************************************************
762 * OLEPictureImpl_SelectPicture
764 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
765 HDC hdcIn,
766 HDC *phdcOut,
767 OLE_HANDLE *phbmpOut)
769 OLEPictureImpl *This = impl_from_IPicture(iface);
770 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
771 if (This->desc.picType == PICTYPE_BITMAP) {
772 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
774 if (phdcOut)
775 *phdcOut = This->hDCCur;
776 This->hDCCur = hdcIn;
777 if (phbmpOut)
778 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
779 return S_OK;
780 } else {
781 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
782 return E_FAIL;
786 /************************************************************************
787 * OLEPictureImpl_get_KeepOriginalFormat
789 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
790 BOOL *pfKeep)
792 OLEPictureImpl *This = impl_from_IPicture(iface);
793 TRACE("(%p)->(%p)\n", This, pfKeep);
794 if (!pfKeep)
795 return E_POINTER;
796 *pfKeep = This->keepOrigFormat;
797 return S_OK;
800 /************************************************************************
801 * OLEPictureImpl_put_KeepOriginalFormat
803 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
804 BOOL keep)
806 OLEPictureImpl *This = impl_from_IPicture(iface);
807 TRACE("(%p)->(%d)\n", This, keep);
808 This->keepOrigFormat = keep;
809 /* FIXME: what DISPID notification here? */
810 return S_OK;
813 /************************************************************************
814 * OLEPictureImpl_PictureChanged
816 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
818 OLEPictureImpl *This = impl_from_IPicture(iface);
819 TRACE("(%p)->()\n", This);
820 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
821 This->bIsDirty = TRUE;
822 return S_OK;
825 /************************************************************************
826 * OLEPictureImpl_SaveAsFile
828 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
829 IStream *pstream,
830 BOOL SaveMemCopy,
831 LONG *pcbSize)
833 OLEPictureImpl *This = impl_from_IPicture(iface);
834 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
835 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
838 /************************************************************************
839 * OLEPictureImpl_get_Attributes
841 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
842 DWORD *pdwAttr)
844 OLEPictureImpl *This = impl_from_IPicture(iface);
845 TRACE("(%p)->(%p).\n", This, pdwAttr);
847 if(!pdwAttr)
848 return E_POINTER;
850 *pdwAttr = 0;
851 switch (This->desc.picType) {
852 case PICTYPE_UNINITIALIZED:
853 case PICTYPE_NONE: break;
854 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
855 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
856 case PICTYPE_ENHMETAFILE: /* fall through */
857 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
858 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
860 return S_OK;
864 /************************************************************************
865 * IConnectionPointContainer
867 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
868 IConnectionPointContainer* iface,
869 REFIID riid,
870 VOID** ppvoid)
872 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
874 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
877 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
878 IConnectionPointContainer* iface)
880 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
882 return IPicture_AddRef(&This->IPicture_iface);
885 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
886 IConnectionPointContainer* iface)
888 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
890 return IPicture_Release(&This->IPicture_iface);
893 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
894 IConnectionPointContainer* iface,
895 IEnumConnectionPoints** ppEnum)
897 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
899 FIXME("(%p,%p), stub!\n",This,ppEnum);
900 return E_NOTIMPL;
903 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
904 IConnectionPointContainer* iface,
905 REFIID riid,
906 IConnectionPoint **ppCP)
908 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
909 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
910 if (!ppCP)
911 return E_POINTER;
912 *ppCP = NULL;
913 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
914 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
915 FIXME("no connection point for %s\n",debugstr_guid(riid));
916 return CONNECT_E_NOCONNECTION;
920 /************************************************************************
921 * IPersistStream
924 /************************************************************************
925 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
927 * See Windows documentation for more details on IUnknown methods.
929 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
930 IPersistStream* iface,
931 REFIID riid,
932 VOID** ppvoid)
934 OLEPictureImpl *This = impl_from_IPersistStream(iface);
936 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
939 /************************************************************************
940 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
942 * See Windows documentation for more details on IUnknown methods.
944 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
945 IPersistStream* iface)
947 OLEPictureImpl *This = impl_from_IPersistStream(iface);
949 return IPicture_AddRef(&This->IPicture_iface);
952 /************************************************************************
953 * OLEPictureImpl_IPersistStream_Release (IUnknown)
955 * See Windows documentation for more details on IUnknown methods.
957 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
958 IPersistStream* iface)
960 OLEPictureImpl *This = impl_from_IPersistStream(iface);
962 return IPicture_Release(&This->IPicture_iface);
965 /************************************************************************
966 * OLEPictureImpl_IPersistStream_GetClassID
968 static HRESULT WINAPI OLEPictureImpl_GetClassID(
969 IPersistStream* iface,CLSID* pClassID)
971 TRACE("(%p)\n", pClassID);
972 *pClassID = CLSID_StdPicture;
973 return S_OK;
976 /************************************************************************
977 * OLEPictureImpl_IPersistStream_IsDirty
979 static HRESULT WINAPI OLEPictureImpl_IsDirty(
980 IPersistStream* iface)
982 OLEPictureImpl *This = impl_from_IPersistStream(iface);
983 FIXME("(%p),stub!\n",This);
984 return E_NOTIMPL;
987 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
989 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
990 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
991 HDC hdcref;
993 /* Does not matter whether this is a coreheader or not, we only use
994 * components which are in both
996 hdcref = GetDC(0);
997 This->desc.u.bmp.hbitmap = CreateDIBitmap(
998 hdcref,
999 &(bi->bmiHeader),
1000 CBM_INIT,
1001 xbuf+bfh->bfOffBits,
1003 DIB_RGB_COLORS
1005 ReleaseDC(0, hdcref);
1006 if (This->desc.u.bmp.hbitmap == 0)
1007 return E_FAIL;
1008 This->desc.picType = PICTYPE_BITMAP;
1009 OLEPictureImpl_SetBitmap(This);
1010 return S_OK;
1013 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1015 HRESULT hr;
1016 BITMAPINFOHEADER bih;
1017 HDC hdcref;
1018 UINT width, height;
1019 UINT stride, buffersize;
1020 LPBYTE bits=NULL;
1021 WICRect rc;
1022 IWICBitmapSource *real_source;
1023 UINT x, y;
1024 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1025 BOOL has_alpha=FALSE;
1027 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1028 if (FAILED(hr)) return hr;
1030 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1031 if (FAILED(hr)) goto end;
1033 bih.biSize = sizeof(bih);
1034 bih.biWidth = width;
1035 bih.biHeight = -height;
1036 bih.biPlanes = 1;
1037 bih.biBitCount = 32;
1038 bih.biCompression = BI_RGB;
1039 bih.biSizeImage = 0;
1040 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1041 bih.biYPelsPerMeter = 4085;
1042 bih.biClrUsed = 0;
1043 bih.biClrImportant = 0;
1045 stride = 4 * width;
1046 buffersize = stride * height;
1048 bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1049 if (!bits)
1051 hr = E_OUTOFMEMORY;
1052 goto end;
1055 rc.X = 0;
1056 rc.Y = 0;
1057 rc.Width = width;
1058 rc.Height = height;
1059 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1060 if (FAILED(hr))
1061 goto end;
1063 hdcref = GetDC(0);
1064 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1065 hdcref,
1066 &bih,
1067 CBM_INIT,
1068 bits,
1069 (BITMAPINFO*)&bih,
1070 DIB_RGB_COLORS);
1072 if (This->desc.u.bmp.hbitmap == 0)
1074 hr = E_FAIL;
1075 ReleaseDC(0, hdcref);
1076 goto end;
1079 This->desc.picType = PICTYPE_BITMAP;
1080 OLEPictureImpl_SetBitmap(This);
1082 /* set transparent pixels to black, all others to white */
1083 for(y = 0; y < height; y++){
1084 for(x = 0; x < width; x++){
1085 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1086 if((*pixel & 0x80000000) == 0)
1088 has_alpha = TRUE;
1089 *pixel = black;
1091 else
1092 *pixel = white;
1096 if (has_alpha)
1098 HDC hdcBmp, hdcXor, hdcMask;
1099 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1101 This->hbmXor = CreateDIBitmap(
1102 hdcref,
1103 &bih,
1104 CBM_INIT,
1105 bits,
1106 (BITMAPINFO*)&bih,
1107 DIB_RGB_COLORS
1110 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1111 hdcBmp = CreateCompatibleDC(NULL);
1112 hdcXor = CreateCompatibleDC(NULL);
1113 hdcMask = CreateCompatibleDC(NULL);
1115 hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1116 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1117 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1119 SetBkColor(hdcXor,black);
1120 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1121 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1123 SelectObject(hdcBmp,hbmoldBmp);
1124 SelectObject(hdcXor,hbmoldXor);
1125 SelectObject(hdcMask,hbmoldMask);
1127 DeleteDC(hdcBmp);
1128 DeleteDC(hdcXor);
1129 DeleteDC(hdcMask);
1132 ReleaseDC(0, hdcref);
1134 end:
1135 HeapFree(GetProcessHeap(), 0, bits);
1136 IWICBitmapSource_Release(real_source);
1137 return hr;
1140 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1142 HRESULT hr;
1143 IWICImagingFactory *factory;
1144 IWICBitmapDecoder *decoder;
1145 IWICBitmapFrameDecode *framedecode;
1146 HRESULT initresult;
1147 IWICStream *stream;
1149 initresult = CoInitialize(NULL);
1151 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1152 &IID_IWICImagingFactory, (void**)&factory);
1153 if (SUCCEEDED(hr)) /* created factory */
1155 hr = IWICImagingFactory_CreateStream(factory, &stream);
1156 IWICImagingFactory_Release(factory);
1159 if (SUCCEEDED(hr)) /* created stream */
1161 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1163 if (SUCCEEDED(hr)) /* initialized stream */
1165 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1166 &IID_IWICBitmapDecoder, (void**)&decoder);
1167 if (SUCCEEDED(hr)) /* created decoder */
1169 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1171 if (SUCCEEDED(hr)) /* initialized decoder */
1172 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1174 IWICBitmapDecoder_Release(decoder);
1178 IWICStream_Release(stream);
1181 if (SUCCEEDED(hr)) /* got framedecode */
1183 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1184 IWICBitmapFrameDecode_Release(framedecode);
1187 if (SUCCEEDED(initresult)) CoUninitialize();
1188 return hr;
1191 /*****************************************************
1192 * start of Icon-specific code
1195 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1197 HICON hicon;
1198 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1199 HDC hdcRef;
1200 int i;
1203 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1204 FIXME("icon.idType=%d\n",cifd->idType);
1205 FIXME("icon.idCount=%d\n",cifd->idCount);
1207 for (i=0;i<cifd->idCount;i++) {
1208 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1209 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1210 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1211 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1212 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1213 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1214 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1215 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1218 i=0;
1219 /* If we have more than one icon, try to find the best.
1220 * this currently means '32 pixel wide'.
1222 if (cifd->idCount!=1) {
1223 for (i=0;i<cifd->idCount;i++) {
1224 if (cifd->idEntries[i].bWidth == 32)
1225 break;
1227 if (i==cifd->idCount) i=0;
1230 hicon = CreateIconFromResourceEx(
1231 xbuf+cifd->idEntries[i].dwDIBOffset,
1232 cifd->idEntries[i].dwDIBSize,
1233 TRUE, /* is icon */
1234 0x00030000,
1235 cifd->idEntries[i].bWidth,
1236 cifd->idEntries[i].bHeight,
1239 if (!hicon) {
1240 ERR("CreateIcon failed.\n");
1241 return E_FAIL;
1242 } else {
1243 This->desc.picType = PICTYPE_ICON;
1244 This->desc.u.icon.hicon = hicon;
1245 This->origWidth = cifd->idEntries[i].bWidth;
1246 This->origHeight = cifd->idEntries[i].bHeight;
1247 hdcRef = CreateCompatibleDC(0);
1248 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1249 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1250 DeleteDC(hdcRef);
1251 return S_OK;
1255 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1256 const BYTE *data, ULONG size)
1258 HENHMETAFILE hemf;
1259 ENHMETAHEADER hdr;
1261 hemf = SetEnhMetaFileBits(size, data);
1262 if (!hemf) return E_FAIL;
1264 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1266 This->desc.picType = PICTYPE_ENHMETAFILE;
1267 This->desc.u.emf.hemf = hemf;
1269 This->origWidth = 0;
1270 This->origHeight = 0;
1271 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1272 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1274 return S_OK;
1277 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1278 const BYTE *data, ULONG size)
1280 const APM_HEADER *header = (const APM_HEADER *)data;
1281 HMETAFILE hmf;
1283 if (size < sizeof(APM_HEADER))
1284 return E_FAIL;
1285 if (header->key != 0x9ac6cdd7)
1286 return E_FAIL;
1288 /* SetMetaFileBitsEx performs data check on its own */
1289 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1290 if (!hmf) return E_FAIL;
1292 This->desc.picType = PICTYPE_METAFILE;
1293 This->desc.u.wmf.hmeta = hmf;
1294 This->desc.u.wmf.xExt = 0;
1295 This->desc.u.wmf.yExt = 0;
1297 This->origWidth = 0;
1298 This->origHeight = 0;
1299 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1300 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1301 return S_OK;
1304 /************************************************************************
1305 * BITMAP FORMAT FLAGS -
1306 * Flags that differentiate between different types of bitmaps.
1309 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1310 #define BITMAP_FORMAT_JPEG 0xd8ff
1311 #define BITMAP_FORMAT_GIF 0x4947
1312 #define BITMAP_FORMAT_PNG 0x5089
1313 #define BITMAP_FORMAT_APM 0xcdd7
1315 /************************************************************************
1316 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1318 * Loads the binary data from the IStream. Starts at current position.
1319 * There appears to be an 2 DWORD header:
1320 * DWORD magic;
1321 * DWORD len;
1323 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1325 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1326 HRESULT hr;
1327 BOOL headerisdata;
1328 BOOL statfailed = FALSE;
1329 ULONG xread, toread;
1330 ULONG headerread;
1331 BYTE *xbuf;
1332 DWORD header[2];
1333 WORD magic;
1334 STATSTG statstg;
1335 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1337 TRACE("(%p,%p)\n",This,pStm);
1339 /****************************************************************************************
1340 * Part 1: Load the data
1342 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1343 * out whether we do.
1345 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1346 * compound file. This may explain most, if not all, of the cases of "no
1347 * header", and the header validation should take this into account.
1348 * At least in Visual Basic 6, resource streams, valid headers are
1349 * header[0] == "lt\0\0",
1350 * header[1] == length_of_stream.
1352 * Also handle streams where we do not have a working "Stat" method by
1353 * reading all data until the end of the stream.
1355 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1356 if (hr != S_OK) {
1357 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1358 statfailed = TRUE;
1359 /* we will read at least 8 byte ... just right below */
1360 statstg.cbSize.QuadPart = 8;
1363 toread = 0;
1364 headerread = 0;
1365 headerisdata = FALSE;
1366 do {
1367 hr = IStream_Read(pStm, header, 8, &xread);
1368 if (hr != S_OK || xread!=8) {
1369 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1370 return (hr?hr:E_FAIL);
1372 headerread += xread;
1373 xread = 0;
1375 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1376 if (toread != 0 && toread != header[1])
1377 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1378 toread, header[1]);
1379 toread = header[1];
1380 if (toread == 0) break;
1381 } else {
1382 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1383 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1384 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1385 (header[0] == EMR_HEADER) || /* EMF header */
1386 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1387 (header[1]==0)
1388 ) {/* Found start of bitmap data */
1389 headerisdata = TRUE;
1390 if (toread == 0)
1391 toread = statstg.cbSize.QuadPart-8;
1392 else toread -= 8;
1393 xread = 8;
1394 } else {
1395 FIXME("Unknown stream header magic: %08x\n", header[0]);
1396 toread = header[1];
1399 } while (!headerisdata);
1401 if (statfailed) { /* we don't know the size ... read all we get */
1402 int sizeinc = 4096;
1403 int origsize = sizeinc;
1404 ULONG nread = 42;
1406 TRACE("Reading all data from stream.\n");
1407 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1408 if (headerisdata)
1409 memcpy (xbuf, header, 8);
1410 while (1) {
1411 while (xread < origsize) {
1412 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1413 xread += nread;
1414 if (hr != S_OK || !nread)
1415 break;
1417 if (!nread || hr != S_OK) /* done, or error */
1418 break;
1419 if (xread == origsize) {
1420 origsize += sizeinc;
1421 sizeinc = 2*sizeinc; /* exponential increase */
1422 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1425 if (hr != S_OK)
1426 TRACE("hr in no-stat loader case is %08x\n", hr);
1427 TRACE("loaded %d bytes.\n", xread);
1428 This->datalen = xread;
1429 This->data = xbuf;
1430 } else {
1431 This->datalen = toread+(headerisdata?8:0);
1432 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1433 if (!xbuf)
1434 return E_OUTOFMEMORY;
1436 if (headerisdata)
1437 memcpy (xbuf, header, 8);
1439 while (xread < This->datalen) {
1440 ULONG nread;
1441 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1442 xread += nread;
1443 if (hr != S_OK || !nread)
1444 break;
1446 if (xread != This->datalen)
1447 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1449 if (This->datalen == 0) { /* Marks the "NONE" picture */
1450 This->desc.picType = PICTYPE_NONE;
1451 return S_OK;
1455 /****************************************************************************************
1456 * Part 2: Process the loaded data
1459 magic = xbuf[0] + (xbuf[1]<<8);
1460 This->loadtime_format = magic;
1462 switch (magic) {
1463 case BITMAP_FORMAT_GIF: /* GIF */
1464 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1465 break;
1466 case BITMAP_FORMAT_JPEG: /* JPEG */
1467 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1468 break;
1469 case BITMAP_FORMAT_BMP: /* Bitmap */
1470 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1471 break;
1472 case BITMAP_FORMAT_PNG: /* PNG */
1473 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1474 break;
1475 case BITMAP_FORMAT_APM: /* APM */
1476 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1477 break;
1478 case 0x0000: { /* ICON , first word is dwReserved */
1479 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1480 break;
1482 default:
1484 unsigned int i;
1486 /* let's see if it's a EMF */
1487 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1488 if (hr == S_OK) break;
1490 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1491 hr=E_FAIL;
1492 for (i=0;i<xread+8;i++) {
1493 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1494 else MESSAGE("%02x ",xbuf[i-8]);
1495 if (i % 10 == 9) MESSAGE("\n");
1497 MESSAGE("\n");
1498 break;
1501 This->bIsDirty = FALSE;
1503 /* FIXME: this notify is not really documented */
1504 if (hr==S_OK)
1505 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1506 return hr;
1509 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1511 int iSuccess = 0;
1512 HDC hDC;
1513 BITMAPINFO * pInfoBitmap;
1514 int iNumPaletteEntries;
1515 unsigned char * pPixelData;
1516 BITMAPFILEHEADER * pFileHeader;
1517 BITMAPINFO * pInfoHeader;
1519 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1520 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1522 /* Find out bitmap size and padded length */
1523 hDC = GetDC(0);
1524 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1525 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1527 /* Fetch bitmap palette & pixel data */
1529 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1530 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1532 /* Calculate the total length required for the BMP data */
1533 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1534 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1535 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1536 } else {
1537 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1538 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1539 else
1540 iNumPaletteEntries = 0;
1542 *pLength =
1543 sizeof(BITMAPFILEHEADER) +
1544 sizeof(BITMAPINFOHEADER) +
1545 iNumPaletteEntries * sizeof(RGBQUAD) +
1546 pInfoBitmap->bmiHeader.biSizeImage;
1547 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1549 /* Fill the BITMAPFILEHEADER */
1550 pFileHeader = *ppBuffer;
1551 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1552 pFileHeader->bfSize = *pLength;
1553 pFileHeader->bfOffBits =
1554 sizeof(BITMAPFILEHEADER) +
1555 sizeof(BITMAPINFOHEADER) +
1556 iNumPaletteEntries * sizeof(RGBQUAD);
1558 /* Fill the BITMAPINFOHEADER and the palette data */
1559 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1560 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1561 memcpy(
1562 (unsigned char *)(*ppBuffer) +
1563 sizeof(BITMAPFILEHEADER) +
1564 sizeof(BITMAPINFOHEADER) +
1565 iNumPaletteEntries * sizeof(RGBQUAD),
1566 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1567 iSuccess = 1;
1569 HeapFree(GetProcessHeap(), 0, pPixelData);
1570 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1571 return iSuccess;
1574 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1576 ICONINFO infoIcon;
1577 int iSuccess = 0;
1579 *ppBuffer = NULL; *pLength = 0;
1580 if (GetIconInfo(hIcon, &infoIcon)) {
1581 HDC hDC;
1582 BITMAPINFO * pInfoBitmap;
1583 unsigned char * pIconData = NULL;
1584 unsigned int iDataSize = 0;
1586 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1588 /* Find out icon size */
1589 hDC = GetDC(0);
1590 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1591 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1592 if (1) {
1593 /* Auxiliary pointers */
1594 CURSORICONFILEDIR * pIconDir;
1595 CURSORICONFILEDIRENTRY * pIconEntry;
1596 BITMAPINFOHEADER * pIconBitmapHeader;
1597 unsigned int iOffsetPalette;
1598 unsigned int iOffsetColorData;
1599 unsigned int iOffsetMaskData;
1601 unsigned int iLengthScanLineMask;
1602 unsigned int iNumEntriesPalette;
1604 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1606 FIXME("DEBUG: bitmap size is %d x %d\n",
1607 pInfoBitmap->bmiHeader.biWidth,
1608 pInfoBitmap->bmiHeader.biHeight);
1609 FIXME("DEBUG: bitmap bpp is %d\n",
1610 pInfoBitmap->bmiHeader.biBitCount);
1611 FIXME("DEBUG: bitmap nplanes is %d\n",
1612 pInfoBitmap->bmiHeader.biPlanes);
1613 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1614 pInfoBitmap->bmiHeader.biSizeImage);
1616 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1617 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1618 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1620 /* Fill out the CURSORICONFILEDIR */
1621 pIconDir = (CURSORICONFILEDIR *)pIconData;
1622 pIconDir->idType = 1;
1623 pIconDir->idCount = 1;
1625 /* Fill out the CURSORICONFILEDIRENTRY */
1626 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1627 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1628 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1629 pIconEntry->bColorCount =
1630 (pInfoBitmap->bmiHeader.biBitCount < 8)
1631 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1632 : 0;
1633 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1634 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1635 pIconEntry->dwDIBSize = 0;
1636 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1638 /* Fill out the BITMAPINFOHEADER */
1639 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1640 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1642 /* Find out whether a palette exists for the bitmap */
1643 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1644 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1645 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1646 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1647 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1648 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1649 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1650 iNumEntriesPalette = 3;
1651 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1652 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1653 } else {
1654 iNumEntriesPalette = 0;
1657 /* Add bitmap size and header size to icon data size. */
1658 iOffsetPalette = iDataSize;
1659 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1660 iOffsetColorData = iDataSize;
1661 iDataSize += pIconBitmapHeader->biSizeImage;
1662 iOffsetMaskData = iDataSize;
1663 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1664 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1665 pIconBitmapHeader->biHeight *= 2;
1666 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1667 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1668 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1669 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1671 /* Get the actual bitmap data from the icon bitmap */
1672 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1673 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1674 if (iNumEntriesPalette > 0) {
1675 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1676 iNumEntriesPalette * sizeof(RGBQUAD));
1679 /* Reset all values so that GetDIBits call succeeds */
1680 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1681 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1682 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1684 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1685 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1686 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1688 printf("ERROR: unable to get bitmap mask (error %u)\n",
1689 GetLastError());
1693 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1694 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1696 /* Write out everything produced so far to the stream */
1697 *ppBuffer = pIconData; *pLength = iDataSize;
1698 iSuccess = 1;
1699 } else {
1701 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1702 GetLastError());
1706 Remarks (from MSDN entry on GetIconInfo):
1708 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1709 members of ICONINFO. The calling application must manage
1710 these bitmaps and delete them when they are no longer
1711 necessary.
1713 if (hDC) ReleaseDC(0, hDC);
1714 DeleteObject(infoIcon.hbmMask);
1715 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1716 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1717 } else {
1718 printf("ERROR: Unable to get icon information (error %u)\n",
1719 GetLastError());
1721 return iSuccess;
1724 static HRESULT WINAPI OLEPictureImpl_Save(
1725 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1727 HRESULT hResult = E_NOTIMPL;
1728 void * pIconData;
1729 unsigned int iDataSize;
1730 ULONG dummy;
1731 int iSerializeResult = 0;
1732 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1734 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1736 switch (This->desc.picType) {
1737 case PICTYPE_ICON:
1738 if (This->bIsDirty || !This->data) {
1739 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1740 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1741 hResult = E_FAIL;
1742 break;
1744 HeapFree(GetProcessHeap(), 0, This->data);
1745 This->data = pIconData;
1746 This->datalen = iDataSize;
1748 if (This->loadtime_magic != 0xdeadbeef) {
1749 DWORD header[2];
1751 header[0] = This->loadtime_magic;
1752 header[1] = This->datalen;
1753 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1755 IStream_Write(pStm, This->data, This->datalen, &dummy);
1757 hResult = S_OK;
1758 break;
1759 case PICTYPE_BITMAP:
1760 if (This->bIsDirty) {
1761 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1762 case BITMAP_FORMAT_BMP:
1763 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1764 break;
1765 case BITMAP_FORMAT_JPEG:
1766 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1767 break;
1768 case BITMAP_FORMAT_GIF:
1769 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1770 break;
1771 case BITMAP_FORMAT_PNG:
1772 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1773 break;
1774 default:
1775 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1776 break;
1778 if (iSerializeResult) {
1780 if (This->loadtime_magic != 0xdeadbeef) {
1782 if (1) {
1783 DWORD header[2];
1785 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1786 header[1] = iDataSize;
1787 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1789 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1791 HeapFree(GetProcessHeap(), 0, This->data);
1792 This->data = pIconData;
1793 This->datalen = iDataSize;
1794 hResult = S_OK;
1796 } else {
1798 if (This->loadtime_magic != 0xdeadbeef) {
1800 if (1) {
1801 DWORD header[2];
1803 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1804 header[1] = This->datalen;
1805 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1807 IStream_Write(pStm, This->data, This->datalen, &dummy);
1808 hResult = S_OK;
1810 break;
1811 case PICTYPE_METAFILE:
1812 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1813 break;
1814 case PICTYPE_ENHMETAFILE:
1815 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1816 break;
1817 default:
1818 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1819 break;
1821 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1822 return hResult;
1825 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1826 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1828 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1829 FIXME("(%p,%p),stub!\n",This,pcbSize);
1830 return E_NOTIMPL;
1834 /************************************************************************
1835 * IDispatch
1838 /************************************************************************
1839 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1841 * See Windows documentation for more details on IUnknown methods.
1843 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1844 IDispatch* iface,
1845 REFIID riid,
1846 VOID** ppvoid)
1848 OLEPictureImpl *This = impl_from_IDispatch(iface);
1850 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1853 /************************************************************************
1854 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1856 * See Windows documentation for more details on IUnknown methods.
1858 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1859 IDispatch* iface)
1861 OLEPictureImpl *This = impl_from_IDispatch(iface);
1863 return IPicture_AddRef(&This->IPicture_iface);
1866 /************************************************************************
1867 * OLEPictureImpl_IDispatch_Release (IUnknown)
1869 * See Windows documentation for more details on IUnknown methods.
1871 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1872 IDispatch* iface)
1874 OLEPictureImpl *This = impl_from_IDispatch(iface);
1876 return IPicture_Release(&This->IPicture_iface);
1879 /************************************************************************
1880 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1882 * See Windows documentation for more details on IDispatch methods.
1884 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1885 IDispatch* iface,
1886 unsigned int* pctinfo)
1888 TRACE("(%p)\n", pctinfo);
1890 *pctinfo = 1;
1892 return S_OK;
1895 /************************************************************************
1896 * OLEPictureImpl_GetTypeInfo (IDispatch)
1898 * See Windows documentation for more details on IDispatch methods.
1900 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1901 IDispatch* iface,
1902 UINT iTInfo,
1903 LCID lcid,
1904 ITypeInfo** ppTInfo)
1906 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1907 ITypeLib *tl;
1908 HRESULT hres;
1910 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1912 if (iTInfo != 0)
1913 return E_FAIL;
1915 hres = LoadTypeLib(stdole2tlb, &tl);
1916 if (FAILED(hres))
1918 ERR("Could not load stdole2.tlb\n");
1919 return hres;
1922 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1923 if (FAILED(hres))
1924 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1926 return hres;
1929 /************************************************************************
1930 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1932 * See Windows documentation for more details on IDispatch methods.
1934 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1935 IDispatch* iface,
1936 REFIID riid,
1937 LPOLESTR* rgszNames,
1938 UINT cNames,
1939 LCID lcid,
1940 DISPID* rgDispId)
1942 ITypeInfo * pTInfo;
1943 HRESULT hres;
1945 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1946 rgszNames, cNames, (int)lcid, rgDispId);
1948 if (cNames == 0)
1950 return E_INVALIDARG;
1952 else
1954 /* retrieve type information */
1955 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1957 if (FAILED(hres))
1959 ERR("GetTypeInfo failed.\n");
1960 return hres;
1963 /* convert names to DISPIDs */
1964 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1965 ITypeInfo_Release(pTInfo);
1967 return hres;
1971 /************************************************************************
1972 * OLEPictureImpl_Invoke (IDispatch)
1974 * See Windows documentation for more details on IDispatch methods.
1976 static HRESULT WINAPI OLEPictureImpl_Invoke(
1977 IDispatch* iface,
1978 DISPID dispIdMember,
1979 REFIID riid,
1980 LCID lcid,
1981 WORD wFlags,
1982 DISPPARAMS* pDispParams,
1983 VARIANT* pVarResult,
1984 EXCEPINFO* pExepInfo,
1985 UINT* puArgErr)
1987 OLEPictureImpl *This = impl_from_IDispatch(iface);
1989 /* validate parameters */
1991 if (!IsEqualIID(riid, &IID_NULL))
1993 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
1994 return DISP_E_UNKNOWNNAME;
1997 if (!pDispParams)
1999 ERR("null pDispParams not allowed\n");
2000 return DISP_E_PARAMNOTOPTIONAL;
2003 if (wFlags & DISPATCH_PROPERTYGET)
2005 if (pDispParams->cArgs != 0)
2007 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2008 return DISP_E_BADPARAMCOUNT;
2010 if (!pVarResult)
2012 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2013 return DISP_E_PARAMNOTOPTIONAL;
2016 else if (wFlags & DISPATCH_PROPERTYPUT)
2018 if (pDispParams->cArgs != 1)
2020 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2021 return DISP_E_BADPARAMCOUNT;
2025 switch (dispIdMember)
2027 case DISPID_PICT_HANDLE:
2028 if (wFlags & DISPATCH_PROPERTYGET)
2030 TRACE("DISPID_PICT_HANDLE\n");
2031 V_VT(pVarResult) = VT_I4;
2032 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2034 break;
2035 case DISPID_PICT_HPAL:
2036 if (wFlags & DISPATCH_PROPERTYGET)
2038 TRACE("DISPID_PICT_HPAL\n");
2039 V_VT(pVarResult) = VT_I4;
2040 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2042 else if (wFlags & DISPATCH_PROPERTYPUT)
2044 VARIANTARG vararg;
2045 HRESULT hr;
2046 TRACE("DISPID_PICT_HPAL\n");
2048 VariantInit(&vararg);
2049 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2050 if (FAILED(hr))
2051 return hr;
2053 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2055 VariantClear(&vararg);
2056 return hr;
2058 break;
2059 case DISPID_PICT_TYPE:
2060 if (wFlags & DISPATCH_PROPERTYGET)
2062 TRACE("DISPID_PICT_TYPE\n");
2063 V_VT(pVarResult) = VT_I2;
2064 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2066 break;
2067 case DISPID_PICT_WIDTH:
2068 if (wFlags & DISPATCH_PROPERTYGET)
2070 TRACE("DISPID_PICT_WIDTH\n");
2071 V_VT(pVarResult) = VT_I4;
2072 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2074 break;
2075 case DISPID_PICT_HEIGHT:
2076 if (wFlags & DISPATCH_PROPERTYGET)
2078 TRACE("DISPID_PICT_HEIGHT\n");
2079 V_VT(pVarResult) = VT_I4;
2080 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2082 break;
2085 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2086 return DISP_E_MEMBERNOTFOUND;
2090 static const IPictureVtbl OLEPictureImpl_VTable =
2092 OLEPictureImpl_QueryInterface,
2093 OLEPictureImpl_AddRef,
2094 OLEPictureImpl_Release,
2095 OLEPictureImpl_get_Handle,
2096 OLEPictureImpl_get_hPal,
2097 OLEPictureImpl_get_Type,
2098 OLEPictureImpl_get_Width,
2099 OLEPictureImpl_get_Height,
2100 OLEPictureImpl_Render,
2101 OLEPictureImpl_set_hPal,
2102 OLEPictureImpl_get_CurDC,
2103 OLEPictureImpl_SelectPicture,
2104 OLEPictureImpl_get_KeepOriginalFormat,
2105 OLEPictureImpl_put_KeepOriginalFormat,
2106 OLEPictureImpl_PictureChanged,
2107 OLEPictureImpl_SaveAsFile,
2108 OLEPictureImpl_get_Attributes
2111 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2113 OLEPictureImpl_IDispatch_QueryInterface,
2114 OLEPictureImpl_IDispatch_AddRef,
2115 OLEPictureImpl_IDispatch_Release,
2116 OLEPictureImpl_GetTypeInfoCount,
2117 OLEPictureImpl_GetTypeInfo,
2118 OLEPictureImpl_GetIDsOfNames,
2119 OLEPictureImpl_Invoke
2122 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2124 OLEPictureImpl_IPersistStream_QueryInterface,
2125 OLEPictureImpl_IPersistStream_AddRef,
2126 OLEPictureImpl_IPersistStream_Release,
2127 OLEPictureImpl_GetClassID,
2128 OLEPictureImpl_IsDirty,
2129 OLEPictureImpl_Load,
2130 OLEPictureImpl_Save,
2131 OLEPictureImpl_GetSizeMax
2134 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2136 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2137 OLEPictureImpl_IConnectionPointContainer_AddRef,
2138 OLEPictureImpl_IConnectionPointContainer_Release,
2139 OLEPictureImpl_EnumConnectionPoints,
2140 OLEPictureImpl_FindConnectionPoint
2143 /***********************************************************************
2144 * OleCreatePictureIndirect (OLEAUT32.419)
2146 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2147 BOOL Own, void **ppvObj )
2149 OLEPictureImpl* newPict;
2150 HRESULT hr;
2152 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2154 *ppvObj = NULL;
2156 newPict = OLEPictureImpl_Construct(lpPictDesc, Own);
2158 if (newPict == NULL)
2159 return E_OUTOFMEMORY;
2162 * Make sure it supports the interface required by the caller.
2164 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2167 * Release the reference obtained in the constructor. If
2168 * the QueryInterface was unsuccessful, it will free the class.
2170 IPicture_Release(&newPict->IPicture_iface);
2172 return hr;
2176 /***********************************************************************
2177 * OleLoadPicture (OLEAUT32.418)
2179 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2180 REFIID riid, LPVOID *ppvObj )
2182 LPPERSISTSTREAM ps;
2183 IPicture *newpic;
2184 HRESULT hr;
2186 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2187 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2189 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2190 if (hr != S_OK)
2191 return hr;
2192 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2193 if (hr != S_OK) {
2194 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2195 IPicture_Release(newpic);
2196 *ppvObj = NULL;
2197 return hr;
2199 hr = IPersistStream_Load(ps,lpstream);
2200 IPersistStream_Release(ps);
2201 if (FAILED(hr))
2203 ERR("IPersistStream_Load failed\n");
2204 IPicture_Release(newpic);
2205 *ppvObj = NULL;
2206 return hr;
2208 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2209 if (hr != S_OK)
2210 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2211 IPicture_Release(newpic);
2212 return hr;
2215 /***********************************************************************
2216 * OleLoadPictureEx (OLEAUT32.401)
2218 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2219 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2221 LPPERSISTSTREAM ps;
2222 IPicture *newpic;
2223 HRESULT hr;
2225 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2226 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2228 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2229 if (hr != S_OK)
2230 return hr;
2231 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2232 if (hr != S_OK) {
2233 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2234 IPicture_Release(newpic);
2235 *ppvObj = NULL;
2236 return hr;
2238 hr = IPersistStream_Load(ps,lpstream);
2239 IPersistStream_Release(ps);
2240 if (FAILED(hr))
2242 ERR("IPersistStream_Load failed\n");
2243 IPicture_Release(newpic);
2244 *ppvObj = NULL;
2245 return hr;
2247 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2248 if (hr != S_OK)
2249 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2250 IPicture_Release(newpic);
2251 return hr;
2254 /***********************************************************************
2255 * OleLoadPicturePath (OLEAUT32.424)
2257 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2258 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2259 LPVOID *ppvRet )
2261 static const WCHAR file[] = { 'f','i','l','e',':',0 };
2262 IPicture *ipicture;
2263 HANDLE hFile;
2264 DWORD dwFileSize;
2265 HGLOBAL hGlobal = NULL;
2266 DWORD dwBytesRead = 0;
2267 IStream *stream;
2268 BOOL bRead;
2269 IPersistStream *pStream;
2270 HRESULT hRes;
2271 HRESULT init_res;
2272 WCHAR *file_candidate;
2273 WCHAR path_buf[MAX_PATH];
2275 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2276 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2277 debugstr_guid(riid), ppvRet);
2279 if (!szURLorPath || !ppvRet)
2280 return E_INVALIDARG;
2282 *ppvRet = NULL;
2284 /* Convert file URLs to DOS paths. */
2285 if (strncmpW(szURLorPath, file, 5) == 0) {
2286 DWORD size;
2287 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2288 sizeof(path_buf)/sizeof(WCHAR), &size, 0);
2289 if (FAILED(hRes))
2290 return hRes;
2292 file_candidate = path_buf;
2294 else
2295 file_candidate = szURLorPath;
2297 /* Handle candidate DOS paths separately. */
2298 if (file_candidate[1] == ':') {
2299 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2300 0, NULL);
2301 if (hFile == INVALID_HANDLE_VALUE)
2302 return INET_E_RESOURCE_NOT_FOUND;
2304 dwFileSize = GetFileSize(hFile, NULL);
2305 if (dwFileSize != INVALID_FILE_SIZE )
2307 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2308 if ( hGlobal)
2310 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2311 if (!bRead)
2313 GlobalFree(hGlobal);
2314 hGlobal = 0;
2318 CloseHandle(hFile);
2320 if (!hGlobal)
2321 return INET_E_RESOURCE_NOT_FOUND;
2323 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2324 if (FAILED(hRes))
2326 GlobalFree(hGlobal);
2327 return hRes;
2329 } else {
2330 IMoniker *pmnk;
2331 IBindCtx *pbc;
2333 hRes = CreateBindCtx(0, &pbc);
2334 if (SUCCEEDED(hRes))
2336 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2337 if (SUCCEEDED(hRes))
2339 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2340 IMoniker_Release(pmnk);
2342 IBindCtx_Release(pbc);
2344 if (FAILED(hRes))
2345 return hRes;
2348 init_res = CoInitialize(NULL);
2350 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2351 &IID_IPicture, (LPVOID*)&ipicture);
2352 if (SUCCEEDED(hRes)) {
2353 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2355 if (SUCCEEDED(hRes)) {
2356 hRes = IPersistStream_Load(pStream, stream);
2358 if (SUCCEEDED(hRes)) {
2359 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2361 if (FAILED(hRes))
2362 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2364 IPersistStream_Release(pStream);
2366 IPicture_Release(ipicture);
2369 IStream_Release(stream);
2371 if (SUCCEEDED(init_res))
2372 CoUninitialize();
2374 return hRes;
2377 /*******************************************************************************
2378 * StdPic ClassFactory
2380 typedef struct
2382 /* IUnknown fields */
2383 IClassFactory IClassFactory_iface;
2384 LONG ref;
2385 } IClassFactoryImpl;
2387 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2389 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2392 static HRESULT WINAPI
2393 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2394 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2396 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2397 return E_NOINTERFACE;
2400 static ULONG WINAPI
2401 SPCF_AddRef(LPCLASSFACTORY iface) {
2402 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2403 return InterlockedIncrement(&This->ref);
2406 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2407 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2408 /* static class, won't be freed */
2409 return InterlockedDecrement(&This->ref);
2412 static HRESULT WINAPI SPCF_CreateInstance(
2413 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2415 /* Creates an uninitialized picture */
2416 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2420 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2421 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2422 FIXME("(%p)->(%d),stub!\n",This,dolock);
2423 return S_OK;
2426 static const IClassFactoryVtbl SPCF_Vtbl = {
2427 SPCF_QueryInterface,
2428 SPCF_AddRef,
2429 SPCF_Release,
2430 SPCF_CreateInstance,
2431 SPCF_LockServer
2433 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2435 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }