user32: Specify the new queue mask separately from the PeekMessage flags.
[wine/wine64.git] / dlls / oleaut32 / olepicture.c
blob93b932f7a056e6d95fb7e57b4084c57d86216822
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 #ifdef SONAME_LIBJPEG
50 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
51 #define XMD_H
52 #define UINT8 JPEG_UINT8
53 #define UINT16 JPEG_UINT16
54 #define boolean jpeg_boolean
55 # include <jpeglib.h>
56 #undef UINT8
57 #undef UINT16
58 #undef boolean
59 #endif
61 #ifdef HAVE_PNG_H
62 #include <png.h>
63 #endif
65 /* Must be before wine includes, the header has things conflicting with
66 * WINE headers.
68 #define COBJMACROS
69 #define NONAMELESSUNION
70 #define NONAMELESSSTRUCT
72 #include "winerror.h"
73 #include "windef.h"
74 #include "winbase.h"
75 #include "wingdi.h"
76 #include "winuser.h"
77 #include "ole2.h"
78 #include "olectl.h"
79 #include "oleauto.h"
80 #include "connpt.h"
81 #include "urlmon.h"
82 #include "wine/debug.h"
83 #include "wine/unicode.h"
85 #include "wine/wingdi16.h"
87 #include "ungif.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(ole);
91 #include "pshpack1.h"
93 /* Header for Aldus Placable Metafiles - a standard metafile follows */
94 typedef struct _APM_HEADER
96 DWORD key;
97 WORD handle;
98 SHORT left;
99 SHORT top;
100 SHORT right;
101 SHORT bottom;
102 WORD inch;
103 DWORD reserved;
104 WORD checksum;
105 } APM_HEADER;
107 typedef struct {
108 BYTE bWidth;
109 BYTE bHeight;
110 BYTE bColorCount;
111 BYTE bReserved;
112 WORD xHotspot;
113 WORD yHotspot;
114 DWORD dwDIBSize;
115 DWORD dwDIBOffset;
116 } CURSORICONFILEDIRENTRY;
118 typedef struct
120 WORD idReserved;
121 WORD idType;
122 WORD idCount;
123 CURSORICONFILEDIRENTRY idEntries[1];
124 } CURSORICONFILEDIR;
126 #include "poppack.h"
128 /*************************************************************************
129 * Declaration of implementation class
132 typedef struct OLEPictureImpl {
135 * IPicture handles IUnknown
138 const IPictureVtbl *lpVtbl;
139 const IDispatchVtbl *lpvtblIDispatch;
140 const IPersistStreamVtbl *lpvtblIPersistStream;
141 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
143 /* Object reference count */
144 LONG ref;
146 /* We own the object and must destroy it ourselves */
147 BOOL fOwn;
149 /* Picture description */
150 PICTDESC desc;
152 /* These are the pixel size of a bitmap */
153 DWORD origWidth;
154 DWORD origHeight;
156 /* And these are the size of the picture converted into HIMETRIC units */
157 OLE_XSIZE_HIMETRIC himetricWidth;
158 OLE_YSIZE_HIMETRIC himetricHeight;
160 IConnectionPoint *pCP;
162 BOOL keepOrigFormat;
163 HDC hDCCur;
165 /* Bitmap transparency mask */
166 HBITMAP hbmMask;
167 HBITMAP hbmXor;
168 COLORREF rgbTrans;
170 /* data */
171 void* data;
172 int datalen;
173 BOOL bIsDirty; /* Set to TRUE if picture has changed */
174 unsigned int loadtime_magic; /* If a length header was found, saves value */
175 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
176 } OLEPictureImpl;
179 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
182 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
184 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
187 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
189 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
192 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
194 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
198 * Predeclare VTables. They get initialized at the end.
200 static const IPictureVtbl OLEPictureImpl_VTable;
201 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
202 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
203 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
205 /***********************************************************************
206 * Implementation of the OLEPictureImpl class.
209 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
210 BITMAP bm;
211 HDC hdcRef;
213 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
214 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
215 ERR("GetObject fails\n");
216 return;
218 This->origWidth = bm.bmWidth;
219 This->origHeight = bm.bmHeight;
220 /* The width and height are stored in HIMETRIC units (0.01 mm),
221 so we take our pixel width divide by pixels per inch and
222 multiply by 25.4 * 100 */
223 /* Should we use GetBitmapDimension if available? */
224 hdcRef = CreateCompatibleDC(0);
225 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
226 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
227 DeleteDC(hdcRef);
230 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
232 ICONINFO infoIcon;
234 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
235 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
236 HDC hdcRef;
237 BITMAP bm;
239 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
240 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
241 ERR("GetObject fails on icon bitmap\n");
242 return;
245 This->origWidth = bm.bmWidth;
246 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
247 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
248 hdcRef = GetDC(0);
249 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
250 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
251 ReleaseDC(0, hdcRef);
253 DeleteObject(infoIcon.hbmMask);
254 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
255 } else {
256 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
260 /************************************************************************
261 * OLEPictureImpl_Construct
263 * This method will construct a new instance of the OLEPictureImpl
264 * class.
266 * The caller of this method must release the object when it's
267 * done with it.
269 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
271 OLEPictureImpl* newObject = 0;
273 if (pictDesc)
274 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
277 * Allocate space for the object.
279 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
281 if (newObject==0)
282 return newObject;
285 * Initialize the virtual function table.
287 newObject->lpVtbl = &OLEPictureImpl_VTable;
288 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
289 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
290 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
292 newObject->pCP = NULL;
293 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
294 if (!newObject->pCP)
296 HeapFree(GetProcessHeap(), 0, newObject);
297 return NULL;
301 * Start with one reference count. The caller of this function
302 * must release the interface pointer when it is done.
304 newObject->ref = 1;
305 newObject->hDCCur = 0;
307 newObject->fOwn = fOwn;
309 /* dunno about original value */
310 newObject->keepOrigFormat = TRUE;
312 newObject->hbmMask = NULL;
313 newObject->hbmXor = NULL;
314 newObject->loadtime_magic = 0xdeadbeef;
315 newObject->loadtime_format = 0;
316 newObject->bIsDirty = FALSE;
318 if (pictDesc) {
319 newObject->desc = *pictDesc;
321 switch(pictDesc->picType) {
322 case PICTYPE_BITMAP:
323 OLEPictureImpl_SetBitmap(newObject);
324 break;
326 case PICTYPE_METAFILE:
327 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
328 newObject->himetricWidth = pictDesc->u.wmf.xExt;
329 newObject->himetricHeight = pictDesc->u.wmf.yExt;
330 break;
332 case PICTYPE_NONE:
333 /* not sure what to do here */
334 newObject->himetricWidth = newObject->himetricHeight = 0;
335 break;
337 case PICTYPE_ICON:
338 OLEPictureImpl_SetIcon(newObject);
339 break;
340 case PICTYPE_ENHMETAFILE:
341 default:
342 FIXME("Unsupported type %d\n", pictDesc->picType);
343 newObject->himetricWidth = newObject->himetricHeight = 0;
344 break;
346 } else {
347 newObject->desc.picType = PICTYPE_UNINITIALIZED;
350 TRACE("returning %p\n", newObject);
351 return newObject;
354 /************************************************************************
355 * OLEPictureImpl_Destroy
357 * This method is called by the Release method when the reference
358 * count goes down to 0. It will free all resources used by
359 * this object. */
360 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
362 TRACE("(%p)\n", Obj);
364 if (Obj->pCP)
365 IConnectionPoint_Release(Obj->pCP);
367 if(Obj->fOwn) { /* We need to destroy the picture */
368 switch(Obj->desc.picType) {
369 case PICTYPE_BITMAP:
370 DeleteObject(Obj->desc.u.bmp.hbitmap);
371 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
372 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
373 break;
374 case PICTYPE_METAFILE:
375 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
376 break;
377 case PICTYPE_ICON:
378 DestroyIcon(Obj->desc.u.icon.hicon);
379 break;
380 case PICTYPE_ENHMETAFILE:
381 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
382 break;
383 case PICTYPE_NONE:
384 case PICTYPE_UNINITIALIZED:
385 /* Nothing to do */
386 break;
387 default:
388 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
389 break;
392 HeapFree(GetProcessHeap(), 0, Obj->data);
393 HeapFree(GetProcessHeap(), 0, Obj);
397 /************************************************************************
398 * OLEPictureImpl_AddRef (IUnknown)
400 * See Windows documentation for more details on IUnknown methods.
402 static ULONG WINAPI OLEPictureImpl_AddRef(
403 IPicture* iface)
405 OLEPictureImpl *This = (OLEPictureImpl *)iface;
406 ULONG refCount = InterlockedIncrement(&This->ref);
408 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
410 return refCount;
413 /************************************************************************
414 * OLEPictureImpl_Release (IUnknown)
416 * See Windows documentation for more details on IUnknown methods.
418 static ULONG WINAPI OLEPictureImpl_Release(
419 IPicture* iface)
421 OLEPictureImpl *This = (OLEPictureImpl *)iface;
422 ULONG refCount = InterlockedDecrement(&This->ref);
424 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
427 * If the reference count goes down to 0, perform suicide.
429 if (!refCount) OLEPictureImpl_Destroy(This);
431 return refCount;
434 /************************************************************************
435 * OLEPictureImpl_QueryInterface (IUnknown)
437 * See Windows documentation for more details on IUnknown methods.
439 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
440 IPicture* iface,
441 REFIID riid,
442 void** ppvObject)
444 OLEPictureImpl *This = (OLEPictureImpl *)iface;
445 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
448 * Perform a sanity check on the parameters.
450 if ( (This==0) || (ppvObject==0) )
451 return E_INVALIDARG;
454 * Initialize the return parameter.
456 *ppvObject = 0;
459 * Compare the riid with the interface IDs implemented by this object.
461 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
462 *ppvObject = (IPicture*)This;
463 else if (IsEqualIID(&IID_IDispatch, riid))
464 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
465 else if (IsEqualIID(&IID_IPictureDisp, riid))
466 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
467 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
468 *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
469 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
470 *ppvObject = (IConnectionPointContainer*)&(This->lpvtblIConnectionPointContainer);
473 * Check that we obtained an interface.
475 if ((*ppvObject)==0)
477 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
478 return E_NOINTERFACE;
482 * Query Interface always increases the reference count by one when it is
483 * successful
485 OLEPictureImpl_AddRef((IPicture*)This);
487 return S_OK;
490 /***********************************************************************
491 * OLEPicture_SendNotify (internal)
493 * Sends notification messages of changed properties to any interested
494 * connections.
496 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
498 IEnumConnections *pEnum;
499 CONNECTDATA CD;
501 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
502 return;
503 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
504 IPropertyNotifySink *sink;
506 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
507 IPropertyNotifySink_OnChanged(sink, dispID);
508 IPropertyNotifySink_Release(sink);
509 IUnknown_Release(CD.pUnk);
511 IEnumConnections_Release(pEnum);
514 /************************************************************************
515 * OLEPictureImpl_get_Handle
517 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
518 OLE_HANDLE *phandle)
520 OLEPictureImpl *This = (OLEPictureImpl *)iface;
521 TRACE("(%p)->(%p)\n", This, phandle);
522 switch(This->desc.picType) {
523 case PICTYPE_NONE:
524 case PICTYPE_UNINITIALIZED:
525 *phandle = 0;
526 break;
527 case PICTYPE_BITMAP:
528 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
529 break;
530 case PICTYPE_METAFILE:
531 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
532 break;
533 case PICTYPE_ICON:
534 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
535 break;
536 case PICTYPE_ENHMETAFILE:
537 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
538 break;
539 default:
540 FIXME("Unimplemented type %d\n", This->desc.picType);
541 return E_NOTIMPL;
543 TRACE("returning handle %08x\n", *phandle);
544 return S_OK;
547 /************************************************************************
548 * OLEPictureImpl_get_hPal
550 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
551 OLE_HANDLE *phandle)
553 OLEPictureImpl *This = (OLEPictureImpl *)iface;
554 HRESULT hres;
555 TRACE("(%p)->(%p)\n", This, phandle);
557 if (!phandle)
558 return E_POINTER;
560 switch (This->desc.picType) {
561 case (UINT)PICTYPE_UNINITIALIZED:
562 case PICTYPE_NONE:
563 *phandle = 0;
564 hres = S_FALSE;
565 break;
566 case PICTYPE_BITMAP:
567 *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
568 hres = S_OK;
569 break;
570 case PICTYPE_METAFILE:
571 hres = E_FAIL;
572 break;
573 case PICTYPE_ICON:
574 case PICTYPE_ENHMETAFILE:
575 default:
576 FIXME("unimplemented for type %d. Returning 0 palette.\n",
577 This->desc.picType);
578 *phandle = 0;
579 hres = S_OK;
582 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
583 return hres;
586 /************************************************************************
587 * OLEPictureImpl_get_Type
589 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
590 short *ptype)
592 OLEPictureImpl *This = (OLEPictureImpl *)iface;
593 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
594 *ptype = This->desc.picType;
595 return S_OK;
598 /************************************************************************
599 * OLEPictureImpl_get_Width
601 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
602 OLE_XSIZE_HIMETRIC *pwidth)
604 OLEPictureImpl *This = (OLEPictureImpl *)iface;
605 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
606 *pwidth = This->himetricWidth;
607 return S_OK;
610 /************************************************************************
611 * OLEPictureImpl_get_Height
613 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
614 OLE_YSIZE_HIMETRIC *pheight)
616 OLEPictureImpl *This = (OLEPictureImpl *)iface;
617 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
618 *pheight = This->himetricHeight;
619 return S_OK;
622 /************************************************************************
623 * OLEPictureImpl_Render
625 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
626 LONG x, LONG y, LONG cx, LONG cy,
627 OLE_XPOS_HIMETRIC xSrc,
628 OLE_YPOS_HIMETRIC ySrc,
629 OLE_XSIZE_HIMETRIC cxSrc,
630 OLE_YSIZE_HIMETRIC cySrc,
631 LPCRECT prcWBounds)
633 OLEPictureImpl *This = (OLEPictureImpl *)iface;
634 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
635 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
636 if(prcWBounds)
637 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
638 prcWBounds->right, prcWBounds->bottom);
641 * While the documentation suggests this to be here (or after rendering?)
642 * it does cause an endless recursion in my sample app. -MM 20010804
643 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
646 switch(This->desc.picType) {
647 case PICTYPE_BITMAP:
649 HBITMAP hbmpOld;
650 HDC hdcBmp;
652 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
653 NB y-axis gets flipped */
655 hdcBmp = CreateCompatibleDC(0);
656 SetMapMode(hdcBmp, MM_ANISOTROPIC);
657 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
658 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
659 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
660 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
662 if (This->hbmMask) {
663 HDC hdcMask = CreateCompatibleDC(0);
664 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
666 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
668 SetMapMode(hdcMask, MM_ANISOTROPIC);
669 SetWindowOrgEx(hdcMask, 0, 0, NULL);
670 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
671 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
672 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
674 SetBkColor(hdc, RGB(255, 255, 255));
675 SetTextColor(hdc, RGB(0, 0, 0));
676 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
677 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
679 SelectObject(hdcMask, hOldbm);
680 DeleteDC(hdcMask);
681 } else {
682 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
683 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
686 SelectObject(hdcBmp, hbmpOld);
687 DeleteDC(hdcBmp);
689 break;
690 case PICTYPE_ICON:
691 FIXME("Not quite correct implementation of rendering icons...\n");
692 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
693 break;
695 case PICTYPE_METAFILE:
697 POINT prevOrg;
698 SIZE prevExt;
699 int oldmode;
701 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
702 SetViewportOrgEx(hdc, x, y, &prevOrg);
703 SetViewportExtEx(hdc, cx, cy, &prevExt);
705 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
706 ERR("PlayMetaFile failed!\n");
708 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
709 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
710 SetMapMode(hdc, oldmode);
711 break;
714 case PICTYPE_ENHMETAFILE:
716 RECT rc = { x, y, x + cx, y + cy };
717 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
718 break;
721 default:
722 FIXME("type %d not implemented\n", This->desc.picType);
723 return E_NOTIMPL;
725 return S_OK;
728 /************************************************************************
729 * OLEPictureImpl_set_hPal
731 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
732 OLE_HANDLE hpal)
734 OLEPictureImpl *This = (OLEPictureImpl *)iface;
735 FIXME("(%p)->(%08x): stub\n", This, hpal);
736 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
737 return E_NOTIMPL;
740 /************************************************************************
741 * OLEPictureImpl_get_CurDC
743 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
744 HDC *phdc)
746 OLEPictureImpl *This = (OLEPictureImpl *)iface;
747 TRACE("(%p), returning %p\n", This, This->hDCCur);
748 if (phdc) *phdc = This->hDCCur;
749 return S_OK;
752 /************************************************************************
753 * OLEPictureImpl_SelectPicture
755 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
756 HDC hdcIn,
757 HDC *phdcOut,
758 OLE_HANDLE *phbmpOut)
760 OLEPictureImpl *This = (OLEPictureImpl *)iface;
761 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
762 if (This->desc.picType == PICTYPE_BITMAP) {
763 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
765 if (phdcOut)
766 *phdcOut = This->hDCCur;
767 This->hDCCur = hdcIn;
768 if (phbmpOut)
769 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
770 return S_OK;
771 } else {
772 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
773 return E_FAIL;
777 /************************************************************************
778 * OLEPictureImpl_get_KeepOriginalFormat
780 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
781 BOOL *pfKeep)
783 OLEPictureImpl *This = (OLEPictureImpl *)iface;
784 TRACE("(%p)->(%p)\n", This, pfKeep);
785 if (!pfKeep)
786 return E_POINTER;
787 *pfKeep = This->keepOrigFormat;
788 return S_OK;
791 /************************************************************************
792 * OLEPictureImpl_put_KeepOriginalFormat
794 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
795 BOOL keep)
797 OLEPictureImpl *This = (OLEPictureImpl *)iface;
798 TRACE("(%p)->(%d)\n", This, keep);
799 This->keepOrigFormat = keep;
800 /* FIXME: what DISPID notification here? */
801 return S_OK;
804 /************************************************************************
805 * OLEPictureImpl_PictureChanged
807 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
809 OLEPictureImpl *This = (OLEPictureImpl *)iface;
810 TRACE("(%p)->()\n", This);
811 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
812 This->bIsDirty = TRUE;
813 return S_OK;
816 /************************************************************************
817 * OLEPictureImpl_SaveAsFile
819 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
820 IStream *pstream,
821 BOOL SaveMemCopy,
822 LONG *pcbSize)
824 OLEPictureImpl *This = (OLEPictureImpl *)iface;
825 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
826 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
829 /************************************************************************
830 * OLEPictureImpl_get_Attributes
832 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
833 DWORD *pdwAttr)
835 OLEPictureImpl *This = (OLEPictureImpl *)iface;
836 TRACE("(%p)->(%p).\n", This, pdwAttr);
837 *pdwAttr = 0;
838 switch (This->desc.picType) {
839 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
840 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
841 case PICTYPE_ENHMETAFILE: /* fall through */
842 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
843 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
845 return S_OK;
849 /************************************************************************
850 * IConnectionPointContainer
852 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
853 IConnectionPointContainer* iface,
854 REFIID riid,
855 VOID** ppvoid)
857 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
859 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
862 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
863 IConnectionPointContainer* iface)
865 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
867 return IPicture_AddRef((IPicture *)This);
870 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
871 IConnectionPointContainer* iface)
873 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
875 return IPicture_Release((IPicture *)This);
878 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
879 IConnectionPointContainer* iface,
880 IEnumConnectionPoints** ppEnum)
882 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
884 FIXME("(%p,%p), stub!\n",This,ppEnum);
885 return E_NOTIMPL;
888 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
889 IConnectionPointContainer* iface,
890 REFIID riid,
891 IConnectionPoint **ppCP)
893 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
894 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
895 if (!ppCP)
896 return E_POINTER;
897 *ppCP = NULL;
898 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
899 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
900 FIXME("no connection point for %s\n",debugstr_guid(riid));
901 return CONNECT_E_NOCONNECTION;
905 /************************************************************************
906 * IPersistStream
909 /************************************************************************
910 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
912 * See Windows documentation for more details on IUnknown methods.
914 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
915 IPersistStream* iface,
916 REFIID riid,
917 VOID** ppvoid)
919 OLEPictureImpl *This = impl_from_IPersistStream(iface);
921 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
924 /************************************************************************
925 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
927 * See Windows documentation for more details on IUnknown methods.
929 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
930 IPersistStream* iface)
932 OLEPictureImpl *This = impl_from_IPersistStream(iface);
934 return IPicture_AddRef((IPicture *)This);
937 /************************************************************************
938 * OLEPictureImpl_IPersistStream_Release (IUnknown)
940 * See Windows documentation for more details on IUnknown methods.
942 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
943 IPersistStream* iface)
945 OLEPictureImpl *This = impl_from_IPersistStream(iface);
947 return IPicture_Release((IPicture *)This);
950 /************************************************************************
951 * OLEPictureImpl_IPersistStream_GetClassID
953 static HRESULT WINAPI OLEPictureImpl_GetClassID(
954 IPersistStream* iface,CLSID* pClassID)
956 TRACE("(%p)\n", pClassID);
957 *pClassID = CLSID_StdPicture;
958 return S_OK;
961 /************************************************************************
962 * OLEPictureImpl_IPersistStream_IsDirty
964 static HRESULT WINAPI OLEPictureImpl_IsDirty(
965 IPersistStream* iface)
967 OLEPictureImpl *This = impl_from_IPersistStream(iface);
968 FIXME("(%p),stub!\n",This);
969 return E_NOTIMPL;
972 #ifdef SONAME_LIBJPEG
974 static void *libjpeg_handle;
975 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
976 MAKE_FUNCPTR(jpeg_std_error);
977 MAKE_FUNCPTR(jpeg_CreateDecompress);
978 MAKE_FUNCPTR(jpeg_read_header);
979 MAKE_FUNCPTR(jpeg_start_decompress);
980 MAKE_FUNCPTR(jpeg_read_scanlines);
981 MAKE_FUNCPTR(jpeg_finish_decompress);
982 MAKE_FUNCPTR(jpeg_destroy_decompress);
983 #undef MAKE_FUNCPTR
985 static void *load_libjpeg(void)
987 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
989 #define LOAD_FUNCPTR(f) \
990 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
991 libjpeg_handle = NULL; \
992 return NULL; \
995 LOAD_FUNCPTR(jpeg_std_error);
996 LOAD_FUNCPTR(jpeg_CreateDecompress);
997 LOAD_FUNCPTR(jpeg_read_header);
998 LOAD_FUNCPTR(jpeg_start_decompress);
999 LOAD_FUNCPTR(jpeg_read_scanlines);
1000 LOAD_FUNCPTR(jpeg_finish_decompress);
1001 LOAD_FUNCPTR(jpeg_destroy_decompress);
1002 #undef LOAD_FUNCPTR
1004 return libjpeg_handle;
1007 /* for the jpeg decompressor source manager. */
1008 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1010 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1011 ERR("(), should not get here.\n");
1012 return FALSE;
1015 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1016 TRACE("Skipping %ld bytes...\n", num_bytes);
1017 cinfo->src->next_input_byte += num_bytes;
1018 cinfo->src->bytes_in_buffer -= num_bytes;
1021 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1022 ERR("(desired=%d), should not get here.\n",desired);
1023 return FALSE;
1025 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1026 #endif /* SONAME_LIBJPEG */
1028 struct gifdata {
1029 unsigned char *data;
1030 unsigned int curoff;
1031 unsigned int len;
1034 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1035 struct gifdata *gd = (struct gifdata*)gif->UserData;
1037 if (len+gd->curoff > gd->len) {
1038 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1039 len = gd->len - gd->curoff;
1041 memcpy(data, gd->data+gd->curoff, len);
1042 gd->curoff += len;
1043 return len;
1047 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1049 struct gifdata gd;
1050 GifFileType *gif;
1051 BITMAPINFO *bmi;
1052 HDC hdcref;
1053 LPBYTE bytes;
1054 int i,j,ret;
1055 GifImageDesc *gid;
1056 SavedImage *si;
1057 ColorMapObject *cm;
1058 int transparent = -1;
1059 ExtensionBlock *eb;
1060 int padding;
1062 gd.data = xbuf;
1063 gd.curoff = 0;
1064 gd.len = xread;
1065 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1066 ret = DGifSlurp(gif);
1067 if (ret == GIF_ERROR) {
1068 ERR("Failed reading GIF using libgif.\n");
1069 return E_FAIL;
1071 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1072 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1073 TRACE("imgcnt %d\n", gif->ImageCount);
1074 if (gif->ImageCount<1) {
1075 ERR("GIF stream does not have images inside?\n");
1076 return E_FAIL;
1078 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1079 gif->Image.Width, gif->Image.Height,
1080 gif->Image.Left, gif->Image.Top,
1081 gif->Image.Interlace
1083 /* */
1084 padding = (gif->SWidth+3) & ~3;
1085 si = gif->SavedImages+0;
1086 gid = &(si->ImageDesc);
1087 cm = gid->ColorMap;
1088 if (!cm) cm = gif->SColorMap;
1089 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1090 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1092 /* look for the transparent color extension */
1093 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1094 eb = si->ExtensionBlocks + i;
1095 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1096 if ((eb->Bytes[0] & 1) == 1) {
1097 transparent = (unsigned char)eb->Bytes[3];
1102 for (i = 0; i < cm->ColorCount; i++) {
1103 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1104 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1105 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1106 if (i == transparent) {
1107 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1108 bmi->bmiColors[i].rgbGreen,
1109 bmi->bmiColors[i].rgbBlue);
1113 /* Map to in picture coordinates */
1114 for (i = 0, j = 0; i < gid->Height; i++) {
1115 if (gif->Image.Interlace) {
1116 memcpy(
1117 bytes + (gid->Top + j) * padding + gid->Left,
1118 si->RasterBits + i * gid->Width,
1119 gid->Width);
1121 /* Lower bits of interlaced counter encode current interlace */
1122 if (j & 1) j += 2; /* Currently filling odd rows */
1123 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1124 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1126 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1127 /* End of current interlace, go to next interlace */
1128 if (j & 2) j = 1; /* Next iteration fills odd rows */
1129 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1130 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1132 } else {
1133 memcpy(
1134 bytes + (gid->Top + i) * padding + gid->Left,
1135 si->RasterBits + i * gid->Width,
1136 gid->Width);
1140 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1141 bmi->bmiHeader.biWidth = gif->SWidth;
1142 bmi->bmiHeader.biHeight = -gif->SHeight;
1143 bmi->bmiHeader.biPlanes = 1;
1144 bmi->bmiHeader.biBitCount = 8;
1145 bmi->bmiHeader.biCompression = BI_RGB;
1146 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1147 bmi->bmiHeader.biXPelsPerMeter = 0;
1148 bmi->bmiHeader.biYPelsPerMeter = 0;
1149 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1150 bmi->bmiHeader.biClrImportant = 0;
1152 hdcref = GetDC(0);
1153 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1154 hdcref,
1155 &bmi->bmiHeader,
1156 CBM_INIT,
1157 bytes,
1158 bmi,
1159 DIB_RGB_COLORS
1162 if (transparent > -1) {
1163 /* Create the Mask */
1164 HDC hdc = CreateCompatibleDC(0);
1165 HDC hdcMask = CreateCompatibleDC(0);
1166 HBITMAP hOldbitmap;
1167 HBITMAP hOldbitmapmask;
1169 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1170 HBITMAP hTempMask;
1172 This->hbmXor = CreateDIBitmap(
1173 hdcref,
1174 &bmi->bmiHeader,
1175 CBM_INIT,
1176 bytes,
1177 bmi,
1178 DIB_RGB_COLORS
1181 bmi->bmiColors[0].rgbRed = 0;
1182 bmi->bmiColors[0].rgbGreen = 0;
1183 bmi->bmiColors[0].rgbBlue = 0;
1184 bmi->bmiColors[1].rgbRed = 255;
1185 bmi->bmiColors[1].rgbGreen = 255;
1186 bmi->bmiColors[1].rgbBlue = 255;
1188 bmi->bmiHeader.biBitCount = 1;
1189 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1190 bmi->bmiHeader.biClrUsed = 2;
1192 for (i = 0; i < gif->SHeight; i++) {
1193 unsigned char * colorPointer = bytes + padding * i;
1194 unsigned char * monoPointer = bytes + monopadding * i;
1195 for (j = 0; j < gif->SWidth; j++) {
1196 unsigned char pixel = colorPointer[j];
1197 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1198 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1201 hdcref = GetDC(0);
1202 hTempMask = CreateDIBitmap(
1203 hdcref,
1204 &bmi->bmiHeader,
1205 CBM_INIT,
1206 bytes,
1207 bmi,
1208 DIB_RGB_COLORS
1210 DeleteDC(hdcref);
1212 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1213 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1214 hOldbitmap = SelectObject(hdc, hTempMask);
1215 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1217 SetBkColor(hdc, RGB(255, 255, 255));
1218 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1220 /* We no longer need the original bitmap, so we apply the first
1221 transformation with the mask to speed up the rendering */
1222 SelectObject(hdc, This->hbmXor);
1223 SetBkColor(hdc, RGB(0,0,0));
1224 SetTextColor(hdc, RGB(255,255,255));
1225 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1226 hdcMask, 0, 0, SRCAND);
1228 SelectObject(hdc, hOldbitmap);
1229 SelectObject(hdcMask, hOldbitmapmask);
1230 DeleteDC(hdcMask);
1231 DeleteDC(hdc);
1232 DeleteObject(hTempMask);
1235 DeleteDC(hdcref);
1236 This->desc.picType = PICTYPE_BITMAP;
1237 OLEPictureImpl_SetBitmap(This);
1238 DGifCloseFile(gif);
1239 HeapFree(GetProcessHeap(),0,bmi);
1240 HeapFree(GetProcessHeap(),0,bytes);
1241 return S_OK;
1244 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1246 #ifdef SONAME_LIBJPEG
1247 struct jpeg_decompress_struct jd;
1248 struct jpeg_error_mgr jerr;
1249 int ret;
1250 JDIMENSION x;
1251 JSAMPROW samprow,oldsamprow;
1252 BITMAPINFOHEADER bmi;
1253 LPBYTE bits;
1254 HDC hdcref;
1255 struct jpeg_source_mgr xjsm;
1256 LPBYTE oldbits;
1257 unsigned int i;
1259 if(!libjpeg_handle) {
1260 if(!load_libjpeg()) {
1261 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1262 return E_FAIL;
1266 /* This is basically so we can use in-memory data for jpeg decompression.
1267 * We need to have all the functions.
1269 xjsm.next_input_byte = xbuf;
1270 xjsm.bytes_in_buffer = xread;
1271 xjsm.init_source = _jpeg_init_source;
1272 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1273 xjsm.skip_input_data = _jpeg_skip_input_data;
1274 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1275 xjsm.term_source = _jpeg_term_source;
1277 jd.err = pjpeg_std_error(&jerr);
1278 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1279 * jpeg_create_decompress(&jd); */
1280 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1281 jd.src = &xjsm;
1282 ret=pjpeg_read_header(&jd,TRUE);
1283 jd.out_color_space = JCS_RGB;
1284 pjpeg_start_decompress(&jd);
1285 if (ret != JPEG_HEADER_OK) {
1286 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1287 HeapFree(GetProcessHeap(),0,xbuf);
1288 return E_FAIL;
1291 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1292 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1293 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1295 oldbits = bits;
1296 oldsamprow = samprow;
1297 while ( jd.output_scanline<jd.output_height ) {
1298 x = pjpeg_read_scanlines(&jd,&samprow,1);
1299 if (x != 1) {
1300 ERR("failed to read current scanline?\n");
1301 break;
1303 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1304 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1305 *(bits++) = *(samprow+2);
1306 *(bits++) = *(samprow+1);
1307 *(bits++) = *(samprow);
1309 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1310 samprow = oldsamprow;
1312 bits = oldbits;
1314 bmi.biSize = sizeof(bmi);
1315 bmi.biWidth = jd.output_width;
1316 bmi.biHeight = -jd.output_height;
1317 bmi.biPlanes = 1;
1318 bmi.biBitCount = jd.output_components<<3;
1319 bmi.biCompression = BI_RGB;
1320 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1321 bmi.biXPelsPerMeter = 0;
1322 bmi.biYPelsPerMeter = 0;
1323 bmi.biClrUsed = 0;
1324 bmi.biClrImportant = 0;
1326 HeapFree(GetProcessHeap(),0,samprow);
1327 pjpeg_finish_decompress(&jd);
1328 pjpeg_destroy_decompress(&jd);
1329 hdcref = GetDC(0);
1330 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1331 hdcref,
1332 &bmi,
1333 CBM_INIT,
1334 bits,
1335 (BITMAPINFO*)&bmi,
1336 DIB_RGB_COLORS
1338 DeleteDC(hdcref);
1339 This->desc.picType = PICTYPE_BITMAP;
1340 OLEPictureImpl_SetBitmap(This);
1341 HeapFree(GetProcessHeap(),0,bits);
1342 return S_OK;
1343 #else
1344 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1345 return E_FAIL;
1346 #endif
1349 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1351 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1352 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1353 HDC hdcref;
1355 /* Does not matter whether this is a coreheader or not, we only use
1356 * components which are in both
1358 hdcref = GetDC(0);
1359 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1360 hdcref,
1361 &(bi->bmiHeader),
1362 CBM_INIT,
1363 xbuf+bfh->bfOffBits,
1365 DIB_RGB_COLORS
1367 DeleteDC(hdcref);
1368 if (This->desc.u.bmp.hbitmap == 0)
1369 return E_FAIL;
1370 This->desc.picType = PICTYPE_BITMAP;
1371 OLEPictureImpl_SetBitmap(This);
1372 return S_OK;
1375 /*****************************************************
1376 * start of PNG-specific code
1377 * currently only supports colortype PNG_COLOR_TYPE_RGB
1379 #ifdef SONAME_LIBPNG
1380 typedef struct{
1381 ULONG position;
1382 ULONG size;
1383 BYTE * buff;
1384 } png_io;
1386 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1387 png_size_t length)
1389 png_io * io_ptr = png_ptr->io_ptr;
1391 if(length + io_ptr->position > io_ptr->size){
1392 length = io_ptr->size - io_ptr->position;
1395 memcpy(data, io_ptr->buff + io_ptr->position, length);
1397 io_ptr->position += length;
1400 static void *libpng_handle;
1401 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1402 MAKE_FUNCPTR(png_create_read_struct);
1403 MAKE_FUNCPTR(png_create_info_struct);
1404 MAKE_FUNCPTR(png_set_read_fn);
1405 MAKE_FUNCPTR(png_read_info);
1406 MAKE_FUNCPTR(png_read_image);
1407 MAKE_FUNCPTR(png_get_rowbytes);
1408 MAKE_FUNCPTR(png_set_bgr);
1409 MAKE_FUNCPTR(png_destroy_read_struct);
1410 MAKE_FUNCPTR(png_set_palette_to_rgb);
1411 MAKE_FUNCPTR(png_read_update_info);
1412 MAKE_FUNCPTR(png_get_tRNS);
1413 MAKE_FUNCPTR(png_get_PLTE);
1414 MAKE_FUNCPTR(png_set_expand);
1415 #undef MAKE_FUNCPTR
1417 static void *load_libpng(void)
1419 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1421 #define LOAD_FUNCPTR(f) \
1422 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1423 libpng_handle = NULL; \
1424 return NULL; \
1426 LOAD_FUNCPTR(png_create_read_struct);
1427 LOAD_FUNCPTR(png_create_info_struct);
1428 LOAD_FUNCPTR(png_set_read_fn);
1429 LOAD_FUNCPTR(png_read_info);
1430 LOAD_FUNCPTR(png_read_image);
1431 LOAD_FUNCPTR(png_get_rowbytes);
1432 LOAD_FUNCPTR(png_set_bgr);
1433 LOAD_FUNCPTR(png_destroy_read_struct);
1434 LOAD_FUNCPTR(png_set_palette_to_rgb);
1435 LOAD_FUNCPTR(png_read_update_info);
1436 LOAD_FUNCPTR(png_get_tRNS);
1437 LOAD_FUNCPTR(png_get_PLTE);
1438 LOAD_FUNCPTR(png_set_expand);
1440 #undef LOAD_FUNCPTR
1442 return libpng_handle;
1444 #endif /* SONAME_LIBPNG */
1446 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1448 #ifdef SONAME_LIBPNG
1449 png_io io;
1450 png_structp png_ptr = NULL;
1451 png_infop info_ptr = NULL;
1452 INT row, rowsize, height, width, num_trans, i, j;
1453 png_bytep* row_pointers = NULL;
1454 png_bytep pngdata = NULL;
1455 BITMAPINFOHEADER bmi;
1456 HDC hdcref = NULL, hdcXor, hdcMask;
1457 HRESULT ret;
1458 BOOL transparency;
1459 png_bytep trans;
1460 png_color_16p trans_values;
1461 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1462 HBITMAP hbmoldXor, hbmoldMask, temp;
1464 if(!libpng_handle) {
1465 if(!load_libpng()) {
1466 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1467 return E_FAIL;
1471 io.size = xread;
1472 io.position = 0;
1473 io.buff = xbuf;
1475 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1476 NULL, NULL, NULL);
1478 if(setjmp(png_jmpbuf(png_ptr))){
1479 TRACE("Error in libpng\n");
1480 ret = E_FAIL;
1481 goto end;
1484 info_ptr = ppng_create_info_struct(png_ptr);
1485 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1486 ppng_read_info(png_ptr, info_ptr);
1488 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1489 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1490 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1491 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1492 ret = E_FAIL;
1493 goto end;
1496 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1497 == PNG_INFO_tRNS);
1499 /* sets format from anything to RGBA */
1500 ppng_set_expand(png_ptr);
1501 /* sets format to BGRA */
1502 ppng_set_bgr(png_ptr);
1504 ppng_read_update_info(png_ptr, info_ptr);
1506 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1507 /* align rowsize to 4-byte boundary */
1508 rowsize = (rowsize + 3) & ~3;
1509 height = info_ptr->height;
1510 width = info_ptr->width;
1512 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1513 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1515 if(!pngdata || !row_pointers){
1516 ret = E_FAIL;
1517 goto end;
1520 for (row = 0; row < height; row++){
1521 row_pointers[row] = pngdata + row * rowsize;
1524 ppng_read_image(png_ptr, row_pointers);
1526 bmi.biSize = sizeof(bmi);
1527 bmi.biWidth = width;
1528 bmi.biHeight = -height;
1529 bmi.biPlanes = 1;
1530 bmi.biBitCount = info_ptr->channels * 8;
1531 bmi.biCompression = BI_RGB;
1532 bmi.biSizeImage = height * rowsize;
1533 bmi.biXPelsPerMeter = 0;
1534 bmi.biYPelsPerMeter = 0;
1535 bmi.biClrUsed = 0;
1536 bmi.biClrImportant = 0;
1538 hdcref = GetDC(0);
1539 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1540 hdcref,
1541 &bmi,
1542 CBM_INIT,
1543 pngdata,
1544 (BITMAPINFO*)&bmi,
1545 DIB_RGB_COLORS
1548 /* only fully-transparent alpha is handled */
1549 if((info_ptr->channels != 4) || !transparency){
1550 ReleaseDC(0, hdcref);
1551 goto succ;
1554 This->hbmXor = CreateDIBitmap(
1555 hdcref,
1556 &bmi,
1557 CBM_INIT,
1558 pngdata,
1559 (BITMAPINFO*)&bmi,
1560 DIB_RGB_COLORS
1563 /* set transparent pixels to black, all others to white */
1564 for(i = 0; i < height; i++){
1565 for(j = 3; j < rowsize; j += 4){
1566 if(row_pointers[i][j] == 0)
1567 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1568 else
1569 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1573 temp = CreateDIBitmap(
1574 hdcref,
1575 &bmi,
1576 CBM_INIT,
1577 pngdata,
1578 (BITMAPINFO*)&bmi,
1579 DIB_RGB_COLORS
1582 ReleaseDC(0, hdcref);
1584 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1585 hdcXor = CreateCompatibleDC(NULL);
1586 hdcMask = CreateCompatibleDC(NULL);
1588 hbmoldXor = SelectObject(hdcXor,temp);
1589 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1590 SetBkColor(hdcXor,black);
1591 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1593 SelectObject(hdcXor,This->hbmXor);
1594 DeleteObject(temp);
1596 SetTextColor(hdcXor,white);
1597 SetBkColor(hdcXor,black);
1598 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1600 SelectObject(hdcXor,hbmoldXor);
1601 SelectObject(hdcMask,hbmoldMask);
1603 DeleteDC(hdcXor);
1604 DeleteDC(hdcMask);
1606 succ:
1607 This->desc.picType = PICTYPE_BITMAP;
1608 OLEPictureImpl_SetBitmap(This);
1609 ret = S_OK;
1611 end:
1612 if(png_ptr)
1613 ppng_destroy_read_struct(&png_ptr,
1614 (info_ptr ? &info_ptr : (png_infopp) NULL),
1615 (png_infopp)NULL);
1616 HeapFree(GetProcessHeap(), 0, row_pointers);
1617 HeapFree(GetProcessHeap(), 0, pngdata);
1618 return ret;
1619 #else /* SONAME_LIBPNG */
1620 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1621 return E_FAIL;
1622 #endif
1625 /*****************************************************
1626 * start of Icon-specific code
1629 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1631 HICON hicon;
1632 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1633 HDC hdcRef;
1634 int i;
1637 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1638 FIXME("icon.idType=%d\n",cifd->idType);
1639 FIXME("icon.idCount=%d\n",cifd->idCount);
1641 for (i=0;i<cifd->idCount;i++) {
1642 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1643 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1644 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1645 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1646 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1647 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1648 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1649 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1652 i=0;
1653 /* If we have more than one icon, try to find the best.
1654 * this currently means '32 pixel wide'.
1656 if (cifd->idCount!=1) {
1657 for (i=0;i<cifd->idCount;i++) {
1658 if (cifd->idEntries[i].bWidth == 32)
1659 break;
1661 if (i==cifd->idCount) i=0;
1664 hicon = CreateIconFromResourceEx(
1665 xbuf+cifd->idEntries[i].dwDIBOffset,
1666 cifd->idEntries[i].dwDIBSize,
1667 TRUE, /* is icon */
1668 0x00030000,
1669 cifd->idEntries[i].bWidth,
1670 cifd->idEntries[i].bHeight,
1673 if (!hicon) {
1674 ERR("CreateIcon failed.\n");
1675 return E_FAIL;
1676 } else {
1677 This->desc.picType = PICTYPE_ICON;
1678 This->desc.u.icon.hicon = hicon;
1679 This->origWidth = cifd->idEntries[i].bWidth;
1680 This->origHeight = cifd->idEntries[i].bHeight;
1681 hdcRef = CreateCompatibleDC(0);
1682 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1683 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1684 DeleteDC(hdcRef);
1685 return S_OK;
1689 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1690 const BYTE *data, ULONG size)
1692 HENHMETAFILE hemf;
1693 ENHMETAHEADER hdr;
1695 hemf = SetEnhMetaFileBits(size, data);
1696 if (!hemf) return E_FAIL;
1698 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1700 This->desc.picType = PICTYPE_ENHMETAFILE;
1701 This->desc.u.emf.hemf = hemf;
1703 This->origWidth = 0;
1704 This->origHeight = 0;
1705 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1706 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1708 return S_OK;
1711 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1712 const BYTE *data, ULONG size)
1714 APM_HEADER *header = (APM_HEADER *)data;
1715 HMETAFILE hmf;
1717 if (size < sizeof(APM_HEADER))
1718 return E_FAIL;
1719 if (header->key != 0x9ac6cdd7)
1720 return E_FAIL;
1722 /* SetMetaFileBitsEx performs data check on its own */
1723 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1724 if (!hmf) return E_FAIL;
1726 This->desc.picType = PICTYPE_METAFILE;
1727 This->desc.u.wmf.hmeta = hmf;
1728 This->desc.u.wmf.xExt = 0;
1729 This->desc.u.wmf.yExt = 0;
1731 This->origWidth = 0;
1732 This->origHeight = 0;
1733 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1734 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1735 return S_OK;
1738 /************************************************************************
1739 * BITMAP FORMAT FLAGS -
1740 * Flags that differentiate between different types of bitmaps.
1743 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1744 #define BITMAP_FORMAT_JPEG 0xd8ff
1745 #define BITMAP_FORMAT_GIF 0x4947
1746 #define BITMAP_FORMAT_PNG 0x5089
1747 #define BITMAP_FORMAT_APM 0xcdd7
1749 /************************************************************************
1750 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1752 * Loads the binary data from the IStream. Starts at current position.
1753 * There appears to be an 2 DWORD header:
1754 * DWORD magic;
1755 * DWORD len;
1757 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1759 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1760 HRESULT hr = E_FAIL;
1761 BOOL headerisdata = FALSE;
1762 BOOL statfailed = FALSE;
1763 ULONG xread, toread;
1764 ULONG headerread;
1765 BYTE *xbuf;
1766 DWORD header[2];
1767 WORD magic;
1768 STATSTG statstg;
1769 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1771 TRACE("(%p,%p)\n",This,pStm);
1773 /****************************************************************************************
1774 * Part 1: Load the data
1776 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1777 * out whether we do.
1779 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1780 * compound file. This may explain most, if not all, of the cases of "no
1781 * header", and the header validation should take this into account.
1782 * At least in Visual Basic 6, resource streams, valid headers are
1783 * header[0] == "lt\0\0",
1784 * header[1] == length_of_stream.
1786 * Also handle streams where we do not have a working "Stat" method by
1787 * reading all data until the end of the stream.
1789 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1790 if (hr) {
1791 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1792 statfailed = TRUE;
1793 /* we will read at least 8 byte ... just right below */
1794 statstg.cbSize.QuadPart = 8;
1797 toread = 0;
1798 headerread = 0;
1799 headerisdata = FALSE;
1800 do {
1801 hr=IStream_Read(pStm,header,8,&xread);
1802 if (hr || xread!=8) {
1803 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1804 return (hr?hr:E_FAIL);
1806 headerread += xread;
1807 xread = 0;
1809 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1810 if (toread != 0 && toread != header[1])
1811 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1812 toread, header[1]);
1813 toread = header[1];
1814 if (toread == 0) break;
1815 } else {
1816 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1817 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1818 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1819 (header[0] == EMR_HEADER) || /* EMF header */
1820 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1821 (header[1]==0)
1822 ) {/* Found start of bitmap data */
1823 headerisdata = TRUE;
1824 if (toread == 0)
1825 toread = statstg.cbSize.QuadPart-8;
1826 else toread -= 8;
1827 xread = 8;
1828 } else {
1829 FIXME("Unknown stream header magic: %08x\n", header[0]);
1830 toread = header[1];
1833 } while (!headerisdata);
1835 if (statfailed) { /* we don't know the size ... read all we get */
1836 int sizeinc = 4096;
1837 int origsize = sizeinc;
1838 ULONG nread = 42;
1840 TRACE("Reading all data from stream.\n");
1841 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1842 if (headerisdata)
1843 memcpy (xbuf, header, 8);
1844 while (1) {
1845 while (xread < origsize) {
1846 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1847 xread+=nread;
1848 if (hr || !nread)
1849 break;
1851 if (!nread || hr) /* done, or error */
1852 break;
1853 if (xread == origsize) {
1854 origsize += sizeinc;
1855 sizeinc = 2*sizeinc; /* exponential increase */
1856 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1859 if (hr)
1860 TRACE("hr in no-stat loader case is %08x\n", hr);
1861 TRACE("loaded %d bytes.\n", xread);
1862 This->datalen = xread;
1863 This->data = xbuf;
1864 } else {
1865 This->datalen = toread+(headerisdata?8:0);
1866 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1867 if (!xbuf)
1868 return E_OUTOFMEMORY;
1870 if (headerisdata)
1871 memcpy (xbuf, header, 8);
1873 while (xread < This->datalen) {
1874 ULONG nread;
1875 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1876 xread+=nread;
1877 if (hr || !nread)
1878 break;
1880 if (xread != This->datalen)
1881 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1883 if (This->datalen == 0) { /* Marks the "NONE" picture */
1884 This->desc.picType = PICTYPE_NONE;
1885 return S_OK;
1889 /****************************************************************************************
1890 * Part 2: Process the loaded data
1893 magic = xbuf[0] + (xbuf[1]<<8);
1894 This->loadtime_format = magic;
1896 switch (magic) {
1897 case BITMAP_FORMAT_GIF: /* GIF */
1898 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1899 break;
1900 case BITMAP_FORMAT_JPEG: /* JPEG */
1901 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1902 break;
1903 case BITMAP_FORMAT_BMP: /* Bitmap */
1904 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1905 break;
1906 case BITMAP_FORMAT_PNG: /* PNG */
1907 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1908 break;
1909 case BITMAP_FORMAT_APM: /* APM */
1910 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1911 break;
1912 case 0x0000: { /* ICON , first word is dwReserved */
1913 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1914 break;
1916 default:
1918 unsigned int i;
1920 /* let's see if it's a EMF */
1921 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1922 if (hr == S_OK) break;
1924 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1925 hr=E_FAIL;
1926 for (i=0;i<xread+8;i++) {
1927 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1928 else MESSAGE("%02x ",xbuf[i-8]);
1929 if (i % 10 == 9) MESSAGE("\n");
1931 MESSAGE("\n");
1932 break;
1935 This->bIsDirty = FALSE;
1937 /* FIXME: this notify is not really documented */
1938 if (hr==S_OK)
1939 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1940 return hr;
1943 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1945 int iSuccess = 0;
1946 HDC hDC;
1947 BITMAPINFO * pInfoBitmap;
1948 int iNumPaletteEntries;
1949 unsigned char * pPixelData;
1950 BITMAPFILEHEADER * pFileHeader;
1951 BITMAPINFO * pInfoHeader;
1953 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1954 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1956 /* Find out bitmap size and padded length */
1957 hDC = GetDC(0);
1958 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1959 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1961 /* Fetch bitmap palette & pixel data */
1963 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1964 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1966 /* Calculate the total length required for the BMP data */
1967 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1968 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1969 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1970 } else {
1971 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1972 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1973 else
1974 iNumPaletteEntries = 0;
1976 *pLength =
1977 sizeof(BITMAPFILEHEADER) +
1978 sizeof(BITMAPINFOHEADER) +
1979 iNumPaletteEntries * sizeof(RGBQUAD) +
1980 pInfoBitmap->bmiHeader.biSizeImage;
1981 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1983 /* Fill the BITMAPFILEHEADER */
1984 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1985 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1986 pFileHeader->bfSize = *pLength;
1987 pFileHeader->bfOffBits =
1988 sizeof(BITMAPFILEHEADER) +
1989 sizeof(BITMAPINFOHEADER) +
1990 iNumPaletteEntries * sizeof(RGBQUAD);
1992 /* Fill the BITMAPINFOHEADER and the palette data */
1993 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1994 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1995 memcpy(
1996 (unsigned char *)(*ppBuffer) +
1997 sizeof(BITMAPFILEHEADER) +
1998 sizeof(BITMAPINFOHEADER) +
1999 iNumPaletteEntries * sizeof(RGBQUAD),
2000 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2001 iSuccess = 1;
2003 HeapFree(GetProcessHeap(), 0, pPixelData);
2004 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2005 return iSuccess;
2008 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2010 ICONINFO infoIcon;
2011 int iSuccess = 0;
2013 *ppBuffer = NULL; *pLength = 0;
2014 if (GetIconInfo(hIcon, &infoIcon)) {
2015 HDC hDC;
2016 BITMAPINFO * pInfoBitmap;
2017 unsigned char * pIconData = NULL;
2018 unsigned int iDataSize = 0;
2020 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2022 /* Find out icon size */
2023 hDC = GetDC(0);
2024 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2025 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2026 if (1) {
2027 /* Auxiliary pointers */
2028 CURSORICONFILEDIR * pIconDir;
2029 CURSORICONFILEDIRENTRY * pIconEntry;
2030 BITMAPINFOHEADER * pIconBitmapHeader;
2031 unsigned int iOffsetPalette;
2032 unsigned int iOffsetColorData;
2033 unsigned int iOffsetMaskData;
2035 unsigned int iLengthScanLineColor;
2036 unsigned int iLengthScanLineMask;
2037 unsigned int iNumEntriesPalette;
2039 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2040 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2042 FIXME("DEBUG: bitmap size is %d x %d\n",
2043 pInfoBitmap->bmiHeader.biWidth,
2044 pInfoBitmap->bmiHeader.biHeight);
2045 FIXME("DEBUG: bitmap bpp is %d\n",
2046 pInfoBitmap->bmiHeader.biBitCount);
2047 FIXME("DEBUG: bitmap nplanes is %d\n",
2048 pInfoBitmap->bmiHeader.biPlanes);
2049 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2050 pInfoBitmap->bmiHeader.biSizeImage);
2052 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2053 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2054 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2056 /* Fill out the CURSORICONFILEDIR */
2057 pIconDir = (CURSORICONFILEDIR *)pIconData;
2058 pIconDir->idType = 1;
2059 pIconDir->idCount = 1;
2061 /* Fill out the CURSORICONFILEDIRENTRY */
2062 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2063 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2064 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2065 pIconEntry->bColorCount =
2066 (pInfoBitmap->bmiHeader.biBitCount < 8)
2067 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2068 : 0;
2069 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2070 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2071 pIconEntry->dwDIBSize = 0;
2072 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2074 /* Fill out the BITMAPINFOHEADER */
2075 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2076 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2078 /* Find out whether a palette exists for the bitmap */
2079 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2080 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2081 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2082 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2083 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2084 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2085 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2086 iNumEntriesPalette = 3;
2087 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2088 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2089 } else {
2090 iNumEntriesPalette = 0;
2093 /* Add bitmap size and header size to icon data size. */
2094 iOffsetPalette = iDataSize;
2095 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2096 iOffsetColorData = iDataSize;
2097 iDataSize += pIconBitmapHeader->biSizeImage;
2098 iOffsetMaskData = iDataSize;
2099 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2100 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2101 pIconBitmapHeader->biHeight *= 2;
2102 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2103 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2104 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2105 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2107 /* Get the actual bitmap data from the icon bitmap */
2108 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2109 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2110 if (iNumEntriesPalette > 0) {
2111 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2112 iNumEntriesPalette * sizeof(RGBQUAD));
2115 /* Reset all values so that GetDIBits call succeeds */
2116 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2117 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2118 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2120 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2121 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2122 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2124 printf("ERROR: unable to get bitmap mask (error %u)\n",
2125 GetLastError());
2129 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2130 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2132 /* Write out everything produced so far to the stream */
2133 *ppBuffer = pIconData; *pLength = iDataSize;
2134 iSuccess = 1;
2135 } else {
2137 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2138 GetLastError());
2142 Remarks (from MSDN entry on GetIconInfo):
2144 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2145 members of ICONINFO. The calling application must manage
2146 these bitmaps and delete them when they are no longer
2147 necessary.
2149 if (hDC) ReleaseDC(0, hDC);
2150 DeleteObject(infoIcon.hbmMask);
2151 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2152 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2153 } else {
2154 printf("ERROR: Unable to get icon information (error %u)\n",
2155 GetLastError());
2157 return iSuccess;
2160 static HRESULT WINAPI OLEPictureImpl_Save(
2161 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2163 HRESULT hResult = E_NOTIMPL;
2164 void * pIconData;
2165 unsigned int iDataSize;
2166 ULONG dummy;
2167 int iSerializeResult = 0;
2168 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2170 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2172 switch (This->desc.picType) {
2173 case PICTYPE_ICON:
2174 if (This->bIsDirty || !This->data) {
2175 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2176 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2177 hResult = E_FAIL;
2178 break;
2180 HeapFree(GetProcessHeap(), 0, This->data);
2181 This->data = pIconData;
2182 This->datalen = iDataSize;
2184 if (This->loadtime_magic != 0xdeadbeef) {
2185 DWORD header[2];
2187 header[0] = This->loadtime_magic;
2188 header[1] = This->datalen;
2189 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2191 IStream_Write(pStm, This->data, This->datalen, &dummy);
2193 hResult = S_OK;
2194 break;
2195 case PICTYPE_BITMAP:
2196 if (This->bIsDirty) {
2197 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2198 case BITMAP_FORMAT_BMP:
2199 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2200 break;
2201 case BITMAP_FORMAT_JPEG:
2202 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2203 break;
2204 case BITMAP_FORMAT_GIF:
2205 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2206 break;
2207 case BITMAP_FORMAT_PNG:
2208 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2209 break;
2210 default:
2211 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2212 break;
2214 if (iSerializeResult) {
2216 if (This->loadtime_magic != 0xdeadbeef) {
2218 if (1) {
2219 DWORD header[2];
2221 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2222 header[1] = iDataSize;
2223 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2225 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2227 HeapFree(GetProcessHeap(), 0, This->data);
2228 This->data = pIconData;
2229 This->datalen = iDataSize;
2230 hResult = S_OK;
2232 } else {
2234 if (This->loadtime_magic != 0xdeadbeef) {
2236 if (1) {
2237 DWORD header[2];
2239 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2240 header[1] = This->datalen;
2241 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2243 IStream_Write(pStm, This->data, This->datalen, &dummy);
2244 hResult = S_OK;
2246 break;
2247 case PICTYPE_METAFILE:
2248 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2249 break;
2250 case PICTYPE_ENHMETAFILE:
2251 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2252 break;
2253 default:
2254 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2255 break;
2257 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2258 return hResult;
2261 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2262 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2264 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2265 FIXME("(%p,%p),stub!\n",This,pcbSize);
2266 return E_NOTIMPL;
2270 /************************************************************************
2271 * IDispatch
2274 /************************************************************************
2275 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2277 * See Windows documentation for more details on IUnknown methods.
2279 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2280 IDispatch* iface,
2281 REFIID riid,
2282 VOID** ppvoid)
2284 OLEPictureImpl *This = impl_from_IDispatch(iface);
2286 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2289 /************************************************************************
2290 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2292 * See Windows documentation for more details on IUnknown methods.
2294 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2295 IDispatch* iface)
2297 OLEPictureImpl *This = impl_from_IDispatch(iface);
2299 return IPicture_AddRef((IPicture *)This);
2302 /************************************************************************
2303 * OLEPictureImpl_IDispatch_Release (IUnknown)
2305 * See Windows documentation for more details on IUnknown methods.
2307 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2308 IDispatch* iface)
2310 OLEPictureImpl *This = impl_from_IDispatch(iface);
2312 return IPicture_Release((IPicture *)This);
2315 /************************************************************************
2316 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2318 * See Windows documentation for more details on IDispatch methods.
2320 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2321 IDispatch* iface,
2322 unsigned int* pctinfo)
2324 TRACE("(%p)\n", pctinfo);
2326 *pctinfo = 1;
2328 return S_OK;
2331 /************************************************************************
2332 * OLEPictureImpl_GetTypeInfo (IDispatch)
2334 * See Windows documentation for more details on IDispatch methods.
2336 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2337 IDispatch* iface,
2338 UINT iTInfo,
2339 LCID lcid,
2340 ITypeInfo** ppTInfo)
2342 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2343 ITypeLib *tl;
2344 HRESULT hres;
2346 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2348 if (iTInfo != 0)
2349 return E_FAIL;
2351 hres = LoadTypeLib(stdole2tlb, &tl);
2352 if (FAILED(hres))
2354 ERR("Could not load stdole2.tlb\n");
2355 return hres;
2358 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2359 if (FAILED(hres))
2360 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2362 return hres;
2365 /************************************************************************
2366 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2368 * See Windows documentation for more details on IDispatch methods.
2370 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2371 IDispatch* iface,
2372 REFIID riid,
2373 LPOLESTR* rgszNames,
2374 UINT cNames,
2375 LCID lcid,
2376 DISPID* rgDispId)
2378 ITypeInfo * pTInfo;
2379 HRESULT hres;
2381 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2382 rgszNames, cNames, (int)lcid, rgDispId);
2384 if (cNames == 0)
2386 return E_INVALIDARG;
2388 else
2390 /* retrieve type information */
2391 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2393 if (FAILED(hres))
2395 ERR("GetTypeInfo failed.\n");
2396 return hres;
2399 /* convert names to DISPIDs */
2400 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2401 ITypeInfo_Release(pTInfo);
2403 return hres;
2407 /************************************************************************
2408 * OLEPictureImpl_Invoke (IDispatch)
2410 * See Windows documentation for more details on IDispatch methods.
2412 static HRESULT WINAPI OLEPictureImpl_Invoke(
2413 IDispatch* iface,
2414 DISPID dispIdMember,
2415 REFIID riid,
2416 LCID lcid,
2417 WORD wFlags,
2418 DISPPARAMS* pDispParams,
2419 VARIANT* pVarResult,
2420 EXCEPINFO* pExepInfo,
2421 UINT* puArgErr)
2423 OLEPictureImpl *This = impl_from_IDispatch(iface);
2425 /* validate parameters */
2427 if (!IsEqualIID(riid, &IID_NULL))
2429 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2430 return DISP_E_UNKNOWNNAME;
2433 if (!pDispParams)
2435 ERR("null pDispParams not allowed\n");
2436 return DISP_E_PARAMNOTOPTIONAL;
2439 if (wFlags & DISPATCH_PROPERTYGET)
2441 if (pDispParams->cArgs != 0)
2443 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2444 return DISP_E_BADPARAMCOUNT;
2446 if (!pVarResult)
2448 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2449 return DISP_E_PARAMNOTOPTIONAL;
2452 else if (wFlags & DISPATCH_PROPERTYPUT)
2454 if (pDispParams->cArgs != 1)
2456 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2457 return DISP_E_BADPARAMCOUNT;
2461 switch (dispIdMember)
2463 case DISPID_PICT_HANDLE:
2464 if (wFlags & DISPATCH_PROPERTYGET)
2466 TRACE("DISPID_PICT_HANDLE\n");
2467 V_VT(pVarResult) = VT_I4;
2468 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2470 break;
2471 case DISPID_PICT_HPAL:
2472 if (wFlags & DISPATCH_PROPERTYGET)
2474 TRACE("DISPID_PICT_HPAL\n");
2475 V_VT(pVarResult) = VT_I4;
2476 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2478 else if (wFlags & DISPATCH_PROPERTYPUT)
2480 VARIANTARG vararg;
2481 HRESULT hr;
2482 TRACE("DISPID_PICT_HPAL\n");
2484 VariantInit(&vararg);
2485 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2486 if (FAILED(hr))
2487 return hr;
2489 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2491 VariantClear(&vararg);
2492 return hr;
2494 break;
2495 case DISPID_PICT_TYPE:
2496 if (wFlags & DISPATCH_PROPERTYGET)
2498 TRACE("DISPID_PICT_TYPE\n");
2499 V_VT(pVarResult) = VT_I2;
2500 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2502 break;
2503 case DISPID_PICT_WIDTH:
2504 if (wFlags & DISPATCH_PROPERTYGET)
2506 TRACE("DISPID_PICT_WIDTH\n");
2507 V_VT(pVarResult) = VT_I4;
2508 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2510 break;
2511 case DISPID_PICT_HEIGHT:
2512 if (wFlags & DISPATCH_PROPERTYGET)
2514 TRACE("DISPID_PICT_HEIGHT\n");
2515 V_VT(pVarResult) = VT_I4;
2516 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2518 break;
2521 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2522 return DISP_E_MEMBERNOTFOUND;
2526 static const IPictureVtbl OLEPictureImpl_VTable =
2528 OLEPictureImpl_QueryInterface,
2529 OLEPictureImpl_AddRef,
2530 OLEPictureImpl_Release,
2531 OLEPictureImpl_get_Handle,
2532 OLEPictureImpl_get_hPal,
2533 OLEPictureImpl_get_Type,
2534 OLEPictureImpl_get_Width,
2535 OLEPictureImpl_get_Height,
2536 OLEPictureImpl_Render,
2537 OLEPictureImpl_set_hPal,
2538 OLEPictureImpl_get_CurDC,
2539 OLEPictureImpl_SelectPicture,
2540 OLEPictureImpl_get_KeepOriginalFormat,
2541 OLEPictureImpl_put_KeepOriginalFormat,
2542 OLEPictureImpl_PictureChanged,
2543 OLEPictureImpl_SaveAsFile,
2544 OLEPictureImpl_get_Attributes
2547 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2549 OLEPictureImpl_IDispatch_QueryInterface,
2550 OLEPictureImpl_IDispatch_AddRef,
2551 OLEPictureImpl_IDispatch_Release,
2552 OLEPictureImpl_GetTypeInfoCount,
2553 OLEPictureImpl_GetTypeInfo,
2554 OLEPictureImpl_GetIDsOfNames,
2555 OLEPictureImpl_Invoke
2558 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2560 OLEPictureImpl_IPersistStream_QueryInterface,
2561 OLEPictureImpl_IPersistStream_AddRef,
2562 OLEPictureImpl_IPersistStream_Release,
2563 OLEPictureImpl_GetClassID,
2564 OLEPictureImpl_IsDirty,
2565 OLEPictureImpl_Load,
2566 OLEPictureImpl_Save,
2567 OLEPictureImpl_GetSizeMax
2570 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2572 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2573 OLEPictureImpl_IConnectionPointContainer_AddRef,
2574 OLEPictureImpl_IConnectionPointContainer_Release,
2575 OLEPictureImpl_EnumConnectionPoints,
2576 OLEPictureImpl_FindConnectionPoint
2579 /***********************************************************************
2580 * OleCreatePictureIndirect (OLEAUT32.419)
2582 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2583 BOOL fOwn, LPVOID *ppvObj )
2585 OLEPictureImpl* newPict = NULL;
2586 HRESULT hr = S_OK;
2588 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2591 * Sanity check
2593 if (ppvObj==0)
2594 return E_POINTER;
2596 *ppvObj = NULL;
2599 * Try to construct a new instance of the class.
2601 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2603 if (newPict == NULL)
2604 return E_OUTOFMEMORY;
2607 * Make sure it supports the interface required by the caller.
2609 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2612 * Release the reference obtained in the constructor. If
2613 * the QueryInterface was unsuccessful, it will free the class.
2615 IPicture_Release((IPicture*)newPict);
2617 return hr;
2621 /***********************************************************************
2622 * OleLoadPicture (OLEAUT32.418)
2624 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2625 REFIID riid, LPVOID *ppvObj )
2627 LPPERSISTSTREAM ps;
2628 IPicture *newpic;
2629 HRESULT hr;
2631 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2632 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2634 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2635 if (hr)
2636 return hr;
2637 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2638 if (hr) {
2639 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2640 IPicture_Release(newpic);
2641 *ppvObj = NULL;
2642 return hr;
2644 hr = IPersistStream_Load(ps,lpstream);
2645 IPersistStream_Release(ps);
2646 if (FAILED(hr))
2648 ERR("IPersistStream_Load failed\n");
2649 IPicture_Release(newpic);
2650 *ppvObj = NULL;
2651 return hr;
2653 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2654 if (hr)
2655 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2656 IPicture_Release(newpic);
2657 return hr;
2660 /***********************************************************************
2661 * OleLoadPictureEx (OLEAUT32.401)
2663 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2664 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2666 LPPERSISTSTREAM ps;
2667 IPicture *newpic;
2668 HRESULT hr;
2670 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2671 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2673 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2674 if (hr)
2675 return hr;
2676 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2677 if (hr) {
2678 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2679 IPicture_Release(newpic);
2680 *ppvObj = NULL;
2681 return hr;
2683 hr = IPersistStream_Load(ps,lpstream);
2684 IPersistStream_Release(ps);
2685 if (FAILED(hr))
2687 ERR("IPersistStream_Load failed\n");
2688 IPicture_Release(newpic);
2689 *ppvObj = NULL;
2690 return hr;
2692 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2693 if (hr)
2694 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2695 IPicture_Release(newpic);
2696 return hr;
2699 /***********************************************************************
2700 * OleLoadPicturePath (OLEAUT32.424)
2702 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2703 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2704 LPVOID *ppvRet )
2706 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2707 IPicture *ipicture;
2708 HANDLE hFile;
2709 DWORD dwFileSize;
2710 HGLOBAL hGlobal = NULL;
2711 DWORD dwBytesRead = 0;
2712 IStream *stream;
2713 BOOL bRead;
2714 IPersistStream *pStream;
2715 HRESULT hRes;
2717 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2718 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2719 debugstr_guid(riid), ppvRet);
2721 if (!ppvRet) return E_POINTER;
2723 if (strncmpW(szURLorPath, file, 7) == 0) {
2724 szURLorPath += 7;
2726 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2727 0, NULL);
2728 if (hFile == INVALID_HANDLE_VALUE)
2729 return E_UNEXPECTED;
2731 dwFileSize = GetFileSize(hFile, NULL);
2732 if (dwFileSize != INVALID_FILE_SIZE )
2734 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2735 if ( hGlobal)
2737 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2738 if (!bRead)
2740 GlobalFree(hGlobal);
2741 hGlobal = 0;
2745 CloseHandle(hFile);
2747 if (!hGlobal)
2748 return E_UNEXPECTED;
2750 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2751 if (FAILED(hRes))
2753 GlobalFree(hGlobal);
2754 return hRes;
2756 } else {
2757 IMoniker *pmnk;
2758 IBindCtx *pbc;
2760 hRes = CreateBindCtx(0, &pbc);
2761 if (SUCCEEDED(hRes))
2763 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2764 if (SUCCEEDED(hRes))
2766 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2767 IMoniker_Release(pmnk);
2769 IBindCtx_Release(pbc);
2771 if (FAILED(hRes))
2772 return hRes;
2775 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2776 &IID_IPicture, (LPVOID*)&ipicture);
2777 if (hRes != S_OK) {
2778 IStream_Release(stream);
2779 return hRes;
2782 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2783 if (hRes) {
2784 IStream_Release(stream);
2785 IPicture_Release(ipicture);
2786 return hRes;
2789 hRes = IPersistStream_Load(pStream, stream);
2790 IPersistStream_Release(pStream);
2791 IStream_Release(stream);
2793 if (hRes) {
2794 IPicture_Release(ipicture);
2795 return hRes;
2798 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2799 if (hRes)
2800 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2802 IPicture_Release(ipicture);
2803 return hRes;
2806 /*******************************************************************************
2807 * StdPic ClassFactory
2809 typedef struct
2811 /* IUnknown fields */
2812 const IClassFactoryVtbl *lpVtbl;
2813 LONG ref;
2814 } IClassFactoryImpl;
2816 static HRESULT WINAPI
2817 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2818 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2820 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2821 return E_NOINTERFACE;
2824 static ULONG WINAPI
2825 SPCF_AddRef(LPCLASSFACTORY iface) {
2826 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2827 return InterlockedIncrement(&This->ref);
2830 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2831 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2832 /* static class, won't be freed */
2833 return InterlockedDecrement(&This->ref);
2836 static HRESULT WINAPI SPCF_CreateInstance(
2837 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2839 /* Creates an uninitialized picture */
2840 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2844 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2845 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2846 FIXME("(%p)->(%d),stub!\n",This,dolock);
2847 return S_OK;
2850 static const IClassFactoryVtbl SPCF_Vtbl = {
2851 SPCF_QueryInterface,
2852 SPCF_AddRef,
2853 SPCF_Release,
2854 SPCF_CreateInstance,
2855 SPCF_LockServer
2857 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2859 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }