kernel32: Change all functions to use CDECL.
[wine/wine64.git] / dlls / oleaut32 / olepicture.c
blobbdce729639ff50ae13ef9d44eaf7566df6a301b4
1 /*
2 * OLE Picture object
4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
8 * Copyright 2008 Kirill K. Smirnov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * BUGS
26 * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
27 * Lots of methods are just stubs.
30 * NOTES (or things that msdn doesn't tell you)
32 * The width and height properties are returned in HIMETRIC units (0.01mm)
33 * IPicture::Render also uses these to select a region of the src picture.
34 * A bitmap's size is converted into these units by using the screen resolution
35 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
39 #include "config.h"
40 #include "wine/port.h"
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <string.h>
49 #ifdef SONAME_LIBJPEG
50 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
51 #define XMD_H
52 #define UINT8 JPEG_UINT8
53 #define UINT16 JPEG_UINT16
54 #define boolean jpeg_boolean
55 # include <jpeglib.h>
56 #undef UINT8
57 #undef UINT16
58 #undef boolean
59 #endif
61 #ifdef HAVE_PNG_H
62 #include <png.h>
63 #endif
65 /* Must be before wine includes, the header has things conflicting with
66 * WINE headers.
68 #define COBJMACROS
69 #define NONAMELESSUNION
70 #define NONAMELESSSTRUCT
72 #include "winerror.h"
73 #include "windef.h"
74 #include "winbase.h"
75 #include "wingdi.h"
76 #include "winuser.h"
77 #include "ole2.h"
78 #include "olectl.h"
79 #include "oleauto.h"
80 #include "connpt.h"
81 #include "urlmon.h"
82 #include "wine/debug.h"
83 #include "wine/unicode.h"
85 #include "wine/wingdi16.h"
87 #include "ungif.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(ole);
91 #include "pshpack1.h"
93 /* Header for Aldus Placable Metafiles - a standard metafile follows */
94 typedef struct _APM_HEADER
96 DWORD key;
97 WORD handle;
98 SHORT left;
99 SHORT top;
100 SHORT right;
101 SHORT bottom;
102 WORD inch;
103 DWORD reserved;
104 WORD checksum;
105 } APM_HEADER;
107 typedef struct {
108 BYTE bWidth;
109 BYTE bHeight;
110 BYTE bColorCount;
111 BYTE bReserved;
112 WORD xHotspot;
113 WORD yHotspot;
114 DWORD dwDIBSize;
115 DWORD dwDIBOffset;
116 } CURSORICONFILEDIRENTRY;
118 typedef struct
120 WORD idReserved;
121 WORD idType;
122 WORD idCount;
123 CURSORICONFILEDIRENTRY idEntries[1];
124 } CURSORICONFILEDIR;
126 #include "poppack.h"
128 /*************************************************************************
129 * Declaration of implementation class
132 typedef struct OLEPictureImpl {
135 * IPicture handles IUnknown
138 const IPictureVtbl *lpVtbl;
139 const IDispatchVtbl *lpvtblIDispatch;
140 const IPersistStreamVtbl *lpvtblIPersistStream;
141 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
143 /* Object reference count */
144 LONG ref;
146 /* We own the object and must destroy it ourselves */
147 BOOL fOwn;
149 /* Picture description */
150 PICTDESC desc;
152 /* These are the pixel size of a bitmap */
153 DWORD origWidth;
154 DWORD origHeight;
156 /* And these are the size of the picture converted into HIMETRIC units */
157 OLE_XSIZE_HIMETRIC himetricWidth;
158 OLE_YSIZE_HIMETRIC himetricHeight;
160 IConnectionPoint *pCP;
162 BOOL keepOrigFormat;
163 HDC hDCCur;
165 /* Bitmap transparency mask */
166 HBITMAP hbmMask;
167 HBITMAP hbmXor;
168 COLORREF rgbTrans;
170 /* data */
171 void* data;
172 int datalen;
173 BOOL bIsDirty; /* Set to TRUE if picture has changed */
174 unsigned int loadtime_magic; /* If a length header was found, saves value */
175 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
176 } OLEPictureImpl;
179 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
182 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
184 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
187 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
189 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
192 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
194 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
198 * Predeclare VTables. They get initialized at the end.
200 static const IPictureVtbl OLEPictureImpl_VTable;
201 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
202 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
203 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
205 /***********************************************************************
206 * Implementation of the OLEPictureImpl class.
209 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
210 BITMAP bm;
211 HDC hdcRef;
213 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
214 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
215 ERR("GetObject fails\n");
216 return;
218 This->origWidth = bm.bmWidth;
219 This->origHeight = bm.bmHeight;
220 /* The width and height are stored in HIMETRIC units (0.01 mm),
221 so we take our pixel width divide by pixels per inch and
222 multiply by 25.4 * 100 */
223 /* Should we use GetBitmapDimension if available? */
224 hdcRef = CreateCompatibleDC(0);
225 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
226 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
227 DeleteDC(hdcRef);
230 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
232 ICONINFO infoIcon;
234 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
235 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
236 HDC hdcRef;
237 BITMAP bm;
239 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
240 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
241 ERR("GetObject fails on icon bitmap\n");
242 return;
245 This->origWidth = bm.bmWidth;
246 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
247 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
248 hdcRef = GetDC(0);
249 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
250 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
251 ReleaseDC(0, hdcRef);
253 DeleteObject(infoIcon.hbmMask);
254 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
255 } else {
256 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
260 /************************************************************************
261 * OLEPictureImpl_Construct
263 * This method will construct a new instance of the OLEPictureImpl
264 * class.
266 * The caller of this method must release the object when it's
267 * done with it.
269 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
271 OLEPictureImpl* newObject = 0;
273 if (pictDesc)
274 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
277 * Allocate space for the object.
279 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
281 if (newObject==0)
282 return newObject;
285 * Initialize the virtual function table.
287 newObject->lpVtbl = &OLEPictureImpl_VTable;
288 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
289 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
290 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
292 newObject->pCP = NULL;
293 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
294 if (!newObject->pCP)
296 HeapFree(GetProcessHeap(), 0, newObject);
297 return NULL;
301 * Start with one reference count. The caller of this function
302 * must release the interface pointer when it is done.
304 newObject->ref = 1;
305 newObject->hDCCur = 0;
307 newObject->fOwn = fOwn;
309 /* dunno about original value */
310 newObject->keepOrigFormat = TRUE;
312 newObject->hbmMask = NULL;
313 newObject->hbmXor = NULL;
314 newObject->loadtime_magic = 0xdeadbeef;
315 newObject->loadtime_format = 0;
316 newObject->bIsDirty = FALSE;
318 if (pictDesc) {
319 newObject->desc = *pictDesc;
321 switch(pictDesc->picType) {
322 case PICTYPE_BITMAP:
323 OLEPictureImpl_SetBitmap(newObject);
324 break;
326 case PICTYPE_METAFILE:
327 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
328 newObject->himetricWidth = pictDesc->u.wmf.xExt;
329 newObject->himetricHeight = pictDesc->u.wmf.yExt;
330 break;
332 case PICTYPE_NONE:
333 /* not sure what to do here */
334 newObject->himetricWidth = newObject->himetricHeight = 0;
335 break;
337 case PICTYPE_ICON:
338 OLEPictureImpl_SetIcon(newObject);
339 break;
340 case PICTYPE_ENHMETAFILE:
341 default:
342 FIXME("Unsupported type %d\n", pictDesc->picType);
343 newObject->himetricWidth = newObject->himetricHeight = 0;
344 break;
346 } else {
347 newObject->desc.picType = PICTYPE_UNINITIALIZED;
350 TRACE("returning %p\n", newObject);
351 return newObject;
354 /************************************************************************
355 * OLEPictureImpl_Destroy
357 * This method is called by the Release method when the reference
358 * count goes down to 0. It will free all resources used by
359 * this object. */
360 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
362 TRACE("(%p)\n", Obj);
364 if (Obj->pCP)
365 IConnectionPoint_Release(Obj->pCP);
367 if(Obj->fOwn) { /* We need to destroy the picture */
368 switch(Obj->desc.picType) {
369 case PICTYPE_BITMAP:
370 DeleteObject(Obj->desc.u.bmp.hbitmap);
371 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
372 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
373 break;
374 case PICTYPE_METAFILE:
375 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
376 break;
377 case PICTYPE_ICON:
378 DestroyIcon(Obj->desc.u.icon.hicon);
379 break;
380 case PICTYPE_ENHMETAFILE:
381 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
382 break;
383 case PICTYPE_NONE:
384 case PICTYPE_UNINITIALIZED:
385 /* Nothing to do */
386 break;
387 default:
388 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
389 break;
392 HeapFree(GetProcessHeap(), 0, Obj->data);
393 HeapFree(GetProcessHeap(), 0, Obj);
397 /************************************************************************
398 * OLEPictureImpl_AddRef (IUnknown)
400 * See Windows documentation for more details on IUnknown methods.
402 static ULONG WINAPI OLEPictureImpl_AddRef(
403 IPicture* iface)
405 OLEPictureImpl *This = (OLEPictureImpl *)iface;
406 ULONG refCount = InterlockedIncrement(&This->ref);
408 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
410 return refCount;
413 /************************************************************************
414 * OLEPictureImpl_Release (IUnknown)
416 * See Windows documentation for more details on IUnknown methods.
418 static ULONG WINAPI OLEPictureImpl_Release(
419 IPicture* iface)
421 OLEPictureImpl *This = (OLEPictureImpl *)iface;
422 ULONG refCount = InterlockedDecrement(&This->ref);
424 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
427 * If the reference count goes down to 0, perform suicide.
429 if (!refCount) OLEPictureImpl_Destroy(This);
431 return refCount;
434 /************************************************************************
435 * OLEPictureImpl_QueryInterface (IUnknown)
437 * See Windows documentation for more details on IUnknown methods.
439 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
440 IPicture* iface,
441 REFIID riid,
442 void** ppvObject)
444 OLEPictureImpl *This = (OLEPictureImpl *)iface;
445 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
448 * Perform a sanity check on the parameters.
450 if ( (This==0) || (ppvObject==0) )
451 return E_INVALIDARG;
454 * Initialize the return parameter.
456 *ppvObject = 0;
459 * Compare the riid with the interface IDs implemented by this object.
461 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
462 *ppvObject = (IPicture*)This;
463 else if (IsEqualIID(&IID_IDispatch, riid))
464 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
465 else if (IsEqualIID(&IID_IPictureDisp, riid))
466 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
467 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
468 *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
469 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
470 *ppvObject = (IConnectionPointContainer*)&(This->lpvtblIConnectionPointContainer);
473 * Check that we obtained an interface.
475 if ((*ppvObject)==0)
477 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
478 return E_NOINTERFACE;
482 * Query Interface always increases the reference count by one when it is
483 * successful
485 OLEPictureImpl_AddRef((IPicture*)This);
487 return S_OK;
490 /***********************************************************************
491 * OLEPicture_SendNotify (internal)
493 * Sends notification messages of changed properties to any interested
494 * connections.
496 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
498 IEnumConnections *pEnum;
499 CONNECTDATA CD;
501 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
502 return;
503 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
504 IPropertyNotifySink *sink;
506 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
507 IPropertyNotifySink_OnChanged(sink, dispID);
508 IPropertyNotifySink_Release(sink);
509 IUnknown_Release(CD.pUnk);
511 IEnumConnections_Release(pEnum);
514 /************************************************************************
515 * OLEPictureImpl_get_Handle
517 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
518 OLE_HANDLE *phandle)
520 OLEPictureImpl *This = (OLEPictureImpl *)iface;
521 TRACE("(%p)->(%p)\n", This, phandle);
522 switch(This->desc.picType) {
523 case PICTYPE_NONE:
524 case PICTYPE_UNINITIALIZED:
525 *phandle = 0;
526 break;
527 case PICTYPE_BITMAP:
528 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
529 break;
530 case PICTYPE_METAFILE:
531 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
532 break;
533 case PICTYPE_ICON:
534 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
535 break;
536 case PICTYPE_ENHMETAFILE:
537 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
538 break;
539 default:
540 FIXME("Unimplemented type %d\n", This->desc.picType);
541 return E_NOTIMPL;
543 TRACE("returning handle %08x\n", *phandle);
544 return S_OK;
547 /************************************************************************
548 * OLEPictureImpl_get_hPal
550 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
551 OLE_HANDLE *phandle)
553 OLEPictureImpl *This = (OLEPictureImpl *)iface;
554 HRESULT hres;
555 TRACE("(%p)->(%p)\n", This, phandle);
557 if (!phandle)
558 return E_POINTER;
560 switch (This->desc.picType) {
561 case (UINT)PICTYPE_UNINITIALIZED:
562 case PICTYPE_NONE:
563 *phandle = 0;
564 hres = S_FALSE;
565 break;
566 case PICTYPE_BITMAP:
567 *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
568 hres = S_OK;
569 break;
570 case PICTYPE_METAFILE:
571 hres = E_FAIL;
572 break;
573 case PICTYPE_ICON:
574 case PICTYPE_ENHMETAFILE:
575 default:
576 FIXME("unimplemented for type %d. Returning 0 palette.\n",
577 This->desc.picType);
578 *phandle = 0;
579 hres = S_OK;
582 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
583 return hres;
586 /************************************************************************
587 * OLEPictureImpl_get_Type
589 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
590 short *ptype)
592 OLEPictureImpl *This = (OLEPictureImpl *)iface;
593 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
594 *ptype = This->desc.picType;
595 return S_OK;
598 /************************************************************************
599 * OLEPictureImpl_get_Width
601 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
602 OLE_XSIZE_HIMETRIC *pwidth)
604 OLEPictureImpl *This = (OLEPictureImpl *)iface;
605 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
606 *pwidth = This->himetricWidth;
607 return S_OK;
610 /************************************************************************
611 * OLEPictureImpl_get_Height
613 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
614 OLE_YSIZE_HIMETRIC *pheight)
616 OLEPictureImpl *This = (OLEPictureImpl *)iface;
617 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
618 *pheight = This->himetricHeight;
619 return S_OK;
622 /************************************************************************
623 * OLEPictureImpl_Render
625 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
626 LONG x, LONG y, LONG cx, LONG cy,
627 OLE_XPOS_HIMETRIC xSrc,
628 OLE_YPOS_HIMETRIC ySrc,
629 OLE_XSIZE_HIMETRIC cxSrc,
630 OLE_YSIZE_HIMETRIC cySrc,
631 LPCRECT prcWBounds)
633 OLEPictureImpl *This = (OLEPictureImpl *)iface;
634 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
635 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
636 if(prcWBounds)
637 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
638 prcWBounds->right, prcWBounds->bottom);
640 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
641 return CTL_E_INVALIDPROPERTYVALUE;
645 * While the documentation suggests this to be here (or after rendering?)
646 * it does cause an endless recursion in my sample app. -MM 20010804
647 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
650 switch(This->desc.picType) {
651 case PICTYPE_UNINITIALIZED:
652 case PICTYPE_NONE:
653 /* nothing to do */
654 return S_OK;
655 case PICTYPE_BITMAP:
657 HBITMAP hbmpOld;
658 HDC hdcBmp;
660 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
661 NB y-axis gets flipped */
663 hdcBmp = CreateCompatibleDC(0);
664 SetMapMode(hdcBmp, MM_ANISOTROPIC);
665 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
666 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
667 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
668 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
670 if (This->hbmMask) {
671 HDC hdcMask = CreateCompatibleDC(0);
672 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
674 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
676 SetMapMode(hdcMask, MM_ANISOTROPIC);
677 SetWindowOrgEx(hdcMask, 0, 0, NULL);
678 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
679 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
680 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
682 SetBkColor(hdc, RGB(255, 255, 255));
683 SetTextColor(hdc, RGB(0, 0, 0));
684 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
685 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
687 SelectObject(hdcMask, hOldbm);
688 DeleteDC(hdcMask);
689 } else {
690 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
691 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
694 SelectObject(hdcBmp, hbmpOld);
695 DeleteDC(hdcBmp);
697 break;
698 case PICTYPE_ICON:
699 FIXME("Not quite correct implementation of rendering icons...\n");
700 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
701 break;
703 case PICTYPE_METAFILE:
705 POINT prevOrg;
706 SIZE prevExt;
707 int oldmode;
709 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
710 SetViewportOrgEx(hdc, x, y, &prevOrg);
711 SetViewportExtEx(hdc, cx, cy, &prevExt);
713 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
714 ERR("PlayMetaFile failed!\n");
716 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
717 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
718 SetMapMode(hdc, oldmode);
719 break;
722 case PICTYPE_ENHMETAFILE:
724 RECT rc = { x, y, x + cx, y + cy };
725 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
726 break;
729 default:
730 FIXME("type %d not implemented\n", This->desc.picType);
731 return E_NOTIMPL;
733 return S_OK;
736 /************************************************************************
737 * OLEPictureImpl_set_hPal
739 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
740 OLE_HANDLE hpal)
742 OLEPictureImpl *This = (OLEPictureImpl *)iface;
743 FIXME("(%p)->(%08x): stub\n", This, hpal);
744 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
745 return E_NOTIMPL;
748 /************************************************************************
749 * OLEPictureImpl_get_CurDC
751 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
752 HDC *phdc)
754 OLEPictureImpl *This = (OLEPictureImpl *)iface;
755 TRACE("(%p), returning %p\n", This, This->hDCCur);
756 if (phdc) *phdc = This->hDCCur;
757 return S_OK;
760 /************************************************************************
761 * OLEPictureImpl_SelectPicture
763 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
764 HDC hdcIn,
765 HDC *phdcOut,
766 OLE_HANDLE *phbmpOut)
768 OLEPictureImpl *This = (OLEPictureImpl *)iface;
769 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
770 if (This->desc.picType == PICTYPE_BITMAP) {
771 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
773 if (phdcOut)
774 *phdcOut = This->hDCCur;
775 This->hDCCur = hdcIn;
776 if (phbmpOut)
777 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
778 return S_OK;
779 } else {
780 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
781 return E_FAIL;
785 /************************************************************************
786 * OLEPictureImpl_get_KeepOriginalFormat
788 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
789 BOOL *pfKeep)
791 OLEPictureImpl *This = (OLEPictureImpl *)iface;
792 TRACE("(%p)->(%p)\n", This, pfKeep);
793 if (!pfKeep)
794 return E_POINTER;
795 *pfKeep = This->keepOrigFormat;
796 return S_OK;
799 /************************************************************************
800 * OLEPictureImpl_put_KeepOriginalFormat
802 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
803 BOOL keep)
805 OLEPictureImpl *This = (OLEPictureImpl *)iface;
806 TRACE("(%p)->(%d)\n", This, keep);
807 This->keepOrigFormat = keep;
808 /* FIXME: what DISPID notification here? */
809 return S_OK;
812 /************************************************************************
813 * OLEPictureImpl_PictureChanged
815 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
817 OLEPictureImpl *This = (OLEPictureImpl *)iface;
818 TRACE("(%p)->()\n", This);
819 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
820 This->bIsDirty = TRUE;
821 return S_OK;
824 /************************************************************************
825 * OLEPictureImpl_SaveAsFile
827 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
828 IStream *pstream,
829 BOOL SaveMemCopy,
830 LONG *pcbSize)
832 OLEPictureImpl *This = (OLEPictureImpl *)iface;
833 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
834 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
837 /************************************************************************
838 * OLEPictureImpl_get_Attributes
840 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
841 DWORD *pdwAttr)
843 OLEPictureImpl *This = (OLEPictureImpl *)iface;
844 TRACE("(%p)->(%p).\n", This, pdwAttr);
845 *pdwAttr = 0;
846 switch (This->desc.picType) {
847 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
848 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
849 case PICTYPE_ENHMETAFILE: /* fall through */
850 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
851 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
853 return S_OK;
857 /************************************************************************
858 * IConnectionPointContainer
860 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
861 IConnectionPointContainer* iface,
862 REFIID riid,
863 VOID** ppvoid)
865 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
867 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
870 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
871 IConnectionPointContainer* iface)
873 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
875 return IPicture_AddRef((IPicture *)This);
878 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
879 IConnectionPointContainer* iface)
881 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
883 return IPicture_Release((IPicture *)This);
886 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
887 IConnectionPointContainer* iface,
888 IEnumConnectionPoints** ppEnum)
890 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
892 FIXME("(%p,%p), stub!\n",This,ppEnum);
893 return E_NOTIMPL;
896 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
897 IConnectionPointContainer* iface,
898 REFIID riid,
899 IConnectionPoint **ppCP)
901 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
902 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
903 if (!ppCP)
904 return E_POINTER;
905 *ppCP = NULL;
906 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
907 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
908 FIXME("no connection point for %s\n",debugstr_guid(riid));
909 return CONNECT_E_NOCONNECTION;
913 /************************************************************************
914 * IPersistStream
917 /************************************************************************
918 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
920 * See Windows documentation for more details on IUnknown methods.
922 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
923 IPersistStream* iface,
924 REFIID riid,
925 VOID** ppvoid)
927 OLEPictureImpl *This = impl_from_IPersistStream(iface);
929 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
932 /************************************************************************
933 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
935 * See Windows documentation for more details on IUnknown methods.
937 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
938 IPersistStream* iface)
940 OLEPictureImpl *This = impl_from_IPersistStream(iface);
942 return IPicture_AddRef((IPicture *)This);
945 /************************************************************************
946 * OLEPictureImpl_IPersistStream_Release (IUnknown)
948 * See Windows documentation for more details on IUnknown methods.
950 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
951 IPersistStream* iface)
953 OLEPictureImpl *This = impl_from_IPersistStream(iface);
955 return IPicture_Release((IPicture *)This);
958 /************************************************************************
959 * OLEPictureImpl_IPersistStream_GetClassID
961 static HRESULT WINAPI OLEPictureImpl_GetClassID(
962 IPersistStream* iface,CLSID* pClassID)
964 TRACE("(%p)\n", pClassID);
965 *pClassID = CLSID_StdPicture;
966 return S_OK;
969 /************************************************************************
970 * OLEPictureImpl_IPersistStream_IsDirty
972 static HRESULT WINAPI OLEPictureImpl_IsDirty(
973 IPersistStream* iface)
975 OLEPictureImpl *This = impl_from_IPersistStream(iface);
976 FIXME("(%p),stub!\n",This);
977 return E_NOTIMPL;
980 #ifdef SONAME_LIBJPEG
982 static void *libjpeg_handle;
983 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
984 MAKE_FUNCPTR(jpeg_std_error);
985 MAKE_FUNCPTR(jpeg_CreateDecompress);
986 MAKE_FUNCPTR(jpeg_read_header);
987 MAKE_FUNCPTR(jpeg_start_decompress);
988 MAKE_FUNCPTR(jpeg_read_scanlines);
989 MAKE_FUNCPTR(jpeg_finish_decompress);
990 MAKE_FUNCPTR(jpeg_destroy_decompress);
991 #undef MAKE_FUNCPTR
993 static void *load_libjpeg(void)
995 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
997 #define LOAD_FUNCPTR(f) \
998 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
999 libjpeg_handle = NULL; \
1000 return NULL; \
1003 LOAD_FUNCPTR(jpeg_std_error);
1004 LOAD_FUNCPTR(jpeg_CreateDecompress);
1005 LOAD_FUNCPTR(jpeg_read_header);
1006 LOAD_FUNCPTR(jpeg_start_decompress);
1007 LOAD_FUNCPTR(jpeg_read_scanlines);
1008 LOAD_FUNCPTR(jpeg_finish_decompress);
1009 LOAD_FUNCPTR(jpeg_destroy_decompress);
1010 #undef LOAD_FUNCPTR
1012 return libjpeg_handle;
1015 /* for the jpeg decompressor source manager. */
1016 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1018 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1019 ERR("(), should not get here.\n");
1020 return FALSE;
1023 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1024 TRACE("Skipping %ld bytes...\n", num_bytes);
1025 cinfo->src->next_input_byte += num_bytes;
1026 cinfo->src->bytes_in_buffer -= num_bytes;
1029 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1030 ERR("(desired=%d), should not get here.\n",desired);
1031 return FALSE;
1033 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1034 #endif /* SONAME_LIBJPEG */
1036 struct gifdata {
1037 unsigned char *data;
1038 unsigned int curoff;
1039 unsigned int len;
1042 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1043 struct gifdata *gd = (struct gifdata*)gif->UserData;
1045 if (len+gd->curoff > gd->len) {
1046 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1047 len = gd->len - gd->curoff;
1049 memcpy(data, gd->data+gd->curoff, len);
1050 gd->curoff += len;
1051 return len;
1055 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1057 struct gifdata gd;
1058 GifFileType *gif;
1059 BITMAPINFO *bmi;
1060 HDC hdcref;
1061 LPBYTE bytes;
1062 int i,j,ret;
1063 GifImageDesc *gid;
1064 SavedImage *si;
1065 ColorMapObject *cm;
1066 int transparent = -1;
1067 ExtensionBlock *eb;
1068 int padding;
1070 gd.data = xbuf;
1071 gd.curoff = 0;
1072 gd.len = xread;
1073 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1074 ret = DGifSlurp(gif);
1075 if (ret == GIF_ERROR) {
1076 ERR("Failed reading GIF using libgif.\n");
1077 return E_FAIL;
1079 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1080 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1081 TRACE("imgcnt %d\n", gif->ImageCount);
1082 if (gif->ImageCount<1) {
1083 ERR("GIF stream does not have images inside?\n");
1084 return E_FAIL;
1086 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1087 gif->Image.Width, gif->Image.Height,
1088 gif->Image.Left, gif->Image.Top,
1089 gif->Image.Interlace
1091 /* */
1092 padding = (gif->SWidth+3) & ~3;
1093 si = gif->SavedImages+0;
1094 gid = &(si->ImageDesc);
1095 cm = gid->ColorMap;
1096 if (!cm) cm = gif->SColorMap;
1097 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1098 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1100 /* look for the transparent color extension */
1101 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1102 eb = si->ExtensionBlocks + i;
1103 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1104 if ((eb->Bytes[0] & 1) == 1) {
1105 transparent = (unsigned char)eb->Bytes[3];
1110 for (i = 0; i < cm->ColorCount; i++) {
1111 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1112 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1113 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1114 if (i == transparent) {
1115 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1116 bmi->bmiColors[i].rgbGreen,
1117 bmi->bmiColors[i].rgbBlue);
1121 /* Map to in picture coordinates */
1122 for (i = 0, j = 0; i < gid->Height; i++) {
1123 if (gif->Image.Interlace) {
1124 memcpy(
1125 bytes + (gid->Top + j) * padding + gid->Left,
1126 si->RasterBits + i * gid->Width,
1127 gid->Width);
1129 /* Lower bits of interlaced counter encode current interlace */
1130 if (j & 1) j += 2; /* Currently filling odd rows */
1131 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1132 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1134 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1135 /* End of current interlace, go to next interlace */
1136 if (j & 2) j = 1; /* Next iteration fills odd rows */
1137 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1138 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1140 } else {
1141 memcpy(
1142 bytes + (gid->Top + i) * padding + gid->Left,
1143 si->RasterBits + i * gid->Width,
1144 gid->Width);
1148 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1149 bmi->bmiHeader.biWidth = gif->SWidth;
1150 bmi->bmiHeader.biHeight = -gif->SHeight;
1151 bmi->bmiHeader.biPlanes = 1;
1152 bmi->bmiHeader.biBitCount = 8;
1153 bmi->bmiHeader.biCompression = BI_RGB;
1154 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1155 bmi->bmiHeader.biXPelsPerMeter = 0;
1156 bmi->bmiHeader.biYPelsPerMeter = 0;
1157 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1158 bmi->bmiHeader.biClrImportant = 0;
1160 hdcref = GetDC(0);
1161 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1162 hdcref,
1163 &bmi->bmiHeader,
1164 CBM_INIT,
1165 bytes,
1166 bmi,
1167 DIB_RGB_COLORS
1170 if (transparent > -1) {
1171 /* Create the Mask */
1172 HDC hdc = CreateCompatibleDC(0);
1173 HDC hdcMask = CreateCompatibleDC(0);
1174 HBITMAP hOldbitmap;
1175 HBITMAP hOldbitmapmask;
1177 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1178 HBITMAP hTempMask;
1180 This->hbmXor = CreateDIBitmap(
1181 hdcref,
1182 &bmi->bmiHeader,
1183 CBM_INIT,
1184 bytes,
1185 bmi,
1186 DIB_RGB_COLORS
1189 bmi->bmiColors[0].rgbRed = 0;
1190 bmi->bmiColors[0].rgbGreen = 0;
1191 bmi->bmiColors[0].rgbBlue = 0;
1192 bmi->bmiColors[1].rgbRed = 255;
1193 bmi->bmiColors[1].rgbGreen = 255;
1194 bmi->bmiColors[1].rgbBlue = 255;
1196 bmi->bmiHeader.biBitCount = 1;
1197 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1198 bmi->bmiHeader.biClrUsed = 2;
1200 for (i = 0; i < gif->SHeight; i++) {
1201 unsigned char * colorPointer = bytes + padding * i;
1202 unsigned char * monoPointer = bytes + monopadding * i;
1203 for (j = 0; j < gif->SWidth; j++) {
1204 unsigned char pixel = colorPointer[j];
1205 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1206 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1209 hdcref = GetDC(0);
1210 hTempMask = CreateDIBitmap(
1211 hdcref,
1212 &bmi->bmiHeader,
1213 CBM_INIT,
1214 bytes,
1215 bmi,
1216 DIB_RGB_COLORS
1218 DeleteDC(hdcref);
1220 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1221 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1222 hOldbitmap = SelectObject(hdc, hTempMask);
1223 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1225 SetBkColor(hdc, RGB(255, 255, 255));
1226 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1228 /* We no longer need the original bitmap, so we apply the first
1229 transformation with the mask to speed up the rendering */
1230 SelectObject(hdc, This->hbmXor);
1231 SetBkColor(hdc, RGB(0,0,0));
1232 SetTextColor(hdc, RGB(255,255,255));
1233 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1234 hdcMask, 0, 0, SRCAND);
1236 SelectObject(hdc, hOldbitmap);
1237 SelectObject(hdcMask, hOldbitmapmask);
1238 DeleteDC(hdcMask);
1239 DeleteDC(hdc);
1240 DeleteObject(hTempMask);
1243 DeleteDC(hdcref);
1244 This->desc.picType = PICTYPE_BITMAP;
1245 OLEPictureImpl_SetBitmap(This);
1246 DGifCloseFile(gif);
1247 HeapFree(GetProcessHeap(),0,bmi);
1248 HeapFree(GetProcessHeap(),0,bytes);
1249 return S_OK;
1252 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1254 #ifdef SONAME_LIBJPEG
1255 struct jpeg_decompress_struct jd;
1256 struct jpeg_error_mgr jerr;
1257 int ret;
1258 JDIMENSION x;
1259 JSAMPROW samprow,oldsamprow;
1260 BITMAPINFOHEADER bmi;
1261 LPBYTE bits;
1262 HDC hdcref;
1263 struct jpeg_source_mgr xjsm;
1264 LPBYTE oldbits;
1265 unsigned int i;
1267 if(!libjpeg_handle) {
1268 if(!load_libjpeg()) {
1269 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1270 return E_FAIL;
1274 /* This is basically so we can use in-memory data for jpeg decompression.
1275 * We need to have all the functions.
1277 xjsm.next_input_byte = xbuf;
1278 xjsm.bytes_in_buffer = xread;
1279 xjsm.init_source = _jpeg_init_source;
1280 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1281 xjsm.skip_input_data = _jpeg_skip_input_data;
1282 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1283 xjsm.term_source = _jpeg_term_source;
1285 jd.err = pjpeg_std_error(&jerr);
1286 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1287 * jpeg_create_decompress(&jd); */
1288 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1289 jd.src = &xjsm;
1290 ret=pjpeg_read_header(&jd,TRUE);
1291 jd.out_color_space = JCS_RGB;
1292 pjpeg_start_decompress(&jd);
1293 if (ret != JPEG_HEADER_OK) {
1294 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1295 HeapFree(GetProcessHeap(),0,xbuf);
1296 return E_FAIL;
1299 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1300 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1301 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1303 oldbits = bits;
1304 oldsamprow = samprow;
1305 while ( jd.output_scanline<jd.output_height ) {
1306 x = pjpeg_read_scanlines(&jd,&samprow,1);
1307 if (x != 1) {
1308 ERR("failed to read current scanline?\n");
1309 break;
1311 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1312 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1313 *(bits++) = *(samprow+2);
1314 *(bits++) = *(samprow+1);
1315 *(bits++) = *(samprow);
1317 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1318 samprow = oldsamprow;
1320 bits = oldbits;
1322 bmi.biSize = sizeof(bmi);
1323 bmi.biWidth = jd.output_width;
1324 bmi.biHeight = -jd.output_height;
1325 bmi.biPlanes = 1;
1326 bmi.biBitCount = jd.output_components<<3;
1327 bmi.biCompression = BI_RGB;
1328 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1329 bmi.biXPelsPerMeter = 0;
1330 bmi.biYPelsPerMeter = 0;
1331 bmi.biClrUsed = 0;
1332 bmi.biClrImportant = 0;
1334 HeapFree(GetProcessHeap(),0,samprow);
1335 pjpeg_finish_decompress(&jd);
1336 pjpeg_destroy_decompress(&jd);
1337 hdcref = GetDC(0);
1338 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1339 hdcref,
1340 &bmi,
1341 CBM_INIT,
1342 bits,
1343 (BITMAPINFO*)&bmi,
1344 DIB_RGB_COLORS
1346 DeleteDC(hdcref);
1347 This->desc.picType = PICTYPE_BITMAP;
1348 OLEPictureImpl_SetBitmap(This);
1349 HeapFree(GetProcessHeap(),0,bits);
1350 return S_OK;
1351 #else
1352 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1353 return E_FAIL;
1354 #endif
1357 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1359 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1360 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1361 HDC hdcref;
1363 /* Does not matter whether this is a coreheader or not, we only use
1364 * components which are in both
1366 hdcref = GetDC(0);
1367 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1368 hdcref,
1369 &(bi->bmiHeader),
1370 CBM_INIT,
1371 xbuf+bfh->bfOffBits,
1373 DIB_RGB_COLORS
1375 DeleteDC(hdcref);
1376 if (This->desc.u.bmp.hbitmap == 0)
1377 return E_FAIL;
1378 This->desc.picType = PICTYPE_BITMAP;
1379 OLEPictureImpl_SetBitmap(This);
1380 return S_OK;
1383 /*****************************************************
1384 * start of PNG-specific code
1385 * currently only supports colortype PNG_COLOR_TYPE_RGB
1387 #ifdef SONAME_LIBPNG
1388 typedef struct{
1389 ULONG position;
1390 ULONG size;
1391 BYTE * buff;
1392 } png_io;
1394 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1395 png_size_t length)
1397 png_io * io_ptr = png_ptr->io_ptr;
1399 if(length + io_ptr->position > io_ptr->size){
1400 length = io_ptr->size - io_ptr->position;
1403 memcpy(data, io_ptr->buff + io_ptr->position, length);
1405 io_ptr->position += length;
1408 static void *libpng_handle;
1409 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1410 MAKE_FUNCPTR(png_create_read_struct);
1411 MAKE_FUNCPTR(png_create_info_struct);
1412 MAKE_FUNCPTR(png_set_read_fn);
1413 MAKE_FUNCPTR(png_read_info);
1414 MAKE_FUNCPTR(png_read_image);
1415 MAKE_FUNCPTR(png_get_rowbytes);
1416 MAKE_FUNCPTR(png_set_bgr);
1417 MAKE_FUNCPTR(png_destroy_read_struct);
1418 MAKE_FUNCPTR(png_set_palette_to_rgb);
1419 MAKE_FUNCPTR(png_read_update_info);
1420 MAKE_FUNCPTR(png_get_tRNS);
1421 MAKE_FUNCPTR(png_get_PLTE);
1422 MAKE_FUNCPTR(png_set_expand);
1423 #undef MAKE_FUNCPTR
1425 static void *load_libpng(void)
1427 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1429 #define LOAD_FUNCPTR(f) \
1430 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1431 libpng_handle = NULL; \
1432 return NULL; \
1434 LOAD_FUNCPTR(png_create_read_struct);
1435 LOAD_FUNCPTR(png_create_info_struct);
1436 LOAD_FUNCPTR(png_set_read_fn);
1437 LOAD_FUNCPTR(png_read_info);
1438 LOAD_FUNCPTR(png_read_image);
1439 LOAD_FUNCPTR(png_get_rowbytes);
1440 LOAD_FUNCPTR(png_set_bgr);
1441 LOAD_FUNCPTR(png_destroy_read_struct);
1442 LOAD_FUNCPTR(png_set_palette_to_rgb);
1443 LOAD_FUNCPTR(png_read_update_info);
1444 LOAD_FUNCPTR(png_get_tRNS);
1445 LOAD_FUNCPTR(png_get_PLTE);
1446 LOAD_FUNCPTR(png_set_expand);
1448 #undef LOAD_FUNCPTR
1450 return libpng_handle;
1452 #endif /* SONAME_LIBPNG */
1454 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1456 #ifdef SONAME_LIBPNG
1457 png_io io;
1458 png_structp png_ptr = NULL;
1459 png_infop info_ptr = NULL;
1460 INT row, rowsize, height, width, num_trans, i, j;
1461 png_bytep* row_pointers = NULL;
1462 png_bytep pngdata = NULL;
1463 BITMAPINFOHEADER bmi;
1464 HDC hdcref = NULL, hdcXor, hdcMask;
1465 HRESULT ret;
1466 BOOL transparency;
1467 png_bytep trans;
1468 png_color_16p trans_values;
1469 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1470 HBITMAP hbmoldXor, hbmoldMask, temp;
1472 if(!libpng_handle) {
1473 if(!load_libpng()) {
1474 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1475 return E_FAIL;
1479 io.size = xread;
1480 io.position = 0;
1481 io.buff = xbuf;
1483 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1484 NULL, NULL, NULL);
1486 if(setjmp(png_jmpbuf(png_ptr))){
1487 TRACE("Error in libpng\n");
1488 ret = E_FAIL;
1489 goto end;
1492 info_ptr = ppng_create_info_struct(png_ptr);
1493 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1494 ppng_read_info(png_ptr, info_ptr);
1496 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1497 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1498 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1499 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1500 ret = E_FAIL;
1501 goto end;
1504 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1505 == PNG_INFO_tRNS);
1507 /* sets format from anything to RGBA */
1508 ppng_set_expand(png_ptr);
1509 /* sets format to BGRA */
1510 ppng_set_bgr(png_ptr);
1512 ppng_read_update_info(png_ptr, info_ptr);
1514 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1515 /* align rowsize to 4-byte boundary */
1516 rowsize = (rowsize + 3) & ~3;
1517 height = info_ptr->height;
1518 width = info_ptr->width;
1520 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1521 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1523 if(!pngdata || !row_pointers){
1524 ret = E_FAIL;
1525 goto end;
1528 for (row = 0; row < height; row++){
1529 row_pointers[row] = pngdata + row * rowsize;
1532 ppng_read_image(png_ptr, row_pointers);
1534 bmi.biSize = sizeof(bmi);
1535 bmi.biWidth = width;
1536 bmi.biHeight = -height;
1537 bmi.biPlanes = 1;
1538 bmi.biBitCount = info_ptr->channels * 8;
1539 bmi.biCompression = BI_RGB;
1540 bmi.biSizeImage = height * rowsize;
1541 bmi.biXPelsPerMeter = 0;
1542 bmi.biYPelsPerMeter = 0;
1543 bmi.biClrUsed = 0;
1544 bmi.biClrImportant = 0;
1546 hdcref = GetDC(0);
1547 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1548 hdcref,
1549 &bmi,
1550 CBM_INIT,
1551 pngdata,
1552 (BITMAPINFO*)&bmi,
1553 DIB_RGB_COLORS
1556 /* only fully-transparent alpha is handled */
1557 if((info_ptr->channels != 4) || !transparency){
1558 ReleaseDC(0, hdcref);
1559 goto succ;
1562 This->hbmXor = CreateDIBitmap(
1563 hdcref,
1564 &bmi,
1565 CBM_INIT,
1566 pngdata,
1567 (BITMAPINFO*)&bmi,
1568 DIB_RGB_COLORS
1571 /* set transparent pixels to black, all others to white */
1572 for(i = 0; i < height; i++){
1573 for(j = 3; j < rowsize; j += 4){
1574 if(row_pointers[i][j] == 0)
1575 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1576 else
1577 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1581 temp = CreateDIBitmap(
1582 hdcref,
1583 &bmi,
1584 CBM_INIT,
1585 pngdata,
1586 (BITMAPINFO*)&bmi,
1587 DIB_RGB_COLORS
1590 ReleaseDC(0, hdcref);
1592 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1593 hdcXor = CreateCompatibleDC(NULL);
1594 hdcMask = CreateCompatibleDC(NULL);
1596 hbmoldXor = SelectObject(hdcXor,temp);
1597 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1598 SetBkColor(hdcXor,black);
1599 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1601 SelectObject(hdcXor,This->hbmXor);
1602 DeleteObject(temp);
1604 SetTextColor(hdcXor,white);
1605 SetBkColor(hdcXor,black);
1606 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1608 SelectObject(hdcXor,hbmoldXor);
1609 SelectObject(hdcMask,hbmoldMask);
1611 DeleteDC(hdcXor);
1612 DeleteDC(hdcMask);
1614 succ:
1615 This->desc.picType = PICTYPE_BITMAP;
1616 OLEPictureImpl_SetBitmap(This);
1617 ret = S_OK;
1619 end:
1620 if(png_ptr)
1621 ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1622 HeapFree(GetProcessHeap(), 0, row_pointers);
1623 HeapFree(GetProcessHeap(), 0, pngdata);
1624 return ret;
1625 #else /* SONAME_LIBPNG */
1626 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1627 return E_FAIL;
1628 #endif
1631 /*****************************************************
1632 * start of Icon-specific code
1635 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1637 HICON hicon;
1638 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1639 HDC hdcRef;
1640 int i;
1643 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1644 FIXME("icon.idType=%d\n",cifd->idType);
1645 FIXME("icon.idCount=%d\n",cifd->idCount);
1647 for (i=0;i<cifd->idCount;i++) {
1648 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1649 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1650 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1651 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1652 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1653 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1654 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1655 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1658 i=0;
1659 /* If we have more than one icon, try to find the best.
1660 * this currently means '32 pixel wide'.
1662 if (cifd->idCount!=1) {
1663 for (i=0;i<cifd->idCount;i++) {
1664 if (cifd->idEntries[i].bWidth == 32)
1665 break;
1667 if (i==cifd->idCount) i=0;
1670 hicon = CreateIconFromResourceEx(
1671 xbuf+cifd->idEntries[i].dwDIBOffset,
1672 cifd->idEntries[i].dwDIBSize,
1673 TRUE, /* is icon */
1674 0x00030000,
1675 cifd->idEntries[i].bWidth,
1676 cifd->idEntries[i].bHeight,
1679 if (!hicon) {
1680 ERR("CreateIcon failed.\n");
1681 return E_FAIL;
1682 } else {
1683 This->desc.picType = PICTYPE_ICON;
1684 This->desc.u.icon.hicon = hicon;
1685 This->origWidth = cifd->idEntries[i].bWidth;
1686 This->origHeight = cifd->idEntries[i].bHeight;
1687 hdcRef = CreateCompatibleDC(0);
1688 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1689 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1690 DeleteDC(hdcRef);
1691 return S_OK;
1695 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1696 const BYTE *data, ULONG size)
1698 HENHMETAFILE hemf;
1699 ENHMETAHEADER hdr;
1701 hemf = SetEnhMetaFileBits(size, data);
1702 if (!hemf) return E_FAIL;
1704 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1706 This->desc.picType = PICTYPE_ENHMETAFILE;
1707 This->desc.u.emf.hemf = hemf;
1709 This->origWidth = 0;
1710 This->origHeight = 0;
1711 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1712 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1714 return S_OK;
1717 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1718 const BYTE *data, ULONG size)
1720 APM_HEADER *header = (APM_HEADER *)data;
1721 HMETAFILE hmf;
1723 if (size < sizeof(APM_HEADER))
1724 return E_FAIL;
1725 if (header->key != 0x9ac6cdd7)
1726 return E_FAIL;
1728 /* SetMetaFileBitsEx performs data check on its own */
1729 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1730 if (!hmf) return E_FAIL;
1732 This->desc.picType = PICTYPE_METAFILE;
1733 This->desc.u.wmf.hmeta = hmf;
1734 This->desc.u.wmf.xExt = 0;
1735 This->desc.u.wmf.yExt = 0;
1737 This->origWidth = 0;
1738 This->origHeight = 0;
1739 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1740 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1741 return S_OK;
1744 /************************************************************************
1745 * BITMAP FORMAT FLAGS -
1746 * Flags that differentiate between different types of bitmaps.
1749 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1750 #define BITMAP_FORMAT_JPEG 0xd8ff
1751 #define BITMAP_FORMAT_GIF 0x4947
1752 #define BITMAP_FORMAT_PNG 0x5089
1753 #define BITMAP_FORMAT_APM 0xcdd7
1755 /************************************************************************
1756 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1758 * Loads the binary data from the IStream. Starts at current position.
1759 * There appears to be an 2 DWORD header:
1760 * DWORD magic;
1761 * DWORD len;
1763 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1765 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1766 HRESULT hr = E_FAIL;
1767 BOOL headerisdata = FALSE;
1768 BOOL statfailed = FALSE;
1769 ULONG xread, toread;
1770 ULONG headerread;
1771 BYTE *xbuf;
1772 DWORD header[2];
1773 WORD magic;
1774 STATSTG statstg;
1775 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1777 TRACE("(%p,%p)\n",This,pStm);
1779 /****************************************************************************************
1780 * Part 1: Load the data
1782 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1783 * out whether we do.
1785 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1786 * compound file. This may explain most, if not all, of the cases of "no
1787 * header", and the header validation should take this into account.
1788 * At least in Visual Basic 6, resource streams, valid headers are
1789 * header[0] == "lt\0\0",
1790 * header[1] == length_of_stream.
1792 * Also handle streams where we do not have a working "Stat" method by
1793 * reading all data until the end of the stream.
1795 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1796 if (hr) {
1797 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1798 statfailed = TRUE;
1799 /* we will read at least 8 byte ... just right below */
1800 statstg.cbSize.QuadPart = 8;
1803 toread = 0;
1804 headerread = 0;
1805 headerisdata = FALSE;
1806 do {
1807 hr=IStream_Read(pStm,header,8,&xread);
1808 if (hr || xread!=8) {
1809 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1810 return (hr?hr:E_FAIL);
1812 headerread += xread;
1813 xread = 0;
1815 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1816 if (toread != 0 && toread != header[1])
1817 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1818 toread, header[1]);
1819 toread = header[1];
1820 if (toread == 0) break;
1821 } else {
1822 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1823 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1824 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1825 (header[0] == EMR_HEADER) || /* EMF header */
1826 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1827 (header[1]==0)
1828 ) {/* Found start of bitmap data */
1829 headerisdata = TRUE;
1830 if (toread == 0)
1831 toread = statstg.cbSize.QuadPart-8;
1832 else toread -= 8;
1833 xread = 8;
1834 } else {
1835 FIXME("Unknown stream header magic: %08x\n", header[0]);
1836 toread = header[1];
1839 } while (!headerisdata);
1841 if (statfailed) { /* we don't know the size ... read all we get */
1842 int sizeinc = 4096;
1843 int origsize = sizeinc;
1844 ULONG nread = 42;
1846 TRACE("Reading all data from stream.\n");
1847 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1848 if (headerisdata)
1849 memcpy (xbuf, header, 8);
1850 while (1) {
1851 while (xread < origsize) {
1852 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1853 xread+=nread;
1854 if (hr || !nread)
1855 break;
1857 if (!nread || hr) /* done, or error */
1858 break;
1859 if (xread == origsize) {
1860 origsize += sizeinc;
1861 sizeinc = 2*sizeinc; /* exponential increase */
1862 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1865 if (hr)
1866 TRACE("hr in no-stat loader case is %08x\n", hr);
1867 TRACE("loaded %d bytes.\n", xread);
1868 This->datalen = xread;
1869 This->data = xbuf;
1870 } else {
1871 This->datalen = toread+(headerisdata?8:0);
1872 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1873 if (!xbuf)
1874 return E_OUTOFMEMORY;
1876 if (headerisdata)
1877 memcpy (xbuf, header, 8);
1879 while (xread < This->datalen) {
1880 ULONG nread;
1881 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1882 xread+=nread;
1883 if (hr || !nread)
1884 break;
1886 if (xread != This->datalen)
1887 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1889 if (This->datalen == 0) { /* Marks the "NONE" picture */
1890 This->desc.picType = PICTYPE_NONE;
1891 return S_OK;
1895 /****************************************************************************************
1896 * Part 2: Process the loaded data
1899 magic = xbuf[0] + (xbuf[1]<<8);
1900 This->loadtime_format = magic;
1902 switch (magic) {
1903 case BITMAP_FORMAT_GIF: /* GIF */
1904 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1905 break;
1906 case BITMAP_FORMAT_JPEG: /* JPEG */
1907 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1908 break;
1909 case BITMAP_FORMAT_BMP: /* Bitmap */
1910 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1911 break;
1912 case BITMAP_FORMAT_PNG: /* PNG */
1913 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1914 break;
1915 case BITMAP_FORMAT_APM: /* APM */
1916 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1917 break;
1918 case 0x0000: { /* ICON , first word is dwReserved */
1919 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1920 break;
1922 default:
1924 unsigned int i;
1926 /* let's see if it's a EMF */
1927 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1928 if (hr == S_OK) break;
1930 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1931 hr=E_FAIL;
1932 for (i=0;i<xread+8;i++) {
1933 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1934 else MESSAGE("%02x ",xbuf[i-8]);
1935 if (i % 10 == 9) MESSAGE("\n");
1937 MESSAGE("\n");
1938 break;
1941 This->bIsDirty = FALSE;
1943 /* FIXME: this notify is not really documented */
1944 if (hr==S_OK)
1945 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1946 return hr;
1949 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1951 int iSuccess = 0;
1952 HDC hDC;
1953 BITMAPINFO * pInfoBitmap;
1954 int iNumPaletteEntries;
1955 unsigned char * pPixelData;
1956 BITMAPFILEHEADER * pFileHeader;
1957 BITMAPINFO * pInfoHeader;
1959 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1960 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1962 /* Find out bitmap size and padded length */
1963 hDC = GetDC(0);
1964 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1965 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1967 /* Fetch bitmap palette & pixel data */
1969 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1970 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1972 /* Calculate the total length required for the BMP data */
1973 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1974 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1975 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1976 } else {
1977 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1978 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1979 else
1980 iNumPaletteEntries = 0;
1982 *pLength =
1983 sizeof(BITMAPFILEHEADER) +
1984 sizeof(BITMAPINFOHEADER) +
1985 iNumPaletteEntries * sizeof(RGBQUAD) +
1986 pInfoBitmap->bmiHeader.biSizeImage;
1987 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1989 /* Fill the BITMAPFILEHEADER */
1990 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1991 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1992 pFileHeader->bfSize = *pLength;
1993 pFileHeader->bfOffBits =
1994 sizeof(BITMAPFILEHEADER) +
1995 sizeof(BITMAPINFOHEADER) +
1996 iNumPaletteEntries * sizeof(RGBQUAD);
1998 /* Fill the BITMAPINFOHEADER and the palette data */
1999 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
2000 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
2001 memcpy(
2002 (unsigned char *)(*ppBuffer) +
2003 sizeof(BITMAPFILEHEADER) +
2004 sizeof(BITMAPINFOHEADER) +
2005 iNumPaletteEntries * sizeof(RGBQUAD),
2006 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2007 iSuccess = 1;
2009 HeapFree(GetProcessHeap(), 0, pPixelData);
2010 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2011 return iSuccess;
2014 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2016 ICONINFO infoIcon;
2017 int iSuccess = 0;
2019 *ppBuffer = NULL; *pLength = 0;
2020 if (GetIconInfo(hIcon, &infoIcon)) {
2021 HDC hDC;
2022 BITMAPINFO * pInfoBitmap;
2023 unsigned char * pIconData = NULL;
2024 unsigned int iDataSize = 0;
2026 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2028 /* Find out icon size */
2029 hDC = GetDC(0);
2030 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2031 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2032 if (1) {
2033 /* Auxiliary pointers */
2034 CURSORICONFILEDIR * pIconDir;
2035 CURSORICONFILEDIRENTRY * pIconEntry;
2036 BITMAPINFOHEADER * pIconBitmapHeader;
2037 unsigned int iOffsetPalette;
2038 unsigned int iOffsetColorData;
2039 unsigned int iOffsetMaskData;
2041 unsigned int iLengthScanLineColor;
2042 unsigned int iLengthScanLineMask;
2043 unsigned int iNumEntriesPalette;
2045 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2046 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2048 FIXME("DEBUG: bitmap size is %d x %d\n",
2049 pInfoBitmap->bmiHeader.biWidth,
2050 pInfoBitmap->bmiHeader.biHeight);
2051 FIXME("DEBUG: bitmap bpp is %d\n",
2052 pInfoBitmap->bmiHeader.biBitCount);
2053 FIXME("DEBUG: bitmap nplanes is %d\n",
2054 pInfoBitmap->bmiHeader.biPlanes);
2055 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2056 pInfoBitmap->bmiHeader.biSizeImage);
2058 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2059 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2060 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2062 /* Fill out the CURSORICONFILEDIR */
2063 pIconDir = (CURSORICONFILEDIR *)pIconData;
2064 pIconDir->idType = 1;
2065 pIconDir->idCount = 1;
2067 /* Fill out the CURSORICONFILEDIRENTRY */
2068 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2069 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2070 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2071 pIconEntry->bColorCount =
2072 (pInfoBitmap->bmiHeader.biBitCount < 8)
2073 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2074 : 0;
2075 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2076 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2077 pIconEntry->dwDIBSize = 0;
2078 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2080 /* Fill out the BITMAPINFOHEADER */
2081 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2082 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2084 /* Find out whether a palette exists for the bitmap */
2085 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2086 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2087 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2088 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2089 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2090 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2091 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2092 iNumEntriesPalette = 3;
2093 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2094 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2095 } else {
2096 iNumEntriesPalette = 0;
2099 /* Add bitmap size and header size to icon data size. */
2100 iOffsetPalette = iDataSize;
2101 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2102 iOffsetColorData = iDataSize;
2103 iDataSize += pIconBitmapHeader->biSizeImage;
2104 iOffsetMaskData = iDataSize;
2105 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2106 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2107 pIconBitmapHeader->biHeight *= 2;
2108 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2109 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2110 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2111 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2113 /* Get the actual bitmap data from the icon bitmap */
2114 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2115 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2116 if (iNumEntriesPalette > 0) {
2117 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2118 iNumEntriesPalette * sizeof(RGBQUAD));
2121 /* Reset all values so that GetDIBits call succeeds */
2122 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2123 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2124 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2126 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2127 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2128 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2130 printf("ERROR: unable to get bitmap mask (error %u)\n",
2131 GetLastError());
2135 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2136 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2138 /* Write out everything produced so far to the stream */
2139 *ppBuffer = pIconData; *pLength = iDataSize;
2140 iSuccess = 1;
2141 } else {
2143 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2144 GetLastError());
2148 Remarks (from MSDN entry on GetIconInfo):
2150 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2151 members of ICONINFO. The calling application must manage
2152 these bitmaps and delete them when they are no longer
2153 necessary.
2155 if (hDC) ReleaseDC(0, hDC);
2156 DeleteObject(infoIcon.hbmMask);
2157 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2158 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2159 } else {
2160 printf("ERROR: Unable to get icon information (error %u)\n",
2161 GetLastError());
2163 return iSuccess;
2166 static HRESULT WINAPI OLEPictureImpl_Save(
2167 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2169 HRESULT hResult = E_NOTIMPL;
2170 void * pIconData;
2171 unsigned int iDataSize;
2172 ULONG dummy;
2173 int iSerializeResult = 0;
2174 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2176 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2178 switch (This->desc.picType) {
2179 case PICTYPE_ICON:
2180 if (This->bIsDirty || !This->data) {
2181 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2182 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2183 hResult = E_FAIL;
2184 break;
2186 HeapFree(GetProcessHeap(), 0, This->data);
2187 This->data = pIconData;
2188 This->datalen = iDataSize;
2190 if (This->loadtime_magic != 0xdeadbeef) {
2191 DWORD header[2];
2193 header[0] = This->loadtime_magic;
2194 header[1] = This->datalen;
2195 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2197 IStream_Write(pStm, This->data, This->datalen, &dummy);
2199 hResult = S_OK;
2200 break;
2201 case PICTYPE_BITMAP:
2202 if (This->bIsDirty) {
2203 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2204 case BITMAP_FORMAT_BMP:
2205 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2206 break;
2207 case BITMAP_FORMAT_JPEG:
2208 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2209 break;
2210 case BITMAP_FORMAT_GIF:
2211 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2212 break;
2213 case BITMAP_FORMAT_PNG:
2214 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2215 break;
2216 default:
2217 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2218 break;
2220 if (iSerializeResult) {
2222 if (This->loadtime_magic != 0xdeadbeef) {
2224 if (1) {
2225 DWORD header[2];
2227 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2228 header[1] = iDataSize;
2229 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2231 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2233 HeapFree(GetProcessHeap(), 0, This->data);
2234 This->data = pIconData;
2235 This->datalen = iDataSize;
2236 hResult = S_OK;
2238 } else {
2240 if (This->loadtime_magic != 0xdeadbeef) {
2242 if (1) {
2243 DWORD header[2];
2245 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2246 header[1] = This->datalen;
2247 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2249 IStream_Write(pStm, This->data, This->datalen, &dummy);
2250 hResult = S_OK;
2252 break;
2253 case PICTYPE_METAFILE:
2254 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2255 break;
2256 case PICTYPE_ENHMETAFILE:
2257 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2258 break;
2259 default:
2260 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2261 break;
2263 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2264 return hResult;
2267 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2268 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2270 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2271 FIXME("(%p,%p),stub!\n",This,pcbSize);
2272 return E_NOTIMPL;
2276 /************************************************************************
2277 * IDispatch
2280 /************************************************************************
2281 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2283 * See Windows documentation for more details on IUnknown methods.
2285 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2286 IDispatch* iface,
2287 REFIID riid,
2288 VOID** ppvoid)
2290 OLEPictureImpl *This = impl_from_IDispatch(iface);
2292 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2295 /************************************************************************
2296 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2298 * See Windows documentation for more details on IUnknown methods.
2300 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2301 IDispatch* iface)
2303 OLEPictureImpl *This = impl_from_IDispatch(iface);
2305 return IPicture_AddRef((IPicture *)This);
2308 /************************************************************************
2309 * OLEPictureImpl_IDispatch_Release (IUnknown)
2311 * See Windows documentation for more details on IUnknown methods.
2313 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2314 IDispatch* iface)
2316 OLEPictureImpl *This = impl_from_IDispatch(iface);
2318 return IPicture_Release((IPicture *)This);
2321 /************************************************************************
2322 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2324 * See Windows documentation for more details on IDispatch methods.
2326 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2327 IDispatch* iface,
2328 unsigned int* pctinfo)
2330 TRACE("(%p)\n", pctinfo);
2332 *pctinfo = 1;
2334 return S_OK;
2337 /************************************************************************
2338 * OLEPictureImpl_GetTypeInfo (IDispatch)
2340 * See Windows documentation for more details on IDispatch methods.
2342 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2343 IDispatch* iface,
2344 UINT iTInfo,
2345 LCID lcid,
2346 ITypeInfo** ppTInfo)
2348 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2349 ITypeLib *tl;
2350 HRESULT hres;
2352 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2354 if (iTInfo != 0)
2355 return E_FAIL;
2357 hres = LoadTypeLib(stdole2tlb, &tl);
2358 if (FAILED(hres))
2360 ERR("Could not load stdole2.tlb\n");
2361 return hres;
2364 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2365 if (FAILED(hres))
2366 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2368 return hres;
2371 /************************************************************************
2372 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2374 * See Windows documentation for more details on IDispatch methods.
2376 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2377 IDispatch* iface,
2378 REFIID riid,
2379 LPOLESTR* rgszNames,
2380 UINT cNames,
2381 LCID lcid,
2382 DISPID* rgDispId)
2384 ITypeInfo * pTInfo;
2385 HRESULT hres;
2387 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2388 rgszNames, cNames, (int)lcid, rgDispId);
2390 if (cNames == 0)
2392 return E_INVALIDARG;
2394 else
2396 /* retrieve type information */
2397 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2399 if (FAILED(hres))
2401 ERR("GetTypeInfo failed.\n");
2402 return hres;
2405 /* convert names to DISPIDs */
2406 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2407 ITypeInfo_Release(pTInfo);
2409 return hres;
2413 /************************************************************************
2414 * OLEPictureImpl_Invoke (IDispatch)
2416 * See Windows documentation for more details on IDispatch methods.
2418 static HRESULT WINAPI OLEPictureImpl_Invoke(
2419 IDispatch* iface,
2420 DISPID dispIdMember,
2421 REFIID riid,
2422 LCID lcid,
2423 WORD wFlags,
2424 DISPPARAMS* pDispParams,
2425 VARIANT* pVarResult,
2426 EXCEPINFO* pExepInfo,
2427 UINT* puArgErr)
2429 OLEPictureImpl *This = impl_from_IDispatch(iface);
2431 /* validate parameters */
2433 if (!IsEqualIID(riid, &IID_NULL))
2435 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2436 return DISP_E_UNKNOWNNAME;
2439 if (!pDispParams)
2441 ERR("null pDispParams not allowed\n");
2442 return DISP_E_PARAMNOTOPTIONAL;
2445 if (wFlags & DISPATCH_PROPERTYGET)
2447 if (pDispParams->cArgs != 0)
2449 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2450 return DISP_E_BADPARAMCOUNT;
2452 if (!pVarResult)
2454 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2455 return DISP_E_PARAMNOTOPTIONAL;
2458 else if (wFlags & DISPATCH_PROPERTYPUT)
2460 if (pDispParams->cArgs != 1)
2462 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2463 return DISP_E_BADPARAMCOUNT;
2467 switch (dispIdMember)
2469 case DISPID_PICT_HANDLE:
2470 if (wFlags & DISPATCH_PROPERTYGET)
2472 TRACE("DISPID_PICT_HANDLE\n");
2473 V_VT(pVarResult) = VT_I4;
2474 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2476 break;
2477 case DISPID_PICT_HPAL:
2478 if (wFlags & DISPATCH_PROPERTYGET)
2480 TRACE("DISPID_PICT_HPAL\n");
2481 V_VT(pVarResult) = VT_I4;
2482 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2484 else if (wFlags & DISPATCH_PROPERTYPUT)
2486 VARIANTARG vararg;
2487 HRESULT hr;
2488 TRACE("DISPID_PICT_HPAL\n");
2490 VariantInit(&vararg);
2491 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2492 if (FAILED(hr))
2493 return hr;
2495 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2497 VariantClear(&vararg);
2498 return hr;
2500 break;
2501 case DISPID_PICT_TYPE:
2502 if (wFlags & DISPATCH_PROPERTYGET)
2504 TRACE("DISPID_PICT_TYPE\n");
2505 V_VT(pVarResult) = VT_I2;
2506 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2508 break;
2509 case DISPID_PICT_WIDTH:
2510 if (wFlags & DISPATCH_PROPERTYGET)
2512 TRACE("DISPID_PICT_WIDTH\n");
2513 V_VT(pVarResult) = VT_I4;
2514 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2516 break;
2517 case DISPID_PICT_HEIGHT:
2518 if (wFlags & DISPATCH_PROPERTYGET)
2520 TRACE("DISPID_PICT_HEIGHT\n");
2521 V_VT(pVarResult) = VT_I4;
2522 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2524 break;
2527 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2528 return DISP_E_MEMBERNOTFOUND;
2532 static const IPictureVtbl OLEPictureImpl_VTable =
2534 OLEPictureImpl_QueryInterface,
2535 OLEPictureImpl_AddRef,
2536 OLEPictureImpl_Release,
2537 OLEPictureImpl_get_Handle,
2538 OLEPictureImpl_get_hPal,
2539 OLEPictureImpl_get_Type,
2540 OLEPictureImpl_get_Width,
2541 OLEPictureImpl_get_Height,
2542 OLEPictureImpl_Render,
2543 OLEPictureImpl_set_hPal,
2544 OLEPictureImpl_get_CurDC,
2545 OLEPictureImpl_SelectPicture,
2546 OLEPictureImpl_get_KeepOriginalFormat,
2547 OLEPictureImpl_put_KeepOriginalFormat,
2548 OLEPictureImpl_PictureChanged,
2549 OLEPictureImpl_SaveAsFile,
2550 OLEPictureImpl_get_Attributes
2553 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2555 OLEPictureImpl_IDispatch_QueryInterface,
2556 OLEPictureImpl_IDispatch_AddRef,
2557 OLEPictureImpl_IDispatch_Release,
2558 OLEPictureImpl_GetTypeInfoCount,
2559 OLEPictureImpl_GetTypeInfo,
2560 OLEPictureImpl_GetIDsOfNames,
2561 OLEPictureImpl_Invoke
2564 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2566 OLEPictureImpl_IPersistStream_QueryInterface,
2567 OLEPictureImpl_IPersistStream_AddRef,
2568 OLEPictureImpl_IPersistStream_Release,
2569 OLEPictureImpl_GetClassID,
2570 OLEPictureImpl_IsDirty,
2571 OLEPictureImpl_Load,
2572 OLEPictureImpl_Save,
2573 OLEPictureImpl_GetSizeMax
2576 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2578 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2579 OLEPictureImpl_IConnectionPointContainer_AddRef,
2580 OLEPictureImpl_IConnectionPointContainer_Release,
2581 OLEPictureImpl_EnumConnectionPoints,
2582 OLEPictureImpl_FindConnectionPoint
2585 /***********************************************************************
2586 * OleCreatePictureIndirect (OLEAUT32.419)
2588 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2589 BOOL fOwn, LPVOID *ppvObj )
2591 OLEPictureImpl* newPict = NULL;
2592 HRESULT hr = S_OK;
2594 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2597 * Sanity check
2599 if (ppvObj==0)
2600 return E_POINTER;
2602 *ppvObj = NULL;
2605 * Try to construct a new instance of the class.
2607 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2609 if (newPict == NULL)
2610 return E_OUTOFMEMORY;
2613 * Make sure it supports the interface required by the caller.
2615 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2618 * Release the reference obtained in the constructor. If
2619 * the QueryInterface was unsuccessful, it will free the class.
2621 IPicture_Release((IPicture*)newPict);
2623 return hr;
2627 /***********************************************************************
2628 * OleLoadPicture (OLEAUT32.418)
2630 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2631 REFIID riid, LPVOID *ppvObj )
2633 LPPERSISTSTREAM ps;
2634 IPicture *newpic;
2635 HRESULT hr;
2637 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2638 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2640 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2641 if (hr)
2642 return hr;
2643 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2644 if (hr) {
2645 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2646 IPicture_Release(newpic);
2647 *ppvObj = NULL;
2648 return hr;
2650 hr = IPersistStream_Load(ps,lpstream);
2651 IPersistStream_Release(ps);
2652 if (FAILED(hr))
2654 ERR("IPersistStream_Load failed\n");
2655 IPicture_Release(newpic);
2656 *ppvObj = NULL;
2657 return hr;
2659 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2660 if (hr)
2661 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2662 IPicture_Release(newpic);
2663 return hr;
2666 /***********************************************************************
2667 * OleLoadPictureEx (OLEAUT32.401)
2669 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2670 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2672 LPPERSISTSTREAM ps;
2673 IPicture *newpic;
2674 HRESULT hr;
2676 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2677 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2679 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2680 if (hr)
2681 return hr;
2682 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2683 if (hr) {
2684 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2685 IPicture_Release(newpic);
2686 *ppvObj = NULL;
2687 return hr;
2689 hr = IPersistStream_Load(ps,lpstream);
2690 IPersistStream_Release(ps);
2691 if (FAILED(hr))
2693 ERR("IPersistStream_Load failed\n");
2694 IPicture_Release(newpic);
2695 *ppvObj = NULL;
2696 return hr;
2698 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2699 if (hr)
2700 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2701 IPicture_Release(newpic);
2702 return hr;
2705 /***********************************************************************
2706 * OleLoadPicturePath (OLEAUT32.424)
2708 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2709 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2710 LPVOID *ppvRet )
2712 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2713 IPicture *ipicture;
2714 HANDLE hFile;
2715 DWORD dwFileSize;
2716 HGLOBAL hGlobal = NULL;
2717 DWORD dwBytesRead = 0;
2718 IStream *stream;
2719 BOOL bRead;
2720 IPersistStream *pStream;
2721 HRESULT hRes;
2723 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2724 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2725 debugstr_guid(riid), ppvRet);
2727 if (!ppvRet) return E_POINTER;
2729 if (strncmpW(szURLorPath, file, 7) == 0) {
2730 szURLorPath += 7;
2732 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2733 0, NULL);
2734 if (hFile == INVALID_HANDLE_VALUE)
2735 return E_UNEXPECTED;
2737 dwFileSize = GetFileSize(hFile, NULL);
2738 if (dwFileSize != INVALID_FILE_SIZE )
2740 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2741 if ( hGlobal)
2743 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2744 if (!bRead)
2746 GlobalFree(hGlobal);
2747 hGlobal = 0;
2751 CloseHandle(hFile);
2753 if (!hGlobal)
2754 return E_UNEXPECTED;
2756 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2757 if (FAILED(hRes))
2759 GlobalFree(hGlobal);
2760 return hRes;
2762 } else {
2763 IMoniker *pmnk;
2764 IBindCtx *pbc;
2766 hRes = CreateBindCtx(0, &pbc);
2767 if (SUCCEEDED(hRes))
2769 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2770 if (SUCCEEDED(hRes))
2772 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2773 IMoniker_Release(pmnk);
2775 IBindCtx_Release(pbc);
2777 if (FAILED(hRes))
2778 return hRes;
2781 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2782 &IID_IPicture, (LPVOID*)&ipicture);
2783 if (hRes != S_OK) {
2784 IStream_Release(stream);
2785 return hRes;
2788 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2789 if (hRes) {
2790 IStream_Release(stream);
2791 IPicture_Release(ipicture);
2792 return hRes;
2795 hRes = IPersistStream_Load(pStream, stream);
2796 IPersistStream_Release(pStream);
2797 IStream_Release(stream);
2799 if (hRes) {
2800 IPicture_Release(ipicture);
2801 return hRes;
2804 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2805 if (hRes)
2806 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2808 IPicture_Release(ipicture);
2809 return hRes;
2812 /*******************************************************************************
2813 * StdPic ClassFactory
2815 typedef struct
2817 /* IUnknown fields */
2818 const IClassFactoryVtbl *lpVtbl;
2819 LONG ref;
2820 } IClassFactoryImpl;
2822 static HRESULT WINAPI
2823 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2824 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2826 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2827 return E_NOINTERFACE;
2830 static ULONG WINAPI
2831 SPCF_AddRef(LPCLASSFACTORY iface) {
2832 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2833 return InterlockedIncrement(&This->ref);
2836 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2837 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2838 /* static class, won't be freed */
2839 return InterlockedDecrement(&This->ref);
2842 static HRESULT WINAPI SPCF_CreateInstance(
2843 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2845 /* Creates an uninitialized picture */
2846 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2850 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2851 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2852 FIXME("(%p)->(%d),stub!\n",This,dolock);
2853 return S_OK;
2856 static const IClassFactoryVtbl SPCF_Vtbl = {
2857 SPCF_QueryInterface,
2858 SPCF_AddRef,
2859 SPCF_Release,
2860 SPCF_CreateInstance,
2861 SPCF_LockServer
2863 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2865 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }