oleaut32: Include the system jpeg and png headers before the Windows headers.
[wine/wine-gecko.git] / dlls / oleaut32 / olepicture.c
blobcad5b7b16ce17929d30a6dfdd0beb05684d5f9f9
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
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * BUGS
25 * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
26 * Lots of methods are just stubs.
29 * NOTES (or things that msdn doesn't tell you)
31 * The width and height properties are returned in HIMETRIC units (0.01mm)
32 * IPicture::Render also uses these to select a region of the src picture.
33 * A bitmap's size is converted into these units by using the screen resolution
34 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
38 #include "config.h"
39 #include "wine/port.h"
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <string.h>
48 #ifdef SONAME_LIBJPEG
49 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
50 #define XMD_H
51 #define UINT8 JPEG_UINT8
52 #define UINT16 JPEG_UINT16
53 #define boolean jpeg_boolean
54 # include <jpeglib.h>
55 #undef UINT8
56 #undef UINT16
57 #undef boolean
58 #endif
60 #ifdef HAVE_PNG_H
61 #include <png.h>
62 #endif
64 /* Must be before wine includes, the header has things conflicting with
65 * WINE headers.
67 #define COBJMACROS
68 #define NONAMELESSUNION
69 #define NONAMELESSSTRUCT
71 #include "winerror.h"
72 #include "windef.h"
73 #include "winbase.h"
74 #include "wingdi.h"
75 #include "winuser.h"
76 #include "ole2.h"
77 #include "olectl.h"
78 #include "oleauto.h"
79 #include "connpt.h"
80 #include "urlmon.h"
81 #include "wine/debug.h"
82 #include "wine/unicode.h"
84 #include "wine/wingdi16.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 = (IPicture*)This;
462 else if (IsEqualIID(&IID_IDispatch, riid))
463 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
464 else if (IsEqualIID(&IID_IPictureDisp, riid))
465 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
466 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
467 *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
468 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
469 *ppvObject = (IConnectionPointContainer*)&(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);
511 return;
514 /************************************************************************
515 * OLEPictureImpl_get_Handle
517 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
518 OLE_HANDLE *phandle)
520 OLEPictureImpl *This = (OLEPictureImpl *)iface;
521 TRACE("(%p)->(%p)\n", This, phandle);
522 switch(This->desc.picType) {
523 case PICTYPE_NONE:
524 case PICTYPE_UNINITIALIZED:
525 *phandle = 0;
526 break;
527 case PICTYPE_BITMAP:
528 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
529 break;
530 case PICTYPE_METAFILE:
531 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
532 break;
533 case PICTYPE_ICON:
534 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
535 break;
536 case PICTYPE_ENHMETAFILE:
537 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
538 break;
539 default:
540 FIXME("Unimplemented type %d\n", This->desc.picType);
541 return E_NOTIMPL;
543 TRACE("returning handle %08x\n", *phandle);
544 return S_OK;
547 /************************************************************************
548 * OLEPictureImpl_get_hPal
550 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
551 OLE_HANDLE *phandle)
553 OLEPictureImpl *This = (OLEPictureImpl *)iface;
554 HRESULT hres;
555 TRACE("(%p)->(%p)\n", This, phandle);
557 if (!phandle)
558 return E_POINTER;
560 switch (This->desc.picType) {
561 case (UINT)PICTYPE_UNINITIALIZED:
562 case PICTYPE_NONE:
563 *phandle = 0;
564 hres = S_FALSE;
565 break;
566 case PICTYPE_BITMAP:
567 *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
568 hres = S_OK;
569 break;
570 case PICTYPE_METAFILE:
571 hres = E_FAIL;
572 break;
573 case PICTYPE_ICON:
574 case PICTYPE_ENHMETAFILE:
575 default:
576 FIXME("unimplemented for type %d. Returning 0 palette.\n",
577 This->desc.picType);
578 *phandle = 0;
579 hres = S_OK;
582 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
583 return hres;
586 /************************************************************************
587 * OLEPictureImpl_get_Type
589 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
590 short *ptype)
592 OLEPictureImpl *This = (OLEPictureImpl *)iface;
593 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
594 *ptype = This->desc.picType;
595 return S_OK;
598 /************************************************************************
599 * OLEPictureImpl_get_Width
601 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
602 OLE_XSIZE_HIMETRIC *pwidth)
604 OLEPictureImpl *This = (OLEPictureImpl *)iface;
605 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
606 *pwidth = This->himetricWidth;
607 return S_OK;
610 /************************************************************************
611 * OLEPictureImpl_get_Height
613 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
614 OLE_YSIZE_HIMETRIC *pheight)
616 OLEPictureImpl *This = (OLEPictureImpl *)iface;
617 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
618 *pheight = This->himetricHeight;
619 return S_OK;
622 /************************************************************************
623 * OLEPictureImpl_Render
625 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
626 LONG x, LONG y, LONG cx, LONG cy,
627 OLE_XPOS_HIMETRIC xSrc,
628 OLE_YPOS_HIMETRIC ySrc,
629 OLE_XSIZE_HIMETRIC cxSrc,
630 OLE_YSIZE_HIMETRIC cySrc,
631 LPCRECT prcWBounds)
633 OLEPictureImpl *This = (OLEPictureImpl *)iface;
634 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
635 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
636 if(prcWBounds)
637 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
638 prcWBounds->right, prcWBounds->bottom);
641 * While the documentation suggests this to be here (or after rendering?)
642 * it does cause an endless recursion in my sample app. -MM 20010804
643 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
646 switch(This->desc.picType) {
647 case PICTYPE_BITMAP:
649 HBITMAP hbmpOld;
650 HDC hdcBmp;
652 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
653 NB y-axis gets flipped */
655 hdcBmp = CreateCompatibleDC(0);
656 SetMapMode(hdcBmp, MM_ANISOTROPIC);
657 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
658 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
659 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
660 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
662 if (This->hbmMask) {
663 HDC hdcMask = CreateCompatibleDC(0);
664 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
666 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
668 SetMapMode(hdcMask, MM_ANISOTROPIC);
669 SetWindowOrgEx(hdcMask, 0, 0, NULL);
670 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
671 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
672 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
674 SetBkColor(hdc, RGB(255, 255, 255));
675 SetTextColor(hdc, RGB(0, 0, 0));
676 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
677 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
679 SelectObject(hdcMask, hOldbm);
680 DeleteDC(hdcMask);
681 } else {
682 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
683 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
686 SelectObject(hdcBmp, hbmpOld);
687 DeleteDC(hdcBmp);
689 break;
690 case PICTYPE_ICON:
691 FIXME("Not quite correct implementation of rendering icons...\n");
692 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
693 break;
695 case PICTYPE_METAFILE:
697 POINT prevOrg;
698 SIZE prevExt;
699 int oldmode;
701 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
702 SetViewportOrgEx(hdc, x, y, &prevOrg);
703 SetViewportExtEx(hdc, cx, cy, &prevExt);
705 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
706 ERR("PlayMetaFile failed!\n");
708 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
709 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
710 SetMapMode(hdc, oldmode);
711 break;
714 case PICTYPE_ENHMETAFILE:
716 RECT rc = { x, y, x + cx, y + cy };
717 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
718 break;
721 default:
722 FIXME("type %d not implemented\n", This->desc.picType);
723 return E_NOTIMPL;
725 return S_OK;
728 /************************************************************************
729 * OLEPictureImpl_set_hPal
731 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
732 OLE_HANDLE hpal)
734 OLEPictureImpl *This = (OLEPictureImpl *)iface;
735 FIXME("(%p)->(%08x): stub\n", This, hpal);
736 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
737 return E_NOTIMPL;
740 /************************************************************************
741 * OLEPictureImpl_get_CurDC
743 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
744 HDC *phdc)
746 OLEPictureImpl *This = (OLEPictureImpl *)iface;
747 TRACE("(%p), returning %p\n", This, This->hDCCur);
748 if (phdc) *phdc = This->hDCCur;
749 return S_OK;
752 /************************************************************************
753 * OLEPictureImpl_SelectPicture
755 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
756 HDC hdcIn,
757 HDC *phdcOut,
758 OLE_HANDLE *phbmpOut)
760 OLEPictureImpl *This = (OLEPictureImpl *)iface;
761 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
762 if (This->desc.picType == PICTYPE_BITMAP) {
763 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
765 if (phdcOut)
766 *phdcOut = This->hDCCur;
767 This->hDCCur = hdcIn;
768 if (phbmpOut)
769 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
770 return S_OK;
771 } else {
772 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
773 return E_FAIL;
777 /************************************************************************
778 * OLEPictureImpl_get_KeepOriginalFormat
780 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
781 BOOL *pfKeep)
783 OLEPictureImpl *This = (OLEPictureImpl *)iface;
784 TRACE("(%p)->(%p)\n", This, pfKeep);
785 if (!pfKeep)
786 return E_POINTER;
787 *pfKeep = This->keepOrigFormat;
788 return S_OK;
791 /************************************************************************
792 * OLEPictureImpl_put_KeepOriginalFormat
794 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
795 BOOL keep)
797 OLEPictureImpl *This = (OLEPictureImpl *)iface;
798 TRACE("(%p)->(%d)\n", This, keep);
799 This->keepOrigFormat = keep;
800 /* FIXME: what DISPID notification here? */
801 return S_OK;
804 /************************************************************************
805 * OLEPictureImpl_PictureChanged
807 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
809 OLEPictureImpl *This = (OLEPictureImpl *)iface;
810 TRACE("(%p)->()\n", This);
811 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
812 This->bIsDirty = TRUE;
813 return S_OK;
816 /************************************************************************
817 * OLEPictureImpl_SaveAsFile
819 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
820 IStream *pstream,
821 BOOL SaveMemCopy,
822 LONG *pcbSize)
824 OLEPictureImpl *This = (OLEPictureImpl *)iface;
825 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
826 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
829 /************************************************************************
830 * OLEPictureImpl_get_Attributes
832 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
833 DWORD *pdwAttr)
835 OLEPictureImpl *This = (OLEPictureImpl *)iface;
836 TRACE("(%p)->(%p).\n", This, pdwAttr);
837 *pdwAttr = 0;
838 switch (This->desc.picType) {
839 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
840 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
841 case PICTYPE_ENHMETAFILE: /* fall through */
842 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
843 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
845 return S_OK;
849 /************************************************************************
850 * IConnectionPointContainer
852 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
853 IConnectionPointContainer* iface,
854 REFIID riid,
855 VOID** ppvoid)
857 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
859 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
862 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
863 IConnectionPointContainer* iface)
865 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
867 return IPicture_AddRef((IPicture *)This);
870 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
871 IConnectionPointContainer* iface)
873 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
875 return IPicture_Release((IPicture *)This);
878 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
879 IConnectionPointContainer* iface,
880 IEnumConnectionPoints** ppEnum)
882 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
884 FIXME("(%p,%p), stub!\n",This,ppEnum);
885 return E_NOTIMPL;
888 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
889 IConnectionPointContainer* iface,
890 REFIID riid,
891 IConnectionPoint **ppCP)
893 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
894 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
895 if (!ppCP)
896 return E_POINTER;
897 *ppCP = NULL;
898 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
899 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
900 FIXME("no connection point for %s\n",debugstr_guid(riid));
901 return CONNECT_E_NOCONNECTION;
905 /************************************************************************
906 * IPersistStream
909 /************************************************************************
910 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
912 * See Windows documentation for more details on IUnknown methods.
914 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
915 IPersistStream* iface,
916 REFIID riid,
917 VOID** ppvoid)
919 OLEPictureImpl *This = impl_from_IPersistStream(iface);
921 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
924 /************************************************************************
925 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
927 * See Windows documentation for more details on IUnknown methods.
929 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
930 IPersistStream* iface)
932 OLEPictureImpl *This = impl_from_IPersistStream(iface);
934 return IPicture_AddRef((IPicture *)This);
937 /************************************************************************
938 * OLEPictureImpl_IPersistStream_Release (IUnknown)
940 * See Windows documentation for more details on IUnknown methods.
942 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
943 IPersistStream* iface)
945 OLEPictureImpl *This = impl_from_IPersistStream(iface);
947 return IPicture_Release((IPicture *)This);
950 /************************************************************************
951 * OLEPictureImpl_IPersistStream_GetClassID
953 static HRESULT WINAPI OLEPictureImpl_GetClassID(
954 IPersistStream* iface,CLSID* pClassID)
956 TRACE("(%p)\n", pClassID);
957 *pClassID = CLSID_StdPicture;
958 return S_OK;
961 /************************************************************************
962 * OLEPictureImpl_IPersistStream_IsDirty
964 static HRESULT WINAPI OLEPictureImpl_IsDirty(
965 IPersistStream* iface)
967 OLEPictureImpl *This = impl_from_IPersistStream(iface);
968 FIXME("(%p),stub!\n",This);
969 return E_NOTIMPL;
972 #ifdef SONAME_LIBJPEG
974 static void *libjpeg_handle;
975 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
976 MAKE_FUNCPTR(jpeg_std_error);
977 MAKE_FUNCPTR(jpeg_CreateDecompress);
978 MAKE_FUNCPTR(jpeg_read_header);
979 MAKE_FUNCPTR(jpeg_start_decompress);
980 MAKE_FUNCPTR(jpeg_read_scanlines);
981 MAKE_FUNCPTR(jpeg_finish_decompress);
982 MAKE_FUNCPTR(jpeg_destroy_decompress);
983 #undef MAKE_FUNCPTR
985 static void *load_libjpeg(void)
987 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
989 #define LOAD_FUNCPTR(f) \
990 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
991 libjpeg_handle = NULL; \
992 return NULL; \
995 LOAD_FUNCPTR(jpeg_std_error);
996 LOAD_FUNCPTR(jpeg_CreateDecompress);
997 LOAD_FUNCPTR(jpeg_read_header);
998 LOAD_FUNCPTR(jpeg_start_decompress);
999 LOAD_FUNCPTR(jpeg_read_scanlines);
1000 LOAD_FUNCPTR(jpeg_finish_decompress);
1001 LOAD_FUNCPTR(jpeg_destroy_decompress);
1002 #undef LOAD_FUNCPTR
1004 return libjpeg_handle;
1007 /* for the jpeg decompressor source manager. */
1008 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1010 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1011 ERR("(), should not get here.\n");
1012 return FALSE;
1015 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1016 TRACE("Skipping %ld bytes...\n", num_bytes);
1017 cinfo->src->next_input_byte += num_bytes;
1018 cinfo->src->bytes_in_buffer -= num_bytes;
1021 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1022 ERR("(desired=%d), should not get here.\n",desired);
1023 return FALSE;
1025 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1026 #endif /* SONAME_LIBJPEG */
1028 struct gifdata {
1029 unsigned char *data;
1030 unsigned int curoff;
1031 unsigned int len;
1034 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1035 struct gifdata *gd = (struct gifdata*)gif->UserData;
1037 if (len+gd->curoff > gd->len) {
1038 FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1039 len = gd->len - gd->curoff;
1041 memcpy(data, gd->data+gd->curoff, len);
1042 gd->curoff += len;
1043 return len;
1047 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1049 struct gifdata gd;
1050 GifFileType *gif;
1051 BITMAPINFO *bmi;
1052 HDC hdcref;
1053 LPBYTE bytes;
1054 int i,j,ret;
1055 GifImageDesc *gid;
1056 SavedImage *si;
1057 ColorMapObject *cm;
1058 int transparent = -1;
1059 ExtensionBlock *eb;
1060 int padding;
1062 gd.data = xbuf;
1063 gd.curoff = 0;
1064 gd.len = xread;
1065 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1066 ret = DGifSlurp(gif);
1067 if (ret == GIF_ERROR) {
1068 FIXME("Failed reading GIF using libgif.\n");
1069 return E_FAIL;
1071 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1072 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1073 TRACE("imgcnt %d\n", gif->ImageCount);
1074 if (gif->ImageCount<1) {
1075 FIXME("GIF stream does not have images inside?\n");
1076 return E_FAIL;
1078 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1079 gif->Image.Width, gif->Image.Height,
1080 gif->Image.Left, gif->Image.Top,
1081 gif->Image.Interlace
1083 /* */
1084 padding = (gif->SWidth+3) & ~3;
1085 si = gif->SavedImages+0;
1086 gid = &(si->ImageDesc);
1087 cm = gid->ColorMap;
1088 if (!cm) cm = gif->SColorMap;
1089 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1090 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1092 /* look for the transparent color extension */
1093 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1094 eb = si->ExtensionBlocks + i;
1095 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1096 if ((eb->Bytes[0] & 1) == 1) {
1097 transparent = (unsigned char)eb->Bytes[3];
1102 for (i = 0; i < cm->ColorCount; i++) {
1103 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1104 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1105 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1106 if (i == transparent) {
1107 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1108 bmi->bmiColors[i].rgbGreen,
1109 bmi->bmiColors[i].rgbBlue);
1113 /* Map to in picture coordinates */
1114 for (i = 0, j = 0; i < gid->Height; i++) {
1115 if (gif->Image.Interlace) {
1116 memcpy(
1117 bytes + (gid->Top + j) * padding + gid->Left,
1118 si->RasterBits + i * gid->Width,
1119 gid->Width);
1121 /* Lower bits of interlaced counter encode current interlace */
1122 if (j & 1) j += 2; /* Currently filling odd rows */
1123 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1124 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1126 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1127 /* End of current interlace, go to next interlace */
1128 if (j & 2) j = 1; /* Next iteration fills odd rows */
1129 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1130 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1132 } else {
1133 memcpy(
1134 bytes + (gid->Top + i) * padding + gid->Left,
1135 si->RasterBits + i * gid->Width,
1136 gid->Width);
1140 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1141 bmi->bmiHeader.biWidth = gif->SWidth;
1142 bmi->bmiHeader.biHeight = -gif->SHeight;
1143 bmi->bmiHeader.biPlanes = 1;
1144 bmi->bmiHeader.biBitCount = 8;
1145 bmi->bmiHeader.biCompression = BI_RGB;
1146 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1147 bmi->bmiHeader.biXPelsPerMeter = 0;
1148 bmi->bmiHeader.biYPelsPerMeter = 0;
1149 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1150 bmi->bmiHeader.biClrImportant = 0;
1152 hdcref = GetDC(0);
1153 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1154 hdcref,
1155 &bmi->bmiHeader,
1156 CBM_INIT,
1157 bytes,
1158 bmi,
1159 DIB_RGB_COLORS
1162 if (transparent > -1) {
1163 /* Create the Mask */
1164 HDC hdc = CreateCompatibleDC(0);
1165 HDC hdcMask = CreateCompatibleDC(0);
1166 HBITMAP hOldbitmap;
1167 HBITMAP hOldbitmapmask;
1169 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1170 HBITMAP hTempMask;
1172 This->hbmXor = CreateDIBitmap(
1173 hdcref,
1174 &bmi->bmiHeader,
1175 CBM_INIT,
1176 bytes,
1177 bmi,
1178 DIB_RGB_COLORS
1181 bmi->bmiColors[0].rgbRed = 0;
1182 bmi->bmiColors[0].rgbGreen = 0;
1183 bmi->bmiColors[0].rgbBlue = 0;
1184 bmi->bmiColors[1].rgbRed = 255;
1185 bmi->bmiColors[1].rgbGreen = 255;
1186 bmi->bmiColors[1].rgbBlue = 255;
1188 bmi->bmiHeader.biBitCount = 1;
1189 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1190 bmi->bmiHeader.biClrUsed = 2;
1192 for (i = 0; i < gif->SHeight; i++) {
1193 unsigned char * colorPointer = bytes + padding * i;
1194 unsigned char * monoPointer = bytes + monopadding * i;
1195 for (j = 0; j < gif->SWidth; j++) {
1196 unsigned char pixel = colorPointer[j];
1197 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1198 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1201 hdcref = GetDC(0);
1202 hTempMask = CreateDIBitmap(
1203 hdcref,
1204 &bmi->bmiHeader,
1205 CBM_INIT,
1206 bytes,
1207 bmi,
1208 DIB_RGB_COLORS
1210 DeleteDC(hdcref);
1212 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1213 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1214 hOldbitmap = SelectObject(hdc, hTempMask);
1215 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1217 SetBkColor(hdc, RGB(255, 255, 255));
1218 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1220 /* We no longer need the original bitmap, so we apply the first
1221 transformation with the mask to speed up the rendering */
1222 SelectObject(hdc, This->hbmXor);
1223 SetBkColor(hdc, RGB(0,0,0));
1224 SetTextColor(hdc, RGB(255,255,255));
1225 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1226 hdcMask, 0, 0, SRCAND);
1228 SelectObject(hdc, hOldbitmap);
1229 SelectObject(hdcMask, hOldbitmapmask);
1230 DeleteDC(hdcMask);
1231 DeleteDC(hdc);
1232 DeleteObject(hTempMask);
1235 DeleteDC(hdcref);
1236 This->desc.picType = PICTYPE_BITMAP;
1237 OLEPictureImpl_SetBitmap(This);
1238 DGifCloseFile(gif);
1239 HeapFree(GetProcessHeap(),0,bmi);
1240 HeapFree(GetProcessHeap(),0,bytes);
1241 return S_OK;
1244 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1246 #ifdef SONAME_LIBJPEG
1247 struct jpeg_decompress_struct jd;
1248 struct jpeg_error_mgr jerr;
1249 int ret;
1250 JDIMENSION x;
1251 JSAMPROW samprow,oldsamprow;
1252 BITMAPINFOHEADER bmi;
1253 LPBYTE bits;
1254 HDC hdcref;
1255 struct jpeg_source_mgr xjsm;
1256 LPBYTE oldbits;
1257 unsigned int i;
1259 if(!libjpeg_handle) {
1260 if(!load_libjpeg()) {
1261 FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1262 return E_FAIL;
1266 /* This is basically so we can use in-memory data for jpeg decompression.
1267 * We need to have all the functions.
1269 xjsm.next_input_byte = xbuf;
1270 xjsm.bytes_in_buffer = xread;
1271 xjsm.init_source = _jpeg_init_source;
1272 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1273 xjsm.skip_input_data = _jpeg_skip_input_data;
1274 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1275 xjsm.term_source = _jpeg_term_source;
1277 jd.err = pjpeg_std_error(&jerr);
1278 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1279 * jpeg_create_decompress(&jd); */
1280 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1281 jd.src = &xjsm;
1282 ret=pjpeg_read_header(&jd,TRUE);
1283 jd.out_color_space = JCS_RGB;
1284 pjpeg_start_decompress(&jd);
1285 if (ret != JPEG_HEADER_OK) {
1286 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1287 HeapFree(GetProcessHeap(),0,xbuf);
1288 return E_FAIL;
1291 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1292 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1293 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1295 oldbits = bits;
1296 oldsamprow = samprow;
1297 while ( jd.output_scanline<jd.output_height ) {
1298 x = pjpeg_read_scanlines(&jd,&samprow,1);
1299 if (x != 1) {
1300 FIXME("failed to read current scanline?\n");
1301 break;
1303 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1304 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1305 *(bits++) = *(samprow+2);
1306 *(bits++) = *(samprow+1);
1307 *(bits++) = *(samprow);
1309 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1310 samprow = oldsamprow;
1312 bits = oldbits;
1314 bmi.biSize = sizeof(bmi);
1315 bmi.biWidth = jd.output_width;
1316 bmi.biHeight = -jd.output_height;
1317 bmi.biPlanes = 1;
1318 bmi.biBitCount = jd.output_components<<3;
1319 bmi.biCompression = BI_RGB;
1320 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1321 bmi.biXPelsPerMeter = 0;
1322 bmi.biYPelsPerMeter = 0;
1323 bmi.biClrUsed = 0;
1324 bmi.biClrImportant = 0;
1326 HeapFree(GetProcessHeap(),0,samprow);
1327 pjpeg_finish_decompress(&jd);
1328 pjpeg_destroy_decompress(&jd);
1329 hdcref = GetDC(0);
1330 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1331 hdcref,
1332 &bmi,
1333 CBM_INIT,
1334 bits,
1335 (BITMAPINFO*)&bmi,
1336 DIB_RGB_COLORS
1338 DeleteDC(hdcref);
1339 This->desc.picType = PICTYPE_BITMAP;
1340 OLEPictureImpl_SetBitmap(This);
1341 HeapFree(GetProcessHeap(),0,bits);
1342 return S_OK;
1343 #else
1344 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1345 return E_FAIL;
1346 #endif
1349 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1351 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1352 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1353 HDC hdcref;
1355 /* Does not matter whether this is a coreheader or not, we only use
1356 * components which are in both
1358 hdcref = GetDC(0);
1359 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1360 hdcref,
1361 &(bi->bmiHeader),
1362 CBM_INIT,
1363 xbuf+bfh->bfOffBits,
1365 DIB_RGB_COLORS
1367 DeleteDC(hdcref);
1368 This->desc.picType = PICTYPE_BITMAP;
1369 OLEPictureImpl_SetBitmap(This);
1370 return S_OK;
1373 /*****************************************************
1374 * start of PNG-specific code
1375 * currently only supports colortype PNG_COLOR_TYPE_RGB
1377 #ifdef SONAME_LIBPNG
1378 typedef struct{
1379 ULONG position;
1380 ULONG size;
1381 BYTE * buff;
1382 } png_io;
1384 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1385 png_size_t length)
1387 png_io * io_ptr = png_ptr->io_ptr;
1389 if(length + io_ptr->position > io_ptr->size){
1390 length = io_ptr->size - io_ptr->position;
1393 memcpy(data, io_ptr->buff + io_ptr->position, length);
1395 io_ptr->position += length;
1398 static void *libpng_handle;
1399 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1400 MAKE_FUNCPTR(png_create_read_struct);
1401 MAKE_FUNCPTR(png_create_info_struct);
1402 MAKE_FUNCPTR(png_set_read_fn);
1403 MAKE_FUNCPTR(png_read_info);
1404 MAKE_FUNCPTR(png_read_image);
1405 MAKE_FUNCPTR(png_get_rowbytes);
1406 MAKE_FUNCPTR(png_set_bgr);
1407 MAKE_FUNCPTR(png_destroy_read_struct);
1408 MAKE_FUNCPTR(png_set_palette_to_rgb);
1409 MAKE_FUNCPTR(png_read_update_info);
1410 MAKE_FUNCPTR(png_get_tRNS);
1411 MAKE_FUNCPTR(png_get_PLTE);
1412 MAKE_FUNCPTR(png_set_expand);
1413 #undef MAKE_FUNCPTR
1415 static void *load_libpng(void)
1417 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1419 #define LOAD_FUNCPTR(f) \
1420 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1421 libpng_handle = NULL; \
1422 return NULL; \
1424 LOAD_FUNCPTR(png_create_read_struct);
1425 LOAD_FUNCPTR(png_create_info_struct);
1426 LOAD_FUNCPTR(png_set_read_fn);
1427 LOAD_FUNCPTR(png_read_info);
1428 LOAD_FUNCPTR(png_read_image);
1429 LOAD_FUNCPTR(png_get_rowbytes);
1430 LOAD_FUNCPTR(png_set_bgr);
1431 LOAD_FUNCPTR(png_destroy_read_struct);
1432 LOAD_FUNCPTR(png_set_palette_to_rgb);
1433 LOAD_FUNCPTR(png_read_update_info);
1434 LOAD_FUNCPTR(png_get_tRNS);
1435 LOAD_FUNCPTR(png_get_PLTE);
1436 LOAD_FUNCPTR(png_set_expand);
1438 #undef LOAD_FUNCPTR
1440 return libpng_handle;
1442 #endif /* SONAME_LIBPNG */
1444 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1446 #ifdef SONAME_LIBPNG
1447 png_io io;
1448 png_structp png_ptr = NULL;
1449 png_infop info_ptr = NULL;
1450 INT row, rowsize, height, width, num_trans, i, j;
1451 png_bytep* row_pointers = NULL;
1452 png_bytep pngdata = NULL;
1453 BITMAPINFOHEADER bmi;
1454 HDC hdcref = NULL, hdcXor, hdcMask;
1455 HRESULT ret;
1456 BOOL transparency;
1457 png_bytep trans;
1458 png_color_16p trans_values;
1459 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1460 HBITMAP hbmoldXor, hbmoldMask, temp;
1462 if(!libpng_handle) {
1463 if(!load_libpng()) {
1464 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1465 return E_FAIL;
1469 io.size = xread;
1470 io.position = 0;
1471 io.buff = xbuf;
1473 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1474 NULL, NULL, NULL);
1476 if(setjmp(png_jmpbuf(png_ptr))){
1477 TRACE("Error in libpng\n");
1478 ret = E_FAIL;
1479 goto end;
1482 info_ptr = ppng_create_info_struct(png_ptr);
1483 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1484 ppng_read_info(png_ptr, info_ptr);
1486 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1487 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1488 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1489 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1490 ret = E_FAIL;
1491 goto end;
1494 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1495 == PNG_INFO_tRNS);
1497 /* sets format from anything to RGBA */
1498 ppng_set_expand(png_ptr);
1499 /* sets format to BGRA */
1500 ppng_set_bgr(png_ptr);
1502 ppng_read_update_info(png_ptr, info_ptr);
1504 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1505 /* align rowsize to 4-byte boundary */
1506 rowsize = (rowsize + 3) & ~3;
1507 height = info_ptr->height;
1508 width = info_ptr->width;
1510 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1511 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1513 if(!pngdata || !row_pointers){
1514 ret = E_FAIL;
1515 goto end;
1518 for (row = 0; row < height; row++){
1519 row_pointers[row] = pngdata + row * rowsize;
1522 ppng_read_image(png_ptr, row_pointers);
1524 bmi.biSize = sizeof(bmi);
1525 bmi.biWidth = width;
1526 bmi.biHeight = -height;
1527 bmi.biPlanes = 1;
1528 bmi.biBitCount = info_ptr->channels * 8;
1529 bmi.biCompression = BI_RGB;
1530 bmi.biSizeImage = height * rowsize;
1531 bmi.biXPelsPerMeter = 0;
1532 bmi.biYPelsPerMeter = 0;
1533 bmi.biClrUsed = 0;
1534 bmi.biClrImportant = 0;
1536 hdcref = GetDC(0);
1537 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1538 hdcref,
1539 &bmi,
1540 CBM_INIT,
1541 pngdata,
1542 (BITMAPINFO*)&bmi,
1543 DIB_RGB_COLORS
1546 /* only fully-transparent alpha is handled */
1547 if((info_ptr->channels != 4) || !transparency){
1548 ReleaseDC(0, hdcref);
1549 goto succ;
1552 This->hbmXor = CreateDIBitmap(
1553 hdcref,
1554 &bmi,
1555 CBM_INIT,
1556 pngdata,
1557 (BITMAPINFO*)&bmi,
1558 DIB_RGB_COLORS
1561 /* set transparent pixels to black, all others to white */
1562 for(i = 0; i < height; i++){
1563 for(j = 3; j < rowsize; j += 4){
1564 if(row_pointers[i][j] == 0)
1565 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1566 else
1567 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1571 temp = CreateDIBitmap(
1572 hdcref,
1573 &bmi,
1574 CBM_INIT,
1575 pngdata,
1576 (BITMAPINFO*)&bmi,
1577 DIB_RGB_COLORS
1580 ReleaseDC(0, hdcref);
1582 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1583 hdcXor = CreateCompatibleDC(NULL);
1584 hdcMask = CreateCompatibleDC(NULL);
1586 hbmoldXor = SelectObject(hdcXor,temp);
1587 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1588 SetBkColor(hdcXor,black);
1589 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1591 SelectObject(hdcXor,This->hbmXor);
1592 DeleteObject(temp);
1594 SetTextColor(hdcXor,white);
1595 SetBkColor(hdcXor,black);
1596 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1598 SelectObject(hdcXor,hbmoldXor);
1599 SelectObject(hdcMask,hbmoldMask);
1601 DeleteDC(hdcXor);
1602 DeleteDC(hdcMask);
1604 succ:
1605 This->desc.picType = PICTYPE_BITMAP;
1606 OLEPictureImpl_SetBitmap(This);
1607 ret = S_OK;
1609 end:
1610 if(png_ptr)
1611 ppng_destroy_read_struct(&png_ptr,
1612 (info_ptr ? &info_ptr : (png_infopp) NULL),
1613 (png_infopp)NULL);
1614 HeapFree(GetProcessHeap(), 0, row_pointers);
1615 HeapFree(GetProcessHeap(), 0, pngdata);
1616 return ret;
1617 #else /* SONAME_LIBPNG */
1618 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1619 return E_FAIL;
1620 #endif
1623 /*****************************************************
1624 * start of Icon-specific code
1627 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1629 HICON hicon;
1630 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1631 HDC hdcRef;
1632 int i;
1635 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1636 FIXME("icon.idType=%d\n",cifd->idType);
1637 FIXME("icon.idCount=%d\n",cifd->idCount);
1639 for (i=0;i<cifd->idCount;i++) {
1640 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1641 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1642 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1643 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1644 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1645 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1646 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1647 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1650 i=0;
1651 /* If we have more than one icon, try to find the best.
1652 * this currently means '32 pixel wide'.
1654 if (cifd->idCount!=1) {
1655 for (i=0;i<cifd->idCount;i++) {
1656 if (cifd->idEntries[i].bWidth == 32)
1657 break;
1659 if (i==cifd->idCount) i=0;
1662 hicon = CreateIconFromResourceEx(
1663 xbuf+cifd->idEntries[i].dwDIBOffset,
1664 cifd->idEntries[i].dwDIBSize,
1665 TRUE, /* is icon */
1666 0x00030000,
1667 cifd->idEntries[i].bWidth,
1668 cifd->idEntries[i].bHeight,
1671 if (!hicon) {
1672 FIXME("CreateIcon failed.\n");
1673 return E_FAIL;
1674 } else {
1675 This->desc.picType = PICTYPE_ICON;
1676 This->desc.u.icon.hicon = hicon;
1677 This->origWidth = cifd->idEntries[i].bWidth;
1678 This->origHeight = cifd->idEntries[i].bHeight;
1679 hdcRef = CreateCompatibleDC(0);
1680 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1681 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1682 DeleteDC(hdcRef);
1683 return S_OK;
1687 static HRESULT OLEPictureImpl_LoadMetafile(OLEPictureImpl *This,
1688 const BYTE *data, ULONG size)
1690 HMETAFILE hmf;
1691 HENHMETAFILE hemf;
1693 /* SetMetaFileBitsEx performs data check on its own */
1694 hmf = SetMetaFileBitsEx(size, data);
1695 if (hmf)
1697 This->desc.picType = PICTYPE_METAFILE;
1698 This->desc.u.wmf.hmeta = hmf;
1699 This->desc.u.wmf.xExt = 0;
1700 This->desc.u.wmf.yExt = 0;
1702 This->origWidth = 0;
1703 This->origHeight = 0;
1704 This->himetricWidth = 0;
1705 This->himetricHeight = 0;
1707 return S_OK;
1710 hemf = SetEnhMetaFileBits(size, data);
1711 if (!hemf) return E_FAIL;
1713 This->desc.picType = PICTYPE_ENHMETAFILE;
1714 This->desc.u.emf.hemf = hemf;
1716 This->origWidth = 0;
1717 This->origHeight = 0;
1718 This->himetricWidth = 0;
1719 This->himetricHeight = 0;
1721 return S_OK;
1724 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1725 const BYTE *data, ULONG size)
1727 APM_HEADER *header = (APM_HEADER *)data;
1728 HRESULT hr;
1730 if (size < sizeof(APM_HEADER))
1731 return E_FAIL;
1732 if (header->key != 0x9ac6cdd7)
1733 return E_FAIL;
1735 if ((hr = OLEPictureImpl_LoadMetafile(This, data + sizeof(APM_HEADER), size - sizeof(*header))) != S_OK)
1736 return hr;
1738 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1739 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1740 return S_OK;
1743 /************************************************************************
1744 * BITMAP FORMAT FLAGS -
1745 * Flags that differentiate between different types of bitmaps.
1748 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1749 #define BITMAP_FORMAT_JPEG 0xd8ff
1750 #define BITMAP_FORMAT_GIF 0x4947
1751 #define BITMAP_FORMAT_PNG 0x5089
1752 #define BITMAP_FORMAT_APM 0xcdd7
1754 /************************************************************************
1755 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1757 * Loads the binary data from the IStream. Starts at current position.
1758 * There appears to be an 2 DWORD header:
1759 * DWORD magic;
1760 * DWORD len;
1762 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1764 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1765 HRESULT hr = E_FAIL;
1766 BOOL headerisdata = FALSE;
1767 BOOL statfailed = FALSE;
1768 ULONG xread, toread;
1769 ULONG headerread;
1770 BYTE *xbuf;
1771 DWORD header[2];
1772 WORD magic;
1773 STATSTG statstg;
1774 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1776 TRACE("(%p,%p)\n",This,pStm);
1778 /****************************************************************************************
1779 * Part 1: Load the data
1781 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1782 * out whether we do.
1784 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1785 * compound file. This may explain most, if not all, of the cases of "no
1786 * header", and the header validation should take this into account.
1787 * At least in Visual Basic 6, resource streams, valid headers are
1788 * header[0] == "lt\0\0",
1789 * header[1] == length_of_stream.
1791 * Also handle streams where we do not have a working "Stat" method by
1792 * reading all data until the end of the stream.
1794 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1795 if (hr) {
1796 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1797 statfailed = TRUE;
1798 /* we will read at least 8 byte ... just right below */
1799 statstg.cbSize.QuadPart = 8;
1802 toread = 0;
1803 headerread = 0;
1804 headerisdata = FALSE;
1805 do {
1806 hr=IStream_Read(pStm,header,8,&xread);
1807 if (hr || xread!=8) {
1808 FIXME("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1809 return hr;
1811 headerread += xread;
1812 xread = 0;
1814 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1815 if (toread != 0 && toread != header[1])
1816 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1817 toread, header[1]);
1818 toread = header[1];
1819 if (toread == 0) break;
1820 } else {
1821 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1822 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1823 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1824 (header[0] == EMR_HEADER) || /* EMF header */
1825 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1826 (header[1]==0)
1827 ) {/* Found start of bitmap data */
1828 headerisdata = TRUE;
1829 if (toread == 0)
1830 toread = statstg.cbSize.QuadPart-8;
1831 else toread -= 8;
1832 xread = 8;
1833 } else {
1834 FIXME("Unknown stream header magic: %08x\n", header[0]);
1835 toread = header[1];
1838 } while (!headerisdata);
1840 if (statfailed) { /* we don't know the size ... read all we get */
1841 int sizeinc = 4096;
1842 int origsize = sizeinc;
1843 ULONG nread = 42;
1845 TRACE("Reading all data from stream.\n");
1846 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1847 if (headerisdata)
1848 memcpy (xbuf, &header, 8);
1849 while (1) {
1850 while (xread < origsize) {
1851 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1852 xread+=nread;
1853 if (hr || !nread)
1854 break;
1856 if (!nread || hr) /* done, or error */
1857 break;
1858 if (xread == origsize) {
1859 origsize += sizeinc;
1860 sizeinc = 2*sizeinc; /* exponential increase */
1861 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1864 if (hr)
1865 TRACE("hr in no-stat loader case is %08x\n", hr);
1866 TRACE("loaded %d bytes.\n", xread);
1867 This->datalen = xread;
1868 This->data = xbuf;
1869 } else {
1870 This->datalen = toread+(headerisdata?8:0);
1871 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1873 if (headerisdata)
1874 memcpy (xbuf, &header, 8);
1876 while (xread < This->datalen) {
1877 ULONG nread;
1878 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1879 xread+=nread;
1880 if (hr || !nread)
1881 break;
1883 if (xread != This->datalen)
1884 FIXME("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1886 if (This->datalen == 0) { /* Marks the "NONE" picture */
1887 This->desc.picType = PICTYPE_NONE;
1888 return S_OK;
1892 /****************************************************************************************
1893 * Part 2: Process the loaded data
1896 magic = xbuf[0] + (xbuf[1]<<8);
1897 This->loadtime_format = magic;
1899 switch (magic) {
1900 case BITMAP_FORMAT_GIF: /* GIF */
1901 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1902 break;
1903 case BITMAP_FORMAT_JPEG: /* JPEG */
1904 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1905 break;
1906 case BITMAP_FORMAT_BMP: /* Bitmap */
1907 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1908 break;
1909 case BITMAP_FORMAT_PNG: /* PNG */
1910 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1911 break;
1912 case BITMAP_FORMAT_APM: /* APM */
1913 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1914 break;
1915 case 0x0000: { /* ICON , first word is dwReserved */
1916 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1917 break;
1919 default:
1921 unsigned int i;
1923 /* let's see if it's a metafile */
1924 hr = OLEPictureImpl_LoadMetafile(This, xbuf, xread);
1925 if (hr == S_OK) break;
1927 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1928 hr=E_FAIL;
1929 for (i=0;i<xread+8;i++) {
1930 if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
1931 else MESSAGE("%02x ",xbuf[i-8]);
1932 if (i % 10 == 9) MESSAGE("\n");
1934 MESSAGE("\n");
1935 break;
1938 This->bIsDirty = FALSE;
1940 /* FIXME: this notify is not really documented */
1941 if (hr==S_OK)
1942 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1943 return hr;
1946 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1948 int iSuccess = 0;
1949 HDC hDC;
1950 BITMAPINFO * pInfoBitmap;
1951 int iNumPaletteEntries;
1952 unsigned char * pPixelData;
1953 BITMAPFILEHEADER * pFileHeader;
1954 BITMAPINFO * pInfoHeader;
1956 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1957 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1959 /* Find out bitmap size and padded length */
1960 hDC = GetDC(0);
1961 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1962 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1964 /* Fetch bitmap palette & pixel data */
1966 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1967 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1969 /* Calculate the total length required for the BMP data */
1970 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1971 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1972 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1973 } else {
1974 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1975 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1976 else
1977 iNumPaletteEntries = 0;
1979 *pLength =
1980 sizeof(BITMAPFILEHEADER) +
1981 sizeof(BITMAPINFOHEADER) +
1982 iNumPaletteEntries * sizeof(RGBQUAD) +
1983 pInfoBitmap->bmiHeader.biSizeImage;
1984 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1986 /* Fill the BITMAPFILEHEADER */
1987 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1988 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1989 pFileHeader->bfSize = *pLength;
1990 pFileHeader->bfOffBits =
1991 sizeof(BITMAPFILEHEADER) +
1992 sizeof(BITMAPINFOHEADER) +
1993 iNumPaletteEntries * sizeof(RGBQUAD);
1995 /* Fill the BITMAPINFOHEADER and the palette data */
1996 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1997 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1998 memcpy(
1999 (unsigned char *)(*ppBuffer) +
2000 sizeof(BITMAPFILEHEADER) +
2001 sizeof(BITMAPINFOHEADER) +
2002 iNumPaletteEntries * sizeof(RGBQUAD),
2003 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2004 iSuccess = 1;
2006 HeapFree(GetProcessHeap(), 0, pPixelData);
2007 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2008 return iSuccess;
2011 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2013 ICONINFO infoIcon;
2014 int iSuccess = 0;
2016 *ppBuffer = NULL; *pLength = 0;
2017 if (GetIconInfo(hIcon, &infoIcon)) {
2018 HDC hDC;
2019 BITMAPINFO * pInfoBitmap;
2020 unsigned char * pIconData = NULL;
2021 unsigned int iDataSize = 0;
2023 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2025 /* Find out icon size */
2026 hDC = GetDC(0);
2027 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2028 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2029 if (1) {
2030 /* Auxiliary pointers */
2031 CURSORICONFILEDIR * pIconDir;
2032 CURSORICONFILEDIRENTRY * pIconEntry;
2033 BITMAPINFOHEADER * pIconBitmapHeader;
2034 unsigned int iOffsetPalette;
2035 unsigned int iOffsetColorData;
2036 unsigned int iOffsetMaskData;
2038 unsigned int iLengthScanLineColor;
2039 unsigned int iLengthScanLineMask;
2040 unsigned int iNumEntriesPalette;
2042 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2043 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2045 FIXME("DEBUG: bitmap size is %d x %d\n",
2046 pInfoBitmap->bmiHeader.biWidth,
2047 pInfoBitmap->bmiHeader.biHeight);
2048 FIXME("DEBUG: bitmap bpp is %d\n",
2049 pInfoBitmap->bmiHeader.biBitCount);
2050 FIXME("DEBUG: bitmap nplanes is %d\n",
2051 pInfoBitmap->bmiHeader.biPlanes);
2052 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2053 pInfoBitmap->bmiHeader.biSizeImage);
2055 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2056 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2057 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2059 /* Fill out the CURSORICONFILEDIR */
2060 pIconDir = (CURSORICONFILEDIR *)pIconData;
2061 pIconDir->idType = 1;
2062 pIconDir->idCount = 1;
2064 /* Fill out the CURSORICONFILEDIRENTRY */
2065 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2066 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2067 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2068 pIconEntry->bColorCount =
2069 (pInfoBitmap->bmiHeader.biBitCount < 8)
2070 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2071 : 0;
2072 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2073 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2074 pIconEntry->dwDIBSize = 0;
2075 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2077 /* Fill out the BITMAPINFOHEADER */
2078 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2079 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2081 /* Find out whether a palette exists for the bitmap */
2082 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2083 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2084 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2085 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2086 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2087 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2088 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2089 iNumEntriesPalette = 3;
2090 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2091 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2092 } else {
2093 iNumEntriesPalette = 0;
2096 /* Add bitmap size and header size to icon data size. */
2097 iOffsetPalette = iDataSize;
2098 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2099 iOffsetColorData = iDataSize;
2100 iDataSize += pIconBitmapHeader->biSizeImage;
2101 iOffsetMaskData = iDataSize;
2102 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2103 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2104 pIconBitmapHeader->biHeight *= 2;
2105 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2106 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2107 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2108 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2110 /* Get the actual bitmap data from the icon bitmap */
2111 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2112 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2113 if (iNumEntriesPalette > 0) {
2114 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2115 iNumEntriesPalette * sizeof(RGBQUAD));
2118 /* Reset all values so that GetDIBits call succeeds */
2119 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2120 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2121 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2123 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2124 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2125 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2127 printf("ERROR: unable to get bitmap mask (error %u)\n",
2128 GetLastError());
2132 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2133 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2135 /* Write out everything produced so far to the stream */
2136 *ppBuffer = pIconData; *pLength = iDataSize;
2137 iSuccess = 1;
2138 } else {
2140 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2141 GetLastError());
2145 Remarks (from MSDN entry on GetIconInfo):
2147 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2148 members of ICONINFO. The calling application must manage
2149 these bitmaps and delete them when they are no longer
2150 necessary.
2152 if (hDC) ReleaseDC(0, hDC);
2153 DeleteObject(infoIcon.hbmMask);
2154 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2155 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2156 } else {
2157 printf("ERROR: Unable to get icon information (error %u)\n",
2158 GetLastError());
2160 return iSuccess;
2163 static HRESULT WINAPI OLEPictureImpl_Save(
2164 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2166 HRESULT hResult = E_NOTIMPL;
2167 void * pIconData;
2168 unsigned int iDataSize;
2169 ULONG dummy;
2170 int iSerializeResult = 0;
2171 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2173 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2175 switch (This->desc.picType) {
2176 case PICTYPE_ICON:
2177 if (This->bIsDirty || !This->data) {
2178 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2179 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2180 hResult = E_FAIL;
2181 break;
2183 HeapFree(GetProcessHeap(), 0, This->data);
2184 This->data = pIconData;
2185 This->datalen = iDataSize;
2187 if (This->loadtime_magic != 0xdeadbeef) {
2188 DWORD header[2];
2190 header[0] = This->loadtime_magic;
2191 header[1] = This->datalen;
2192 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2194 IStream_Write(pStm, This->data, This->datalen, &dummy);
2196 hResult = S_OK;
2197 break;
2198 case PICTYPE_BITMAP:
2199 if (This->bIsDirty) {
2200 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2201 case BITMAP_FORMAT_BMP:
2202 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2203 break;
2204 case BITMAP_FORMAT_JPEG:
2205 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2206 break;
2207 case BITMAP_FORMAT_GIF:
2208 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2209 break;
2210 case BITMAP_FORMAT_PNG:
2211 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2212 break;
2213 default:
2214 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2215 break;
2217 if (iSerializeResult) {
2219 if (This->loadtime_magic != 0xdeadbeef) {
2221 if (1) {
2222 DWORD header[2];
2224 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2225 header[1] = iDataSize;
2226 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2228 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2230 HeapFree(GetProcessHeap(), 0, This->data);
2231 This->data = pIconData;
2232 This->datalen = iDataSize;
2233 hResult = S_OK;
2235 } else {
2237 if (This->loadtime_magic != 0xdeadbeef) {
2239 if (1) {
2240 DWORD header[2];
2242 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2243 header[1] = This->datalen;
2244 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2246 IStream_Write(pStm, This->data, This->datalen, &dummy);
2247 hResult = S_OK;
2249 break;
2250 case PICTYPE_METAFILE:
2251 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2252 break;
2253 case PICTYPE_ENHMETAFILE:
2254 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2255 break;
2256 default:
2257 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2258 break;
2260 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2261 return hResult;
2264 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2265 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2267 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2268 FIXME("(%p,%p),stub!\n",This,pcbSize);
2269 return E_NOTIMPL;
2273 /************************************************************************
2274 * IDispatch
2277 /************************************************************************
2278 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2280 * See Windows documentation for more details on IUnknown methods.
2282 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2283 IDispatch* iface,
2284 REFIID riid,
2285 VOID** ppvoid)
2287 OLEPictureImpl *This = impl_from_IDispatch(iface);
2289 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2292 /************************************************************************
2293 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2295 * See Windows documentation for more details on IUnknown methods.
2297 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2298 IDispatch* iface)
2300 OLEPictureImpl *This = impl_from_IDispatch(iface);
2302 return IPicture_AddRef((IPicture *)This);
2305 /************************************************************************
2306 * OLEPictureImpl_IDispatch_Release (IUnknown)
2308 * See Windows documentation for more details on IUnknown methods.
2310 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2311 IDispatch* iface)
2313 OLEPictureImpl *This = impl_from_IDispatch(iface);
2315 return IPicture_Release((IPicture *)This);
2318 /************************************************************************
2319 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2321 * See Windows documentation for more details on IDispatch methods.
2323 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2324 IDispatch* iface,
2325 unsigned int* pctinfo)
2327 TRACE("(%p)\n", pctinfo);
2329 *pctinfo = 1;
2331 return S_OK;
2334 /************************************************************************
2335 * OLEPictureImpl_GetTypeInfo (IDispatch)
2337 * See Windows documentation for more details on IDispatch methods.
2339 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2340 IDispatch* iface,
2341 UINT iTInfo,
2342 LCID lcid,
2343 ITypeInfo** ppTInfo)
2345 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2346 ITypeLib *tl;
2347 HRESULT hres;
2349 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2351 if (iTInfo != 0)
2352 return E_FAIL;
2354 hres = LoadTypeLib(stdole2tlb, &tl);
2355 if (FAILED(hres))
2357 ERR("Could not load stdole2.tlb\n");
2358 return hres;
2361 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2362 if (FAILED(hres))
2363 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2365 return hres;
2368 /************************************************************************
2369 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2371 * See Windows documentation for more details on IDispatch methods.
2373 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2374 IDispatch* iface,
2375 REFIID riid,
2376 LPOLESTR* rgszNames,
2377 UINT cNames,
2378 LCID lcid,
2379 DISPID* rgDispId)
2381 ITypeInfo * pTInfo;
2382 HRESULT hres;
2384 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2385 rgszNames, cNames, (int)lcid, rgDispId);
2387 if (cNames == 0)
2389 return E_INVALIDARG;
2391 else
2393 /* retrieve type information */
2394 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2396 if (FAILED(hres))
2398 ERR("GetTypeInfo failed.\n");
2399 return hres;
2402 /* convert names to DISPIDs */
2403 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2404 ITypeInfo_Release(pTInfo);
2406 return hres;
2410 /************************************************************************
2411 * OLEPictureImpl_Invoke (IDispatch)
2413 * See Windows documentation for more details on IDispatch methods.
2415 static HRESULT WINAPI OLEPictureImpl_Invoke(
2416 IDispatch* iface,
2417 DISPID dispIdMember,
2418 REFIID riid,
2419 LCID lcid,
2420 WORD wFlags,
2421 DISPPARAMS* pDispParams,
2422 VARIANT* pVarResult,
2423 EXCEPINFO* pExepInfo,
2424 UINT* puArgErr)
2426 OLEPictureImpl *This = impl_from_IDispatch(iface);
2428 /* validate parameters */
2430 if (!IsEqualIID(riid, &IID_NULL))
2432 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2433 return DISP_E_UNKNOWNNAME;
2436 if (!pDispParams)
2438 ERR("null pDispParams not allowed\n");
2439 return DISP_E_PARAMNOTOPTIONAL;
2442 if (wFlags & DISPATCH_PROPERTYGET)
2444 if (pDispParams->cArgs != 0)
2446 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2447 return DISP_E_BADPARAMCOUNT;
2449 if (!pVarResult)
2451 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2452 return DISP_E_PARAMNOTOPTIONAL;
2455 else if (wFlags & DISPATCH_PROPERTYPUT)
2457 if (pDispParams->cArgs != 1)
2459 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2460 return DISP_E_BADPARAMCOUNT;
2464 switch (dispIdMember)
2466 case DISPID_PICT_HANDLE:
2467 if (wFlags & DISPATCH_PROPERTYGET)
2469 TRACE("DISPID_PICT_HANDLE\n");
2470 V_VT(pVarResult) = VT_I4;
2471 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2473 break;
2474 case DISPID_PICT_HPAL:
2475 if (wFlags & DISPATCH_PROPERTYGET)
2477 TRACE("DISPID_PICT_HPAL\n");
2478 V_VT(pVarResult) = VT_I4;
2479 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2481 else if (wFlags & DISPATCH_PROPERTYPUT)
2483 VARIANTARG vararg;
2484 HRESULT hr;
2485 TRACE("DISPID_PICT_HPAL\n");
2487 VariantInit(&vararg);
2488 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2489 if (FAILED(hr))
2490 return hr;
2492 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2494 VariantClear(&vararg);
2495 return hr;
2497 break;
2498 case DISPID_PICT_TYPE:
2499 if (wFlags & DISPATCH_PROPERTYGET)
2501 TRACE("DISPID_PICT_TYPE\n");
2502 V_VT(pVarResult) = VT_I2;
2503 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2505 break;
2506 case DISPID_PICT_WIDTH:
2507 if (wFlags & DISPATCH_PROPERTYGET)
2509 TRACE("DISPID_PICT_WIDTH\n");
2510 V_VT(pVarResult) = VT_I4;
2511 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2513 break;
2514 case DISPID_PICT_HEIGHT:
2515 if (wFlags & DISPATCH_PROPERTYGET)
2517 TRACE("DISPID_PICT_HEIGHT\n");
2518 V_VT(pVarResult) = VT_I4;
2519 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2521 break;
2524 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2525 return DISP_E_MEMBERNOTFOUND;
2529 static const IPictureVtbl OLEPictureImpl_VTable =
2531 OLEPictureImpl_QueryInterface,
2532 OLEPictureImpl_AddRef,
2533 OLEPictureImpl_Release,
2534 OLEPictureImpl_get_Handle,
2535 OLEPictureImpl_get_hPal,
2536 OLEPictureImpl_get_Type,
2537 OLEPictureImpl_get_Width,
2538 OLEPictureImpl_get_Height,
2539 OLEPictureImpl_Render,
2540 OLEPictureImpl_set_hPal,
2541 OLEPictureImpl_get_CurDC,
2542 OLEPictureImpl_SelectPicture,
2543 OLEPictureImpl_get_KeepOriginalFormat,
2544 OLEPictureImpl_put_KeepOriginalFormat,
2545 OLEPictureImpl_PictureChanged,
2546 OLEPictureImpl_SaveAsFile,
2547 OLEPictureImpl_get_Attributes
2550 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2552 OLEPictureImpl_IDispatch_QueryInterface,
2553 OLEPictureImpl_IDispatch_AddRef,
2554 OLEPictureImpl_IDispatch_Release,
2555 OLEPictureImpl_GetTypeInfoCount,
2556 OLEPictureImpl_GetTypeInfo,
2557 OLEPictureImpl_GetIDsOfNames,
2558 OLEPictureImpl_Invoke
2561 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2563 OLEPictureImpl_IPersistStream_QueryInterface,
2564 OLEPictureImpl_IPersistStream_AddRef,
2565 OLEPictureImpl_IPersistStream_Release,
2566 OLEPictureImpl_GetClassID,
2567 OLEPictureImpl_IsDirty,
2568 OLEPictureImpl_Load,
2569 OLEPictureImpl_Save,
2570 OLEPictureImpl_GetSizeMax
2573 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2575 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2576 OLEPictureImpl_IConnectionPointContainer_AddRef,
2577 OLEPictureImpl_IConnectionPointContainer_Release,
2578 OLEPictureImpl_EnumConnectionPoints,
2579 OLEPictureImpl_FindConnectionPoint
2582 /***********************************************************************
2583 * OleCreatePictureIndirect (OLEAUT32.419)
2585 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2586 BOOL fOwn, LPVOID *ppvObj )
2588 OLEPictureImpl* newPict = NULL;
2589 HRESULT hr = S_OK;
2591 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2594 * Sanity check
2596 if (ppvObj==0)
2597 return E_POINTER;
2599 *ppvObj = NULL;
2602 * Try to construct a new instance of the class.
2604 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2606 if (newPict == NULL)
2607 return E_OUTOFMEMORY;
2610 * Make sure it supports the interface required by the caller.
2612 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2615 * Release the reference obtained in the constructor. If
2616 * the QueryInterface was unsuccessful, it will free the class.
2618 IPicture_Release((IPicture*)newPict);
2620 return hr;
2624 /***********************************************************************
2625 * OleLoadPicture (OLEAUT32.418)
2627 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2628 REFIID riid, LPVOID *ppvObj )
2630 LPPERSISTSTREAM ps;
2631 IPicture *newpic;
2632 HRESULT hr;
2634 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2635 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2637 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2638 if (hr)
2639 return hr;
2640 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2641 if (hr) {
2642 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2643 IPicture_Release(newpic);
2644 *ppvObj = NULL;
2645 return hr;
2647 IPersistStream_Load(ps,lpstream);
2648 IPersistStream_Release(ps);
2649 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2650 if (hr)
2651 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2652 IPicture_Release(newpic);
2653 return hr;
2656 /***********************************************************************
2657 * OleLoadPictureEx (OLEAUT32.401)
2659 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2660 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2662 LPPERSISTSTREAM ps;
2663 IPicture *newpic;
2664 HRESULT hr;
2666 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2667 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2669 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2670 if (hr)
2671 return hr;
2672 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2673 if (hr) {
2674 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2675 IPicture_Release(newpic);
2676 *ppvObj = NULL;
2677 return hr;
2679 IPersistStream_Load(ps,lpstream);
2680 IPersistStream_Release(ps);
2681 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2682 if (hr)
2683 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2684 IPicture_Release(newpic);
2685 return hr;
2688 /***********************************************************************
2689 * OleLoadPicturePath (OLEAUT32.424)
2691 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2692 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2693 LPVOID *ppvRet )
2695 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2696 IPicture *ipicture;
2697 HANDLE hFile;
2698 DWORD dwFileSize;
2699 HGLOBAL hGlobal = NULL;
2700 DWORD dwBytesRead = 0;
2701 IStream *stream;
2702 BOOL bRead;
2703 IPersistStream *pStream;
2704 HRESULT hRes;
2706 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2707 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2708 debugstr_guid(riid), ppvRet);
2710 if (!ppvRet) return E_POINTER;
2712 if (strncmpW(szURLorPath, file, 7) == 0) {
2713 szURLorPath += 7;
2715 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2716 0, NULL);
2717 if (hFile == INVALID_HANDLE_VALUE)
2718 return E_UNEXPECTED;
2720 dwFileSize = GetFileSize(hFile, NULL);
2721 if (dwFileSize != INVALID_FILE_SIZE )
2723 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2724 if ( hGlobal)
2726 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2727 if (!bRead)
2729 GlobalFree(hGlobal);
2730 hGlobal = 0;
2734 CloseHandle(hFile);
2736 if (!hGlobal)
2737 return E_UNEXPECTED;
2739 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2740 if (FAILED(hRes))
2742 GlobalFree(hGlobal);
2743 return hRes;
2745 } else {
2746 IMoniker *pmnk;
2747 IBindCtx *pbc;
2749 hRes = CreateBindCtx(0, &pbc);
2750 if (SUCCEEDED(hRes))
2752 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2753 if (SUCCEEDED(hRes))
2755 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2756 IMoniker_Release(pmnk);
2758 IBindCtx_Release(pbc);
2760 if (FAILED(hRes))
2761 return hRes;
2764 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2765 &IID_IPicture, (LPVOID*)&ipicture);
2766 if (hRes != S_OK) {
2767 IStream_Release(stream);
2768 return hRes;
2771 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2772 if (hRes) {
2773 IStream_Release(stream);
2774 IPicture_Release(ipicture);
2775 return hRes;
2778 hRes = IPersistStream_Load(pStream, stream);
2779 IPersistStream_Release(pStream);
2780 IStream_Release(stream);
2782 if (hRes) {
2783 IPicture_Release(ipicture);
2784 return hRes;
2787 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2788 if (hRes)
2789 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2791 IPicture_Release(ipicture);
2792 return hRes;
2795 /*******************************************************************************
2796 * StdPic ClassFactory
2798 typedef struct
2800 /* IUnknown fields */
2801 const IClassFactoryVtbl *lpVtbl;
2802 LONG ref;
2803 } IClassFactoryImpl;
2805 static HRESULT WINAPI
2806 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2807 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2809 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2810 return E_NOINTERFACE;
2813 static ULONG WINAPI
2814 SPCF_AddRef(LPCLASSFACTORY iface) {
2815 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2816 return InterlockedIncrement(&This->ref);
2819 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2820 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2821 /* static class, won't be freed */
2822 return InterlockedDecrement(&This->ref);
2825 static HRESULT WINAPI SPCF_CreateInstance(
2826 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2828 /* Creates an uninitialized picture */
2829 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2833 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2834 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2835 FIXME("(%p)->(%d),stub!\n",This,dolock);
2836 return S_OK;
2839 static const IClassFactoryVtbl SPCF_Vtbl = {
2840 SPCF_QueryInterface,
2841 SPCF_AddRef,
2842 SPCF_Release,
2843 SPCF_CreateInstance,
2844 SPCF_LockServer
2846 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2848 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }