oleaut32/olepicture: No need to check interface pointer in vtable methods.
[wine/multimedia.git] / dlls / oleaut32 / olepicture.c
blob4dd25fb4b62b133ee27d1ce626dd5f81d52e6134
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 "wincodec.h"
64 #include "wine/debug.h"
65 #include "wine/unicode.h"
66 #include "wine/library.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(ole);
70 #include "pshpack1.h"
72 /* Header for Aldus Placable Metafiles - a standard metafile follows */
73 typedef struct _APM_HEADER
75 DWORD key;
76 WORD handle;
77 SHORT left;
78 SHORT top;
79 SHORT right;
80 SHORT bottom;
81 WORD inch;
82 DWORD reserved;
83 WORD checksum;
84 } APM_HEADER;
86 typedef struct {
87 BYTE bWidth;
88 BYTE bHeight;
89 BYTE bColorCount;
90 BYTE bReserved;
91 WORD xHotspot;
92 WORD yHotspot;
93 DWORD dwDIBSize;
94 DWORD dwDIBOffset;
95 } CURSORICONFILEDIRENTRY;
97 typedef struct
99 WORD idReserved;
100 WORD idType;
101 WORD idCount;
102 CURSORICONFILEDIRENTRY idEntries[1];
103 } CURSORICONFILEDIR;
105 #include "poppack.h"
107 /*************************************************************************
108 * Declaration of implementation class
111 typedef struct OLEPictureImpl {
114 * IPicture handles IUnknown
117 const IPictureVtbl *lpVtbl;
118 const IDispatchVtbl *lpvtblIDispatch;
119 const IPersistStreamVtbl *lpvtblIPersistStream;
120 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
122 /* Object reference count */
123 LONG ref;
125 /* We own the object and must destroy it ourselves */
126 BOOL fOwn;
128 /* Picture description */
129 PICTDESC desc;
131 /* These are the pixel size of a bitmap */
132 DWORD origWidth;
133 DWORD origHeight;
135 /* And these are the size of the picture converted into HIMETRIC units */
136 OLE_XSIZE_HIMETRIC himetricWidth;
137 OLE_YSIZE_HIMETRIC himetricHeight;
139 IConnectionPoint *pCP;
141 BOOL keepOrigFormat;
142 HDC hDCCur;
144 /* Bitmap transparency mask */
145 HBITMAP hbmMask;
146 HBITMAP hbmXor;
147 COLORREF rgbTrans;
149 /* data */
150 void* data;
151 int datalen;
152 BOOL bIsDirty; /* Set to TRUE if picture has changed */
153 unsigned int loadtime_magic; /* If a length header was found, saves value */
154 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
155 } OLEPictureImpl;
158 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
161 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
163 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
166 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
168 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
171 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
173 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
177 * Predeclare VTables. They get initialized at the end.
179 static const IPictureVtbl OLEPictureImpl_VTable;
180 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
181 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
182 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
184 /* pixels to HIMETRIC units conversion */
185 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
187 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
190 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
192 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
195 /***********************************************************************
196 * Implementation of the OLEPictureImpl class.
199 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
201 BITMAP bm;
202 HDC hdcRef;
204 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
205 if(GetObjectW(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
206 ERR("GetObject fails\n");
207 return;
209 This->origWidth = bm.bmWidth;
210 This->origHeight = bm.bmHeight;
212 /* 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 = xpixels_to_himetric(bm.bmHeight, hdcRef);
221 DeleteDC(hdcRef);
224 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
226 ICONINFO infoIcon;
228 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
229 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
230 HDC hdcRef;
231 BITMAP bm;
233 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
234 if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
235 ERR("GetObject fails on icon bitmap\n");
236 return;
239 This->origWidth = bm.bmWidth;
240 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
241 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
242 hdcRef = GetDC(0);
244 This->himetricWidth = xpixels_to_himetric(This->origWidth, hdcRef);
245 This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
247 ReleaseDC(0, hdcRef);
249 DeleteObject(infoIcon.hbmMask);
250 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
251 } else {
252 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
256 /************************************************************************
257 * OLEPictureImpl_Construct
259 * This method will construct a new instance of the OLEPictureImpl
260 * class.
262 * The caller of this method must release the object when it's
263 * done with it.
265 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
267 OLEPictureImpl* newObject = 0;
269 if (pictDesc)
270 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
273 * Allocate space for the object.
275 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
277 if (newObject==0)
278 return newObject;
281 * Initialize the virtual function table.
283 newObject->lpVtbl = &OLEPictureImpl_VTable;
284 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
285 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
286 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
288 newObject->pCP = NULL;
289 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
290 if (!newObject->pCP)
292 HeapFree(GetProcessHeap(), 0, newObject);
293 return NULL;
297 * Start with one reference count. The caller of this function
298 * must release the interface pointer when it is done.
300 newObject->ref = 1;
301 newObject->hDCCur = 0;
303 newObject->fOwn = fOwn;
305 /* dunno about original value */
306 newObject->keepOrigFormat = TRUE;
308 newObject->hbmMask = NULL;
309 newObject->hbmXor = NULL;
310 newObject->loadtime_magic = 0xdeadbeef;
311 newObject->loadtime_format = 0;
312 newObject->bIsDirty = FALSE;
314 if (pictDesc) {
315 newObject->desc = *pictDesc;
317 switch(pictDesc->picType) {
318 case PICTYPE_BITMAP:
319 OLEPictureImpl_SetBitmap(newObject);
320 break;
322 case PICTYPE_METAFILE:
323 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
324 newObject->himetricWidth = pictDesc->u.wmf.xExt;
325 newObject->himetricHeight = pictDesc->u.wmf.yExt;
326 break;
328 case PICTYPE_NONE:
329 /* not sure what to do here */
330 newObject->himetricWidth = newObject->himetricHeight = 0;
331 break;
333 case PICTYPE_ICON:
334 OLEPictureImpl_SetIcon(newObject);
335 break;
336 case PICTYPE_ENHMETAFILE:
337 default:
338 FIXME("Unsupported type %d\n", pictDesc->picType);
339 newObject->himetricWidth = newObject->himetricHeight = 0;
340 break;
342 } else {
343 newObject->desc.picType = PICTYPE_UNINITIALIZED;
346 TRACE("returning %p\n", newObject);
347 return newObject;
350 /************************************************************************
351 * OLEPictureImpl_Destroy
353 * This method is called by the Release method when the reference
354 * count goes down to 0. It will free all resources used by
355 * this object. */
356 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
358 TRACE("(%p)\n", Obj);
360 if (Obj->pCP)
361 IConnectionPoint_Release(Obj->pCP);
363 if(Obj->fOwn) { /* We need to destroy the picture */
364 switch(Obj->desc.picType) {
365 case PICTYPE_BITMAP:
366 DeleteObject(Obj->desc.u.bmp.hbitmap);
367 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
368 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
369 break;
370 case PICTYPE_METAFILE:
371 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
372 break;
373 case PICTYPE_ICON:
374 DestroyIcon(Obj->desc.u.icon.hicon);
375 break;
376 case PICTYPE_ENHMETAFILE:
377 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
378 break;
379 case PICTYPE_NONE:
380 case PICTYPE_UNINITIALIZED:
381 /* Nothing to do */
382 break;
383 default:
384 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
385 break;
388 HeapFree(GetProcessHeap(), 0, Obj->data);
389 HeapFree(GetProcessHeap(), 0, Obj);
393 /************************************************************************
394 * OLEPictureImpl_AddRef (IUnknown)
396 * See Windows documentation for more details on IUnknown methods.
398 static ULONG WINAPI OLEPictureImpl_AddRef(
399 IPicture* iface)
401 OLEPictureImpl *This = (OLEPictureImpl *)iface;
402 ULONG refCount = InterlockedIncrement(&This->ref);
404 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
406 return refCount;
409 /************************************************************************
410 * OLEPictureImpl_Release (IUnknown)
412 * See Windows documentation for more details on IUnknown methods.
414 static ULONG WINAPI OLEPictureImpl_Release(
415 IPicture* iface)
417 OLEPictureImpl *This = (OLEPictureImpl *)iface;
418 ULONG refCount = InterlockedDecrement(&This->ref);
420 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
423 * If the reference count goes down to 0, perform suicide.
425 if (!refCount) OLEPictureImpl_Destroy(This);
427 return refCount;
430 /************************************************************************
431 * OLEPictureImpl_QueryInterface (IUnknown)
433 * See Windows documentation for more details on IUnknown methods.
435 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
436 IPicture* iface,
437 REFIID riid,
438 void** ppvObject)
440 OLEPictureImpl *This = (OLEPictureImpl *)iface;
442 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
444 if (!ppvObject)
445 return E_INVALIDARG;
447 *ppvObject = 0;
449 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
450 *ppvObject = This;
451 else if (IsEqualIID(&IID_IDispatch, riid))
452 *ppvObject = &This->lpvtblIDispatch;
453 else if (IsEqualIID(&IID_IPictureDisp, riid))
454 *ppvObject = &This->lpvtblIDispatch;
455 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
456 *ppvObject = &This->lpvtblIPersistStream;
457 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
458 *ppvObject = &This->lpvtblIConnectionPointContainer;
460 if (!*ppvObject)
462 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
463 return E_NOINTERFACE;
466 IPicture_AddRef(iface);
468 return S_OK;
471 /***********************************************************************
472 * OLEPicture_SendNotify (internal)
474 * Sends notification messages of changed properties to any interested
475 * connections.
477 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
479 IEnumConnections *pEnum;
480 CONNECTDATA CD;
482 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
483 return;
484 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
485 IPropertyNotifySink *sink;
487 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
488 IPropertyNotifySink_OnChanged(sink, dispID);
489 IPropertyNotifySink_Release(sink);
490 IUnknown_Release(CD.pUnk);
492 IEnumConnections_Release(pEnum);
495 /************************************************************************
496 * OLEPictureImpl_get_Handle
498 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
499 OLE_HANDLE *phandle)
501 OLEPictureImpl *This = (OLEPictureImpl *)iface;
502 TRACE("(%p)->(%p)\n", This, phandle);
504 if(!phandle)
505 return E_POINTER;
507 switch(This->desc.picType) {
508 case PICTYPE_NONE:
509 case PICTYPE_UNINITIALIZED:
510 *phandle = 0;
511 break;
512 case PICTYPE_BITMAP:
513 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
514 break;
515 case PICTYPE_METAFILE:
516 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
517 break;
518 case PICTYPE_ICON:
519 *phandle = HandleToUlong(This->desc.u.icon.hicon);
520 break;
521 case PICTYPE_ENHMETAFILE:
522 *phandle = HandleToUlong(This->desc.u.emf.hemf);
523 break;
524 default:
525 FIXME("Unimplemented type %d\n", This->desc.picType);
526 return E_NOTIMPL;
528 TRACE("returning handle %08x\n", *phandle);
529 return S_OK;
532 /************************************************************************
533 * OLEPictureImpl_get_hPal
535 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
536 OLE_HANDLE *phandle)
538 OLEPictureImpl *This = (OLEPictureImpl *)iface;
539 HRESULT hres;
540 TRACE("(%p)->(%p)\n", This, phandle);
542 if (!phandle)
543 return E_POINTER;
545 switch (This->desc.picType) {
546 case (UINT)PICTYPE_UNINITIALIZED:
547 case PICTYPE_NONE:
548 *phandle = 0;
549 hres = S_FALSE;
550 break;
551 case PICTYPE_BITMAP:
552 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
553 hres = S_OK;
554 break;
555 case PICTYPE_METAFILE:
556 hres = E_FAIL;
557 break;
558 case PICTYPE_ICON:
559 case PICTYPE_ENHMETAFILE:
560 default:
561 FIXME("unimplemented for type %d. Returning 0 palette.\n",
562 This->desc.picType);
563 *phandle = 0;
564 hres = S_OK;
567 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
568 return hres;
571 /************************************************************************
572 * OLEPictureImpl_get_Type
574 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
575 short *ptype)
577 OLEPictureImpl *This = (OLEPictureImpl *)iface;
578 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
580 if(!ptype)
581 return E_POINTER;
583 *ptype = This->desc.picType;
584 return S_OK;
587 /************************************************************************
588 * OLEPictureImpl_get_Width
590 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
591 OLE_XSIZE_HIMETRIC *pwidth)
593 OLEPictureImpl *This = (OLEPictureImpl *)iface;
594 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
595 *pwidth = This->himetricWidth;
596 return S_OK;
599 /************************************************************************
600 * OLEPictureImpl_get_Height
602 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
603 OLE_YSIZE_HIMETRIC *pheight)
605 OLEPictureImpl *This = (OLEPictureImpl *)iface;
606 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
607 *pheight = This->himetricHeight;
608 return S_OK;
611 /************************************************************************
612 * OLEPictureImpl_Render
614 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
615 LONG x, LONG y, LONG cx, LONG cy,
616 OLE_XPOS_HIMETRIC xSrc,
617 OLE_YPOS_HIMETRIC ySrc,
618 OLE_XSIZE_HIMETRIC cxSrc,
619 OLE_YSIZE_HIMETRIC cySrc,
620 LPCRECT prcWBounds)
622 OLEPictureImpl *This = (OLEPictureImpl *)iface;
623 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
624 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
625 if(prcWBounds)
626 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
627 prcWBounds->right, prcWBounds->bottom);
629 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
630 return CTL_E_INVALIDPROPERTYVALUE;
634 * While the documentation suggests this to be here (or after rendering?)
635 * it does cause an endless recursion in my sample app. -MM 20010804
636 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
639 switch(This->desc.picType) {
640 case PICTYPE_UNINITIALIZED:
641 case PICTYPE_NONE:
642 /* nothing to do */
643 return S_OK;
644 case PICTYPE_BITMAP:
646 HBITMAP hbmpOld;
647 HDC hdcBmp;
649 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
650 NB y-axis gets flipped */
652 hdcBmp = CreateCompatibleDC(0);
653 SetMapMode(hdcBmp, MM_ANISOTROPIC);
654 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
655 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
656 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
657 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
659 if (This->hbmMask) {
660 HDC hdcMask = CreateCompatibleDC(0);
661 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
663 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
665 SetMapMode(hdcMask, MM_ANISOTROPIC);
666 SetWindowOrgEx(hdcMask, 0, 0, NULL);
667 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
668 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
669 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
671 SetBkColor(hdc, RGB(255, 255, 255));
672 SetTextColor(hdc, RGB(0, 0, 0));
673 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
674 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
676 SelectObject(hdcMask, hOldbm);
677 DeleteDC(hdcMask);
678 } else {
679 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
680 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
683 SelectObject(hdcBmp, hbmpOld);
684 DeleteDC(hdcBmp);
686 break;
687 case PICTYPE_ICON:
688 FIXME("Not quite correct implementation of rendering icons...\n");
689 DrawIconEx(hdc, x, y, This->desc.u.icon.hicon, cx, cy, 0, NULL, DI_NORMAL);
690 break;
692 case PICTYPE_METAFILE:
694 POINT prevOrg, prevWndOrg;
695 SIZE prevExt, prevWndExt;
696 int oldmode;
698 /* Render the WMF to the appropriate location by setting the
699 appropriate ratio between "device units" and "logical units" */
700 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
701 /* For the "source rectangle" the y-axis must be inverted */
702 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
703 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
704 /* For the "destination rectangle" no inversion is necessary */
705 SetViewportOrgEx(hdc, x, y, &prevOrg);
706 SetViewportExtEx(hdc, cx, cy, &prevExt);
708 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
709 ERR("PlayMetaFile failed!\n");
711 /* We're done, restore the DC to the previous settings for converting
712 logical units to device units */
713 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
714 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
715 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
716 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
717 SetMapMode(hdc, oldmode);
718 break;
721 case PICTYPE_ENHMETAFILE:
723 RECT rc = { x, y, x + cx, y + cy };
724 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
725 break;
728 default:
729 FIXME("type %d not implemented\n", This->desc.picType);
730 return E_NOTIMPL;
732 return S_OK;
735 /************************************************************************
736 * OLEPictureImpl_set_hPal
738 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
739 OLE_HANDLE hpal)
741 OLEPictureImpl *This = (OLEPictureImpl *)iface;
742 FIXME("(%p)->(%08x): stub\n", This, hpal);
743 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
744 return E_NOTIMPL;
747 /************************************************************************
748 * OLEPictureImpl_get_CurDC
750 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
751 HDC *phdc)
753 OLEPictureImpl *This = (OLEPictureImpl *)iface;
754 TRACE("(%p), returning %p\n", This, This->hDCCur);
755 if (phdc) *phdc = This->hDCCur;
756 return S_OK;
759 /************************************************************************
760 * OLEPictureImpl_SelectPicture
762 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
763 HDC hdcIn,
764 HDC *phdcOut,
765 OLE_HANDLE *phbmpOut)
767 OLEPictureImpl *This = (OLEPictureImpl *)iface;
768 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
769 if (This->desc.picType == PICTYPE_BITMAP) {
770 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
772 if (phdcOut)
773 *phdcOut = This->hDCCur;
774 This->hDCCur = hdcIn;
775 if (phbmpOut)
776 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
777 return S_OK;
778 } else {
779 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
780 return E_FAIL;
784 /************************************************************************
785 * OLEPictureImpl_get_KeepOriginalFormat
787 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
788 BOOL *pfKeep)
790 OLEPictureImpl *This = (OLEPictureImpl *)iface;
791 TRACE("(%p)->(%p)\n", This, pfKeep);
792 if (!pfKeep)
793 return E_POINTER;
794 *pfKeep = This->keepOrigFormat;
795 return S_OK;
798 /************************************************************************
799 * OLEPictureImpl_put_KeepOriginalFormat
801 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
802 BOOL keep)
804 OLEPictureImpl *This = (OLEPictureImpl *)iface;
805 TRACE("(%p)->(%d)\n", This, keep);
806 This->keepOrigFormat = keep;
807 /* FIXME: what DISPID notification here? */
808 return S_OK;
811 /************************************************************************
812 * OLEPictureImpl_PictureChanged
814 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
816 OLEPictureImpl *This = (OLEPictureImpl *)iface;
817 TRACE("(%p)->()\n", This);
818 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
819 This->bIsDirty = TRUE;
820 return S_OK;
823 /************************************************************************
824 * OLEPictureImpl_SaveAsFile
826 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
827 IStream *pstream,
828 BOOL SaveMemCopy,
829 LONG *pcbSize)
831 OLEPictureImpl *This = (OLEPictureImpl *)iface;
832 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
833 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
836 /************************************************************************
837 * OLEPictureImpl_get_Attributes
839 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
840 DWORD *pdwAttr)
842 OLEPictureImpl *This = (OLEPictureImpl *)iface;
843 TRACE("(%p)->(%p).\n", This, pdwAttr);
845 if(!pdwAttr)
846 return E_POINTER;
848 *pdwAttr = 0;
849 switch (This->desc.picType) {
850 case PICTYPE_UNINITIALIZED:
851 case PICTYPE_NONE: break;
852 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
853 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
854 case PICTYPE_ENHMETAFILE: /* fall through */
855 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
856 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
858 return S_OK;
862 /************************************************************************
863 * IConnectionPointContainer
865 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
866 IConnectionPointContainer* iface,
867 REFIID riid,
868 VOID** ppvoid)
870 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
872 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
875 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
876 IConnectionPointContainer* iface)
878 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
880 return IPicture_AddRef((IPicture *)This);
883 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
884 IConnectionPointContainer* iface)
886 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
888 return IPicture_Release((IPicture *)This);
891 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
892 IConnectionPointContainer* iface,
893 IEnumConnectionPoints** ppEnum)
895 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
897 FIXME("(%p,%p), stub!\n",This,ppEnum);
898 return E_NOTIMPL;
901 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
902 IConnectionPointContainer* iface,
903 REFIID riid,
904 IConnectionPoint **ppCP)
906 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
907 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
908 if (!ppCP)
909 return E_POINTER;
910 *ppCP = NULL;
911 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
912 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
913 FIXME("no connection point for %s\n",debugstr_guid(riid));
914 return CONNECT_E_NOCONNECTION;
918 /************************************************************************
919 * IPersistStream
922 /************************************************************************
923 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
925 * See Windows documentation for more details on IUnknown methods.
927 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
928 IPersistStream* iface,
929 REFIID riid,
930 VOID** ppvoid)
932 OLEPictureImpl *This = impl_from_IPersistStream(iface);
934 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
937 /************************************************************************
938 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
940 * See Windows documentation for more details on IUnknown methods.
942 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
943 IPersistStream* iface)
945 OLEPictureImpl *This = impl_from_IPersistStream(iface);
947 return IPicture_AddRef((IPicture *)This);
950 /************************************************************************
951 * OLEPictureImpl_IPersistStream_Release (IUnknown)
953 * See Windows documentation for more details on IUnknown methods.
955 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
956 IPersistStream* iface)
958 OLEPictureImpl *This = impl_from_IPersistStream(iface);
960 return IPicture_Release((IPicture *)This);
963 /************************************************************************
964 * OLEPictureImpl_IPersistStream_GetClassID
966 static HRESULT WINAPI OLEPictureImpl_GetClassID(
967 IPersistStream* iface,CLSID* pClassID)
969 TRACE("(%p)\n", pClassID);
970 *pClassID = CLSID_StdPicture;
971 return S_OK;
974 /************************************************************************
975 * OLEPictureImpl_IPersistStream_IsDirty
977 static HRESULT WINAPI OLEPictureImpl_IsDirty(
978 IPersistStream* iface)
980 OLEPictureImpl *This = impl_from_IPersistStream(iface);
981 FIXME("(%p),stub!\n",This);
982 return E_NOTIMPL;
985 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
987 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
988 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
989 HDC hdcref;
991 /* Does not matter whether this is a coreheader or not, we only use
992 * components which are in both
994 hdcref = GetDC(0);
995 This->desc.u.bmp.hbitmap = CreateDIBitmap(
996 hdcref,
997 &(bi->bmiHeader),
998 CBM_INIT,
999 xbuf+bfh->bfOffBits,
1001 DIB_RGB_COLORS
1003 ReleaseDC(0, hdcref);
1004 if (This->desc.u.bmp.hbitmap == 0)
1005 return E_FAIL;
1006 This->desc.picType = PICTYPE_BITMAP;
1007 OLEPictureImpl_SetBitmap(This);
1008 return S_OK;
1011 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1013 HRESULT hr;
1014 BITMAPINFOHEADER bih;
1015 HDC hdcref;
1016 UINT width, height;
1017 UINT stride, buffersize;
1018 LPBYTE bits=NULL;
1019 WICRect rc;
1020 IWICBitmapSource *real_source;
1021 UINT x, y;
1022 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1023 BOOL has_alpha=FALSE;
1025 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1026 if (FAILED(hr)) return hr;
1028 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1029 if (FAILED(hr)) goto end;
1031 bih.biSize = sizeof(bih);
1032 bih.biWidth = width;
1033 bih.biHeight = -height;
1034 bih.biPlanes = 1;
1035 bih.biBitCount = 32;
1036 bih.biCompression = BI_RGB;
1037 bih.biSizeImage = 0;
1038 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1039 bih.biYPelsPerMeter = 4085;
1040 bih.biClrUsed = 0;
1041 bih.biClrImportant = 0;
1043 stride = 4 * width;
1044 buffersize = stride * height;
1046 bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1047 if (!bits)
1049 hr = E_OUTOFMEMORY;
1050 goto end;
1053 rc.X = 0;
1054 rc.Y = 0;
1055 rc.Width = width;
1056 rc.Height = height;
1057 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1058 if (FAILED(hr))
1059 goto end;
1061 hdcref = GetDC(0);
1062 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1063 hdcref,
1064 &bih,
1065 CBM_INIT,
1066 bits,
1067 (BITMAPINFO*)&bih,
1068 DIB_RGB_COLORS);
1070 if (This->desc.u.bmp.hbitmap == 0)
1072 hr = E_FAIL;
1073 ReleaseDC(0, hdcref);
1074 goto end;
1077 This->desc.picType = PICTYPE_BITMAP;
1078 OLEPictureImpl_SetBitmap(This);
1080 /* set transparent pixels to black, all others to white */
1081 for(y = 0; y < height; y++){
1082 for(x = 0; x < width; x++){
1083 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1084 if((*pixel & 0x80000000) == 0)
1086 has_alpha = TRUE;
1087 *pixel = black;
1089 else
1090 *pixel = white;
1094 if (has_alpha)
1096 HDC hdcBmp, hdcXor, hdcMask;
1097 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1099 This->hbmXor = CreateDIBitmap(
1100 hdcref,
1101 &bih,
1102 CBM_INIT,
1103 bits,
1104 (BITMAPINFO*)&bih,
1105 DIB_RGB_COLORS
1108 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1109 hdcBmp = CreateCompatibleDC(NULL);
1110 hdcXor = CreateCompatibleDC(NULL);
1111 hdcMask = CreateCompatibleDC(NULL);
1113 hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1114 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1115 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1117 SetBkColor(hdcXor,black);
1118 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1119 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1121 SelectObject(hdcBmp,hbmoldBmp);
1122 SelectObject(hdcXor,hbmoldXor);
1123 SelectObject(hdcMask,hbmoldMask);
1125 DeleteDC(hdcBmp);
1126 DeleteDC(hdcXor);
1127 DeleteDC(hdcMask);
1130 ReleaseDC(0, hdcref);
1132 end:
1133 HeapFree(GetProcessHeap(), 0, bits);
1134 IWICBitmapSource_Release(real_source);
1135 return hr;
1138 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1140 HRESULT hr;
1141 IWICImagingFactory *factory;
1142 IWICBitmapDecoder *decoder;
1143 IWICBitmapFrameDecode *framedecode;
1144 HRESULT initresult;
1145 IWICStream *stream;
1147 initresult = CoInitialize(NULL);
1149 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1150 &IID_IWICImagingFactory, (void**)&factory);
1151 if (SUCCEEDED(hr)) /* created factory */
1153 hr = IWICImagingFactory_CreateStream(factory, &stream);
1154 IWICImagingFactory_Release(factory);
1157 if (SUCCEEDED(hr)) /* created stream */
1159 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1161 if (SUCCEEDED(hr)) /* initialized stream */
1163 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1164 &IID_IWICBitmapDecoder, (void**)&decoder);
1165 if (SUCCEEDED(hr)) /* created decoder */
1167 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1169 if (SUCCEEDED(hr)) /* initialized decoder */
1170 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1172 IWICBitmapDecoder_Release(decoder);
1176 IWICStream_Release(stream);
1179 if (SUCCEEDED(hr)) /* got framedecode */
1181 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1182 IWICBitmapFrameDecode_Release(framedecode);
1185 if (SUCCEEDED(initresult)) CoUninitialize();
1186 return hr;
1189 /*****************************************************
1190 * start of Icon-specific code
1193 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1195 HICON hicon;
1196 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1197 HDC hdcRef;
1198 int i;
1201 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1202 FIXME("icon.idType=%d\n",cifd->idType);
1203 FIXME("icon.idCount=%d\n",cifd->idCount);
1205 for (i=0;i<cifd->idCount;i++) {
1206 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1207 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1208 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1209 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1210 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1211 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1212 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1213 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1216 i=0;
1217 /* If we have more than one icon, try to find the best.
1218 * this currently means '32 pixel wide'.
1220 if (cifd->idCount!=1) {
1221 for (i=0;i<cifd->idCount;i++) {
1222 if (cifd->idEntries[i].bWidth == 32)
1223 break;
1225 if (i==cifd->idCount) i=0;
1228 hicon = CreateIconFromResourceEx(
1229 xbuf+cifd->idEntries[i].dwDIBOffset,
1230 cifd->idEntries[i].dwDIBSize,
1231 TRUE, /* is icon */
1232 0x00030000,
1233 cifd->idEntries[i].bWidth,
1234 cifd->idEntries[i].bHeight,
1237 if (!hicon) {
1238 ERR("CreateIcon failed.\n");
1239 return E_FAIL;
1240 } else {
1241 This->desc.picType = PICTYPE_ICON;
1242 This->desc.u.icon.hicon = hicon;
1243 This->origWidth = cifd->idEntries[i].bWidth;
1244 This->origHeight = cifd->idEntries[i].bHeight;
1245 hdcRef = CreateCompatibleDC(0);
1246 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1247 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1248 DeleteDC(hdcRef);
1249 return S_OK;
1253 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1254 const BYTE *data, ULONG size)
1256 HENHMETAFILE hemf;
1257 ENHMETAHEADER hdr;
1259 hemf = SetEnhMetaFileBits(size, data);
1260 if (!hemf) return E_FAIL;
1262 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1264 This->desc.picType = PICTYPE_ENHMETAFILE;
1265 This->desc.u.emf.hemf = hemf;
1267 This->origWidth = 0;
1268 This->origHeight = 0;
1269 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1270 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1272 return S_OK;
1275 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1276 const BYTE *data, ULONG size)
1278 const APM_HEADER *header = (const APM_HEADER *)data;
1279 HMETAFILE hmf;
1281 if (size < sizeof(APM_HEADER))
1282 return E_FAIL;
1283 if (header->key != 0x9ac6cdd7)
1284 return E_FAIL;
1286 /* SetMetaFileBitsEx performs data check on its own */
1287 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1288 if (!hmf) return E_FAIL;
1290 This->desc.picType = PICTYPE_METAFILE;
1291 This->desc.u.wmf.hmeta = hmf;
1292 This->desc.u.wmf.xExt = 0;
1293 This->desc.u.wmf.yExt = 0;
1295 This->origWidth = 0;
1296 This->origHeight = 0;
1297 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1298 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1299 return S_OK;
1302 /************************************************************************
1303 * BITMAP FORMAT FLAGS -
1304 * Flags that differentiate between different types of bitmaps.
1307 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1308 #define BITMAP_FORMAT_JPEG 0xd8ff
1309 #define BITMAP_FORMAT_GIF 0x4947
1310 #define BITMAP_FORMAT_PNG 0x5089
1311 #define BITMAP_FORMAT_APM 0xcdd7
1313 /************************************************************************
1314 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1316 * Loads the binary data from the IStream. Starts at current position.
1317 * There appears to be an 2 DWORD header:
1318 * DWORD magic;
1319 * DWORD len;
1321 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1323 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1324 HRESULT hr;
1325 BOOL headerisdata;
1326 BOOL statfailed = FALSE;
1327 ULONG xread, toread;
1328 ULONG headerread;
1329 BYTE *xbuf;
1330 DWORD header[2];
1331 WORD magic;
1332 STATSTG statstg;
1333 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1335 TRACE("(%p,%p)\n",This,pStm);
1337 /****************************************************************************************
1338 * Part 1: Load the data
1340 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1341 * out whether we do.
1343 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1344 * compound file. This may explain most, if not all, of the cases of "no
1345 * header", and the header validation should take this into account.
1346 * At least in Visual Basic 6, resource streams, valid headers are
1347 * header[0] == "lt\0\0",
1348 * header[1] == length_of_stream.
1350 * Also handle streams where we do not have a working "Stat" method by
1351 * reading all data until the end of the stream.
1353 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1354 if (hr != S_OK) {
1355 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1356 statfailed = TRUE;
1357 /* we will read at least 8 byte ... just right below */
1358 statstg.cbSize.QuadPart = 8;
1361 toread = 0;
1362 headerread = 0;
1363 headerisdata = FALSE;
1364 do {
1365 hr = IStream_Read(pStm, header, 8, &xread);
1366 if (hr != S_OK || xread!=8) {
1367 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1368 return (hr?hr:E_FAIL);
1370 headerread += xread;
1371 xread = 0;
1373 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1374 if (toread != 0 && toread != header[1])
1375 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1376 toread, header[1]);
1377 toread = header[1];
1378 if (toread == 0) break;
1379 } else {
1380 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1381 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1382 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1383 (header[0] == EMR_HEADER) || /* EMF header */
1384 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1385 (header[1]==0)
1386 ) {/* Found start of bitmap data */
1387 headerisdata = TRUE;
1388 if (toread == 0)
1389 toread = statstg.cbSize.QuadPart-8;
1390 else toread -= 8;
1391 xread = 8;
1392 } else {
1393 FIXME("Unknown stream header magic: %08x\n", header[0]);
1394 toread = header[1];
1397 } while (!headerisdata);
1399 if (statfailed) { /* we don't know the size ... read all we get */
1400 int sizeinc = 4096;
1401 int origsize = sizeinc;
1402 ULONG nread = 42;
1404 TRACE("Reading all data from stream.\n");
1405 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1406 if (headerisdata)
1407 memcpy (xbuf, header, 8);
1408 while (1) {
1409 while (xread < origsize) {
1410 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1411 xread += nread;
1412 if (hr != S_OK || !nread)
1413 break;
1415 if (!nread || hr != S_OK) /* done, or error */
1416 break;
1417 if (xread == origsize) {
1418 origsize += sizeinc;
1419 sizeinc = 2*sizeinc; /* exponential increase */
1420 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1423 if (hr != S_OK)
1424 TRACE("hr in no-stat loader case is %08x\n", hr);
1425 TRACE("loaded %d bytes.\n", xread);
1426 This->datalen = xread;
1427 This->data = xbuf;
1428 } else {
1429 This->datalen = toread+(headerisdata?8:0);
1430 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1431 if (!xbuf)
1432 return E_OUTOFMEMORY;
1434 if (headerisdata)
1435 memcpy (xbuf, header, 8);
1437 while (xread < This->datalen) {
1438 ULONG nread;
1439 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1440 xread += nread;
1441 if (hr != S_OK || !nread)
1442 break;
1444 if (xread != This->datalen)
1445 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1447 if (This->datalen == 0) { /* Marks the "NONE" picture */
1448 This->desc.picType = PICTYPE_NONE;
1449 return S_OK;
1453 /****************************************************************************************
1454 * Part 2: Process the loaded data
1457 magic = xbuf[0] + (xbuf[1]<<8);
1458 This->loadtime_format = magic;
1460 switch (magic) {
1461 case BITMAP_FORMAT_GIF: /* GIF */
1462 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1463 break;
1464 case BITMAP_FORMAT_JPEG: /* JPEG */
1465 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1466 break;
1467 case BITMAP_FORMAT_BMP: /* Bitmap */
1468 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1469 break;
1470 case BITMAP_FORMAT_PNG: /* PNG */
1471 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1472 break;
1473 case BITMAP_FORMAT_APM: /* APM */
1474 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1475 break;
1476 case 0x0000: { /* ICON , first word is dwReserved */
1477 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1478 break;
1480 default:
1482 unsigned int i;
1484 /* let's see if it's a EMF */
1485 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1486 if (hr == S_OK) break;
1488 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1489 hr=E_FAIL;
1490 for (i=0;i<xread+8;i++) {
1491 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1492 else MESSAGE("%02x ",xbuf[i-8]);
1493 if (i % 10 == 9) MESSAGE("\n");
1495 MESSAGE("\n");
1496 break;
1499 This->bIsDirty = FALSE;
1501 /* FIXME: this notify is not really documented */
1502 if (hr==S_OK)
1503 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1504 return hr;
1507 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1509 int iSuccess = 0;
1510 HDC hDC;
1511 BITMAPINFO * pInfoBitmap;
1512 int iNumPaletteEntries;
1513 unsigned char * pPixelData;
1514 BITMAPFILEHEADER * pFileHeader;
1515 BITMAPINFO * pInfoHeader;
1517 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1518 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1520 /* Find out bitmap size and padded length */
1521 hDC = GetDC(0);
1522 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1523 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1525 /* Fetch bitmap palette & pixel data */
1527 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1528 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1530 /* Calculate the total length required for the BMP data */
1531 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1532 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1533 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1534 } else {
1535 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1536 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1537 else
1538 iNumPaletteEntries = 0;
1540 *pLength =
1541 sizeof(BITMAPFILEHEADER) +
1542 sizeof(BITMAPINFOHEADER) +
1543 iNumPaletteEntries * sizeof(RGBQUAD) +
1544 pInfoBitmap->bmiHeader.biSizeImage;
1545 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1547 /* Fill the BITMAPFILEHEADER */
1548 pFileHeader = *ppBuffer;
1549 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1550 pFileHeader->bfSize = *pLength;
1551 pFileHeader->bfOffBits =
1552 sizeof(BITMAPFILEHEADER) +
1553 sizeof(BITMAPINFOHEADER) +
1554 iNumPaletteEntries * sizeof(RGBQUAD);
1556 /* Fill the BITMAPINFOHEADER and the palette data */
1557 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1558 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1559 memcpy(
1560 (unsigned char *)(*ppBuffer) +
1561 sizeof(BITMAPFILEHEADER) +
1562 sizeof(BITMAPINFOHEADER) +
1563 iNumPaletteEntries * sizeof(RGBQUAD),
1564 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1565 iSuccess = 1;
1567 HeapFree(GetProcessHeap(), 0, pPixelData);
1568 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1569 return iSuccess;
1572 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1574 ICONINFO infoIcon;
1575 int iSuccess = 0;
1577 *ppBuffer = NULL; *pLength = 0;
1578 if (GetIconInfo(hIcon, &infoIcon)) {
1579 HDC hDC;
1580 BITMAPINFO * pInfoBitmap;
1581 unsigned char * pIconData = NULL;
1582 unsigned int iDataSize = 0;
1584 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1586 /* Find out icon size */
1587 hDC = GetDC(0);
1588 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1589 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1590 if (1) {
1591 /* Auxiliary pointers */
1592 CURSORICONFILEDIR * pIconDir;
1593 CURSORICONFILEDIRENTRY * pIconEntry;
1594 BITMAPINFOHEADER * pIconBitmapHeader;
1595 unsigned int iOffsetPalette;
1596 unsigned int iOffsetColorData;
1597 unsigned int iOffsetMaskData;
1599 unsigned int iLengthScanLineMask;
1600 unsigned int iNumEntriesPalette;
1602 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1604 FIXME("DEBUG: bitmap size is %d x %d\n",
1605 pInfoBitmap->bmiHeader.biWidth,
1606 pInfoBitmap->bmiHeader.biHeight);
1607 FIXME("DEBUG: bitmap bpp is %d\n",
1608 pInfoBitmap->bmiHeader.biBitCount);
1609 FIXME("DEBUG: bitmap nplanes is %d\n",
1610 pInfoBitmap->bmiHeader.biPlanes);
1611 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1612 pInfoBitmap->bmiHeader.biSizeImage);
1614 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1615 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1616 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1618 /* Fill out the CURSORICONFILEDIR */
1619 pIconDir = (CURSORICONFILEDIR *)pIconData;
1620 pIconDir->idType = 1;
1621 pIconDir->idCount = 1;
1623 /* Fill out the CURSORICONFILEDIRENTRY */
1624 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1625 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1626 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1627 pIconEntry->bColorCount =
1628 (pInfoBitmap->bmiHeader.biBitCount < 8)
1629 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1630 : 0;
1631 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1632 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1633 pIconEntry->dwDIBSize = 0;
1634 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1636 /* Fill out the BITMAPINFOHEADER */
1637 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1638 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1640 /* Find out whether a palette exists for the bitmap */
1641 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1642 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1643 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1644 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1645 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1646 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1647 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1648 iNumEntriesPalette = 3;
1649 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1650 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1651 } else {
1652 iNumEntriesPalette = 0;
1655 /* Add bitmap size and header size to icon data size. */
1656 iOffsetPalette = iDataSize;
1657 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1658 iOffsetColorData = iDataSize;
1659 iDataSize += pIconBitmapHeader->biSizeImage;
1660 iOffsetMaskData = iDataSize;
1661 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1662 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1663 pIconBitmapHeader->biHeight *= 2;
1664 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1665 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1666 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1667 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1669 /* Get the actual bitmap data from the icon bitmap */
1670 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1671 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1672 if (iNumEntriesPalette > 0) {
1673 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1674 iNumEntriesPalette * sizeof(RGBQUAD));
1677 /* Reset all values so that GetDIBits call succeeds */
1678 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1679 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1680 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1682 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1683 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1684 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1686 printf("ERROR: unable to get bitmap mask (error %u)\n",
1687 GetLastError());
1691 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1692 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1694 /* Write out everything produced so far to the stream */
1695 *ppBuffer = pIconData; *pLength = iDataSize;
1696 iSuccess = 1;
1697 } else {
1699 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1700 GetLastError());
1704 Remarks (from MSDN entry on GetIconInfo):
1706 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1707 members of ICONINFO. The calling application must manage
1708 these bitmaps and delete them when they are no longer
1709 necessary.
1711 if (hDC) ReleaseDC(0, hDC);
1712 DeleteObject(infoIcon.hbmMask);
1713 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1714 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1715 } else {
1716 printf("ERROR: Unable to get icon information (error %u)\n",
1717 GetLastError());
1719 return iSuccess;
1722 static HRESULT WINAPI OLEPictureImpl_Save(
1723 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1725 HRESULT hResult = E_NOTIMPL;
1726 void * pIconData;
1727 unsigned int iDataSize;
1728 ULONG dummy;
1729 int iSerializeResult = 0;
1730 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1732 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1734 switch (This->desc.picType) {
1735 case PICTYPE_ICON:
1736 if (This->bIsDirty || !This->data) {
1737 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1738 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1739 hResult = E_FAIL;
1740 break;
1742 HeapFree(GetProcessHeap(), 0, This->data);
1743 This->data = pIconData;
1744 This->datalen = iDataSize;
1746 if (This->loadtime_magic != 0xdeadbeef) {
1747 DWORD header[2];
1749 header[0] = This->loadtime_magic;
1750 header[1] = This->datalen;
1751 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1753 IStream_Write(pStm, This->data, This->datalen, &dummy);
1755 hResult = S_OK;
1756 break;
1757 case PICTYPE_BITMAP:
1758 if (This->bIsDirty) {
1759 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1760 case BITMAP_FORMAT_BMP:
1761 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1762 break;
1763 case BITMAP_FORMAT_JPEG:
1764 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1765 break;
1766 case BITMAP_FORMAT_GIF:
1767 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1768 break;
1769 case BITMAP_FORMAT_PNG:
1770 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1771 break;
1772 default:
1773 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1774 break;
1776 if (iSerializeResult) {
1778 if (This->loadtime_magic != 0xdeadbeef) {
1780 if (1) {
1781 DWORD header[2];
1783 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1784 header[1] = iDataSize;
1785 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1787 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1789 HeapFree(GetProcessHeap(), 0, This->data);
1790 This->data = pIconData;
1791 This->datalen = iDataSize;
1792 hResult = S_OK;
1794 } else {
1796 if (This->loadtime_magic != 0xdeadbeef) {
1798 if (1) {
1799 DWORD header[2];
1801 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1802 header[1] = This->datalen;
1803 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1805 IStream_Write(pStm, This->data, This->datalen, &dummy);
1806 hResult = S_OK;
1808 break;
1809 case PICTYPE_METAFILE:
1810 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1811 break;
1812 case PICTYPE_ENHMETAFILE:
1813 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1814 break;
1815 default:
1816 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1817 break;
1819 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1820 return hResult;
1823 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1824 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1826 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1827 FIXME("(%p,%p),stub!\n",This,pcbSize);
1828 return E_NOTIMPL;
1832 /************************************************************************
1833 * IDispatch
1836 /************************************************************************
1837 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1839 * See Windows documentation for more details on IUnknown methods.
1841 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1842 IDispatch* iface,
1843 REFIID riid,
1844 VOID** ppvoid)
1846 OLEPictureImpl *This = impl_from_IDispatch(iface);
1848 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
1851 /************************************************************************
1852 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1854 * See Windows documentation for more details on IUnknown methods.
1856 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1857 IDispatch* iface)
1859 OLEPictureImpl *This = impl_from_IDispatch(iface);
1861 return IPicture_AddRef((IPicture *)This);
1864 /************************************************************************
1865 * OLEPictureImpl_IDispatch_Release (IUnknown)
1867 * See Windows documentation for more details on IUnknown methods.
1869 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1870 IDispatch* iface)
1872 OLEPictureImpl *This = impl_from_IDispatch(iface);
1874 return IPicture_Release((IPicture *)This);
1877 /************************************************************************
1878 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1880 * See Windows documentation for more details on IDispatch methods.
1882 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1883 IDispatch* iface,
1884 unsigned int* pctinfo)
1886 TRACE("(%p)\n", pctinfo);
1888 *pctinfo = 1;
1890 return S_OK;
1893 /************************************************************************
1894 * OLEPictureImpl_GetTypeInfo (IDispatch)
1896 * See Windows documentation for more details on IDispatch methods.
1898 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1899 IDispatch* iface,
1900 UINT iTInfo,
1901 LCID lcid,
1902 ITypeInfo** ppTInfo)
1904 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1905 ITypeLib *tl;
1906 HRESULT hres;
1908 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1910 if (iTInfo != 0)
1911 return E_FAIL;
1913 hres = LoadTypeLib(stdole2tlb, &tl);
1914 if (FAILED(hres))
1916 ERR("Could not load stdole2.tlb\n");
1917 return hres;
1920 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1921 if (FAILED(hres))
1922 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1924 return hres;
1927 /************************************************************************
1928 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1930 * See Windows documentation for more details on IDispatch methods.
1932 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1933 IDispatch* iface,
1934 REFIID riid,
1935 LPOLESTR* rgszNames,
1936 UINT cNames,
1937 LCID lcid,
1938 DISPID* rgDispId)
1940 ITypeInfo * pTInfo;
1941 HRESULT hres;
1943 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1944 rgszNames, cNames, (int)lcid, rgDispId);
1946 if (cNames == 0)
1948 return E_INVALIDARG;
1950 else
1952 /* retrieve type information */
1953 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1955 if (FAILED(hres))
1957 ERR("GetTypeInfo failed.\n");
1958 return hres;
1961 /* convert names to DISPIDs */
1962 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1963 ITypeInfo_Release(pTInfo);
1965 return hres;
1969 /************************************************************************
1970 * OLEPictureImpl_Invoke (IDispatch)
1972 * See Windows documentation for more details on IDispatch methods.
1974 static HRESULT WINAPI OLEPictureImpl_Invoke(
1975 IDispatch* iface,
1976 DISPID dispIdMember,
1977 REFIID riid,
1978 LCID lcid,
1979 WORD wFlags,
1980 DISPPARAMS* pDispParams,
1981 VARIANT* pVarResult,
1982 EXCEPINFO* pExepInfo,
1983 UINT* puArgErr)
1985 OLEPictureImpl *This = impl_from_IDispatch(iface);
1987 /* validate parameters */
1989 if (!IsEqualIID(riid, &IID_NULL))
1991 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
1992 return DISP_E_UNKNOWNNAME;
1995 if (!pDispParams)
1997 ERR("null pDispParams not allowed\n");
1998 return DISP_E_PARAMNOTOPTIONAL;
2001 if (wFlags & DISPATCH_PROPERTYGET)
2003 if (pDispParams->cArgs != 0)
2005 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2006 return DISP_E_BADPARAMCOUNT;
2008 if (!pVarResult)
2010 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2011 return DISP_E_PARAMNOTOPTIONAL;
2014 else if (wFlags & DISPATCH_PROPERTYPUT)
2016 if (pDispParams->cArgs != 1)
2018 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2019 return DISP_E_BADPARAMCOUNT;
2023 switch (dispIdMember)
2025 case DISPID_PICT_HANDLE:
2026 if (wFlags & DISPATCH_PROPERTYGET)
2028 TRACE("DISPID_PICT_HANDLE\n");
2029 V_VT(pVarResult) = VT_I4;
2030 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2032 break;
2033 case DISPID_PICT_HPAL:
2034 if (wFlags & DISPATCH_PROPERTYGET)
2036 TRACE("DISPID_PICT_HPAL\n");
2037 V_VT(pVarResult) = VT_I4;
2038 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2040 else if (wFlags & DISPATCH_PROPERTYPUT)
2042 VARIANTARG vararg;
2043 HRESULT hr;
2044 TRACE("DISPID_PICT_HPAL\n");
2046 VariantInit(&vararg);
2047 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2048 if (FAILED(hr))
2049 return hr;
2051 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2053 VariantClear(&vararg);
2054 return hr;
2056 break;
2057 case DISPID_PICT_TYPE:
2058 if (wFlags & DISPATCH_PROPERTYGET)
2060 TRACE("DISPID_PICT_TYPE\n");
2061 V_VT(pVarResult) = VT_I2;
2062 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2064 break;
2065 case DISPID_PICT_WIDTH:
2066 if (wFlags & DISPATCH_PROPERTYGET)
2068 TRACE("DISPID_PICT_WIDTH\n");
2069 V_VT(pVarResult) = VT_I4;
2070 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2072 break;
2073 case DISPID_PICT_HEIGHT:
2074 if (wFlags & DISPATCH_PROPERTYGET)
2076 TRACE("DISPID_PICT_HEIGHT\n");
2077 V_VT(pVarResult) = VT_I4;
2078 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2080 break;
2083 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2084 return DISP_E_MEMBERNOTFOUND;
2088 static const IPictureVtbl OLEPictureImpl_VTable =
2090 OLEPictureImpl_QueryInterface,
2091 OLEPictureImpl_AddRef,
2092 OLEPictureImpl_Release,
2093 OLEPictureImpl_get_Handle,
2094 OLEPictureImpl_get_hPal,
2095 OLEPictureImpl_get_Type,
2096 OLEPictureImpl_get_Width,
2097 OLEPictureImpl_get_Height,
2098 OLEPictureImpl_Render,
2099 OLEPictureImpl_set_hPal,
2100 OLEPictureImpl_get_CurDC,
2101 OLEPictureImpl_SelectPicture,
2102 OLEPictureImpl_get_KeepOriginalFormat,
2103 OLEPictureImpl_put_KeepOriginalFormat,
2104 OLEPictureImpl_PictureChanged,
2105 OLEPictureImpl_SaveAsFile,
2106 OLEPictureImpl_get_Attributes
2109 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2111 OLEPictureImpl_IDispatch_QueryInterface,
2112 OLEPictureImpl_IDispatch_AddRef,
2113 OLEPictureImpl_IDispatch_Release,
2114 OLEPictureImpl_GetTypeInfoCount,
2115 OLEPictureImpl_GetTypeInfo,
2116 OLEPictureImpl_GetIDsOfNames,
2117 OLEPictureImpl_Invoke
2120 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2122 OLEPictureImpl_IPersistStream_QueryInterface,
2123 OLEPictureImpl_IPersistStream_AddRef,
2124 OLEPictureImpl_IPersistStream_Release,
2125 OLEPictureImpl_GetClassID,
2126 OLEPictureImpl_IsDirty,
2127 OLEPictureImpl_Load,
2128 OLEPictureImpl_Save,
2129 OLEPictureImpl_GetSizeMax
2132 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2134 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2135 OLEPictureImpl_IConnectionPointContainer_AddRef,
2136 OLEPictureImpl_IConnectionPointContainer_Release,
2137 OLEPictureImpl_EnumConnectionPoints,
2138 OLEPictureImpl_FindConnectionPoint
2141 /***********************************************************************
2142 * OleCreatePictureIndirect (OLEAUT32.419)
2144 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2145 BOOL fOwn, LPVOID *ppvObj )
2147 OLEPictureImpl* newPict;
2148 HRESULT hr;
2150 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2153 * Sanity check
2155 if (ppvObj==0)
2156 return E_POINTER;
2158 *ppvObj = NULL;
2161 * Try to construct a new instance of the class.
2163 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2165 if (newPict == NULL)
2166 return E_OUTOFMEMORY;
2169 * Make sure it supports the interface required by the caller.
2171 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2174 * Release the reference obtained in the constructor. If
2175 * the QueryInterface was unsuccessful, it will free the class.
2177 IPicture_Release((IPicture*)newPict);
2179 return hr;
2183 /***********************************************************************
2184 * OleLoadPicture (OLEAUT32.418)
2186 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2187 REFIID riid, LPVOID *ppvObj )
2189 LPPERSISTSTREAM ps;
2190 IPicture *newpic;
2191 HRESULT hr;
2193 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2194 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2196 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2197 if (hr != S_OK)
2198 return hr;
2199 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2200 if (hr != S_OK) {
2201 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2202 IPicture_Release(newpic);
2203 *ppvObj = NULL;
2204 return hr;
2206 hr = IPersistStream_Load(ps,lpstream);
2207 IPersistStream_Release(ps);
2208 if (FAILED(hr))
2210 ERR("IPersistStream_Load failed\n");
2211 IPicture_Release(newpic);
2212 *ppvObj = NULL;
2213 return hr;
2215 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2216 if (hr != S_OK)
2217 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2218 IPicture_Release(newpic);
2219 return hr;
2222 /***********************************************************************
2223 * OleLoadPictureEx (OLEAUT32.401)
2225 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2226 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2228 LPPERSISTSTREAM ps;
2229 IPicture *newpic;
2230 HRESULT hr;
2232 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2233 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, 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 * OleLoadPicturePath (OLEAUT32.424)
2264 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2265 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2266 LPVOID *ppvRet )
2268 static const WCHAR file[] = { 'f','i','l','e',':',0 };
2269 IPicture *ipicture;
2270 HANDLE hFile;
2271 DWORD dwFileSize;
2272 HGLOBAL hGlobal = NULL;
2273 DWORD dwBytesRead = 0;
2274 IStream *stream;
2275 BOOL bRead;
2276 IPersistStream *pStream;
2277 HRESULT hRes;
2278 HRESULT init_res;
2279 WCHAR *file_candidate;
2280 WCHAR path_buf[MAX_PATH];
2282 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2283 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2284 debugstr_guid(riid), ppvRet);
2286 if (!szURLorPath || !ppvRet)
2287 return E_INVALIDARG;
2289 *ppvRet = NULL;
2291 /* Convert file URLs to DOS paths. */
2292 if (strncmpW(szURLorPath, file, 5) == 0) {
2293 DWORD size;
2294 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2295 sizeof(path_buf)/sizeof(WCHAR), &size, 0);
2296 if (FAILED(hRes))
2297 return hRes;
2299 file_candidate = path_buf;
2301 else
2302 file_candidate = szURLorPath;
2304 /* Handle candidate DOS paths separately. */
2305 if (file_candidate[1] == ':') {
2306 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2307 0, NULL);
2308 if (hFile == INVALID_HANDLE_VALUE)
2309 return E_UNEXPECTED;
2311 dwFileSize = GetFileSize(hFile, NULL);
2312 if (dwFileSize != INVALID_FILE_SIZE )
2314 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2315 if ( hGlobal)
2317 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2318 if (!bRead)
2320 GlobalFree(hGlobal);
2321 hGlobal = 0;
2325 CloseHandle(hFile);
2327 if (!hGlobal)
2328 return E_UNEXPECTED;
2330 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2331 if (FAILED(hRes))
2333 GlobalFree(hGlobal);
2334 return hRes;
2336 } else {
2337 IMoniker *pmnk;
2338 IBindCtx *pbc;
2340 hRes = CreateBindCtx(0, &pbc);
2341 if (SUCCEEDED(hRes))
2343 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2344 if (SUCCEEDED(hRes))
2346 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2347 IMoniker_Release(pmnk);
2349 IBindCtx_Release(pbc);
2351 if (FAILED(hRes))
2352 return hRes;
2355 init_res = CoInitialize(NULL);
2357 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2358 &IID_IPicture, (LPVOID*)&ipicture);
2359 if (SUCCEEDED(hRes)) {
2360 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2362 if (SUCCEEDED(hRes)) {
2363 hRes = IPersistStream_Load(pStream, stream);
2365 if (SUCCEEDED(hRes)) {
2366 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2368 if (FAILED(hRes))
2369 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2371 IPersistStream_Release(pStream);
2373 IPicture_Release(ipicture);
2376 IStream_Release(stream);
2378 if (SUCCEEDED(init_res))
2379 CoUninitialize();
2381 return hRes;
2384 /*******************************************************************************
2385 * StdPic ClassFactory
2387 typedef struct
2389 /* IUnknown fields */
2390 const IClassFactoryVtbl *lpVtbl;
2391 LONG ref;
2392 } IClassFactoryImpl;
2394 static HRESULT WINAPI
2395 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2396 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2398 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2399 return E_NOINTERFACE;
2402 static ULONG WINAPI
2403 SPCF_AddRef(LPCLASSFACTORY iface) {
2404 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2405 return InterlockedIncrement(&This->ref);
2408 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2409 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2410 /* static class, won't be freed */
2411 return InterlockedDecrement(&This->ref);
2414 static HRESULT WINAPI SPCF_CreateInstance(
2415 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2417 /* Creates an uninitialized picture */
2418 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2422 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2423 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2424 FIXME("(%p)->(%d),stub!\n",This,dolock);
2425 return S_OK;
2428 static const IClassFactoryVtbl SPCF_Vtbl = {
2429 SPCF_QueryInterface,
2430 SPCF_AddRef,
2431 SPCF_Release,
2432 SPCF_CreateInstance,
2433 SPCF_LockServer
2435 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2437 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }