push d2ed94b6221baa59db3b40852d651a773c374f7d
[wine/hacks.git] / dlls / oleaut32 / olepicture.c
blobadaad97def661f86bb09ed8aa7ef253df1385509
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"
84 #include "wine/library.h"
86 #include "ungif.h"
88 WINE_DEFAULT_DEBUG_CHANNEL(ole);
90 #include "pshpack1.h"
92 /* Header for Aldus Placable Metafiles - a standard metafile follows */
93 typedef struct _APM_HEADER
95 DWORD key;
96 WORD handle;
97 SHORT left;
98 SHORT top;
99 SHORT right;
100 SHORT bottom;
101 WORD inch;
102 DWORD reserved;
103 WORD checksum;
104 } APM_HEADER;
106 typedef struct {
107 BYTE bWidth;
108 BYTE bHeight;
109 BYTE bColorCount;
110 BYTE bReserved;
111 WORD xHotspot;
112 WORD yHotspot;
113 DWORD dwDIBSize;
114 DWORD dwDIBOffset;
115 } CURSORICONFILEDIRENTRY;
117 typedef struct
119 WORD idReserved;
120 WORD idType;
121 WORD idCount;
122 CURSORICONFILEDIRENTRY idEntries[1];
123 } CURSORICONFILEDIR;
125 #include "poppack.h"
127 /*************************************************************************
128 * Declaration of implementation class
131 typedef struct OLEPictureImpl {
134 * IPicture handles IUnknown
137 const IPictureVtbl *lpVtbl;
138 const IDispatchVtbl *lpvtblIDispatch;
139 const IPersistStreamVtbl *lpvtblIPersistStream;
140 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
142 /* Object reference count */
143 LONG ref;
145 /* We own the object and must destroy it ourselves */
146 BOOL fOwn;
148 /* Picture description */
149 PICTDESC desc;
151 /* These are the pixel size of a bitmap */
152 DWORD origWidth;
153 DWORD origHeight;
155 /* And these are the size of the picture converted into HIMETRIC units */
156 OLE_XSIZE_HIMETRIC himetricWidth;
157 OLE_YSIZE_HIMETRIC himetricHeight;
159 IConnectionPoint *pCP;
161 BOOL keepOrigFormat;
162 HDC hDCCur;
164 /* Bitmap transparency mask */
165 HBITMAP hbmMask;
166 HBITMAP hbmXor;
167 COLORREF rgbTrans;
169 /* data */
170 void* data;
171 int datalen;
172 BOOL bIsDirty; /* Set to TRUE if picture has changed */
173 unsigned int loadtime_magic; /* If a length header was found, saves value */
174 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
175 } OLEPictureImpl;
178 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
181 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
183 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
186 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
188 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
191 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
193 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
197 * Predeclare VTables. They get initialized at the end.
199 static const IPictureVtbl OLEPictureImpl_VTable;
200 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
201 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
202 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
204 /***********************************************************************
205 * Implementation of the OLEPictureImpl class.
208 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
209 BITMAP bm;
210 HDC hdcRef;
212 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
213 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
214 ERR("GetObject fails\n");
215 return;
217 This->origWidth = bm.bmWidth;
218 This->origHeight = bm.bmHeight;
219 /* The width and height are stored in HIMETRIC units (0.01 mm),
220 so we take our pixel width divide by pixels per inch and
221 multiply by 25.4 * 100 */
222 /* Should we use GetBitmapDimension if available? */
223 hdcRef = CreateCompatibleDC(0);
224 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
225 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
226 DeleteDC(hdcRef);
229 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
231 ICONINFO infoIcon;
233 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
234 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
235 HDC hdcRef;
236 BITMAP bm;
238 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
239 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
240 ERR("GetObject fails on icon bitmap\n");
241 return;
244 This->origWidth = bm.bmWidth;
245 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
246 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
247 hdcRef = GetDC(0);
248 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
249 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
250 ReleaseDC(0, hdcRef);
252 DeleteObject(infoIcon.hbmMask);
253 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
254 } else {
255 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
259 /************************************************************************
260 * OLEPictureImpl_Construct
262 * This method will construct a new instance of the OLEPictureImpl
263 * class.
265 * The caller of this method must release the object when it's
266 * done with it.
268 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
270 OLEPictureImpl* newObject = 0;
272 if (pictDesc)
273 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
276 * Allocate space for the object.
278 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
280 if (newObject==0)
281 return newObject;
284 * Initialize the virtual function table.
286 newObject->lpVtbl = &OLEPictureImpl_VTable;
287 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
288 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
289 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
291 newObject->pCP = NULL;
292 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
293 if (!newObject->pCP)
295 HeapFree(GetProcessHeap(), 0, newObject);
296 return NULL;
300 * Start with one reference count. The caller of this function
301 * must release the interface pointer when it is done.
303 newObject->ref = 1;
304 newObject->hDCCur = 0;
306 newObject->fOwn = fOwn;
308 /* dunno about original value */
309 newObject->keepOrigFormat = TRUE;
311 newObject->hbmMask = NULL;
312 newObject->hbmXor = NULL;
313 newObject->loadtime_magic = 0xdeadbeef;
314 newObject->loadtime_format = 0;
315 newObject->bIsDirty = FALSE;
317 if (pictDesc) {
318 newObject->desc = *pictDesc;
320 switch(pictDesc->picType) {
321 case PICTYPE_BITMAP:
322 OLEPictureImpl_SetBitmap(newObject);
323 break;
325 case PICTYPE_METAFILE:
326 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
327 newObject->himetricWidth = pictDesc->u.wmf.xExt;
328 newObject->himetricHeight = pictDesc->u.wmf.yExt;
329 break;
331 case PICTYPE_NONE:
332 /* not sure what to do here */
333 newObject->himetricWidth = newObject->himetricHeight = 0;
334 break;
336 case PICTYPE_ICON:
337 OLEPictureImpl_SetIcon(newObject);
338 break;
339 case PICTYPE_ENHMETAFILE:
340 default:
341 FIXME("Unsupported type %d\n", pictDesc->picType);
342 newObject->himetricWidth = newObject->himetricHeight = 0;
343 break;
345 } else {
346 newObject->desc.picType = PICTYPE_UNINITIALIZED;
349 TRACE("returning %p\n", newObject);
350 return newObject;
353 /************************************************************************
354 * OLEPictureImpl_Destroy
356 * This method is called by the Release method when the reference
357 * count goes down to 0. It will free all resources used by
358 * this object. */
359 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
361 TRACE("(%p)\n", Obj);
363 if (Obj->pCP)
364 IConnectionPoint_Release(Obj->pCP);
366 if(Obj->fOwn) { /* We need to destroy the picture */
367 switch(Obj->desc.picType) {
368 case PICTYPE_BITMAP:
369 DeleteObject(Obj->desc.u.bmp.hbitmap);
370 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
371 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
372 break;
373 case PICTYPE_METAFILE:
374 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
375 break;
376 case PICTYPE_ICON:
377 DestroyIcon(Obj->desc.u.icon.hicon);
378 break;
379 case PICTYPE_ENHMETAFILE:
380 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
381 break;
382 case PICTYPE_NONE:
383 case PICTYPE_UNINITIALIZED:
384 /* Nothing to do */
385 break;
386 default:
387 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
388 break;
391 HeapFree(GetProcessHeap(), 0, Obj->data);
392 HeapFree(GetProcessHeap(), 0, Obj);
396 /************************************************************************
397 * OLEPictureImpl_AddRef (IUnknown)
399 * See Windows documentation for more details on IUnknown methods.
401 static ULONG WINAPI OLEPictureImpl_AddRef(
402 IPicture* iface)
404 OLEPictureImpl *This = (OLEPictureImpl *)iface;
405 ULONG refCount = InterlockedIncrement(&This->ref);
407 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
409 return refCount;
412 /************************************************************************
413 * OLEPictureImpl_Release (IUnknown)
415 * See Windows documentation for more details on IUnknown methods.
417 static ULONG WINAPI OLEPictureImpl_Release(
418 IPicture* iface)
420 OLEPictureImpl *This = (OLEPictureImpl *)iface;
421 ULONG refCount = InterlockedDecrement(&This->ref);
423 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
426 * If the reference count goes down to 0, perform suicide.
428 if (!refCount) OLEPictureImpl_Destroy(This);
430 return refCount;
433 /************************************************************************
434 * OLEPictureImpl_QueryInterface (IUnknown)
436 * See Windows documentation for more details on IUnknown methods.
438 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
439 IPicture* iface,
440 REFIID riid,
441 void** ppvObject)
443 OLEPictureImpl *This = (OLEPictureImpl *)iface;
444 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
447 * Perform a sanity check on the parameters.
449 if ( (This==0) || (ppvObject==0) )
450 return E_INVALIDARG;
453 * Initialize the return parameter.
455 *ppvObject = 0;
458 * Compare the riid with the interface IDs implemented by this object.
460 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
461 *ppvObject = This;
462 else if (IsEqualIID(&IID_IDispatch, riid))
463 *ppvObject = &This->lpvtblIDispatch;
464 else if (IsEqualIID(&IID_IPictureDisp, riid))
465 *ppvObject = &This->lpvtblIDispatch;
466 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
467 *ppvObject = &This->lpvtblIPersistStream;
468 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
469 *ppvObject = &This->lpvtblIConnectionPointContainer;
472 * Check that we obtained an interface.
474 if ((*ppvObject)==0)
476 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
477 return E_NOINTERFACE;
481 * Query Interface always increases the reference count by one when it is
482 * successful
484 OLEPictureImpl_AddRef((IPicture*)This);
486 return S_OK;
489 /***********************************************************************
490 * OLEPicture_SendNotify (internal)
492 * Sends notification messages of changed properties to any interested
493 * connections.
495 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
497 IEnumConnections *pEnum;
498 CONNECTDATA CD;
500 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
501 return;
502 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
503 IPropertyNotifySink *sink;
505 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
506 IPropertyNotifySink_OnChanged(sink, dispID);
507 IPropertyNotifySink_Release(sink);
508 IUnknown_Release(CD.pUnk);
510 IEnumConnections_Release(pEnum);
513 /************************************************************************
514 * OLEPictureImpl_get_Handle
516 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
517 OLE_HANDLE *phandle)
519 OLEPictureImpl *This = (OLEPictureImpl *)iface;
520 TRACE("(%p)->(%p)\n", This, phandle);
522 if(!phandle)
523 return E_POINTER;
525 switch(This->desc.picType) {
526 case PICTYPE_NONE:
527 case PICTYPE_UNINITIALIZED:
528 *phandle = 0;
529 break;
530 case PICTYPE_BITMAP:
531 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
532 break;
533 case PICTYPE_METAFILE:
534 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
535 break;
536 case PICTYPE_ICON:
537 *phandle = HandleToUlong(This->desc.u.icon.hicon);
538 break;
539 case PICTYPE_ENHMETAFILE:
540 *phandle = HandleToUlong(This->desc.u.emf.hemf);
541 break;
542 default:
543 FIXME("Unimplemented type %d\n", This->desc.picType);
544 return E_NOTIMPL;
546 TRACE("returning handle %08x\n", *phandle);
547 return S_OK;
550 /************************************************************************
551 * OLEPictureImpl_get_hPal
553 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
554 OLE_HANDLE *phandle)
556 OLEPictureImpl *This = (OLEPictureImpl *)iface;
557 HRESULT hres;
558 TRACE("(%p)->(%p)\n", This, phandle);
560 if (!phandle)
561 return E_POINTER;
563 switch (This->desc.picType) {
564 case (UINT)PICTYPE_UNINITIALIZED:
565 case PICTYPE_NONE:
566 *phandle = 0;
567 hres = S_FALSE;
568 break;
569 case PICTYPE_BITMAP:
570 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
571 hres = S_OK;
572 break;
573 case PICTYPE_METAFILE:
574 hres = E_FAIL;
575 break;
576 case PICTYPE_ICON:
577 case PICTYPE_ENHMETAFILE:
578 default:
579 FIXME("unimplemented for type %d. Returning 0 palette.\n",
580 This->desc.picType);
581 *phandle = 0;
582 hres = S_OK;
585 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
586 return hres;
589 /************************************************************************
590 * OLEPictureImpl_get_Type
592 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
593 short *ptype)
595 OLEPictureImpl *This = (OLEPictureImpl *)iface;
596 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
598 if(!ptype)
599 return E_POINTER;
601 *ptype = This->desc.picType;
602 return S_OK;
605 /************************************************************************
606 * OLEPictureImpl_get_Width
608 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
609 OLE_XSIZE_HIMETRIC *pwidth)
611 OLEPictureImpl *This = (OLEPictureImpl *)iface;
612 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
613 *pwidth = This->himetricWidth;
614 return S_OK;
617 /************************************************************************
618 * OLEPictureImpl_get_Height
620 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
621 OLE_YSIZE_HIMETRIC *pheight)
623 OLEPictureImpl *This = (OLEPictureImpl *)iface;
624 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
625 *pheight = This->himetricHeight;
626 return S_OK;
629 /************************************************************************
630 * OLEPictureImpl_Render
632 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
633 LONG x, LONG y, LONG cx, LONG cy,
634 OLE_XPOS_HIMETRIC xSrc,
635 OLE_YPOS_HIMETRIC ySrc,
636 OLE_XSIZE_HIMETRIC cxSrc,
637 OLE_YSIZE_HIMETRIC cySrc,
638 LPCRECT prcWBounds)
640 OLEPictureImpl *This = (OLEPictureImpl *)iface;
641 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
642 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
643 if(prcWBounds)
644 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
645 prcWBounds->right, prcWBounds->bottom);
647 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
648 return CTL_E_INVALIDPROPERTYVALUE;
652 * While the documentation suggests this to be here (or after rendering?)
653 * it does cause an endless recursion in my sample app. -MM 20010804
654 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
657 switch(This->desc.picType) {
658 case PICTYPE_UNINITIALIZED:
659 case PICTYPE_NONE:
660 /* nothing to do */
661 return S_OK;
662 case PICTYPE_BITMAP:
664 HBITMAP hbmpOld;
665 HDC hdcBmp;
667 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
668 NB y-axis gets flipped */
670 hdcBmp = CreateCompatibleDC(0);
671 SetMapMode(hdcBmp, MM_ANISOTROPIC);
672 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
673 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
674 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
675 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
677 if (This->hbmMask) {
678 HDC hdcMask = CreateCompatibleDC(0);
679 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
681 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
683 SetMapMode(hdcMask, MM_ANISOTROPIC);
684 SetWindowOrgEx(hdcMask, 0, 0, NULL);
685 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
686 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
687 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
689 SetBkColor(hdc, RGB(255, 255, 255));
690 SetTextColor(hdc, RGB(0, 0, 0));
691 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
692 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
694 SelectObject(hdcMask, hOldbm);
695 DeleteDC(hdcMask);
696 } else {
697 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
698 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
701 SelectObject(hdcBmp, hbmpOld);
702 DeleteDC(hdcBmp);
704 break;
705 case PICTYPE_ICON:
706 FIXME("Not quite correct implementation of rendering icons...\n");
707 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
708 break;
710 case PICTYPE_METAFILE:
712 POINT prevOrg, prevWndOrg;
713 SIZE prevExt, prevWndExt;
714 int oldmode;
716 /* Render the WMF to the appropriate location by setting the
717 appropriate ratio between "device units" and "logical units" */
718 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
719 /* For the "source rectangle" the y-axis must be inverted */
720 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
721 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
722 /* For the "destination rectangle" no inversion is necessary */
723 SetViewportOrgEx(hdc, x, y, &prevOrg);
724 SetViewportExtEx(hdc, cx, cy, &prevExt);
726 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
727 ERR("PlayMetaFile failed!\n");
729 /* We're done, restore the DC to the previous settings for converting
730 logical units to device units */
731 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
732 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
733 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
734 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
735 SetMapMode(hdc, oldmode);
736 break;
739 case PICTYPE_ENHMETAFILE:
741 RECT rc = { x, y, x + cx, y + cy };
742 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
743 break;
746 default:
747 FIXME("type %d not implemented\n", This->desc.picType);
748 return E_NOTIMPL;
750 return S_OK;
753 /************************************************************************
754 * OLEPictureImpl_set_hPal
756 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
757 OLE_HANDLE hpal)
759 OLEPictureImpl *This = (OLEPictureImpl *)iface;
760 FIXME("(%p)->(%08x): stub\n", This, hpal);
761 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
762 return E_NOTIMPL;
765 /************************************************************************
766 * OLEPictureImpl_get_CurDC
768 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
769 HDC *phdc)
771 OLEPictureImpl *This = (OLEPictureImpl *)iface;
772 TRACE("(%p), returning %p\n", This, This->hDCCur);
773 if (phdc) *phdc = This->hDCCur;
774 return S_OK;
777 /************************************************************************
778 * OLEPictureImpl_SelectPicture
780 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
781 HDC hdcIn,
782 HDC *phdcOut,
783 OLE_HANDLE *phbmpOut)
785 OLEPictureImpl *This = (OLEPictureImpl *)iface;
786 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
787 if (This->desc.picType == PICTYPE_BITMAP) {
788 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
790 if (phdcOut)
791 *phdcOut = This->hDCCur;
792 This->hDCCur = hdcIn;
793 if (phbmpOut)
794 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
795 return S_OK;
796 } else {
797 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
798 return E_FAIL;
802 /************************************************************************
803 * OLEPictureImpl_get_KeepOriginalFormat
805 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
806 BOOL *pfKeep)
808 OLEPictureImpl *This = (OLEPictureImpl *)iface;
809 TRACE("(%p)->(%p)\n", This, pfKeep);
810 if (!pfKeep)
811 return E_POINTER;
812 *pfKeep = This->keepOrigFormat;
813 return S_OK;
816 /************************************************************************
817 * OLEPictureImpl_put_KeepOriginalFormat
819 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
820 BOOL keep)
822 OLEPictureImpl *This = (OLEPictureImpl *)iface;
823 TRACE("(%p)->(%d)\n", This, keep);
824 This->keepOrigFormat = keep;
825 /* FIXME: what DISPID notification here? */
826 return S_OK;
829 /************************************************************************
830 * OLEPictureImpl_PictureChanged
832 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
834 OLEPictureImpl *This = (OLEPictureImpl *)iface;
835 TRACE("(%p)->()\n", This);
836 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
837 This->bIsDirty = TRUE;
838 return S_OK;
841 /************************************************************************
842 * OLEPictureImpl_SaveAsFile
844 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
845 IStream *pstream,
846 BOOL SaveMemCopy,
847 LONG *pcbSize)
849 OLEPictureImpl *This = (OLEPictureImpl *)iface;
850 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
851 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
854 /************************************************************************
855 * OLEPictureImpl_get_Attributes
857 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
858 DWORD *pdwAttr)
860 OLEPictureImpl *This = (OLEPictureImpl *)iface;
861 TRACE("(%p)->(%p).\n", This, pdwAttr);
863 if(!pdwAttr)
864 return E_POINTER;
866 *pdwAttr = 0;
867 switch (This->desc.picType) {
868 case PICTYPE_UNINITIALIZED:
869 case PICTYPE_NONE: break;
870 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
871 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
872 case PICTYPE_ENHMETAFILE: /* fall through */
873 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
874 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
876 return S_OK;
880 /************************************************************************
881 * IConnectionPointContainer
883 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
884 IConnectionPointContainer* iface,
885 REFIID riid,
886 VOID** ppvoid)
888 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
890 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
893 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
894 IConnectionPointContainer* iface)
896 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
898 return IPicture_AddRef((IPicture *)This);
901 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
902 IConnectionPointContainer* iface)
904 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
906 return IPicture_Release((IPicture *)This);
909 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
910 IConnectionPointContainer* iface,
911 IEnumConnectionPoints** ppEnum)
913 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
915 FIXME("(%p,%p), stub!\n",This,ppEnum);
916 return E_NOTIMPL;
919 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
920 IConnectionPointContainer* iface,
921 REFIID riid,
922 IConnectionPoint **ppCP)
924 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
925 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
926 if (!ppCP)
927 return E_POINTER;
928 *ppCP = NULL;
929 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
930 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
931 FIXME("no connection point for %s\n",debugstr_guid(riid));
932 return CONNECT_E_NOCONNECTION;
936 /************************************************************************
937 * IPersistStream
940 /************************************************************************
941 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
943 * See Windows documentation for more details on IUnknown methods.
945 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
946 IPersistStream* iface,
947 REFIID riid,
948 VOID** ppvoid)
950 OLEPictureImpl *This = impl_from_IPersistStream(iface);
952 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
955 /************************************************************************
956 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
958 * See Windows documentation for more details on IUnknown methods.
960 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
961 IPersistStream* iface)
963 OLEPictureImpl *This = impl_from_IPersistStream(iface);
965 return IPicture_AddRef((IPicture *)This);
968 /************************************************************************
969 * OLEPictureImpl_IPersistStream_Release (IUnknown)
971 * See Windows documentation for more details on IUnknown methods.
973 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
974 IPersistStream* iface)
976 OLEPictureImpl *This = impl_from_IPersistStream(iface);
978 return IPicture_Release((IPicture *)This);
981 /************************************************************************
982 * OLEPictureImpl_IPersistStream_GetClassID
984 static HRESULT WINAPI OLEPictureImpl_GetClassID(
985 IPersistStream* iface,CLSID* pClassID)
987 TRACE("(%p)\n", pClassID);
988 *pClassID = CLSID_StdPicture;
989 return S_OK;
992 /************************************************************************
993 * OLEPictureImpl_IPersistStream_IsDirty
995 static HRESULT WINAPI OLEPictureImpl_IsDirty(
996 IPersistStream* iface)
998 OLEPictureImpl *This = impl_from_IPersistStream(iface);
999 FIXME("(%p),stub!\n",This);
1000 return E_NOTIMPL;
1003 #ifdef SONAME_LIBJPEG
1005 static void *libjpeg_handle;
1006 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1007 MAKE_FUNCPTR(jpeg_std_error);
1008 MAKE_FUNCPTR(jpeg_CreateDecompress);
1009 MAKE_FUNCPTR(jpeg_read_header);
1010 MAKE_FUNCPTR(jpeg_start_decompress);
1011 MAKE_FUNCPTR(jpeg_read_scanlines);
1012 MAKE_FUNCPTR(jpeg_finish_decompress);
1013 MAKE_FUNCPTR(jpeg_destroy_decompress);
1014 #undef MAKE_FUNCPTR
1016 static void *load_libjpeg(void)
1018 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
1020 #define LOAD_FUNCPTR(f) \
1021 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
1022 libjpeg_handle = NULL; \
1023 return NULL; \
1026 LOAD_FUNCPTR(jpeg_std_error);
1027 LOAD_FUNCPTR(jpeg_CreateDecompress);
1028 LOAD_FUNCPTR(jpeg_read_header);
1029 LOAD_FUNCPTR(jpeg_start_decompress);
1030 LOAD_FUNCPTR(jpeg_read_scanlines);
1031 LOAD_FUNCPTR(jpeg_finish_decompress);
1032 LOAD_FUNCPTR(jpeg_destroy_decompress);
1033 #undef LOAD_FUNCPTR
1035 return libjpeg_handle;
1038 /* for the jpeg decompressor source manager. */
1039 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1041 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1042 ERR("(), should not get here.\n");
1043 return FALSE;
1046 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1047 TRACE("Skipping %ld bytes...\n", num_bytes);
1048 cinfo->src->next_input_byte += num_bytes;
1049 cinfo->src->bytes_in_buffer -= num_bytes;
1052 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1053 ERR("(desired=%d), should not get here.\n",desired);
1054 return FALSE;
1056 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1057 #endif /* SONAME_LIBJPEG */
1059 struct gifdata {
1060 unsigned char *data;
1061 unsigned int curoff;
1062 unsigned int len;
1065 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1066 struct gifdata *gd = gif->UserData;
1068 if (len+gd->curoff > gd->len) {
1069 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1070 len = gd->len - gd->curoff;
1072 memcpy(data, gd->data+gd->curoff, len);
1073 gd->curoff += len;
1074 return len;
1078 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1080 struct gifdata gd;
1081 GifFileType *gif;
1082 BITMAPINFO *bmi;
1083 HDC hdcref;
1084 LPBYTE bytes;
1085 int i,j,ret;
1086 GifImageDesc *gid;
1087 SavedImage *si;
1088 ColorMapObject *cm;
1089 int transparent = -1;
1090 ExtensionBlock *eb;
1091 int padding;
1093 gd.data = xbuf;
1094 gd.curoff = 0;
1095 gd.len = xread;
1096 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1097 ret = DGifSlurp(gif);
1098 if (ret == GIF_ERROR) {
1099 ERR("Failed reading GIF using libgif.\n");
1100 return E_FAIL;
1102 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1103 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1104 TRACE("imgcnt %d\n", gif->ImageCount);
1105 if (gif->ImageCount<1) {
1106 ERR("GIF stream does not have images inside?\n");
1107 return E_FAIL;
1109 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1110 gif->Image.Width, gif->Image.Height,
1111 gif->Image.Left, gif->Image.Top,
1112 gif->Image.Interlace
1114 /* */
1115 padding = (gif->SWidth+3) & ~3;
1116 si = gif->SavedImages+0;
1117 gid = &(si->ImageDesc);
1118 cm = gid->ColorMap;
1119 if (!cm) cm = gif->SColorMap;
1120 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1121 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1123 /* look for the transparent color extension */
1124 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1125 eb = si->ExtensionBlocks + i;
1126 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1127 if ((eb->Bytes[0] & 1) == 1) {
1128 transparent = (unsigned char)eb->Bytes[3];
1133 for (i = 0; i < cm->ColorCount; i++) {
1134 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1135 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1136 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1137 if (i == transparent) {
1138 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1139 bmi->bmiColors[i].rgbGreen,
1140 bmi->bmiColors[i].rgbBlue);
1144 /* Map to in picture coordinates */
1145 for (i = 0, j = 0; i < gid->Height; i++) {
1146 if (gif->Image.Interlace) {
1147 memcpy(
1148 bytes + (gid->Top + j) * padding + gid->Left,
1149 si->RasterBits + i * gid->Width,
1150 gid->Width);
1152 /* Lower bits of interlaced counter encode current interlace */
1153 if (j & 1) j += 2; /* Currently filling odd rows */
1154 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1155 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1157 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1158 /* End of current interlace, go to next interlace */
1159 if (j & 2) j = 1; /* Next iteration fills odd rows */
1160 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1161 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1163 } else {
1164 memcpy(
1165 bytes + (gid->Top + i) * padding + gid->Left,
1166 si->RasterBits + i * gid->Width,
1167 gid->Width);
1171 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1172 bmi->bmiHeader.biWidth = gif->SWidth;
1173 bmi->bmiHeader.biHeight = -gif->SHeight;
1174 bmi->bmiHeader.biPlanes = 1;
1175 bmi->bmiHeader.biBitCount = 8;
1176 bmi->bmiHeader.biCompression = BI_RGB;
1177 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1178 bmi->bmiHeader.biXPelsPerMeter = 0;
1179 bmi->bmiHeader.biYPelsPerMeter = 0;
1180 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1181 bmi->bmiHeader.biClrImportant = 0;
1183 hdcref = GetDC(0);
1184 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1185 hdcref,
1186 &bmi->bmiHeader,
1187 CBM_INIT,
1188 bytes,
1189 bmi,
1190 DIB_RGB_COLORS
1193 if (transparent > -1) {
1194 /* Create the Mask */
1195 HDC hdc = CreateCompatibleDC(0);
1196 HDC hdcMask = CreateCompatibleDC(0);
1197 HBITMAP hOldbitmap;
1198 HBITMAP hOldbitmapmask;
1200 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1201 HBITMAP hTempMask;
1203 This->hbmXor = CreateDIBitmap(
1204 hdcref,
1205 &bmi->bmiHeader,
1206 CBM_INIT,
1207 bytes,
1208 bmi,
1209 DIB_RGB_COLORS
1212 bmi->bmiColors[0].rgbRed = 0;
1213 bmi->bmiColors[0].rgbGreen = 0;
1214 bmi->bmiColors[0].rgbBlue = 0;
1215 bmi->bmiColors[1].rgbRed = 255;
1216 bmi->bmiColors[1].rgbGreen = 255;
1217 bmi->bmiColors[1].rgbBlue = 255;
1219 bmi->bmiHeader.biBitCount = 1;
1220 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1221 bmi->bmiHeader.biClrUsed = 2;
1223 for (i = 0; i < gif->SHeight; i++) {
1224 unsigned char * colorPointer = bytes + padding * i;
1225 unsigned char * monoPointer = bytes + monopadding * i;
1226 for (j = 0; j < gif->SWidth; j++) {
1227 unsigned char pixel = colorPointer[j];
1228 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1229 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1232 hdcref = GetDC(0);
1233 hTempMask = CreateDIBitmap(
1234 hdcref,
1235 &bmi->bmiHeader,
1236 CBM_INIT,
1237 bytes,
1238 bmi,
1239 DIB_RGB_COLORS
1241 DeleteDC(hdcref);
1243 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1244 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1245 hOldbitmap = SelectObject(hdc, hTempMask);
1246 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1248 SetBkColor(hdc, RGB(255, 255, 255));
1249 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1251 /* We no longer need the original bitmap, so we apply the first
1252 transformation with the mask to speed up the rendering */
1253 SelectObject(hdc, This->hbmXor);
1254 SetBkColor(hdc, RGB(0,0,0));
1255 SetTextColor(hdc, RGB(255,255,255));
1256 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1257 hdcMask, 0, 0, SRCAND);
1259 SelectObject(hdc, hOldbitmap);
1260 SelectObject(hdcMask, hOldbitmapmask);
1261 DeleteDC(hdcMask);
1262 DeleteDC(hdc);
1263 DeleteObject(hTempMask);
1266 DeleteDC(hdcref);
1267 This->desc.picType = PICTYPE_BITMAP;
1268 OLEPictureImpl_SetBitmap(This);
1269 DGifCloseFile(gif);
1270 HeapFree(GetProcessHeap(),0,bmi);
1271 HeapFree(GetProcessHeap(),0,bytes);
1272 return S_OK;
1275 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1277 #ifdef SONAME_LIBJPEG
1278 struct jpeg_decompress_struct jd;
1279 struct jpeg_error_mgr jerr;
1280 int ret;
1281 JDIMENSION x;
1282 JSAMPROW samprow,oldsamprow;
1283 BITMAPINFOHEADER bmi;
1284 LPBYTE bits;
1285 HDC hdcref;
1286 struct jpeg_source_mgr xjsm;
1287 LPBYTE oldbits;
1288 unsigned int i;
1290 if(!libjpeg_handle) {
1291 if(!load_libjpeg()) {
1292 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1293 return E_FAIL;
1297 /* This is basically so we can use in-memory data for jpeg decompression.
1298 * We need to have all the functions.
1300 xjsm.next_input_byte = xbuf;
1301 xjsm.bytes_in_buffer = xread;
1302 xjsm.init_source = _jpeg_init_source;
1303 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1304 xjsm.skip_input_data = _jpeg_skip_input_data;
1305 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1306 xjsm.term_source = _jpeg_term_source;
1308 jd.err = pjpeg_std_error(&jerr);
1309 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1310 * jpeg_create_decompress(&jd); */
1311 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1312 jd.src = &xjsm;
1313 ret=pjpeg_read_header(&jd,TRUE);
1314 jd.out_color_space = JCS_RGB;
1315 pjpeg_start_decompress(&jd);
1316 if (ret != JPEG_HEADER_OK) {
1317 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1318 HeapFree(GetProcessHeap(),0,xbuf);
1319 return E_FAIL;
1322 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1323 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1324 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1326 oldbits = bits;
1327 oldsamprow = samprow;
1328 while ( jd.output_scanline<jd.output_height ) {
1329 x = pjpeg_read_scanlines(&jd,&samprow,1);
1330 if (x != 1) {
1331 ERR("failed to read current scanline?\n");
1332 break;
1334 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1335 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1336 *(bits++) = *(samprow+2);
1337 *(bits++) = *(samprow+1);
1338 *(bits++) = *(samprow);
1340 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1341 samprow = oldsamprow;
1343 bits = oldbits;
1345 bmi.biSize = sizeof(bmi);
1346 bmi.biWidth = jd.output_width;
1347 bmi.biHeight = -jd.output_height;
1348 bmi.biPlanes = 1;
1349 bmi.biBitCount = jd.output_components<<3;
1350 bmi.biCompression = BI_RGB;
1351 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1352 bmi.biXPelsPerMeter = 0;
1353 bmi.biYPelsPerMeter = 0;
1354 bmi.biClrUsed = 0;
1355 bmi.biClrImportant = 0;
1357 HeapFree(GetProcessHeap(),0,samprow);
1358 pjpeg_finish_decompress(&jd);
1359 pjpeg_destroy_decompress(&jd);
1360 hdcref = GetDC(0);
1361 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1362 hdcref,
1363 &bmi,
1364 CBM_INIT,
1365 bits,
1366 (BITMAPINFO*)&bmi,
1367 DIB_RGB_COLORS
1369 DeleteDC(hdcref);
1370 This->desc.picType = PICTYPE_BITMAP;
1371 OLEPictureImpl_SetBitmap(This);
1372 HeapFree(GetProcessHeap(),0,bits);
1373 return S_OK;
1374 #else
1375 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1376 return E_FAIL;
1377 #endif
1380 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1382 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1383 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1384 HDC hdcref;
1386 /* Does not matter whether this is a coreheader or not, we only use
1387 * components which are in both
1389 hdcref = GetDC(0);
1390 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1391 hdcref,
1392 &(bi->bmiHeader),
1393 CBM_INIT,
1394 xbuf+bfh->bfOffBits,
1396 DIB_RGB_COLORS
1398 DeleteDC(hdcref);
1399 if (This->desc.u.bmp.hbitmap == 0)
1400 return E_FAIL;
1401 This->desc.picType = PICTYPE_BITMAP;
1402 OLEPictureImpl_SetBitmap(This);
1403 return S_OK;
1406 /*****************************************************
1407 * start of PNG-specific code
1408 * currently only supports colortype PNG_COLOR_TYPE_RGB
1410 #ifdef SONAME_LIBPNG
1411 typedef struct{
1412 ULONG position;
1413 ULONG size;
1414 BYTE * buff;
1415 } png_io;
1417 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1418 png_size_t length)
1420 png_io * io_ptr = png_ptr->io_ptr;
1422 if(length + io_ptr->position > io_ptr->size){
1423 length = io_ptr->size - io_ptr->position;
1426 memcpy(data, io_ptr->buff + io_ptr->position, length);
1428 io_ptr->position += length;
1431 static void *libpng_handle;
1432 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1433 MAKE_FUNCPTR(png_create_read_struct);
1434 MAKE_FUNCPTR(png_create_info_struct);
1435 MAKE_FUNCPTR(png_set_read_fn);
1436 MAKE_FUNCPTR(png_read_info);
1437 MAKE_FUNCPTR(png_read_image);
1438 MAKE_FUNCPTR(png_get_rowbytes);
1439 MAKE_FUNCPTR(png_set_bgr);
1440 MAKE_FUNCPTR(png_destroy_read_struct);
1441 MAKE_FUNCPTR(png_set_palette_to_rgb);
1442 MAKE_FUNCPTR(png_read_update_info);
1443 MAKE_FUNCPTR(png_get_tRNS);
1444 MAKE_FUNCPTR(png_get_PLTE);
1445 MAKE_FUNCPTR(png_set_expand);
1446 #undef MAKE_FUNCPTR
1448 static void *load_libpng(void)
1450 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1452 #define LOAD_FUNCPTR(f) \
1453 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1454 libpng_handle = NULL; \
1455 return NULL; \
1457 LOAD_FUNCPTR(png_create_read_struct);
1458 LOAD_FUNCPTR(png_create_info_struct);
1459 LOAD_FUNCPTR(png_set_read_fn);
1460 LOAD_FUNCPTR(png_read_info);
1461 LOAD_FUNCPTR(png_read_image);
1462 LOAD_FUNCPTR(png_get_rowbytes);
1463 LOAD_FUNCPTR(png_set_bgr);
1464 LOAD_FUNCPTR(png_destroy_read_struct);
1465 LOAD_FUNCPTR(png_set_palette_to_rgb);
1466 LOAD_FUNCPTR(png_read_update_info);
1467 LOAD_FUNCPTR(png_get_tRNS);
1468 LOAD_FUNCPTR(png_get_PLTE);
1469 LOAD_FUNCPTR(png_set_expand);
1471 #undef LOAD_FUNCPTR
1473 return libpng_handle;
1475 #endif /* SONAME_LIBPNG */
1477 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1479 #ifdef SONAME_LIBPNG
1480 png_io io;
1481 png_structp png_ptr = NULL;
1482 png_infop info_ptr = NULL;
1483 INT row, rowsize, height, width, num_trans, i, j;
1484 png_bytep* row_pointers = NULL;
1485 png_bytep pngdata = NULL;
1486 BITMAPINFOHEADER bmi;
1487 HDC hdcref = NULL, hdcXor, hdcMask;
1488 HRESULT ret;
1489 BOOL transparency;
1490 png_bytep trans;
1491 png_color_16p trans_values;
1492 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1493 HBITMAP hbmoldXor, hbmoldMask, temp;
1495 if(!libpng_handle) {
1496 if(!load_libpng()) {
1497 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1498 return E_FAIL;
1502 io.size = xread;
1503 io.position = 0;
1504 io.buff = xbuf;
1506 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1507 NULL, NULL, NULL);
1509 if(setjmp(png_jmpbuf(png_ptr))){
1510 TRACE("Error in libpng\n");
1511 ret = E_FAIL;
1512 goto end;
1515 info_ptr = ppng_create_info_struct(png_ptr);
1516 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1517 ppng_read_info(png_ptr, info_ptr);
1519 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1520 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1521 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1522 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1523 ret = E_FAIL;
1524 goto end;
1527 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1528 == PNG_INFO_tRNS);
1530 /* sets format from anything to RGBA */
1531 ppng_set_expand(png_ptr);
1532 /* sets format to BGRA */
1533 ppng_set_bgr(png_ptr);
1535 ppng_read_update_info(png_ptr, info_ptr);
1537 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1538 /* align rowsize to 4-byte boundary */
1539 rowsize = (rowsize + 3) & ~3;
1540 height = info_ptr->height;
1541 width = info_ptr->width;
1543 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1544 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1546 if(!pngdata || !row_pointers){
1547 ret = E_FAIL;
1548 goto end;
1551 for (row = 0; row < height; row++){
1552 row_pointers[row] = pngdata + row * rowsize;
1555 ppng_read_image(png_ptr, row_pointers);
1557 bmi.biSize = sizeof(bmi);
1558 bmi.biWidth = width;
1559 bmi.biHeight = -height;
1560 bmi.biPlanes = 1;
1561 bmi.biBitCount = info_ptr->channels * 8;
1562 bmi.biCompression = BI_RGB;
1563 bmi.biSizeImage = height * rowsize;
1564 bmi.biXPelsPerMeter = 0;
1565 bmi.biYPelsPerMeter = 0;
1566 bmi.biClrUsed = 0;
1567 bmi.biClrImportant = 0;
1569 hdcref = GetDC(0);
1570 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1571 hdcref,
1572 &bmi,
1573 CBM_INIT,
1574 pngdata,
1575 (BITMAPINFO*)&bmi,
1576 DIB_RGB_COLORS
1579 /* only fully-transparent alpha is handled */
1580 if((info_ptr->channels != 4) || !transparency){
1581 ReleaseDC(0, hdcref);
1582 goto succ;
1585 This->hbmXor = CreateDIBitmap(
1586 hdcref,
1587 &bmi,
1588 CBM_INIT,
1589 pngdata,
1590 (BITMAPINFO*)&bmi,
1591 DIB_RGB_COLORS
1594 /* set transparent pixels to black, all others to white */
1595 for(i = 0; i < height; i++){
1596 for(j = 3; j < rowsize; j += 4){
1597 if(row_pointers[i][j] == 0)
1598 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1599 else
1600 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1604 temp = CreateDIBitmap(
1605 hdcref,
1606 &bmi,
1607 CBM_INIT,
1608 pngdata,
1609 (BITMAPINFO*)&bmi,
1610 DIB_RGB_COLORS
1613 ReleaseDC(0, hdcref);
1615 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1616 hdcXor = CreateCompatibleDC(NULL);
1617 hdcMask = CreateCompatibleDC(NULL);
1619 hbmoldXor = SelectObject(hdcXor,temp);
1620 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1621 SetBkColor(hdcXor,black);
1622 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1624 SelectObject(hdcXor,This->hbmXor);
1625 DeleteObject(temp);
1627 SetTextColor(hdcXor,white);
1628 SetBkColor(hdcXor,black);
1629 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1631 SelectObject(hdcXor,hbmoldXor);
1632 SelectObject(hdcMask,hbmoldMask);
1634 DeleteDC(hdcXor);
1635 DeleteDC(hdcMask);
1637 succ:
1638 This->desc.picType = PICTYPE_BITMAP;
1639 OLEPictureImpl_SetBitmap(This);
1640 ret = S_OK;
1642 end:
1643 if(png_ptr)
1644 ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1645 HeapFree(GetProcessHeap(), 0, row_pointers);
1646 HeapFree(GetProcessHeap(), 0, pngdata);
1647 return ret;
1648 #else /* SONAME_LIBPNG */
1649 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1650 return E_FAIL;
1651 #endif
1654 /*****************************************************
1655 * start of Icon-specific code
1658 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1660 HICON hicon;
1661 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1662 HDC hdcRef;
1663 int i;
1666 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1667 FIXME("icon.idType=%d\n",cifd->idType);
1668 FIXME("icon.idCount=%d\n",cifd->idCount);
1670 for (i=0;i<cifd->idCount;i++) {
1671 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1672 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1673 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1674 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1675 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1676 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1677 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1678 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1681 i=0;
1682 /* If we have more than one icon, try to find the best.
1683 * this currently means '32 pixel wide'.
1685 if (cifd->idCount!=1) {
1686 for (i=0;i<cifd->idCount;i++) {
1687 if (cifd->idEntries[i].bWidth == 32)
1688 break;
1690 if (i==cifd->idCount) i=0;
1693 hicon = CreateIconFromResourceEx(
1694 xbuf+cifd->idEntries[i].dwDIBOffset,
1695 cifd->idEntries[i].dwDIBSize,
1696 TRUE, /* is icon */
1697 0x00030000,
1698 cifd->idEntries[i].bWidth,
1699 cifd->idEntries[i].bHeight,
1702 if (!hicon) {
1703 ERR("CreateIcon failed.\n");
1704 return E_FAIL;
1705 } else {
1706 This->desc.picType = PICTYPE_ICON;
1707 This->desc.u.icon.hicon = hicon;
1708 This->origWidth = cifd->idEntries[i].bWidth;
1709 This->origHeight = cifd->idEntries[i].bHeight;
1710 hdcRef = CreateCompatibleDC(0);
1711 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1712 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1713 DeleteDC(hdcRef);
1714 return S_OK;
1718 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1719 const BYTE *data, ULONG size)
1721 HENHMETAFILE hemf;
1722 ENHMETAHEADER hdr;
1724 hemf = SetEnhMetaFileBits(size, data);
1725 if (!hemf) return E_FAIL;
1727 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1729 This->desc.picType = PICTYPE_ENHMETAFILE;
1730 This->desc.u.emf.hemf = hemf;
1732 This->origWidth = 0;
1733 This->origHeight = 0;
1734 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1735 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1737 return S_OK;
1740 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1741 const BYTE *data, ULONG size)
1743 APM_HEADER *header = (APM_HEADER *)data;
1744 HMETAFILE hmf;
1746 if (size < sizeof(APM_HEADER))
1747 return E_FAIL;
1748 if (header->key != 0x9ac6cdd7)
1749 return E_FAIL;
1751 /* SetMetaFileBitsEx performs data check on its own */
1752 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1753 if (!hmf) return E_FAIL;
1755 This->desc.picType = PICTYPE_METAFILE;
1756 This->desc.u.wmf.hmeta = hmf;
1757 This->desc.u.wmf.xExt = 0;
1758 This->desc.u.wmf.yExt = 0;
1760 This->origWidth = 0;
1761 This->origHeight = 0;
1762 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1763 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1764 return S_OK;
1767 /************************************************************************
1768 * BITMAP FORMAT FLAGS -
1769 * Flags that differentiate between different types of bitmaps.
1772 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1773 #define BITMAP_FORMAT_JPEG 0xd8ff
1774 #define BITMAP_FORMAT_GIF 0x4947
1775 #define BITMAP_FORMAT_PNG 0x5089
1776 #define BITMAP_FORMAT_APM 0xcdd7
1778 /************************************************************************
1779 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1781 * Loads the binary data from the IStream. Starts at current position.
1782 * There appears to be an 2 DWORD header:
1783 * DWORD magic;
1784 * DWORD len;
1786 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1788 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1789 HRESULT hr = E_FAIL;
1790 BOOL headerisdata = FALSE;
1791 BOOL statfailed = FALSE;
1792 ULONG xread, toread;
1793 ULONG headerread;
1794 BYTE *xbuf;
1795 DWORD header[2];
1796 WORD magic;
1797 STATSTG statstg;
1798 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1800 TRACE("(%p,%p)\n",This,pStm);
1802 /****************************************************************************************
1803 * Part 1: Load the data
1805 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1806 * out whether we do.
1808 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1809 * compound file. This may explain most, if not all, of the cases of "no
1810 * header", and the header validation should take this into account.
1811 * At least in Visual Basic 6, resource streams, valid headers are
1812 * header[0] == "lt\0\0",
1813 * header[1] == length_of_stream.
1815 * Also handle streams where we do not have a working "Stat" method by
1816 * reading all data until the end of the stream.
1818 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1819 if (hr) {
1820 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1821 statfailed = TRUE;
1822 /* we will read at least 8 byte ... just right below */
1823 statstg.cbSize.QuadPart = 8;
1826 toread = 0;
1827 headerread = 0;
1828 headerisdata = FALSE;
1829 do {
1830 hr=IStream_Read(pStm,header,8,&xread);
1831 if (hr || xread!=8) {
1832 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1833 return (hr?hr:E_FAIL);
1835 headerread += xread;
1836 xread = 0;
1838 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1839 if (toread != 0 && toread != header[1])
1840 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1841 toread, header[1]);
1842 toread = header[1];
1843 if (toread == 0) break;
1844 } else {
1845 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1846 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1847 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1848 (header[0] == EMR_HEADER) || /* EMF header */
1849 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1850 (header[1]==0)
1851 ) {/* Found start of bitmap data */
1852 headerisdata = TRUE;
1853 if (toread == 0)
1854 toread = statstg.cbSize.QuadPart-8;
1855 else toread -= 8;
1856 xread = 8;
1857 } else {
1858 FIXME("Unknown stream header magic: %08x\n", header[0]);
1859 toread = header[1];
1862 } while (!headerisdata);
1864 if (statfailed) { /* we don't know the size ... read all we get */
1865 int sizeinc = 4096;
1866 int origsize = sizeinc;
1867 ULONG nread = 42;
1869 TRACE("Reading all data from stream.\n");
1870 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1871 if (headerisdata)
1872 memcpy (xbuf, header, 8);
1873 while (1) {
1874 while (xread < origsize) {
1875 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1876 xread+=nread;
1877 if (hr || !nread)
1878 break;
1880 if (!nread || hr) /* done, or error */
1881 break;
1882 if (xread == origsize) {
1883 origsize += sizeinc;
1884 sizeinc = 2*sizeinc; /* exponential increase */
1885 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1888 if (hr)
1889 TRACE("hr in no-stat loader case is %08x\n", hr);
1890 TRACE("loaded %d bytes.\n", xread);
1891 This->datalen = xread;
1892 This->data = xbuf;
1893 } else {
1894 This->datalen = toread+(headerisdata?8:0);
1895 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1896 if (!xbuf)
1897 return E_OUTOFMEMORY;
1899 if (headerisdata)
1900 memcpy (xbuf, header, 8);
1902 while (xread < This->datalen) {
1903 ULONG nread;
1904 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1905 xread+=nread;
1906 if (hr || !nread)
1907 break;
1909 if (xread != This->datalen)
1910 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1912 if (This->datalen == 0) { /* Marks the "NONE" picture */
1913 This->desc.picType = PICTYPE_NONE;
1914 return S_OK;
1918 /****************************************************************************************
1919 * Part 2: Process the loaded data
1922 magic = xbuf[0] + (xbuf[1]<<8);
1923 This->loadtime_format = magic;
1925 switch (magic) {
1926 case BITMAP_FORMAT_GIF: /* GIF */
1927 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1928 break;
1929 case BITMAP_FORMAT_JPEG: /* JPEG */
1930 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1931 break;
1932 case BITMAP_FORMAT_BMP: /* Bitmap */
1933 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1934 break;
1935 case BITMAP_FORMAT_PNG: /* PNG */
1936 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1937 break;
1938 case BITMAP_FORMAT_APM: /* APM */
1939 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1940 break;
1941 case 0x0000: { /* ICON , first word is dwReserved */
1942 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1943 break;
1945 default:
1947 unsigned int i;
1949 /* let's see if it's a EMF */
1950 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1951 if (hr == S_OK) break;
1953 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1954 hr=E_FAIL;
1955 for (i=0;i<xread+8;i++) {
1956 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1957 else MESSAGE("%02x ",xbuf[i-8]);
1958 if (i % 10 == 9) MESSAGE("\n");
1960 MESSAGE("\n");
1961 break;
1964 This->bIsDirty = FALSE;
1966 /* FIXME: this notify is not really documented */
1967 if (hr==S_OK)
1968 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1969 return hr;
1972 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1974 int iSuccess = 0;
1975 HDC hDC;
1976 BITMAPINFO * pInfoBitmap;
1977 int iNumPaletteEntries;
1978 unsigned char * pPixelData;
1979 BITMAPFILEHEADER * pFileHeader;
1980 BITMAPINFO * pInfoHeader;
1982 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1983 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1985 /* Find out bitmap size and padded length */
1986 hDC = GetDC(0);
1987 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1988 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1990 /* Fetch bitmap palette & pixel data */
1992 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1993 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1995 /* Calculate the total length required for the BMP data */
1996 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1997 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1998 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1999 } else {
2000 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
2001 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
2002 else
2003 iNumPaletteEntries = 0;
2005 *pLength =
2006 sizeof(BITMAPFILEHEADER) +
2007 sizeof(BITMAPINFOHEADER) +
2008 iNumPaletteEntries * sizeof(RGBQUAD) +
2009 pInfoBitmap->bmiHeader.biSizeImage;
2010 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
2012 /* Fill the BITMAPFILEHEADER */
2013 pFileHeader = *ppBuffer;
2014 pFileHeader->bfType = BITMAP_FORMAT_BMP;
2015 pFileHeader->bfSize = *pLength;
2016 pFileHeader->bfOffBits =
2017 sizeof(BITMAPFILEHEADER) +
2018 sizeof(BITMAPINFOHEADER) +
2019 iNumPaletteEntries * sizeof(RGBQUAD);
2021 /* Fill the BITMAPINFOHEADER and the palette data */
2022 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
2023 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
2024 memcpy(
2025 (unsigned char *)(*ppBuffer) +
2026 sizeof(BITMAPFILEHEADER) +
2027 sizeof(BITMAPINFOHEADER) +
2028 iNumPaletteEntries * sizeof(RGBQUAD),
2029 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2030 iSuccess = 1;
2032 HeapFree(GetProcessHeap(), 0, pPixelData);
2033 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2034 return iSuccess;
2037 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2039 ICONINFO infoIcon;
2040 int iSuccess = 0;
2042 *ppBuffer = NULL; *pLength = 0;
2043 if (GetIconInfo(hIcon, &infoIcon)) {
2044 HDC hDC;
2045 BITMAPINFO * pInfoBitmap;
2046 unsigned char * pIconData = NULL;
2047 unsigned int iDataSize = 0;
2049 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2051 /* Find out icon size */
2052 hDC = GetDC(0);
2053 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2054 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2055 if (1) {
2056 /* Auxiliary pointers */
2057 CURSORICONFILEDIR * pIconDir;
2058 CURSORICONFILEDIRENTRY * pIconEntry;
2059 BITMAPINFOHEADER * pIconBitmapHeader;
2060 unsigned int iOffsetPalette;
2061 unsigned int iOffsetColorData;
2062 unsigned int iOffsetMaskData;
2064 unsigned int iLengthScanLineColor;
2065 unsigned int iLengthScanLineMask;
2066 unsigned int iNumEntriesPalette;
2068 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2069 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2071 FIXME("DEBUG: bitmap size is %d x %d\n",
2072 pInfoBitmap->bmiHeader.biWidth,
2073 pInfoBitmap->bmiHeader.biHeight);
2074 FIXME("DEBUG: bitmap bpp is %d\n",
2075 pInfoBitmap->bmiHeader.biBitCount);
2076 FIXME("DEBUG: bitmap nplanes is %d\n",
2077 pInfoBitmap->bmiHeader.biPlanes);
2078 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2079 pInfoBitmap->bmiHeader.biSizeImage);
2081 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2082 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2083 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2085 /* Fill out the CURSORICONFILEDIR */
2086 pIconDir = (CURSORICONFILEDIR *)pIconData;
2087 pIconDir->idType = 1;
2088 pIconDir->idCount = 1;
2090 /* Fill out the CURSORICONFILEDIRENTRY */
2091 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2092 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2093 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2094 pIconEntry->bColorCount =
2095 (pInfoBitmap->bmiHeader.biBitCount < 8)
2096 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2097 : 0;
2098 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2099 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2100 pIconEntry->dwDIBSize = 0;
2101 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2103 /* Fill out the BITMAPINFOHEADER */
2104 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2105 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2107 /* Find out whether a palette exists for the bitmap */
2108 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2109 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2110 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2111 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2112 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2113 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2114 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2115 iNumEntriesPalette = 3;
2116 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2117 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2118 } else {
2119 iNumEntriesPalette = 0;
2122 /* Add bitmap size and header size to icon data size. */
2123 iOffsetPalette = iDataSize;
2124 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2125 iOffsetColorData = iDataSize;
2126 iDataSize += pIconBitmapHeader->biSizeImage;
2127 iOffsetMaskData = iDataSize;
2128 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2129 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2130 pIconBitmapHeader->biHeight *= 2;
2131 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2132 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2133 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2134 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2136 /* Get the actual bitmap data from the icon bitmap */
2137 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2138 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2139 if (iNumEntriesPalette > 0) {
2140 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2141 iNumEntriesPalette * sizeof(RGBQUAD));
2144 /* Reset all values so that GetDIBits call succeeds */
2145 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2146 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2147 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2149 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2150 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2151 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2153 printf("ERROR: unable to get bitmap mask (error %u)\n",
2154 GetLastError());
2158 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2159 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2161 /* Write out everything produced so far to the stream */
2162 *ppBuffer = pIconData; *pLength = iDataSize;
2163 iSuccess = 1;
2164 } else {
2166 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2167 GetLastError());
2171 Remarks (from MSDN entry on GetIconInfo):
2173 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2174 members of ICONINFO. The calling application must manage
2175 these bitmaps and delete them when they are no longer
2176 necessary.
2178 if (hDC) ReleaseDC(0, hDC);
2179 DeleteObject(infoIcon.hbmMask);
2180 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2181 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2182 } else {
2183 printf("ERROR: Unable to get icon information (error %u)\n",
2184 GetLastError());
2186 return iSuccess;
2189 static HRESULT WINAPI OLEPictureImpl_Save(
2190 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2192 HRESULT hResult = E_NOTIMPL;
2193 void * pIconData;
2194 unsigned int iDataSize;
2195 ULONG dummy;
2196 int iSerializeResult = 0;
2197 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2199 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2201 switch (This->desc.picType) {
2202 case PICTYPE_ICON:
2203 if (This->bIsDirty || !This->data) {
2204 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2205 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2206 hResult = E_FAIL;
2207 break;
2209 HeapFree(GetProcessHeap(), 0, This->data);
2210 This->data = pIconData;
2211 This->datalen = iDataSize;
2213 if (This->loadtime_magic != 0xdeadbeef) {
2214 DWORD header[2];
2216 header[0] = This->loadtime_magic;
2217 header[1] = This->datalen;
2218 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2220 IStream_Write(pStm, This->data, This->datalen, &dummy);
2222 hResult = S_OK;
2223 break;
2224 case PICTYPE_BITMAP:
2225 if (This->bIsDirty) {
2226 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2227 case BITMAP_FORMAT_BMP:
2228 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2229 break;
2230 case BITMAP_FORMAT_JPEG:
2231 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2232 break;
2233 case BITMAP_FORMAT_GIF:
2234 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2235 break;
2236 case BITMAP_FORMAT_PNG:
2237 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2238 break;
2239 default:
2240 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2241 break;
2243 if (iSerializeResult) {
2245 if (This->loadtime_magic != 0xdeadbeef) {
2247 if (1) {
2248 DWORD header[2];
2250 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2251 header[1] = iDataSize;
2252 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2254 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2256 HeapFree(GetProcessHeap(), 0, This->data);
2257 This->data = pIconData;
2258 This->datalen = iDataSize;
2259 hResult = S_OK;
2261 } else {
2263 if (This->loadtime_magic != 0xdeadbeef) {
2265 if (1) {
2266 DWORD header[2];
2268 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2269 header[1] = This->datalen;
2270 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2272 IStream_Write(pStm, This->data, This->datalen, &dummy);
2273 hResult = S_OK;
2275 break;
2276 case PICTYPE_METAFILE:
2277 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2278 break;
2279 case PICTYPE_ENHMETAFILE:
2280 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2281 break;
2282 default:
2283 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2284 break;
2286 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2287 return hResult;
2290 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2291 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2293 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2294 FIXME("(%p,%p),stub!\n",This,pcbSize);
2295 return E_NOTIMPL;
2299 /************************************************************************
2300 * IDispatch
2303 /************************************************************************
2304 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2306 * See Windows documentation for more details on IUnknown methods.
2308 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2309 IDispatch* iface,
2310 REFIID riid,
2311 VOID** ppvoid)
2313 OLEPictureImpl *This = impl_from_IDispatch(iface);
2315 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2318 /************************************************************************
2319 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2321 * See Windows documentation for more details on IUnknown methods.
2323 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2324 IDispatch* iface)
2326 OLEPictureImpl *This = impl_from_IDispatch(iface);
2328 return IPicture_AddRef((IPicture *)This);
2331 /************************************************************************
2332 * OLEPictureImpl_IDispatch_Release (IUnknown)
2334 * See Windows documentation for more details on IUnknown methods.
2336 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2337 IDispatch* iface)
2339 OLEPictureImpl *This = impl_from_IDispatch(iface);
2341 return IPicture_Release((IPicture *)This);
2344 /************************************************************************
2345 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2347 * See Windows documentation for more details on IDispatch methods.
2349 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2350 IDispatch* iface,
2351 unsigned int* pctinfo)
2353 TRACE("(%p)\n", pctinfo);
2355 *pctinfo = 1;
2357 return S_OK;
2360 /************************************************************************
2361 * OLEPictureImpl_GetTypeInfo (IDispatch)
2363 * See Windows documentation for more details on IDispatch methods.
2365 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2366 IDispatch* iface,
2367 UINT iTInfo,
2368 LCID lcid,
2369 ITypeInfo** ppTInfo)
2371 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2372 ITypeLib *tl;
2373 HRESULT hres;
2375 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2377 if (iTInfo != 0)
2378 return E_FAIL;
2380 hres = LoadTypeLib(stdole2tlb, &tl);
2381 if (FAILED(hres))
2383 ERR("Could not load stdole2.tlb\n");
2384 return hres;
2387 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2388 if (FAILED(hres))
2389 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2391 return hres;
2394 /************************************************************************
2395 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2397 * See Windows documentation for more details on IDispatch methods.
2399 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2400 IDispatch* iface,
2401 REFIID riid,
2402 LPOLESTR* rgszNames,
2403 UINT cNames,
2404 LCID lcid,
2405 DISPID* rgDispId)
2407 ITypeInfo * pTInfo;
2408 HRESULT hres;
2410 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2411 rgszNames, cNames, (int)lcid, rgDispId);
2413 if (cNames == 0)
2415 return E_INVALIDARG;
2417 else
2419 /* retrieve type information */
2420 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2422 if (FAILED(hres))
2424 ERR("GetTypeInfo failed.\n");
2425 return hres;
2428 /* convert names to DISPIDs */
2429 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2430 ITypeInfo_Release(pTInfo);
2432 return hres;
2436 /************************************************************************
2437 * OLEPictureImpl_Invoke (IDispatch)
2439 * See Windows documentation for more details on IDispatch methods.
2441 static HRESULT WINAPI OLEPictureImpl_Invoke(
2442 IDispatch* iface,
2443 DISPID dispIdMember,
2444 REFIID riid,
2445 LCID lcid,
2446 WORD wFlags,
2447 DISPPARAMS* pDispParams,
2448 VARIANT* pVarResult,
2449 EXCEPINFO* pExepInfo,
2450 UINT* puArgErr)
2452 OLEPictureImpl *This = impl_from_IDispatch(iface);
2454 /* validate parameters */
2456 if (!IsEqualIID(riid, &IID_NULL))
2458 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2459 return DISP_E_UNKNOWNNAME;
2462 if (!pDispParams)
2464 ERR("null pDispParams not allowed\n");
2465 return DISP_E_PARAMNOTOPTIONAL;
2468 if (wFlags & DISPATCH_PROPERTYGET)
2470 if (pDispParams->cArgs != 0)
2472 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2473 return DISP_E_BADPARAMCOUNT;
2475 if (!pVarResult)
2477 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2478 return DISP_E_PARAMNOTOPTIONAL;
2481 else if (wFlags & DISPATCH_PROPERTYPUT)
2483 if (pDispParams->cArgs != 1)
2485 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2486 return DISP_E_BADPARAMCOUNT;
2490 switch (dispIdMember)
2492 case DISPID_PICT_HANDLE:
2493 if (wFlags & DISPATCH_PROPERTYGET)
2495 TRACE("DISPID_PICT_HANDLE\n");
2496 V_VT(pVarResult) = VT_I4;
2497 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2499 break;
2500 case DISPID_PICT_HPAL:
2501 if (wFlags & DISPATCH_PROPERTYGET)
2503 TRACE("DISPID_PICT_HPAL\n");
2504 V_VT(pVarResult) = VT_I4;
2505 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2507 else if (wFlags & DISPATCH_PROPERTYPUT)
2509 VARIANTARG vararg;
2510 HRESULT hr;
2511 TRACE("DISPID_PICT_HPAL\n");
2513 VariantInit(&vararg);
2514 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2515 if (FAILED(hr))
2516 return hr;
2518 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2520 VariantClear(&vararg);
2521 return hr;
2523 break;
2524 case DISPID_PICT_TYPE:
2525 if (wFlags & DISPATCH_PROPERTYGET)
2527 TRACE("DISPID_PICT_TYPE\n");
2528 V_VT(pVarResult) = VT_I2;
2529 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2531 break;
2532 case DISPID_PICT_WIDTH:
2533 if (wFlags & DISPATCH_PROPERTYGET)
2535 TRACE("DISPID_PICT_WIDTH\n");
2536 V_VT(pVarResult) = VT_I4;
2537 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2539 break;
2540 case DISPID_PICT_HEIGHT:
2541 if (wFlags & DISPATCH_PROPERTYGET)
2543 TRACE("DISPID_PICT_HEIGHT\n");
2544 V_VT(pVarResult) = VT_I4;
2545 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2547 break;
2550 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2551 return DISP_E_MEMBERNOTFOUND;
2555 static const IPictureVtbl OLEPictureImpl_VTable =
2557 OLEPictureImpl_QueryInterface,
2558 OLEPictureImpl_AddRef,
2559 OLEPictureImpl_Release,
2560 OLEPictureImpl_get_Handle,
2561 OLEPictureImpl_get_hPal,
2562 OLEPictureImpl_get_Type,
2563 OLEPictureImpl_get_Width,
2564 OLEPictureImpl_get_Height,
2565 OLEPictureImpl_Render,
2566 OLEPictureImpl_set_hPal,
2567 OLEPictureImpl_get_CurDC,
2568 OLEPictureImpl_SelectPicture,
2569 OLEPictureImpl_get_KeepOriginalFormat,
2570 OLEPictureImpl_put_KeepOriginalFormat,
2571 OLEPictureImpl_PictureChanged,
2572 OLEPictureImpl_SaveAsFile,
2573 OLEPictureImpl_get_Attributes
2576 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2578 OLEPictureImpl_IDispatch_QueryInterface,
2579 OLEPictureImpl_IDispatch_AddRef,
2580 OLEPictureImpl_IDispatch_Release,
2581 OLEPictureImpl_GetTypeInfoCount,
2582 OLEPictureImpl_GetTypeInfo,
2583 OLEPictureImpl_GetIDsOfNames,
2584 OLEPictureImpl_Invoke
2587 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2589 OLEPictureImpl_IPersistStream_QueryInterface,
2590 OLEPictureImpl_IPersistStream_AddRef,
2591 OLEPictureImpl_IPersistStream_Release,
2592 OLEPictureImpl_GetClassID,
2593 OLEPictureImpl_IsDirty,
2594 OLEPictureImpl_Load,
2595 OLEPictureImpl_Save,
2596 OLEPictureImpl_GetSizeMax
2599 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2601 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2602 OLEPictureImpl_IConnectionPointContainer_AddRef,
2603 OLEPictureImpl_IConnectionPointContainer_Release,
2604 OLEPictureImpl_EnumConnectionPoints,
2605 OLEPictureImpl_FindConnectionPoint
2608 /***********************************************************************
2609 * OleCreatePictureIndirect (OLEAUT32.419)
2611 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2612 BOOL fOwn, LPVOID *ppvObj )
2614 OLEPictureImpl* newPict = NULL;
2615 HRESULT hr = S_OK;
2617 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2620 * Sanity check
2622 if (ppvObj==0)
2623 return E_POINTER;
2625 *ppvObj = NULL;
2628 * Try to construct a new instance of the class.
2630 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2632 if (newPict == NULL)
2633 return E_OUTOFMEMORY;
2636 * Make sure it supports the interface required by the caller.
2638 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2641 * Release the reference obtained in the constructor. If
2642 * the QueryInterface was unsuccessful, it will free the class.
2644 IPicture_Release((IPicture*)newPict);
2646 return hr;
2650 /***********************************************************************
2651 * OleLoadPicture (OLEAUT32.418)
2653 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2654 REFIID riid, LPVOID *ppvObj )
2656 LPPERSISTSTREAM ps;
2657 IPicture *newpic;
2658 HRESULT hr;
2660 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2661 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2663 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2664 if (hr)
2665 return hr;
2666 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2667 if (hr) {
2668 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2669 IPicture_Release(newpic);
2670 *ppvObj = NULL;
2671 return hr;
2673 hr = IPersistStream_Load(ps,lpstream);
2674 IPersistStream_Release(ps);
2675 if (FAILED(hr))
2677 ERR("IPersistStream_Load failed\n");
2678 IPicture_Release(newpic);
2679 *ppvObj = NULL;
2680 return hr;
2682 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2683 if (hr)
2684 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2685 IPicture_Release(newpic);
2686 return hr;
2689 /***********************************************************************
2690 * OleLoadPictureEx (OLEAUT32.401)
2692 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2693 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2695 LPPERSISTSTREAM ps;
2696 IPicture *newpic;
2697 HRESULT hr;
2699 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2700 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2702 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2703 if (hr)
2704 return hr;
2705 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2706 if (hr) {
2707 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2708 IPicture_Release(newpic);
2709 *ppvObj = NULL;
2710 return hr;
2712 hr = IPersistStream_Load(ps,lpstream);
2713 IPersistStream_Release(ps);
2714 if (FAILED(hr))
2716 ERR("IPersistStream_Load failed\n");
2717 IPicture_Release(newpic);
2718 *ppvObj = NULL;
2719 return hr;
2721 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2722 if (hr)
2723 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2724 IPicture_Release(newpic);
2725 return hr;
2728 /***********************************************************************
2729 * OleLoadPicturePath (OLEAUT32.424)
2731 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2732 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2733 LPVOID *ppvRet )
2735 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2736 IPicture *ipicture;
2737 HANDLE hFile;
2738 DWORD dwFileSize;
2739 HGLOBAL hGlobal = NULL;
2740 DWORD dwBytesRead = 0;
2741 IStream *stream;
2742 BOOL bRead;
2743 IPersistStream *pStream;
2744 HRESULT hRes;
2746 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2747 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2748 debugstr_guid(riid), ppvRet);
2750 if (!ppvRet) return E_POINTER;
2752 if (strncmpW(szURLorPath, file, 7) == 0) {
2753 szURLorPath += 7;
2755 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2756 0, NULL);
2757 if (hFile == INVALID_HANDLE_VALUE)
2758 return E_UNEXPECTED;
2760 dwFileSize = GetFileSize(hFile, NULL);
2761 if (dwFileSize != INVALID_FILE_SIZE )
2763 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2764 if ( hGlobal)
2766 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2767 if (!bRead)
2769 GlobalFree(hGlobal);
2770 hGlobal = 0;
2774 CloseHandle(hFile);
2776 if (!hGlobal)
2777 return E_UNEXPECTED;
2779 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2780 if (FAILED(hRes))
2782 GlobalFree(hGlobal);
2783 return hRes;
2785 } else {
2786 IMoniker *pmnk;
2787 IBindCtx *pbc;
2789 hRes = CreateBindCtx(0, &pbc);
2790 if (SUCCEEDED(hRes))
2792 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2793 if (SUCCEEDED(hRes))
2795 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2796 IMoniker_Release(pmnk);
2798 IBindCtx_Release(pbc);
2800 if (FAILED(hRes))
2801 return hRes;
2804 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2805 &IID_IPicture, (LPVOID*)&ipicture);
2806 if (hRes != S_OK) {
2807 IStream_Release(stream);
2808 return hRes;
2811 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2812 if (hRes) {
2813 IStream_Release(stream);
2814 IPicture_Release(ipicture);
2815 return hRes;
2818 hRes = IPersistStream_Load(pStream, stream);
2819 IPersistStream_Release(pStream);
2820 IStream_Release(stream);
2822 if (hRes) {
2823 IPicture_Release(ipicture);
2824 return hRes;
2827 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2828 if (hRes)
2829 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2831 IPicture_Release(ipicture);
2832 return hRes;
2835 /*******************************************************************************
2836 * StdPic ClassFactory
2838 typedef struct
2840 /* IUnknown fields */
2841 const IClassFactoryVtbl *lpVtbl;
2842 LONG ref;
2843 } IClassFactoryImpl;
2845 static HRESULT WINAPI
2846 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2847 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2849 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2850 return E_NOINTERFACE;
2853 static ULONG WINAPI
2854 SPCF_AddRef(LPCLASSFACTORY iface) {
2855 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2856 return InterlockedIncrement(&This->ref);
2859 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2860 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2861 /* static class, won't be freed */
2862 return InterlockedDecrement(&This->ref);
2865 static HRESULT WINAPI SPCF_CreateInstance(
2866 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2868 /* Creates an uninitialized picture */
2869 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2873 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2874 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2875 FIXME("(%p)->(%d),stub!\n",This,dolock);
2876 return S_OK;
2879 static const IClassFactoryVtbl SPCF_Vtbl = {
2880 SPCF_QueryInterface,
2881 SPCF_AddRef,
2882 SPCF_Release,
2883 SPCF_CreateInstance,
2884 SPCF_LockServer
2886 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2888 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }