push 9d6e510d5bb9560a6aa2e6ec402cb2d2444b5081
[wine/hacks.git] / dlls / oleaut32 / olepicture.c
bloba0f18558784c449bf942bc02f5d88e3ba6ac25d8
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);
523 if(!phandle)
524 return E_POINTER;
526 switch(This->desc.picType) {
527 case PICTYPE_NONE:
528 case PICTYPE_UNINITIALIZED:
529 *phandle = 0;
530 break;
531 case PICTYPE_BITMAP:
532 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
533 break;
534 case PICTYPE_METAFILE:
535 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
536 break;
537 case PICTYPE_ICON:
538 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
539 break;
540 case PICTYPE_ENHMETAFILE:
541 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
542 break;
543 default:
544 FIXME("Unimplemented type %d\n", This->desc.picType);
545 return E_NOTIMPL;
547 TRACE("returning handle %08x\n", *phandle);
548 return S_OK;
551 /************************************************************************
552 * OLEPictureImpl_get_hPal
554 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
555 OLE_HANDLE *phandle)
557 OLEPictureImpl *This = (OLEPictureImpl *)iface;
558 HRESULT hres;
559 TRACE("(%p)->(%p)\n", This, phandle);
561 if (!phandle)
562 return E_POINTER;
564 switch (This->desc.picType) {
565 case (UINT)PICTYPE_UNINITIALIZED:
566 case PICTYPE_NONE:
567 *phandle = 0;
568 hres = S_FALSE;
569 break;
570 case PICTYPE_BITMAP:
571 *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
572 hres = S_OK;
573 break;
574 case PICTYPE_METAFILE:
575 hres = E_FAIL;
576 break;
577 case PICTYPE_ICON:
578 case PICTYPE_ENHMETAFILE:
579 default:
580 FIXME("unimplemented for type %d. Returning 0 palette.\n",
581 This->desc.picType);
582 *phandle = 0;
583 hres = S_OK;
586 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
587 return hres;
590 /************************************************************************
591 * OLEPictureImpl_get_Type
593 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
594 short *ptype)
596 OLEPictureImpl *This = (OLEPictureImpl *)iface;
597 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
599 if(!ptype)
600 return E_POINTER;
602 *ptype = This->desc.picType;
603 return S_OK;
606 /************************************************************************
607 * OLEPictureImpl_get_Width
609 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
610 OLE_XSIZE_HIMETRIC *pwidth)
612 OLEPictureImpl *This = (OLEPictureImpl *)iface;
613 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
614 *pwidth = This->himetricWidth;
615 return S_OK;
618 /************************************************************************
619 * OLEPictureImpl_get_Height
621 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
622 OLE_YSIZE_HIMETRIC *pheight)
624 OLEPictureImpl *This = (OLEPictureImpl *)iface;
625 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
626 *pheight = This->himetricHeight;
627 return S_OK;
630 /************************************************************************
631 * OLEPictureImpl_Render
633 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
634 LONG x, LONG y, LONG cx, LONG cy,
635 OLE_XPOS_HIMETRIC xSrc,
636 OLE_YPOS_HIMETRIC ySrc,
637 OLE_XSIZE_HIMETRIC cxSrc,
638 OLE_YSIZE_HIMETRIC cySrc,
639 LPCRECT prcWBounds)
641 OLEPictureImpl *This = (OLEPictureImpl *)iface;
642 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
643 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
644 if(prcWBounds)
645 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
646 prcWBounds->right, prcWBounds->bottom);
648 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
649 return CTL_E_INVALIDPROPERTYVALUE;
653 * While the documentation suggests this to be here (or after rendering?)
654 * it does cause an endless recursion in my sample app. -MM 20010804
655 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
658 switch(This->desc.picType) {
659 case PICTYPE_UNINITIALIZED:
660 case PICTYPE_NONE:
661 /* nothing to do */
662 return S_OK;
663 case PICTYPE_BITMAP:
665 HBITMAP hbmpOld;
666 HDC hdcBmp;
668 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
669 NB y-axis gets flipped */
671 hdcBmp = CreateCompatibleDC(0);
672 SetMapMode(hdcBmp, MM_ANISOTROPIC);
673 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
674 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
675 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
676 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
678 if (This->hbmMask) {
679 HDC hdcMask = CreateCompatibleDC(0);
680 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
682 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
684 SetMapMode(hdcMask, MM_ANISOTROPIC);
685 SetWindowOrgEx(hdcMask, 0, 0, NULL);
686 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
687 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
688 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
690 SetBkColor(hdc, RGB(255, 255, 255));
691 SetTextColor(hdc, RGB(0, 0, 0));
692 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
693 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
695 SelectObject(hdcMask, hOldbm);
696 DeleteDC(hdcMask);
697 } else {
698 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
699 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
702 SelectObject(hdcBmp, hbmpOld);
703 DeleteDC(hdcBmp);
705 break;
706 case PICTYPE_ICON:
707 FIXME("Not quite correct implementation of rendering icons...\n");
708 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
709 break;
711 case PICTYPE_METAFILE:
713 POINT prevOrg;
714 SIZE prevExt;
715 int oldmode;
717 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
718 SetViewportOrgEx(hdc, x, y, &prevOrg);
719 SetViewportExtEx(hdc, cx, cy, &prevExt);
721 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
722 ERR("PlayMetaFile failed!\n");
724 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
725 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
726 SetMapMode(hdc, oldmode);
727 break;
730 case PICTYPE_ENHMETAFILE:
732 RECT rc = { x, y, x + cx, y + cy };
733 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
734 break;
737 default:
738 FIXME("type %d not implemented\n", This->desc.picType);
739 return E_NOTIMPL;
741 return S_OK;
744 /************************************************************************
745 * OLEPictureImpl_set_hPal
747 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
748 OLE_HANDLE hpal)
750 OLEPictureImpl *This = (OLEPictureImpl *)iface;
751 FIXME("(%p)->(%08x): stub\n", This, hpal);
752 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
753 return E_NOTIMPL;
756 /************************************************************************
757 * OLEPictureImpl_get_CurDC
759 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
760 HDC *phdc)
762 OLEPictureImpl *This = (OLEPictureImpl *)iface;
763 TRACE("(%p), returning %p\n", This, This->hDCCur);
764 if (phdc) *phdc = This->hDCCur;
765 return S_OK;
768 /************************************************************************
769 * OLEPictureImpl_SelectPicture
771 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
772 HDC hdcIn,
773 HDC *phdcOut,
774 OLE_HANDLE *phbmpOut)
776 OLEPictureImpl *This = (OLEPictureImpl *)iface;
777 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
778 if (This->desc.picType == PICTYPE_BITMAP) {
779 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
781 if (phdcOut)
782 *phdcOut = This->hDCCur;
783 This->hDCCur = hdcIn;
784 if (phbmpOut)
785 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
786 return S_OK;
787 } else {
788 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
789 return E_FAIL;
793 /************************************************************************
794 * OLEPictureImpl_get_KeepOriginalFormat
796 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
797 BOOL *pfKeep)
799 OLEPictureImpl *This = (OLEPictureImpl *)iface;
800 TRACE("(%p)->(%p)\n", This, pfKeep);
801 if (!pfKeep)
802 return E_POINTER;
803 *pfKeep = This->keepOrigFormat;
804 return S_OK;
807 /************************************************************************
808 * OLEPictureImpl_put_KeepOriginalFormat
810 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
811 BOOL keep)
813 OLEPictureImpl *This = (OLEPictureImpl *)iface;
814 TRACE("(%p)->(%d)\n", This, keep);
815 This->keepOrigFormat = keep;
816 /* FIXME: what DISPID notification here? */
817 return S_OK;
820 /************************************************************************
821 * OLEPictureImpl_PictureChanged
823 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
825 OLEPictureImpl *This = (OLEPictureImpl *)iface;
826 TRACE("(%p)->()\n", This);
827 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
828 This->bIsDirty = TRUE;
829 return S_OK;
832 /************************************************************************
833 * OLEPictureImpl_SaveAsFile
835 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
836 IStream *pstream,
837 BOOL SaveMemCopy,
838 LONG *pcbSize)
840 OLEPictureImpl *This = (OLEPictureImpl *)iface;
841 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
842 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
845 /************************************************************************
846 * OLEPictureImpl_get_Attributes
848 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
849 DWORD *pdwAttr)
851 OLEPictureImpl *This = (OLEPictureImpl *)iface;
852 TRACE("(%p)->(%p).\n", This, pdwAttr);
854 if(!pdwAttr)
855 return E_POINTER;
857 *pdwAttr = 0;
858 switch (This->desc.picType) {
859 case PICTYPE_UNINITIALIZED:
860 case PICTYPE_NONE: break;
861 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
862 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
863 case PICTYPE_ENHMETAFILE: /* fall through */
864 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
865 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
867 return S_OK;
871 /************************************************************************
872 * IConnectionPointContainer
874 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
875 IConnectionPointContainer* iface,
876 REFIID riid,
877 VOID** ppvoid)
879 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
881 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
884 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
885 IConnectionPointContainer* iface)
887 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
889 return IPicture_AddRef((IPicture *)This);
892 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
893 IConnectionPointContainer* iface)
895 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
897 return IPicture_Release((IPicture *)This);
900 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
901 IConnectionPointContainer* iface,
902 IEnumConnectionPoints** ppEnum)
904 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
906 FIXME("(%p,%p), stub!\n",This,ppEnum);
907 return E_NOTIMPL;
910 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
911 IConnectionPointContainer* iface,
912 REFIID riid,
913 IConnectionPoint **ppCP)
915 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
916 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
917 if (!ppCP)
918 return E_POINTER;
919 *ppCP = NULL;
920 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
921 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
922 FIXME("no connection point for %s\n",debugstr_guid(riid));
923 return CONNECT_E_NOCONNECTION;
927 /************************************************************************
928 * IPersistStream
931 /************************************************************************
932 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
934 * See Windows documentation for more details on IUnknown methods.
936 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
937 IPersistStream* iface,
938 REFIID riid,
939 VOID** ppvoid)
941 OLEPictureImpl *This = impl_from_IPersistStream(iface);
943 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
946 /************************************************************************
947 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
949 * See Windows documentation for more details on IUnknown methods.
951 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
952 IPersistStream* iface)
954 OLEPictureImpl *This = impl_from_IPersistStream(iface);
956 return IPicture_AddRef((IPicture *)This);
959 /************************************************************************
960 * OLEPictureImpl_IPersistStream_Release (IUnknown)
962 * See Windows documentation for more details on IUnknown methods.
964 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
965 IPersistStream* iface)
967 OLEPictureImpl *This = impl_from_IPersistStream(iface);
969 return IPicture_Release((IPicture *)This);
972 /************************************************************************
973 * OLEPictureImpl_IPersistStream_GetClassID
975 static HRESULT WINAPI OLEPictureImpl_GetClassID(
976 IPersistStream* iface,CLSID* pClassID)
978 TRACE("(%p)\n", pClassID);
979 *pClassID = CLSID_StdPicture;
980 return S_OK;
983 /************************************************************************
984 * OLEPictureImpl_IPersistStream_IsDirty
986 static HRESULT WINAPI OLEPictureImpl_IsDirty(
987 IPersistStream* iface)
989 OLEPictureImpl *This = impl_from_IPersistStream(iface);
990 FIXME("(%p),stub!\n",This);
991 return E_NOTIMPL;
994 #ifdef SONAME_LIBJPEG
996 static void *libjpeg_handle;
997 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
998 MAKE_FUNCPTR(jpeg_std_error);
999 MAKE_FUNCPTR(jpeg_CreateDecompress);
1000 MAKE_FUNCPTR(jpeg_read_header);
1001 MAKE_FUNCPTR(jpeg_start_decompress);
1002 MAKE_FUNCPTR(jpeg_read_scanlines);
1003 MAKE_FUNCPTR(jpeg_finish_decompress);
1004 MAKE_FUNCPTR(jpeg_destroy_decompress);
1005 #undef MAKE_FUNCPTR
1007 static void *load_libjpeg(void)
1009 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
1011 #define LOAD_FUNCPTR(f) \
1012 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
1013 libjpeg_handle = NULL; \
1014 return NULL; \
1017 LOAD_FUNCPTR(jpeg_std_error);
1018 LOAD_FUNCPTR(jpeg_CreateDecompress);
1019 LOAD_FUNCPTR(jpeg_read_header);
1020 LOAD_FUNCPTR(jpeg_start_decompress);
1021 LOAD_FUNCPTR(jpeg_read_scanlines);
1022 LOAD_FUNCPTR(jpeg_finish_decompress);
1023 LOAD_FUNCPTR(jpeg_destroy_decompress);
1024 #undef LOAD_FUNCPTR
1026 return libjpeg_handle;
1029 /* for the jpeg decompressor source manager. */
1030 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1032 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1033 ERR("(), should not get here.\n");
1034 return FALSE;
1037 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1038 TRACE("Skipping %ld bytes...\n", num_bytes);
1039 cinfo->src->next_input_byte += num_bytes;
1040 cinfo->src->bytes_in_buffer -= num_bytes;
1043 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1044 ERR("(desired=%d), should not get here.\n",desired);
1045 return FALSE;
1047 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1048 #endif /* SONAME_LIBJPEG */
1050 struct gifdata {
1051 unsigned char *data;
1052 unsigned int curoff;
1053 unsigned int len;
1056 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1057 struct gifdata *gd = (struct gifdata*)gif->UserData;
1059 if (len+gd->curoff > gd->len) {
1060 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1061 len = gd->len - gd->curoff;
1063 memcpy(data, gd->data+gd->curoff, len);
1064 gd->curoff += len;
1065 return len;
1069 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1071 struct gifdata gd;
1072 GifFileType *gif;
1073 BITMAPINFO *bmi;
1074 HDC hdcref;
1075 LPBYTE bytes;
1076 int i,j,ret;
1077 GifImageDesc *gid;
1078 SavedImage *si;
1079 ColorMapObject *cm;
1080 int transparent = -1;
1081 ExtensionBlock *eb;
1082 int padding;
1084 gd.data = xbuf;
1085 gd.curoff = 0;
1086 gd.len = xread;
1087 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1088 ret = DGifSlurp(gif);
1089 if (ret == GIF_ERROR) {
1090 ERR("Failed reading GIF using libgif.\n");
1091 return E_FAIL;
1093 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1094 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1095 TRACE("imgcnt %d\n", gif->ImageCount);
1096 if (gif->ImageCount<1) {
1097 ERR("GIF stream does not have images inside?\n");
1098 return E_FAIL;
1100 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1101 gif->Image.Width, gif->Image.Height,
1102 gif->Image.Left, gif->Image.Top,
1103 gif->Image.Interlace
1105 /* */
1106 padding = (gif->SWidth+3) & ~3;
1107 si = gif->SavedImages+0;
1108 gid = &(si->ImageDesc);
1109 cm = gid->ColorMap;
1110 if (!cm) cm = gif->SColorMap;
1111 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1112 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1114 /* look for the transparent color extension */
1115 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1116 eb = si->ExtensionBlocks + i;
1117 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1118 if ((eb->Bytes[0] & 1) == 1) {
1119 transparent = (unsigned char)eb->Bytes[3];
1124 for (i = 0; i < cm->ColorCount; i++) {
1125 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1126 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1127 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1128 if (i == transparent) {
1129 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1130 bmi->bmiColors[i].rgbGreen,
1131 bmi->bmiColors[i].rgbBlue);
1135 /* Map to in picture coordinates */
1136 for (i = 0, j = 0; i < gid->Height; i++) {
1137 if (gif->Image.Interlace) {
1138 memcpy(
1139 bytes + (gid->Top + j) * padding + gid->Left,
1140 si->RasterBits + i * gid->Width,
1141 gid->Width);
1143 /* Lower bits of interlaced counter encode current interlace */
1144 if (j & 1) j += 2; /* Currently filling odd rows */
1145 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1146 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1148 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1149 /* End of current interlace, go to next interlace */
1150 if (j & 2) j = 1; /* Next iteration fills odd rows */
1151 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1152 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1154 } else {
1155 memcpy(
1156 bytes + (gid->Top + i) * padding + gid->Left,
1157 si->RasterBits + i * gid->Width,
1158 gid->Width);
1162 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1163 bmi->bmiHeader.biWidth = gif->SWidth;
1164 bmi->bmiHeader.biHeight = -gif->SHeight;
1165 bmi->bmiHeader.biPlanes = 1;
1166 bmi->bmiHeader.biBitCount = 8;
1167 bmi->bmiHeader.biCompression = BI_RGB;
1168 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1169 bmi->bmiHeader.biXPelsPerMeter = 0;
1170 bmi->bmiHeader.biYPelsPerMeter = 0;
1171 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1172 bmi->bmiHeader.biClrImportant = 0;
1174 hdcref = GetDC(0);
1175 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1176 hdcref,
1177 &bmi->bmiHeader,
1178 CBM_INIT,
1179 bytes,
1180 bmi,
1181 DIB_RGB_COLORS
1184 if (transparent > -1) {
1185 /* Create the Mask */
1186 HDC hdc = CreateCompatibleDC(0);
1187 HDC hdcMask = CreateCompatibleDC(0);
1188 HBITMAP hOldbitmap;
1189 HBITMAP hOldbitmapmask;
1191 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1192 HBITMAP hTempMask;
1194 This->hbmXor = CreateDIBitmap(
1195 hdcref,
1196 &bmi->bmiHeader,
1197 CBM_INIT,
1198 bytes,
1199 bmi,
1200 DIB_RGB_COLORS
1203 bmi->bmiColors[0].rgbRed = 0;
1204 bmi->bmiColors[0].rgbGreen = 0;
1205 bmi->bmiColors[0].rgbBlue = 0;
1206 bmi->bmiColors[1].rgbRed = 255;
1207 bmi->bmiColors[1].rgbGreen = 255;
1208 bmi->bmiColors[1].rgbBlue = 255;
1210 bmi->bmiHeader.biBitCount = 1;
1211 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1212 bmi->bmiHeader.biClrUsed = 2;
1214 for (i = 0; i < gif->SHeight; i++) {
1215 unsigned char * colorPointer = bytes + padding * i;
1216 unsigned char * monoPointer = bytes + monopadding * i;
1217 for (j = 0; j < gif->SWidth; j++) {
1218 unsigned char pixel = colorPointer[j];
1219 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1220 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1223 hdcref = GetDC(0);
1224 hTempMask = CreateDIBitmap(
1225 hdcref,
1226 &bmi->bmiHeader,
1227 CBM_INIT,
1228 bytes,
1229 bmi,
1230 DIB_RGB_COLORS
1232 DeleteDC(hdcref);
1234 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1235 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1236 hOldbitmap = SelectObject(hdc, hTempMask);
1237 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1239 SetBkColor(hdc, RGB(255, 255, 255));
1240 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1242 /* We no longer need the original bitmap, so we apply the first
1243 transformation with the mask to speed up the rendering */
1244 SelectObject(hdc, This->hbmXor);
1245 SetBkColor(hdc, RGB(0,0,0));
1246 SetTextColor(hdc, RGB(255,255,255));
1247 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1248 hdcMask, 0, 0, SRCAND);
1250 SelectObject(hdc, hOldbitmap);
1251 SelectObject(hdcMask, hOldbitmapmask);
1252 DeleteDC(hdcMask);
1253 DeleteDC(hdc);
1254 DeleteObject(hTempMask);
1257 DeleteDC(hdcref);
1258 This->desc.picType = PICTYPE_BITMAP;
1259 OLEPictureImpl_SetBitmap(This);
1260 DGifCloseFile(gif);
1261 HeapFree(GetProcessHeap(),0,bmi);
1262 HeapFree(GetProcessHeap(),0,bytes);
1263 return S_OK;
1266 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1268 #ifdef SONAME_LIBJPEG
1269 struct jpeg_decompress_struct jd;
1270 struct jpeg_error_mgr jerr;
1271 int ret;
1272 JDIMENSION x;
1273 JSAMPROW samprow,oldsamprow;
1274 BITMAPINFOHEADER bmi;
1275 LPBYTE bits;
1276 HDC hdcref;
1277 struct jpeg_source_mgr xjsm;
1278 LPBYTE oldbits;
1279 unsigned int i;
1281 if(!libjpeg_handle) {
1282 if(!load_libjpeg()) {
1283 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1284 return E_FAIL;
1288 /* This is basically so we can use in-memory data for jpeg decompression.
1289 * We need to have all the functions.
1291 xjsm.next_input_byte = xbuf;
1292 xjsm.bytes_in_buffer = xread;
1293 xjsm.init_source = _jpeg_init_source;
1294 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1295 xjsm.skip_input_data = _jpeg_skip_input_data;
1296 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1297 xjsm.term_source = _jpeg_term_source;
1299 jd.err = pjpeg_std_error(&jerr);
1300 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1301 * jpeg_create_decompress(&jd); */
1302 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1303 jd.src = &xjsm;
1304 ret=pjpeg_read_header(&jd,TRUE);
1305 jd.out_color_space = JCS_RGB;
1306 pjpeg_start_decompress(&jd);
1307 if (ret != JPEG_HEADER_OK) {
1308 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1309 HeapFree(GetProcessHeap(),0,xbuf);
1310 return E_FAIL;
1313 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1314 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1315 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1317 oldbits = bits;
1318 oldsamprow = samprow;
1319 while ( jd.output_scanline<jd.output_height ) {
1320 x = pjpeg_read_scanlines(&jd,&samprow,1);
1321 if (x != 1) {
1322 ERR("failed to read current scanline?\n");
1323 break;
1325 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1326 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1327 *(bits++) = *(samprow+2);
1328 *(bits++) = *(samprow+1);
1329 *(bits++) = *(samprow);
1331 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1332 samprow = oldsamprow;
1334 bits = oldbits;
1336 bmi.biSize = sizeof(bmi);
1337 bmi.biWidth = jd.output_width;
1338 bmi.biHeight = -jd.output_height;
1339 bmi.biPlanes = 1;
1340 bmi.biBitCount = jd.output_components<<3;
1341 bmi.biCompression = BI_RGB;
1342 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1343 bmi.biXPelsPerMeter = 0;
1344 bmi.biYPelsPerMeter = 0;
1345 bmi.biClrUsed = 0;
1346 bmi.biClrImportant = 0;
1348 HeapFree(GetProcessHeap(),0,samprow);
1349 pjpeg_finish_decompress(&jd);
1350 pjpeg_destroy_decompress(&jd);
1351 hdcref = GetDC(0);
1352 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1353 hdcref,
1354 &bmi,
1355 CBM_INIT,
1356 bits,
1357 (BITMAPINFO*)&bmi,
1358 DIB_RGB_COLORS
1360 DeleteDC(hdcref);
1361 This->desc.picType = PICTYPE_BITMAP;
1362 OLEPictureImpl_SetBitmap(This);
1363 HeapFree(GetProcessHeap(),0,bits);
1364 return S_OK;
1365 #else
1366 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1367 return E_FAIL;
1368 #endif
1371 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1373 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1374 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1375 HDC hdcref;
1377 /* Does not matter whether this is a coreheader or not, we only use
1378 * components which are in both
1380 hdcref = GetDC(0);
1381 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1382 hdcref,
1383 &(bi->bmiHeader),
1384 CBM_INIT,
1385 xbuf+bfh->bfOffBits,
1387 DIB_RGB_COLORS
1389 DeleteDC(hdcref);
1390 if (This->desc.u.bmp.hbitmap == 0)
1391 return E_FAIL;
1392 This->desc.picType = PICTYPE_BITMAP;
1393 OLEPictureImpl_SetBitmap(This);
1394 return S_OK;
1397 /*****************************************************
1398 * start of PNG-specific code
1399 * currently only supports colortype PNG_COLOR_TYPE_RGB
1401 #ifdef SONAME_LIBPNG
1402 typedef struct{
1403 ULONG position;
1404 ULONG size;
1405 BYTE * buff;
1406 } png_io;
1408 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1409 png_size_t length)
1411 png_io * io_ptr = png_ptr->io_ptr;
1413 if(length + io_ptr->position > io_ptr->size){
1414 length = io_ptr->size - io_ptr->position;
1417 memcpy(data, io_ptr->buff + io_ptr->position, length);
1419 io_ptr->position += length;
1422 static void *libpng_handle;
1423 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1424 MAKE_FUNCPTR(png_create_read_struct);
1425 MAKE_FUNCPTR(png_create_info_struct);
1426 MAKE_FUNCPTR(png_set_read_fn);
1427 MAKE_FUNCPTR(png_read_info);
1428 MAKE_FUNCPTR(png_read_image);
1429 MAKE_FUNCPTR(png_get_rowbytes);
1430 MAKE_FUNCPTR(png_set_bgr);
1431 MAKE_FUNCPTR(png_destroy_read_struct);
1432 MAKE_FUNCPTR(png_set_palette_to_rgb);
1433 MAKE_FUNCPTR(png_read_update_info);
1434 MAKE_FUNCPTR(png_get_tRNS);
1435 MAKE_FUNCPTR(png_get_PLTE);
1436 MAKE_FUNCPTR(png_set_expand);
1437 #undef MAKE_FUNCPTR
1439 static void *load_libpng(void)
1441 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1443 #define LOAD_FUNCPTR(f) \
1444 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1445 libpng_handle = NULL; \
1446 return NULL; \
1448 LOAD_FUNCPTR(png_create_read_struct);
1449 LOAD_FUNCPTR(png_create_info_struct);
1450 LOAD_FUNCPTR(png_set_read_fn);
1451 LOAD_FUNCPTR(png_read_info);
1452 LOAD_FUNCPTR(png_read_image);
1453 LOAD_FUNCPTR(png_get_rowbytes);
1454 LOAD_FUNCPTR(png_set_bgr);
1455 LOAD_FUNCPTR(png_destroy_read_struct);
1456 LOAD_FUNCPTR(png_set_palette_to_rgb);
1457 LOAD_FUNCPTR(png_read_update_info);
1458 LOAD_FUNCPTR(png_get_tRNS);
1459 LOAD_FUNCPTR(png_get_PLTE);
1460 LOAD_FUNCPTR(png_set_expand);
1462 #undef LOAD_FUNCPTR
1464 return libpng_handle;
1466 #endif /* SONAME_LIBPNG */
1468 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1470 #ifdef SONAME_LIBPNG
1471 png_io io;
1472 png_structp png_ptr = NULL;
1473 png_infop info_ptr = NULL;
1474 INT row, rowsize, height, width, num_trans, i, j;
1475 png_bytep* row_pointers = NULL;
1476 png_bytep pngdata = NULL;
1477 BITMAPINFOHEADER bmi;
1478 HDC hdcref = NULL, hdcXor, hdcMask;
1479 HRESULT ret;
1480 BOOL transparency;
1481 png_bytep trans;
1482 png_color_16p trans_values;
1483 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1484 HBITMAP hbmoldXor, hbmoldMask, temp;
1486 if(!libpng_handle) {
1487 if(!load_libpng()) {
1488 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1489 return E_FAIL;
1493 io.size = xread;
1494 io.position = 0;
1495 io.buff = xbuf;
1497 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1498 NULL, NULL, NULL);
1500 if(setjmp(png_jmpbuf(png_ptr))){
1501 TRACE("Error in libpng\n");
1502 ret = E_FAIL;
1503 goto end;
1506 info_ptr = ppng_create_info_struct(png_ptr);
1507 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1508 ppng_read_info(png_ptr, info_ptr);
1510 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1511 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1512 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1513 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1514 ret = E_FAIL;
1515 goto end;
1518 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1519 == PNG_INFO_tRNS);
1521 /* sets format from anything to RGBA */
1522 ppng_set_expand(png_ptr);
1523 /* sets format to BGRA */
1524 ppng_set_bgr(png_ptr);
1526 ppng_read_update_info(png_ptr, info_ptr);
1528 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1529 /* align rowsize to 4-byte boundary */
1530 rowsize = (rowsize + 3) & ~3;
1531 height = info_ptr->height;
1532 width = info_ptr->width;
1534 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1535 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1537 if(!pngdata || !row_pointers){
1538 ret = E_FAIL;
1539 goto end;
1542 for (row = 0; row < height; row++){
1543 row_pointers[row] = pngdata + row * rowsize;
1546 ppng_read_image(png_ptr, row_pointers);
1548 bmi.biSize = sizeof(bmi);
1549 bmi.biWidth = width;
1550 bmi.biHeight = -height;
1551 bmi.biPlanes = 1;
1552 bmi.biBitCount = info_ptr->channels * 8;
1553 bmi.biCompression = BI_RGB;
1554 bmi.biSizeImage = height * rowsize;
1555 bmi.biXPelsPerMeter = 0;
1556 bmi.biYPelsPerMeter = 0;
1557 bmi.biClrUsed = 0;
1558 bmi.biClrImportant = 0;
1560 hdcref = GetDC(0);
1561 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1562 hdcref,
1563 &bmi,
1564 CBM_INIT,
1565 pngdata,
1566 (BITMAPINFO*)&bmi,
1567 DIB_RGB_COLORS
1570 /* only fully-transparent alpha is handled */
1571 if((info_ptr->channels != 4) || !transparency){
1572 ReleaseDC(0, hdcref);
1573 goto succ;
1576 This->hbmXor = CreateDIBitmap(
1577 hdcref,
1578 &bmi,
1579 CBM_INIT,
1580 pngdata,
1581 (BITMAPINFO*)&bmi,
1582 DIB_RGB_COLORS
1585 /* set transparent pixels to black, all others to white */
1586 for(i = 0; i < height; i++){
1587 for(j = 3; j < rowsize; j += 4){
1588 if(row_pointers[i][j] == 0)
1589 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1590 else
1591 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1595 temp = CreateDIBitmap(
1596 hdcref,
1597 &bmi,
1598 CBM_INIT,
1599 pngdata,
1600 (BITMAPINFO*)&bmi,
1601 DIB_RGB_COLORS
1604 ReleaseDC(0, hdcref);
1606 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1607 hdcXor = CreateCompatibleDC(NULL);
1608 hdcMask = CreateCompatibleDC(NULL);
1610 hbmoldXor = SelectObject(hdcXor,temp);
1611 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1612 SetBkColor(hdcXor,black);
1613 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1615 SelectObject(hdcXor,This->hbmXor);
1616 DeleteObject(temp);
1618 SetTextColor(hdcXor,white);
1619 SetBkColor(hdcXor,black);
1620 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1622 SelectObject(hdcXor,hbmoldXor);
1623 SelectObject(hdcMask,hbmoldMask);
1625 DeleteDC(hdcXor);
1626 DeleteDC(hdcMask);
1628 succ:
1629 This->desc.picType = PICTYPE_BITMAP;
1630 OLEPictureImpl_SetBitmap(This);
1631 ret = S_OK;
1633 end:
1634 if(png_ptr)
1635 ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1636 HeapFree(GetProcessHeap(), 0, row_pointers);
1637 HeapFree(GetProcessHeap(), 0, pngdata);
1638 return ret;
1639 #else /* SONAME_LIBPNG */
1640 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1641 return E_FAIL;
1642 #endif
1645 /*****************************************************
1646 * start of Icon-specific code
1649 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1651 HICON hicon;
1652 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1653 HDC hdcRef;
1654 int i;
1657 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1658 FIXME("icon.idType=%d\n",cifd->idType);
1659 FIXME("icon.idCount=%d\n",cifd->idCount);
1661 for (i=0;i<cifd->idCount;i++) {
1662 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1663 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1664 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1665 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1666 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1667 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1668 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1669 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1672 i=0;
1673 /* If we have more than one icon, try to find the best.
1674 * this currently means '32 pixel wide'.
1676 if (cifd->idCount!=1) {
1677 for (i=0;i<cifd->idCount;i++) {
1678 if (cifd->idEntries[i].bWidth == 32)
1679 break;
1681 if (i==cifd->idCount) i=0;
1684 hicon = CreateIconFromResourceEx(
1685 xbuf+cifd->idEntries[i].dwDIBOffset,
1686 cifd->idEntries[i].dwDIBSize,
1687 TRUE, /* is icon */
1688 0x00030000,
1689 cifd->idEntries[i].bWidth,
1690 cifd->idEntries[i].bHeight,
1693 if (!hicon) {
1694 ERR("CreateIcon failed.\n");
1695 return E_FAIL;
1696 } else {
1697 This->desc.picType = PICTYPE_ICON;
1698 This->desc.u.icon.hicon = hicon;
1699 This->origWidth = cifd->idEntries[i].bWidth;
1700 This->origHeight = cifd->idEntries[i].bHeight;
1701 hdcRef = CreateCompatibleDC(0);
1702 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1703 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1704 DeleteDC(hdcRef);
1705 return S_OK;
1709 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1710 const BYTE *data, ULONG size)
1712 HENHMETAFILE hemf;
1713 ENHMETAHEADER hdr;
1715 hemf = SetEnhMetaFileBits(size, data);
1716 if (!hemf) return E_FAIL;
1718 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1720 This->desc.picType = PICTYPE_ENHMETAFILE;
1721 This->desc.u.emf.hemf = hemf;
1723 This->origWidth = 0;
1724 This->origHeight = 0;
1725 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1726 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1728 return S_OK;
1731 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1732 const BYTE *data, ULONG size)
1734 APM_HEADER *header = (APM_HEADER *)data;
1735 HMETAFILE hmf;
1737 if (size < sizeof(APM_HEADER))
1738 return E_FAIL;
1739 if (header->key != 0x9ac6cdd7)
1740 return E_FAIL;
1742 /* SetMetaFileBitsEx performs data check on its own */
1743 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1744 if (!hmf) return E_FAIL;
1746 This->desc.picType = PICTYPE_METAFILE;
1747 This->desc.u.wmf.hmeta = hmf;
1748 This->desc.u.wmf.xExt = 0;
1749 This->desc.u.wmf.yExt = 0;
1751 This->origWidth = 0;
1752 This->origHeight = 0;
1753 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1754 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1755 return S_OK;
1758 /************************************************************************
1759 * BITMAP FORMAT FLAGS -
1760 * Flags that differentiate between different types of bitmaps.
1763 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1764 #define BITMAP_FORMAT_JPEG 0xd8ff
1765 #define BITMAP_FORMAT_GIF 0x4947
1766 #define BITMAP_FORMAT_PNG 0x5089
1767 #define BITMAP_FORMAT_APM 0xcdd7
1769 /************************************************************************
1770 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1772 * Loads the binary data from the IStream. Starts at current position.
1773 * There appears to be an 2 DWORD header:
1774 * DWORD magic;
1775 * DWORD len;
1777 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1779 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1780 HRESULT hr = E_FAIL;
1781 BOOL headerisdata = FALSE;
1782 BOOL statfailed = FALSE;
1783 ULONG xread, toread;
1784 ULONG headerread;
1785 BYTE *xbuf;
1786 DWORD header[2];
1787 WORD magic;
1788 STATSTG statstg;
1789 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1791 TRACE("(%p,%p)\n",This,pStm);
1793 /****************************************************************************************
1794 * Part 1: Load the data
1796 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1797 * out whether we do.
1799 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1800 * compound file. This may explain most, if not all, of the cases of "no
1801 * header", and the header validation should take this into account.
1802 * At least in Visual Basic 6, resource streams, valid headers are
1803 * header[0] == "lt\0\0",
1804 * header[1] == length_of_stream.
1806 * Also handle streams where we do not have a working "Stat" method by
1807 * reading all data until the end of the stream.
1809 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1810 if (hr) {
1811 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1812 statfailed = TRUE;
1813 /* we will read at least 8 byte ... just right below */
1814 statstg.cbSize.QuadPart = 8;
1817 toread = 0;
1818 headerread = 0;
1819 headerisdata = FALSE;
1820 do {
1821 hr=IStream_Read(pStm,header,8,&xread);
1822 if (hr || xread!=8) {
1823 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1824 return (hr?hr:E_FAIL);
1826 headerread += xread;
1827 xread = 0;
1829 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1830 if (toread != 0 && toread != header[1])
1831 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1832 toread, header[1]);
1833 toread = header[1];
1834 if (toread == 0) break;
1835 } else {
1836 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1837 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1838 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1839 (header[0] == EMR_HEADER) || /* EMF header */
1840 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1841 (header[1]==0)
1842 ) {/* Found start of bitmap data */
1843 headerisdata = TRUE;
1844 if (toread == 0)
1845 toread = statstg.cbSize.QuadPart-8;
1846 else toread -= 8;
1847 xread = 8;
1848 } else {
1849 FIXME("Unknown stream header magic: %08x\n", header[0]);
1850 toread = header[1];
1853 } while (!headerisdata);
1855 if (statfailed) { /* we don't know the size ... read all we get */
1856 int sizeinc = 4096;
1857 int origsize = sizeinc;
1858 ULONG nread = 42;
1860 TRACE("Reading all data from stream.\n");
1861 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1862 if (headerisdata)
1863 memcpy (xbuf, header, 8);
1864 while (1) {
1865 while (xread < origsize) {
1866 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1867 xread+=nread;
1868 if (hr || !nread)
1869 break;
1871 if (!nread || hr) /* done, or error */
1872 break;
1873 if (xread == origsize) {
1874 origsize += sizeinc;
1875 sizeinc = 2*sizeinc; /* exponential increase */
1876 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1879 if (hr)
1880 TRACE("hr in no-stat loader case is %08x\n", hr);
1881 TRACE("loaded %d bytes.\n", xread);
1882 This->datalen = xread;
1883 This->data = xbuf;
1884 } else {
1885 This->datalen = toread+(headerisdata?8:0);
1886 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1887 if (!xbuf)
1888 return E_OUTOFMEMORY;
1890 if (headerisdata)
1891 memcpy (xbuf, header, 8);
1893 while (xread < This->datalen) {
1894 ULONG nread;
1895 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1896 xread+=nread;
1897 if (hr || !nread)
1898 break;
1900 if (xread != This->datalen)
1901 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1903 if (This->datalen == 0) { /* Marks the "NONE" picture */
1904 This->desc.picType = PICTYPE_NONE;
1905 return S_OK;
1909 /****************************************************************************************
1910 * Part 2: Process the loaded data
1913 magic = xbuf[0] + (xbuf[1]<<8);
1914 This->loadtime_format = magic;
1916 switch (magic) {
1917 case BITMAP_FORMAT_GIF: /* GIF */
1918 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1919 break;
1920 case BITMAP_FORMAT_JPEG: /* JPEG */
1921 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1922 break;
1923 case BITMAP_FORMAT_BMP: /* Bitmap */
1924 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1925 break;
1926 case BITMAP_FORMAT_PNG: /* PNG */
1927 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1928 break;
1929 case BITMAP_FORMAT_APM: /* APM */
1930 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1931 break;
1932 case 0x0000: { /* ICON , first word is dwReserved */
1933 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1934 break;
1936 default:
1938 unsigned int i;
1940 /* let's see if it's a EMF */
1941 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1942 if (hr == S_OK) break;
1944 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1945 hr=E_FAIL;
1946 for (i=0;i<xread+8;i++) {
1947 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1948 else MESSAGE("%02x ",xbuf[i-8]);
1949 if (i % 10 == 9) MESSAGE("\n");
1951 MESSAGE("\n");
1952 break;
1955 This->bIsDirty = FALSE;
1957 /* FIXME: this notify is not really documented */
1958 if (hr==S_OK)
1959 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1960 return hr;
1963 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1965 int iSuccess = 0;
1966 HDC hDC;
1967 BITMAPINFO * pInfoBitmap;
1968 int iNumPaletteEntries;
1969 unsigned char * pPixelData;
1970 BITMAPFILEHEADER * pFileHeader;
1971 BITMAPINFO * pInfoHeader;
1973 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1974 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1976 /* Find out bitmap size and padded length */
1977 hDC = GetDC(0);
1978 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1979 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1981 /* Fetch bitmap palette & pixel data */
1983 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1984 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1986 /* Calculate the total length required for the BMP data */
1987 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1988 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1989 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1990 } else {
1991 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1992 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1993 else
1994 iNumPaletteEntries = 0;
1996 *pLength =
1997 sizeof(BITMAPFILEHEADER) +
1998 sizeof(BITMAPINFOHEADER) +
1999 iNumPaletteEntries * sizeof(RGBQUAD) +
2000 pInfoBitmap->bmiHeader.biSizeImage;
2001 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
2003 /* Fill the BITMAPFILEHEADER */
2004 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
2005 pFileHeader->bfType = BITMAP_FORMAT_BMP;
2006 pFileHeader->bfSize = *pLength;
2007 pFileHeader->bfOffBits =
2008 sizeof(BITMAPFILEHEADER) +
2009 sizeof(BITMAPINFOHEADER) +
2010 iNumPaletteEntries * sizeof(RGBQUAD);
2012 /* Fill the BITMAPINFOHEADER and the palette data */
2013 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
2014 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
2015 memcpy(
2016 (unsigned char *)(*ppBuffer) +
2017 sizeof(BITMAPFILEHEADER) +
2018 sizeof(BITMAPINFOHEADER) +
2019 iNumPaletteEntries * sizeof(RGBQUAD),
2020 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2021 iSuccess = 1;
2023 HeapFree(GetProcessHeap(), 0, pPixelData);
2024 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2025 return iSuccess;
2028 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2030 ICONINFO infoIcon;
2031 int iSuccess = 0;
2033 *ppBuffer = NULL; *pLength = 0;
2034 if (GetIconInfo(hIcon, &infoIcon)) {
2035 HDC hDC;
2036 BITMAPINFO * pInfoBitmap;
2037 unsigned char * pIconData = NULL;
2038 unsigned int iDataSize = 0;
2040 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2042 /* Find out icon size */
2043 hDC = GetDC(0);
2044 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2045 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2046 if (1) {
2047 /* Auxiliary pointers */
2048 CURSORICONFILEDIR * pIconDir;
2049 CURSORICONFILEDIRENTRY * pIconEntry;
2050 BITMAPINFOHEADER * pIconBitmapHeader;
2051 unsigned int iOffsetPalette;
2052 unsigned int iOffsetColorData;
2053 unsigned int iOffsetMaskData;
2055 unsigned int iLengthScanLineColor;
2056 unsigned int iLengthScanLineMask;
2057 unsigned int iNumEntriesPalette;
2059 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2060 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2062 FIXME("DEBUG: bitmap size is %d x %d\n",
2063 pInfoBitmap->bmiHeader.biWidth,
2064 pInfoBitmap->bmiHeader.biHeight);
2065 FIXME("DEBUG: bitmap bpp is %d\n",
2066 pInfoBitmap->bmiHeader.biBitCount);
2067 FIXME("DEBUG: bitmap nplanes is %d\n",
2068 pInfoBitmap->bmiHeader.biPlanes);
2069 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2070 pInfoBitmap->bmiHeader.biSizeImage);
2072 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2073 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2074 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2076 /* Fill out the CURSORICONFILEDIR */
2077 pIconDir = (CURSORICONFILEDIR *)pIconData;
2078 pIconDir->idType = 1;
2079 pIconDir->idCount = 1;
2081 /* Fill out the CURSORICONFILEDIRENTRY */
2082 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2083 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2084 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2085 pIconEntry->bColorCount =
2086 (pInfoBitmap->bmiHeader.biBitCount < 8)
2087 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2088 : 0;
2089 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2090 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2091 pIconEntry->dwDIBSize = 0;
2092 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2094 /* Fill out the BITMAPINFOHEADER */
2095 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2096 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2098 /* Find out whether a palette exists for the bitmap */
2099 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2100 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2101 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2102 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2103 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2104 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2105 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2106 iNumEntriesPalette = 3;
2107 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2108 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2109 } else {
2110 iNumEntriesPalette = 0;
2113 /* Add bitmap size and header size to icon data size. */
2114 iOffsetPalette = iDataSize;
2115 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2116 iOffsetColorData = iDataSize;
2117 iDataSize += pIconBitmapHeader->biSizeImage;
2118 iOffsetMaskData = iDataSize;
2119 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2120 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2121 pIconBitmapHeader->biHeight *= 2;
2122 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2123 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2124 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2125 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2127 /* Get the actual bitmap data from the icon bitmap */
2128 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2129 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2130 if (iNumEntriesPalette > 0) {
2131 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2132 iNumEntriesPalette * sizeof(RGBQUAD));
2135 /* Reset all values so that GetDIBits call succeeds */
2136 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2137 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2138 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2140 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2141 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2142 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2144 printf("ERROR: unable to get bitmap mask (error %u)\n",
2145 GetLastError());
2149 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2150 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2152 /* Write out everything produced so far to the stream */
2153 *ppBuffer = pIconData; *pLength = iDataSize;
2154 iSuccess = 1;
2155 } else {
2157 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2158 GetLastError());
2162 Remarks (from MSDN entry on GetIconInfo):
2164 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2165 members of ICONINFO. The calling application must manage
2166 these bitmaps and delete them when they are no longer
2167 necessary.
2169 if (hDC) ReleaseDC(0, hDC);
2170 DeleteObject(infoIcon.hbmMask);
2171 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2172 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2173 } else {
2174 printf("ERROR: Unable to get icon information (error %u)\n",
2175 GetLastError());
2177 return iSuccess;
2180 static HRESULT WINAPI OLEPictureImpl_Save(
2181 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2183 HRESULT hResult = E_NOTIMPL;
2184 void * pIconData;
2185 unsigned int iDataSize;
2186 ULONG dummy;
2187 int iSerializeResult = 0;
2188 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2190 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2192 switch (This->desc.picType) {
2193 case PICTYPE_ICON:
2194 if (This->bIsDirty || !This->data) {
2195 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2196 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2197 hResult = E_FAIL;
2198 break;
2200 HeapFree(GetProcessHeap(), 0, This->data);
2201 This->data = pIconData;
2202 This->datalen = iDataSize;
2204 if (This->loadtime_magic != 0xdeadbeef) {
2205 DWORD header[2];
2207 header[0] = This->loadtime_magic;
2208 header[1] = This->datalen;
2209 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2211 IStream_Write(pStm, This->data, This->datalen, &dummy);
2213 hResult = S_OK;
2214 break;
2215 case PICTYPE_BITMAP:
2216 if (This->bIsDirty) {
2217 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2218 case BITMAP_FORMAT_BMP:
2219 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2220 break;
2221 case BITMAP_FORMAT_JPEG:
2222 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2223 break;
2224 case BITMAP_FORMAT_GIF:
2225 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2226 break;
2227 case BITMAP_FORMAT_PNG:
2228 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2229 break;
2230 default:
2231 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2232 break;
2234 if (iSerializeResult) {
2236 if (This->loadtime_magic != 0xdeadbeef) {
2238 if (1) {
2239 DWORD header[2];
2241 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2242 header[1] = iDataSize;
2243 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2245 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2247 HeapFree(GetProcessHeap(), 0, This->data);
2248 This->data = pIconData;
2249 This->datalen = iDataSize;
2250 hResult = S_OK;
2252 } else {
2254 if (This->loadtime_magic != 0xdeadbeef) {
2256 if (1) {
2257 DWORD header[2];
2259 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2260 header[1] = This->datalen;
2261 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2263 IStream_Write(pStm, This->data, This->datalen, &dummy);
2264 hResult = S_OK;
2266 break;
2267 case PICTYPE_METAFILE:
2268 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2269 break;
2270 case PICTYPE_ENHMETAFILE:
2271 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2272 break;
2273 default:
2274 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2275 break;
2277 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2278 return hResult;
2281 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2282 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2284 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2285 FIXME("(%p,%p),stub!\n",This,pcbSize);
2286 return E_NOTIMPL;
2290 /************************************************************************
2291 * IDispatch
2294 /************************************************************************
2295 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2297 * See Windows documentation for more details on IUnknown methods.
2299 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2300 IDispatch* iface,
2301 REFIID riid,
2302 VOID** ppvoid)
2304 OLEPictureImpl *This = impl_from_IDispatch(iface);
2306 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2309 /************************************************************************
2310 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2312 * See Windows documentation for more details on IUnknown methods.
2314 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2315 IDispatch* iface)
2317 OLEPictureImpl *This = impl_from_IDispatch(iface);
2319 return IPicture_AddRef((IPicture *)This);
2322 /************************************************************************
2323 * OLEPictureImpl_IDispatch_Release (IUnknown)
2325 * See Windows documentation for more details on IUnknown methods.
2327 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2328 IDispatch* iface)
2330 OLEPictureImpl *This = impl_from_IDispatch(iface);
2332 return IPicture_Release((IPicture *)This);
2335 /************************************************************************
2336 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2338 * See Windows documentation for more details on IDispatch methods.
2340 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2341 IDispatch* iface,
2342 unsigned int* pctinfo)
2344 TRACE("(%p)\n", pctinfo);
2346 *pctinfo = 1;
2348 return S_OK;
2351 /************************************************************************
2352 * OLEPictureImpl_GetTypeInfo (IDispatch)
2354 * See Windows documentation for more details on IDispatch methods.
2356 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2357 IDispatch* iface,
2358 UINT iTInfo,
2359 LCID lcid,
2360 ITypeInfo** ppTInfo)
2362 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2363 ITypeLib *tl;
2364 HRESULT hres;
2366 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2368 if (iTInfo != 0)
2369 return E_FAIL;
2371 hres = LoadTypeLib(stdole2tlb, &tl);
2372 if (FAILED(hres))
2374 ERR("Could not load stdole2.tlb\n");
2375 return hres;
2378 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2379 if (FAILED(hres))
2380 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2382 return hres;
2385 /************************************************************************
2386 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2388 * See Windows documentation for more details on IDispatch methods.
2390 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2391 IDispatch* iface,
2392 REFIID riid,
2393 LPOLESTR* rgszNames,
2394 UINT cNames,
2395 LCID lcid,
2396 DISPID* rgDispId)
2398 ITypeInfo * pTInfo;
2399 HRESULT hres;
2401 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2402 rgszNames, cNames, (int)lcid, rgDispId);
2404 if (cNames == 0)
2406 return E_INVALIDARG;
2408 else
2410 /* retrieve type information */
2411 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2413 if (FAILED(hres))
2415 ERR("GetTypeInfo failed.\n");
2416 return hres;
2419 /* convert names to DISPIDs */
2420 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2421 ITypeInfo_Release(pTInfo);
2423 return hres;
2427 /************************************************************************
2428 * OLEPictureImpl_Invoke (IDispatch)
2430 * See Windows documentation for more details on IDispatch methods.
2432 static HRESULT WINAPI OLEPictureImpl_Invoke(
2433 IDispatch* iface,
2434 DISPID dispIdMember,
2435 REFIID riid,
2436 LCID lcid,
2437 WORD wFlags,
2438 DISPPARAMS* pDispParams,
2439 VARIANT* pVarResult,
2440 EXCEPINFO* pExepInfo,
2441 UINT* puArgErr)
2443 OLEPictureImpl *This = impl_from_IDispatch(iface);
2445 /* validate parameters */
2447 if (!IsEqualIID(riid, &IID_NULL))
2449 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2450 return DISP_E_UNKNOWNNAME;
2453 if (!pDispParams)
2455 ERR("null pDispParams not allowed\n");
2456 return DISP_E_PARAMNOTOPTIONAL;
2459 if (wFlags & DISPATCH_PROPERTYGET)
2461 if (pDispParams->cArgs != 0)
2463 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2464 return DISP_E_BADPARAMCOUNT;
2466 if (!pVarResult)
2468 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2469 return DISP_E_PARAMNOTOPTIONAL;
2472 else if (wFlags & DISPATCH_PROPERTYPUT)
2474 if (pDispParams->cArgs != 1)
2476 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2477 return DISP_E_BADPARAMCOUNT;
2481 switch (dispIdMember)
2483 case DISPID_PICT_HANDLE:
2484 if (wFlags & DISPATCH_PROPERTYGET)
2486 TRACE("DISPID_PICT_HANDLE\n");
2487 V_VT(pVarResult) = VT_I4;
2488 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2490 break;
2491 case DISPID_PICT_HPAL:
2492 if (wFlags & DISPATCH_PROPERTYGET)
2494 TRACE("DISPID_PICT_HPAL\n");
2495 V_VT(pVarResult) = VT_I4;
2496 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2498 else if (wFlags & DISPATCH_PROPERTYPUT)
2500 VARIANTARG vararg;
2501 HRESULT hr;
2502 TRACE("DISPID_PICT_HPAL\n");
2504 VariantInit(&vararg);
2505 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2506 if (FAILED(hr))
2507 return hr;
2509 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2511 VariantClear(&vararg);
2512 return hr;
2514 break;
2515 case DISPID_PICT_TYPE:
2516 if (wFlags & DISPATCH_PROPERTYGET)
2518 TRACE("DISPID_PICT_TYPE\n");
2519 V_VT(pVarResult) = VT_I2;
2520 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2522 break;
2523 case DISPID_PICT_WIDTH:
2524 if (wFlags & DISPATCH_PROPERTYGET)
2526 TRACE("DISPID_PICT_WIDTH\n");
2527 V_VT(pVarResult) = VT_I4;
2528 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2530 break;
2531 case DISPID_PICT_HEIGHT:
2532 if (wFlags & DISPATCH_PROPERTYGET)
2534 TRACE("DISPID_PICT_HEIGHT\n");
2535 V_VT(pVarResult) = VT_I4;
2536 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2538 break;
2541 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2542 return DISP_E_MEMBERNOTFOUND;
2546 static const IPictureVtbl OLEPictureImpl_VTable =
2548 OLEPictureImpl_QueryInterface,
2549 OLEPictureImpl_AddRef,
2550 OLEPictureImpl_Release,
2551 OLEPictureImpl_get_Handle,
2552 OLEPictureImpl_get_hPal,
2553 OLEPictureImpl_get_Type,
2554 OLEPictureImpl_get_Width,
2555 OLEPictureImpl_get_Height,
2556 OLEPictureImpl_Render,
2557 OLEPictureImpl_set_hPal,
2558 OLEPictureImpl_get_CurDC,
2559 OLEPictureImpl_SelectPicture,
2560 OLEPictureImpl_get_KeepOriginalFormat,
2561 OLEPictureImpl_put_KeepOriginalFormat,
2562 OLEPictureImpl_PictureChanged,
2563 OLEPictureImpl_SaveAsFile,
2564 OLEPictureImpl_get_Attributes
2567 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2569 OLEPictureImpl_IDispatch_QueryInterface,
2570 OLEPictureImpl_IDispatch_AddRef,
2571 OLEPictureImpl_IDispatch_Release,
2572 OLEPictureImpl_GetTypeInfoCount,
2573 OLEPictureImpl_GetTypeInfo,
2574 OLEPictureImpl_GetIDsOfNames,
2575 OLEPictureImpl_Invoke
2578 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2580 OLEPictureImpl_IPersistStream_QueryInterface,
2581 OLEPictureImpl_IPersistStream_AddRef,
2582 OLEPictureImpl_IPersistStream_Release,
2583 OLEPictureImpl_GetClassID,
2584 OLEPictureImpl_IsDirty,
2585 OLEPictureImpl_Load,
2586 OLEPictureImpl_Save,
2587 OLEPictureImpl_GetSizeMax
2590 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2592 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2593 OLEPictureImpl_IConnectionPointContainer_AddRef,
2594 OLEPictureImpl_IConnectionPointContainer_Release,
2595 OLEPictureImpl_EnumConnectionPoints,
2596 OLEPictureImpl_FindConnectionPoint
2599 /***********************************************************************
2600 * OleCreatePictureIndirect (OLEAUT32.419)
2602 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2603 BOOL fOwn, LPVOID *ppvObj )
2605 OLEPictureImpl* newPict = NULL;
2606 HRESULT hr = S_OK;
2608 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2611 * Sanity check
2613 if (ppvObj==0)
2614 return E_POINTER;
2616 *ppvObj = NULL;
2619 * Try to construct a new instance of the class.
2621 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2623 if (newPict == NULL)
2624 return E_OUTOFMEMORY;
2627 * Make sure it supports the interface required by the caller.
2629 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2632 * Release the reference obtained in the constructor. If
2633 * the QueryInterface was unsuccessful, it will free the class.
2635 IPicture_Release((IPicture*)newPict);
2637 return hr;
2641 /***********************************************************************
2642 * OleLoadPicture (OLEAUT32.418)
2644 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2645 REFIID riid, LPVOID *ppvObj )
2647 LPPERSISTSTREAM ps;
2648 IPicture *newpic;
2649 HRESULT hr;
2651 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2652 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2654 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2655 if (hr)
2656 return hr;
2657 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2658 if (hr) {
2659 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2660 IPicture_Release(newpic);
2661 *ppvObj = NULL;
2662 return hr;
2664 hr = IPersistStream_Load(ps,lpstream);
2665 IPersistStream_Release(ps);
2666 if (FAILED(hr))
2668 ERR("IPersistStream_Load failed\n");
2669 IPicture_Release(newpic);
2670 *ppvObj = NULL;
2671 return hr;
2673 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2674 if (hr)
2675 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2676 IPicture_Release(newpic);
2677 return hr;
2680 /***********************************************************************
2681 * OleLoadPictureEx (OLEAUT32.401)
2683 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2684 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2686 LPPERSISTSTREAM ps;
2687 IPicture *newpic;
2688 HRESULT hr;
2690 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2691 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2693 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2694 if (hr)
2695 return hr;
2696 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2697 if (hr) {
2698 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2699 IPicture_Release(newpic);
2700 *ppvObj = NULL;
2701 return hr;
2703 hr = IPersistStream_Load(ps,lpstream);
2704 IPersistStream_Release(ps);
2705 if (FAILED(hr))
2707 ERR("IPersistStream_Load failed\n");
2708 IPicture_Release(newpic);
2709 *ppvObj = NULL;
2710 return hr;
2712 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2713 if (hr)
2714 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2715 IPicture_Release(newpic);
2716 return hr;
2719 /***********************************************************************
2720 * OleLoadPicturePath (OLEAUT32.424)
2722 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2723 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2724 LPVOID *ppvRet )
2726 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2727 IPicture *ipicture;
2728 HANDLE hFile;
2729 DWORD dwFileSize;
2730 HGLOBAL hGlobal = NULL;
2731 DWORD dwBytesRead = 0;
2732 IStream *stream;
2733 BOOL bRead;
2734 IPersistStream *pStream;
2735 HRESULT hRes;
2737 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2738 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2739 debugstr_guid(riid), ppvRet);
2741 if (!ppvRet) return E_POINTER;
2743 if (strncmpW(szURLorPath, file, 7) == 0) {
2744 szURLorPath += 7;
2746 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2747 0, NULL);
2748 if (hFile == INVALID_HANDLE_VALUE)
2749 return E_UNEXPECTED;
2751 dwFileSize = GetFileSize(hFile, NULL);
2752 if (dwFileSize != INVALID_FILE_SIZE )
2754 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2755 if ( hGlobal)
2757 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2758 if (!bRead)
2760 GlobalFree(hGlobal);
2761 hGlobal = 0;
2765 CloseHandle(hFile);
2767 if (!hGlobal)
2768 return E_UNEXPECTED;
2770 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2771 if (FAILED(hRes))
2773 GlobalFree(hGlobal);
2774 return hRes;
2776 } else {
2777 IMoniker *pmnk;
2778 IBindCtx *pbc;
2780 hRes = CreateBindCtx(0, &pbc);
2781 if (SUCCEEDED(hRes))
2783 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2784 if (SUCCEEDED(hRes))
2786 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2787 IMoniker_Release(pmnk);
2789 IBindCtx_Release(pbc);
2791 if (FAILED(hRes))
2792 return hRes;
2795 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2796 &IID_IPicture, (LPVOID*)&ipicture);
2797 if (hRes != S_OK) {
2798 IStream_Release(stream);
2799 return hRes;
2802 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2803 if (hRes) {
2804 IStream_Release(stream);
2805 IPicture_Release(ipicture);
2806 return hRes;
2809 hRes = IPersistStream_Load(pStream, stream);
2810 IPersistStream_Release(pStream);
2811 IStream_Release(stream);
2813 if (hRes) {
2814 IPicture_Release(ipicture);
2815 return hRes;
2818 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2819 if (hRes)
2820 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2822 IPicture_Release(ipicture);
2823 return hRes;
2826 /*******************************************************************************
2827 * StdPic ClassFactory
2829 typedef struct
2831 /* IUnknown fields */
2832 const IClassFactoryVtbl *lpVtbl;
2833 LONG ref;
2834 } IClassFactoryImpl;
2836 static HRESULT WINAPI
2837 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2838 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2840 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2841 return E_NOINTERFACE;
2844 static ULONG WINAPI
2845 SPCF_AddRef(LPCLASSFACTORY iface) {
2846 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2847 return InterlockedIncrement(&This->ref);
2850 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2851 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2852 /* static class, won't be freed */
2853 return InterlockedDecrement(&This->ref);
2856 static HRESULT WINAPI SPCF_CreateInstance(
2857 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2859 /* Creates an uninitialized picture */
2860 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2864 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2865 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2866 FIXME("(%p)->(%d),stub!\n",This,dolock);
2867 return S_OK;
2870 static const IClassFactoryVtbl SPCF_Vtbl = {
2871 SPCF_QueryInterface,
2872 SPCF_AddRef,
2873 SPCF_Release,
2874 SPCF_CreateInstance,
2875 SPCF_LockServer
2877 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2879 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }