save old text color during a call of DrawCaptionTempW
[wine/kumbayo.git] / dlls / oleaut32 / olepicture.c
blob8a1c99b204e68dd07e98b163af41bbab02e5b7bd
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, altough 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 /* Must be before wine includes, the header has things conflicting with
49 * WINE headers.
51 #define COBJMACROS
52 #define NONAMELESSUNION
53 #define NONAMELESSSTRUCT
55 #include "winerror.h"
56 #include "windef.h"
57 #include "winbase.h"
58 #include "wingdi.h"
59 #include "winuser.h"
60 #include "ole2.h"
61 #include "olectl.h"
62 #include "oleauto.h"
63 #include "connpt.h"
64 #include "urlmon.h"
65 #include "wine/debug.h"
66 #include "wine/unicode.h"
68 #include "wine/wingdi16.h"
70 #ifdef SONAME_LIBJPEG
71 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
72 #define XMD_H
73 #define UINT8 JPEG_UINT8
74 #define UINT16 JPEG_UINT16
75 #undef FAR
76 #define boolean jpeg_boolean
77 # include <jpeglib.h>
78 #undef jpeg_boolean
79 #undef UINT16
80 #endif
82 #ifdef HAVE_PNG_H
83 #undef FAR
84 #include <png.h>
85 #endif
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 memcpy(&newObject->desc, pictDesc, sizeof(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);
512 return;
515 /************************************************************************
516 * OLEPictureImpl_get_Handle
518 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
519 OLE_HANDLE *phandle)
521 OLEPictureImpl *This = (OLEPictureImpl *)iface;
522 TRACE("(%p)->(%p)\n", This, phandle);
523 switch(This->desc.picType) {
524 case PICTYPE_NONE:
525 case PICTYPE_UNINITIALIZED:
526 *phandle = 0;
527 break;
528 case PICTYPE_BITMAP:
529 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
530 break;
531 case PICTYPE_METAFILE:
532 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
533 break;
534 case PICTYPE_ICON:
535 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
536 break;
537 case PICTYPE_ENHMETAFILE:
538 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
539 break;
540 default:
541 FIXME("Unimplemented type %d\n", This->desc.picType);
542 return E_NOTIMPL;
544 TRACE("returning handle %08x\n", *phandle);
545 return S_OK;
548 /************************************************************************
549 * OLEPictureImpl_get_hPal
551 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
552 OLE_HANDLE *phandle)
554 OLEPictureImpl *This = (OLEPictureImpl *)iface;
555 HRESULT hres;
556 TRACE("(%p)->(%p)\n", This, phandle);
558 if (!phandle)
559 return E_POINTER;
561 switch (This->desc.picType) {
562 case (UINT)PICTYPE_UNINITIALIZED:
563 case PICTYPE_NONE:
564 *phandle = 0;
565 hres = S_FALSE;
566 break;
567 case PICTYPE_BITMAP:
568 *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
569 hres = S_OK;
570 break;
571 case PICTYPE_METAFILE:
572 hres = E_FAIL;
573 break;
574 case PICTYPE_ICON:
575 case PICTYPE_ENHMETAFILE:
576 default:
577 FIXME("unimplemented for type %d. Returning 0 palette.\n",
578 This->desc.picType);
579 *phandle = 0;
580 hres = S_OK;
583 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
584 return hres;
587 /************************************************************************
588 * OLEPictureImpl_get_Type
590 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
591 short *ptype)
593 OLEPictureImpl *This = (OLEPictureImpl *)iface;
594 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
595 *ptype = This->desc.picType;
596 return S_OK;
599 /************************************************************************
600 * OLEPictureImpl_get_Width
602 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
603 OLE_XSIZE_HIMETRIC *pwidth)
605 OLEPictureImpl *This = (OLEPictureImpl *)iface;
606 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
607 *pwidth = This->himetricWidth;
608 return S_OK;
611 /************************************************************************
612 * OLEPictureImpl_get_Height
614 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
615 OLE_YSIZE_HIMETRIC *pheight)
617 OLEPictureImpl *This = (OLEPictureImpl *)iface;
618 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
619 *pheight = This->himetricHeight;
620 return S_OK;
623 /************************************************************************
624 * OLEPictureImpl_Render
626 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
627 LONG x, LONG y, LONG cx, LONG cy,
628 OLE_XPOS_HIMETRIC xSrc,
629 OLE_YPOS_HIMETRIC ySrc,
630 OLE_XSIZE_HIMETRIC cxSrc,
631 OLE_YSIZE_HIMETRIC cySrc,
632 LPCRECT prcWBounds)
634 OLEPictureImpl *This = (OLEPictureImpl *)iface;
635 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
636 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
637 if(prcWBounds)
638 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
639 prcWBounds->right, prcWBounds->bottom);
642 * While the documentation suggests this to be here (or after rendering?)
643 * it does cause an endless recursion in my sample app. -MM 20010804
644 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
647 switch(This->desc.picType) {
648 case PICTYPE_BITMAP:
650 HBITMAP hbmpOld;
651 HDC hdcBmp;
653 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
654 NB y-axis gets flipped */
656 hdcBmp = CreateCompatibleDC(0);
657 SetMapMode(hdcBmp, MM_ANISOTROPIC);
658 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
659 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
660 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
661 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
663 if (This->hbmMask) {
664 HDC hdcMask = CreateCompatibleDC(0);
665 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
667 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
669 SetMapMode(hdcMask, MM_ANISOTROPIC);
670 SetWindowOrgEx(hdcMask, 0, 0, NULL);
671 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
672 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
673 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
675 SetBkColor(hdc, RGB(255, 255, 255));
676 SetTextColor(hdc, RGB(0, 0, 0));
677 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
678 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
680 SelectObject(hdcMask, hOldbm);
681 DeleteDC(hdcMask);
682 } else {
683 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
684 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
687 SelectObject(hdcBmp, hbmpOld);
688 DeleteDC(hdcBmp);
690 break;
691 case PICTYPE_ICON:
692 FIXME("Not quite correct implementation of rendering icons...\n");
693 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
694 break;
696 case PICTYPE_METAFILE:
698 POINT prevOrg;
699 SIZE prevExt;
700 int oldmode;
702 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
703 SetViewportOrgEx(hdc, x, y, &prevOrg);
704 SetViewportExtEx(hdc, cx, cy, &prevExt);
706 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
707 ERR("PlayMetaFile failed!\n");
709 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
710 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
711 SetMapMode(hdc, oldmode);
712 break;
715 case PICTYPE_ENHMETAFILE:
717 RECT rc = { x, y, x + cx, y + cy };
718 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
719 break;
722 default:
723 FIXME("type %d not implemented\n", This->desc.picType);
724 return E_NOTIMPL;
726 return S_OK;
729 /************************************************************************
730 * OLEPictureImpl_set_hPal
732 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
733 OLE_HANDLE hpal)
735 OLEPictureImpl *This = (OLEPictureImpl *)iface;
736 FIXME("(%p)->(%08x): stub\n", This, hpal);
737 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
738 return E_NOTIMPL;
741 /************************************************************************
742 * OLEPictureImpl_get_CurDC
744 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
745 HDC *phdc)
747 OLEPictureImpl *This = (OLEPictureImpl *)iface;
748 TRACE("(%p), returning %p\n", This, This->hDCCur);
749 if (phdc) *phdc = This->hDCCur;
750 return S_OK;
753 /************************************************************************
754 * OLEPictureImpl_SelectPicture
756 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
757 HDC hdcIn,
758 HDC *phdcOut,
759 OLE_HANDLE *phbmpOut)
761 OLEPictureImpl *This = (OLEPictureImpl *)iface;
762 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
763 if (This->desc.picType == PICTYPE_BITMAP) {
764 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
766 if (phdcOut)
767 *phdcOut = This->hDCCur;
768 This->hDCCur = hdcIn;
769 if (phbmpOut)
770 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
771 return S_OK;
772 } else {
773 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
774 return E_FAIL;
778 /************************************************************************
779 * OLEPictureImpl_get_KeepOriginalFormat
781 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
782 BOOL *pfKeep)
784 OLEPictureImpl *This = (OLEPictureImpl *)iface;
785 TRACE("(%p)->(%p)\n", This, pfKeep);
786 if (!pfKeep)
787 return E_POINTER;
788 *pfKeep = This->keepOrigFormat;
789 return S_OK;
792 /************************************************************************
793 * OLEPictureImpl_put_KeepOriginalFormat
795 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
796 BOOL keep)
798 OLEPictureImpl *This = (OLEPictureImpl *)iface;
799 TRACE("(%p)->(%d)\n", This, keep);
800 This->keepOrigFormat = keep;
801 /* FIXME: what DISPID notification here? */
802 return S_OK;
805 /************************************************************************
806 * OLEPictureImpl_PictureChanged
808 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
810 OLEPictureImpl *This = (OLEPictureImpl *)iface;
811 TRACE("(%p)->()\n", This);
812 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
813 This->bIsDirty = TRUE;
814 return S_OK;
817 /************************************************************************
818 * OLEPictureImpl_SaveAsFile
820 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
821 IStream *pstream,
822 BOOL SaveMemCopy,
823 LONG *pcbSize)
825 OLEPictureImpl *This = (OLEPictureImpl *)iface;
826 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
827 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
830 /************************************************************************
831 * OLEPictureImpl_get_Attributes
833 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
834 DWORD *pdwAttr)
836 OLEPictureImpl *This = (OLEPictureImpl *)iface;
837 TRACE("(%p)->(%p).\n", This, pdwAttr);
838 *pdwAttr = 0;
839 switch (This->desc.picType) {
840 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
841 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
842 case PICTYPE_ENHMETAFILE: /* fall through */
843 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
844 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
846 return S_OK;
850 /************************************************************************
851 * IConnectionPointContainer
853 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
854 IConnectionPointContainer* iface,
855 REFIID riid,
856 VOID** ppvoid)
858 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
860 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
863 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
864 IConnectionPointContainer* iface)
866 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
868 return IPicture_AddRef((IPicture *)This);
871 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
872 IConnectionPointContainer* iface)
874 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
876 return IPicture_Release((IPicture *)This);
879 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
880 IConnectionPointContainer* iface,
881 IEnumConnectionPoints** ppEnum)
883 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
885 FIXME("(%p,%p), stub!\n",This,ppEnum);
886 return E_NOTIMPL;
889 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
890 IConnectionPointContainer* iface,
891 REFIID riid,
892 IConnectionPoint **ppCP)
894 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
895 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
896 if (!ppCP)
897 return E_POINTER;
898 *ppCP = NULL;
899 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
900 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
901 FIXME("no connection point for %s\n",debugstr_guid(riid));
902 return CONNECT_E_NOCONNECTION;
906 /************************************************************************
907 * IPersistStream
910 /************************************************************************
911 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
913 * See Windows documentation for more details on IUnknown methods.
915 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
916 IPersistStream* iface,
917 REFIID riid,
918 VOID** ppvoid)
920 OLEPictureImpl *This = impl_from_IPersistStream(iface);
922 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
925 /************************************************************************
926 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
928 * See Windows documentation for more details on IUnknown methods.
930 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
931 IPersistStream* iface)
933 OLEPictureImpl *This = impl_from_IPersistStream(iface);
935 return IPicture_AddRef((IPicture *)This);
938 /************************************************************************
939 * OLEPictureImpl_IPersistStream_Release (IUnknown)
941 * See Windows documentation for more details on IUnknown methods.
943 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
944 IPersistStream* iface)
946 OLEPictureImpl *This = impl_from_IPersistStream(iface);
948 return IPicture_Release((IPicture *)This);
951 /************************************************************************
952 * OLEPictureImpl_IPersistStream_GetClassID
954 static HRESULT WINAPI OLEPictureImpl_GetClassID(
955 IPersistStream* iface,CLSID* pClassID)
957 TRACE("(%p)\n", pClassID);
958 memcpy(pClassID, &CLSID_StdPicture, sizeof(*pClassID));
959 return S_OK;
962 /************************************************************************
963 * OLEPictureImpl_IPersistStream_IsDirty
965 static HRESULT WINAPI OLEPictureImpl_IsDirty(
966 IPersistStream* iface)
968 OLEPictureImpl *This = impl_from_IPersistStream(iface);
969 FIXME("(%p),stub!\n",This);
970 return E_NOTIMPL;
973 #ifdef SONAME_LIBJPEG
975 static void *libjpeg_handle;
976 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
977 MAKE_FUNCPTR(jpeg_std_error);
978 MAKE_FUNCPTR(jpeg_CreateDecompress);
979 MAKE_FUNCPTR(jpeg_read_header);
980 MAKE_FUNCPTR(jpeg_start_decompress);
981 MAKE_FUNCPTR(jpeg_read_scanlines);
982 MAKE_FUNCPTR(jpeg_finish_decompress);
983 MAKE_FUNCPTR(jpeg_destroy_decompress);
984 #undef MAKE_FUNCPTR
986 static void *load_libjpeg(void)
988 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
990 #define LOAD_FUNCPTR(f) \
991 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
992 libjpeg_handle = NULL; \
993 return NULL; \
996 LOAD_FUNCPTR(jpeg_std_error);
997 LOAD_FUNCPTR(jpeg_CreateDecompress);
998 LOAD_FUNCPTR(jpeg_read_header);
999 LOAD_FUNCPTR(jpeg_start_decompress);
1000 LOAD_FUNCPTR(jpeg_read_scanlines);
1001 LOAD_FUNCPTR(jpeg_finish_decompress);
1002 LOAD_FUNCPTR(jpeg_destroy_decompress);
1003 #undef LOAD_FUNCPTR
1005 return libjpeg_handle;
1008 /* for the jpeg decompressor source manager. */
1009 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1011 static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1012 ERR("(), should not get here.\n");
1013 return FALSE;
1016 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1017 TRACE("Skipping %ld bytes...\n", num_bytes);
1018 cinfo->src->next_input_byte += num_bytes;
1019 cinfo->src->bytes_in_buffer -= num_bytes;
1022 static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1023 ERR("(desired=%d), should not get here.\n",desired);
1024 return FALSE;
1026 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1027 #endif /* SONAME_LIBJPEG */
1029 struct gifdata {
1030 unsigned char *data;
1031 unsigned int curoff;
1032 unsigned int len;
1035 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1036 struct gifdata *gd = (struct gifdata*)gif->UserData;
1038 if (len+gd->curoff > gd->len) {
1039 FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1040 len = gd->len - gd->curoff;
1042 memcpy(data, gd->data+gd->curoff, len);
1043 gd->curoff += len;
1044 return len;
1048 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1050 struct gifdata gd;
1051 GifFileType *gif;
1052 BITMAPINFO *bmi;
1053 HDC hdcref;
1054 LPBYTE bytes;
1055 int i,j,ret;
1056 GifImageDesc *gid;
1057 SavedImage *si;
1058 ColorMapObject *cm;
1059 int transparent = -1;
1060 ExtensionBlock *eb;
1061 int padding;
1063 gd.data = xbuf;
1064 gd.curoff = 0;
1065 gd.len = xread;
1066 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1067 ret = DGifSlurp(gif);
1068 if (ret == GIF_ERROR) {
1069 FIXME("Failed reading GIF using libgif.\n");
1070 return E_FAIL;
1072 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1073 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1074 TRACE("imgcnt %d\n", gif->ImageCount);
1075 if (gif->ImageCount<1) {
1076 FIXME("GIF stream does not have images inside?\n");
1077 return E_FAIL;
1079 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1080 gif->Image.Width, gif->Image.Height,
1081 gif->Image.Left, gif->Image.Top,
1082 gif->Image.Interlace
1084 /* */
1085 padding = (gif->SWidth+3) & ~3;
1086 si = gif->SavedImages+0;
1087 gid = &(si->ImageDesc);
1088 cm = gid->ColorMap;
1089 if (!cm) cm = gif->SColorMap;
1090 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1091 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1093 /* look for the transparent color extension */
1094 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1095 eb = si->ExtensionBlocks + i;
1096 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1097 if ((eb->Bytes[0] & 1) == 1) {
1098 transparent = (unsigned char)eb->Bytes[3];
1103 for (i = 0; i < cm->ColorCount; i++) {
1104 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1105 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1106 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1107 if (i == transparent) {
1108 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1109 bmi->bmiColors[i].rgbGreen,
1110 bmi->bmiColors[i].rgbBlue);
1114 /* Map to in picture coordinates */
1115 for (i = 0, j = 0; i < gid->Height; i++) {
1116 if (gif->Image.Interlace) {
1117 memcpy(
1118 bytes + (gid->Top + j) * padding + gid->Left,
1119 si->RasterBits + i * gid->Width,
1120 gid->Width);
1122 /* Lower bits of interlaced counter encode current interlace */
1123 if (j & 1) j += 2; /* Currently filling odd rows */
1124 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1125 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1127 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1128 /* End of current interlace, go to next interlace */
1129 if (j & 2) j = 1; /* Next iteration fills odd rows */
1130 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1131 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1133 } else {
1134 memcpy(
1135 bytes + (gid->Top + i) * padding + gid->Left,
1136 si->RasterBits + i * gid->Width,
1137 gid->Width);
1141 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1142 bmi->bmiHeader.biWidth = gif->SWidth;
1143 bmi->bmiHeader.biHeight = -gif->SHeight;
1144 bmi->bmiHeader.biPlanes = 1;
1145 bmi->bmiHeader.biBitCount = 8;
1146 bmi->bmiHeader.biCompression = BI_RGB;
1147 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1148 bmi->bmiHeader.biXPelsPerMeter = 0;
1149 bmi->bmiHeader.biYPelsPerMeter = 0;
1150 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1151 bmi->bmiHeader.biClrImportant = 0;
1153 hdcref = GetDC(0);
1154 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1155 hdcref,
1156 &bmi->bmiHeader,
1157 CBM_INIT,
1158 bytes,
1159 bmi,
1160 DIB_RGB_COLORS
1163 if (transparent > -1) {
1164 /* Create the Mask */
1165 HDC hdc = CreateCompatibleDC(0);
1166 HDC hdcMask = CreateCompatibleDC(0);
1167 HBITMAP hOldbitmap;
1168 HBITMAP hOldbitmapmask;
1170 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1171 HBITMAP hTempMask;
1173 This->hbmXor = CreateDIBitmap(
1174 hdcref,
1175 &bmi->bmiHeader,
1176 CBM_INIT,
1177 bytes,
1178 bmi,
1179 DIB_RGB_COLORS
1182 bmi->bmiColors[0].rgbRed = 0;
1183 bmi->bmiColors[0].rgbGreen = 0;
1184 bmi->bmiColors[0].rgbBlue = 0;
1185 bmi->bmiColors[1].rgbRed = 255;
1186 bmi->bmiColors[1].rgbGreen = 255;
1187 bmi->bmiColors[1].rgbBlue = 255;
1189 bmi->bmiHeader.biBitCount = 1;
1190 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1191 bmi->bmiHeader.biClrUsed = 2;
1193 for (i = 0; i < gif->SHeight; i++) {
1194 unsigned char * colorPointer = bytes + padding * i;
1195 unsigned char * monoPointer = bytes + monopadding * i;
1196 for (j = 0; j < gif->SWidth; j++) {
1197 unsigned char pixel = colorPointer[j];
1198 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1199 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1202 hdcref = GetDC(0);
1203 hTempMask = CreateDIBitmap(
1204 hdcref,
1205 &bmi->bmiHeader,
1206 CBM_INIT,
1207 bytes,
1208 bmi,
1209 DIB_RGB_COLORS
1211 DeleteDC(hdcref);
1213 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1214 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1215 hOldbitmap = SelectObject(hdc, hTempMask);
1216 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1218 SetBkColor(hdc, RGB(255, 255, 255));
1219 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1221 /* We no longer need the original bitmap, so we apply the first
1222 transformation with the mask to speed up the rendering */
1223 SelectObject(hdc, This->hbmXor);
1224 SetBkColor(hdc, RGB(0,0,0));
1225 SetTextColor(hdc, RGB(255,255,255));
1226 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1227 hdcMask, 0, 0, SRCAND);
1229 SelectObject(hdc, hOldbitmap);
1230 SelectObject(hdcMask, hOldbitmapmask);
1231 DeleteDC(hdcMask);
1232 DeleteDC(hdc);
1233 DeleteObject(hTempMask);
1236 DeleteDC(hdcref);
1237 This->desc.picType = PICTYPE_BITMAP;
1238 OLEPictureImpl_SetBitmap(This);
1239 DGifCloseFile(gif);
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, (size_t) 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 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1746 * Loads the binary data from the IStream. Starts at current position.
1747 * There appears to be an 2 DWORD header:
1748 * DWORD magic;
1749 * DWORD len;
1751 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1753 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1754 HRESULT hr = E_FAIL;
1755 BOOL headerisdata = FALSE;
1756 BOOL statfailed = FALSE;
1757 ULONG xread, toread;
1758 ULONG headerread;
1759 BYTE *xbuf;
1760 DWORD header[2];
1761 WORD magic;
1762 STATSTG statstg;
1763 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1765 TRACE("(%p,%p)\n",This,pStm);
1767 /****************************************************************************************
1768 * Part 1: Load the data
1770 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1771 * out whether we do.
1773 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1774 * compound file. This may explain most, if not all, of the cases of "no
1775 * header", and the header validation should take this into account.
1776 * At least in Visual Basic 6, resource streams, valid headers are
1777 * header[0] == "lt\0\0",
1778 * header[1] == length_of_stream.
1780 * Also handle streams where we do not have a working "Stat" method by
1781 * reading all data until the end of the stream.
1783 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1784 if (hr) {
1785 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1786 statfailed = TRUE;
1787 /* we will read at least 8 byte ... just right below */
1788 statstg.cbSize.QuadPart = 8;
1791 toread = 0;
1792 headerread = 0;
1793 headerisdata = FALSE;
1794 do {
1795 hr=IStream_Read(pStm,header,8,&xread);
1796 if (hr || xread!=8) {
1797 FIXME("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1798 return hr;
1800 headerread += xread;
1801 xread = 0;
1803 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1804 if (toread != 0 && toread != header[1])
1805 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1806 toread, header[1]);
1807 toread = header[1];
1808 if (toread == 0) break;
1809 } else {
1810 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1811 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1812 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1813 (header[0] == EMR_HEADER) || /* EMF header */
1814 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1815 (header[1]==0)
1816 ) {/* Found start of bitmap data */
1817 headerisdata = TRUE;
1818 if (toread == 0)
1819 toread = statstg.cbSize.QuadPart-8;
1820 else toread -= 8;
1821 xread = 8;
1822 } else {
1823 FIXME("Unknown stream header magic: %08x\n", header[0]);
1824 toread = header[1];
1827 } while (!headerisdata);
1829 if (statfailed) { /* we don't know the size ... read all we get */
1830 int sizeinc = 4096;
1831 int origsize = sizeinc;
1832 ULONG nread = 42;
1834 TRACE("Reading all data from stream.\n");
1835 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1836 if (headerisdata)
1837 memcpy (xbuf, &header, 8);
1838 while (1) {
1839 while (xread < origsize) {
1840 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1841 xread+=nread;
1842 if (hr || !nread)
1843 break;
1845 if (!nread || hr) /* done, or error */
1846 break;
1847 if (xread == origsize) {
1848 origsize += sizeinc;
1849 sizeinc = 2*sizeinc; /* exponential increase */
1850 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1853 if (hr)
1854 TRACE("hr in no-stat loader case is %08x\n", hr);
1855 TRACE("loaded %d bytes.\n", xread);
1856 This->datalen = xread;
1857 This->data = xbuf;
1858 } else {
1859 This->datalen = toread+(headerisdata?8:0);
1860 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1862 if (headerisdata)
1863 memcpy (xbuf, &header, 8);
1865 while (xread < This->datalen) {
1866 ULONG nread;
1867 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1868 xread+=nread;
1869 if (hr || !nread)
1870 break;
1872 if (xread != This->datalen)
1873 FIXME("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1875 if (This->datalen == 0) { /* Marks the "NONE" picture */
1876 This->desc.picType = PICTYPE_NONE;
1877 return S_OK;
1881 /****************************************************************************************
1882 * Part 2: Process the loaded data
1885 magic = xbuf[0] + (xbuf[1]<<8);
1886 This->loadtime_format = magic;
1888 switch (magic) {
1889 case 0x4947: /* GIF */
1890 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1891 break;
1892 case 0xd8ff: /* JPEG */
1893 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1894 break;
1895 case 0x4d42: /* Bitmap */
1896 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1897 break;
1898 case 0x5089: /* PNG */
1899 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1900 break;
1901 case 0xcdd7: /* APM */
1902 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1903 break;
1904 case 0x0000: { /* ICON , first word is dwReserved */
1905 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1906 break;
1908 default:
1910 unsigned int i;
1912 /* let's see if it's a metafile */
1913 hr = OLEPictureImpl_LoadMetafile(This, xbuf, xread);
1914 if (hr == S_OK) break;
1916 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1917 hr=E_FAIL;
1918 for (i=0;i<xread+8;i++) {
1919 if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
1920 else MESSAGE("%02x ",xbuf[i-8]);
1921 if (i % 10 == 9) MESSAGE("\n");
1923 MESSAGE("\n");
1924 break;
1927 This->bIsDirty = FALSE;
1929 /* FIXME: this notify is not really documented */
1930 if (hr==S_OK)
1931 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1932 return hr;
1935 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1937 int iSuccess = 0;
1938 HDC hDC;
1939 BITMAPINFO * pInfoBitmap;
1940 int iNumPaletteEntries;
1941 unsigned char * pPixelData;
1942 BITMAPFILEHEADER * pFileHeader;
1943 BITMAPINFO * pInfoHeader;
1945 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1946 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1948 /* Find out bitmap size and padded length */
1949 hDC = GetDC(0);
1950 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1951 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1953 /* Fetch bitmap palette & pixel data */
1955 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1956 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1958 /* Calculate the total length required for the BMP data */
1959 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1960 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1961 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1962 } else {
1963 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1964 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1965 else
1966 iNumPaletteEntries = 0;
1968 *pLength =
1969 sizeof(BITMAPFILEHEADER) +
1970 sizeof(BITMAPINFOHEADER) +
1971 iNumPaletteEntries * sizeof(RGBQUAD) +
1972 pInfoBitmap->bmiHeader.biSizeImage;
1973 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1975 /* Fill the BITMAPFILEHEADER */
1976 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1977 pFileHeader->bfType = 0x4d42;
1978 pFileHeader->bfSize = *pLength;
1979 pFileHeader->bfOffBits =
1980 sizeof(BITMAPFILEHEADER) +
1981 sizeof(BITMAPINFOHEADER) +
1982 iNumPaletteEntries * sizeof(RGBQUAD);
1984 /* Fill the BITMAPINFOHEADER and the palette data */
1985 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1986 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1987 memcpy(
1988 (unsigned char *)(*ppBuffer) +
1989 sizeof(BITMAPFILEHEADER) +
1990 sizeof(BITMAPINFOHEADER) +
1991 iNumPaletteEntries * sizeof(RGBQUAD),
1992 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1993 iSuccess = 1;
1995 HeapFree(GetProcessHeap(), 0, pPixelData);
1996 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1997 return iSuccess;
2000 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2002 ICONINFO infoIcon;
2003 int iSuccess = 0;
2005 *ppBuffer = NULL; *pLength = 0;
2006 if (GetIconInfo(hIcon, &infoIcon)) {
2007 HDC hDC;
2008 BITMAPINFO * pInfoBitmap;
2009 unsigned char * pIconData = NULL;
2010 unsigned int iDataSize = 0;
2012 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2014 /* Find out icon size */
2015 hDC = GetDC(0);
2016 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2017 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2018 if (1) {
2019 /* Auxiliary pointers */
2020 CURSORICONFILEDIR * pIconDir;
2021 CURSORICONFILEDIRENTRY * pIconEntry;
2022 BITMAPINFOHEADER * pIconBitmapHeader;
2023 unsigned int iOffsetPalette;
2024 unsigned int iOffsetColorData;
2025 unsigned int iOffsetMaskData;
2027 unsigned int iLengthScanLineColor;
2028 unsigned int iLengthScanLineMask;
2029 unsigned int iNumEntriesPalette;
2031 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2032 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2034 FIXME("DEBUG: bitmap size is %d x %d\n",
2035 pInfoBitmap->bmiHeader.biWidth,
2036 pInfoBitmap->bmiHeader.biHeight);
2037 FIXME("DEBUG: bitmap bpp is %d\n",
2038 pInfoBitmap->bmiHeader.biBitCount);
2039 FIXME("DEBUG: bitmap nplanes is %d\n",
2040 pInfoBitmap->bmiHeader.biPlanes);
2041 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2042 pInfoBitmap->bmiHeader.biSizeImage);
2044 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2045 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2046 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2048 /* Fill out the CURSORICONFILEDIR */
2049 pIconDir = (CURSORICONFILEDIR *)pIconData;
2050 pIconDir->idType = 1;
2051 pIconDir->idCount = 1;
2053 /* Fill out the CURSORICONFILEDIRENTRY */
2054 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2055 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2056 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2057 pIconEntry->bColorCount =
2058 (pInfoBitmap->bmiHeader.biBitCount < 8)
2059 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2060 : 0;
2061 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2062 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2063 pIconEntry->dwDIBSize = 0;
2064 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2066 /* Fill out the BITMAPINFOHEADER */
2067 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2068 memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
2070 /* Find out whether a palette exists for the bitmap */
2071 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2072 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2073 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2074 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2075 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2076 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2077 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2078 iNumEntriesPalette = 3;
2079 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2080 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2081 } else {
2082 iNumEntriesPalette = 0;
2085 /* Add bitmap size and header size to icon data size. */
2086 iOffsetPalette = iDataSize;
2087 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2088 iOffsetColorData = iDataSize;
2089 iDataSize += pIconBitmapHeader->biSizeImage;
2090 iOffsetMaskData = iDataSize;
2091 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2092 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2093 pIconBitmapHeader->biHeight *= 2;
2094 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2095 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2096 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2097 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2099 /* Get the actual bitmap data from the icon bitmap */
2100 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2101 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2102 if (iNumEntriesPalette > 0) {
2103 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2104 iNumEntriesPalette * sizeof(RGBQUAD));
2107 /* Reset all values so that GetDIBits call succeeds */
2108 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2109 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2110 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2112 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2113 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2114 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2116 printf("ERROR: unable to get bitmap mask (error %u)\n",
2117 GetLastError());
2121 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2122 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2124 /* Write out everything produced so far to the stream */
2125 *ppBuffer = pIconData; *pLength = iDataSize;
2126 iSuccess = 1;
2127 } else {
2129 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2130 GetLastError());
2134 Remarks (from MSDN entry on GetIconInfo):
2136 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2137 members of ICONINFO. The calling application must manage
2138 these bitmaps and delete them when they are no longer
2139 necessary.
2141 if (hDC) ReleaseDC(0, hDC);
2142 DeleteObject(infoIcon.hbmMask);
2143 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2144 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2145 } else {
2146 printf("ERROR: Unable to get icon information (error %u)\n",
2147 GetLastError());
2149 return iSuccess;
2152 static HRESULT WINAPI OLEPictureImpl_Save(
2153 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2155 HRESULT hResult = E_NOTIMPL;
2156 void * pIconData;
2157 unsigned int iDataSize;
2158 ULONG dummy;
2159 int iSerializeResult = 0;
2160 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2162 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2164 switch (This->desc.picType) {
2165 case PICTYPE_ICON:
2166 if (This->bIsDirty || !This->data) {
2167 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2168 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2169 hResult = E_FAIL;
2170 break;
2172 HeapFree(GetProcessHeap(), 0, This->data);
2173 This->data = pIconData;
2174 This->datalen = iDataSize;
2176 if (This->loadtime_magic != 0xdeadbeef) {
2177 DWORD header[2];
2179 header[0] = This->loadtime_magic;
2180 header[1] = This->datalen;
2181 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2183 IStream_Write(pStm, This->data, This->datalen, &dummy);
2185 hResult = S_OK;
2186 break;
2187 case PICTYPE_BITMAP:
2188 if (This->bIsDirty) {
2189 switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) {
2190 case 0x4d42:
2191 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2192 break;
2193 case 0xd8ff:
2194 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2195 break;
2196 case 0x4947:
2197 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2198 break;
2199 case 0x5089:
2200 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2201 break;
2202 default:
2203 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2204 break;
2206 if (iSerializeResult) {
2208 if (This->loadtime_magic != 0xdeadbeef) {
2210 if (1) {
2211 DWORD header[2];
2213 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2214 header[1] = iDataSize;
2215 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2217 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2219 HeapFree(GetProcessHeap(), 0, This->data);
2220 This->data = pIconData;
2221 This->datalen = iDataSize;
2222 hResult = S_OK;
2224 } else {
2226 if (This->loadtime_magic != 0xdeadbeef) {
2228 if (1) {
2229 DWORD header[2];
2231 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2232 header[1] = This->datalen;
2233 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2235 IStream_Write(pStm, This->data, This->datalen, &dummy);
2236 hResult = S_OK;
2238 break;
2239 case PICTYPE_METAFILE:
2240 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2241 break;
2242 case PICTYPE_ENHMETAFILE:
2243 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2244 break;
2245 default:
2246 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2247 break;
2249 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2250 return hResult;
2253 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2254 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2256 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2257 FIXME("(%p,%p),stub!\n",This,pcbSize);
2258 return E_NOTIMPL;
2262 /************************************************************************
2263 * IDispatch
2266 /************************************************************************
2267 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2269 * See Windows documentation for more details on IUnknown methods.
2271 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2272 IDispatch* iface,
2273 REFIID riid,
2274 VOID** ppvoid)
2276 OLEPictureImpl *This = impl_from_IDispatch(iface);
2278 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2281 /************************************************************************
2282 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2284 * See Windows documentation for more details on IUnknown methods.
2286 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2287 IDispatch* iface)
2289 OLEPictureImpl *This = impl_from_IDispatch(iface);
2291 return IPicture_AddRef((IPicture *)This);
2294 /************************************************************************
2295 * OLEPictureImpl_IDispatch_Release (IUnknown)
2297 * See Windows documentation for more details on IUnknown methods.
2299 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2300 IDispatch* iface)
2302 OLEPictureImpl *This = impl_from_IDispatch(iface);
2304 return IPicture_Release((IPicture *)This);
2307 /************************************************************************
2308 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2310 * See Windows documentation for more details on IDispatch methods.
2312 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2313 IDispatch* iface,
2314 unsigned int* pctinfo)
2316 TRACE("(%p)\n", pctinfo);
2318 *pctinfo = 1;
2320 return S_OK;
2323 /************************************************************************
2324 * OLEPictureImpl_GetTypeInfo (IDispatch)
2326 * See Windows documentation for more details on IDispatch methods.
2328 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2329 IDispatch* iface,
2330 UINT iTInfo,
2331 LCID lcid,
2332 ITypeInfo** ppTInfo)
2334 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2335 ITypeLib *tl;
2336 HRESULT hres;
2338 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2340 if (iTInfo != 0)
2341 return E_FAIL;
2343 hres = LoadTypeLib(stdole2tlb, &tl);
2344 if (FAILED(hres))
2346 ERR("Could not load stdole2.tlb\n");
2347 return hres;
2350 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2351 if (FAILED(hres))
2352 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2354 return hres;
2357 /************************************************************************
2358 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2360 * See Windows documentation for more details on IDispatch methods.
2362 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2363 IDispatch* iface,
2364 REFIID riid,
2365 LPOLESTR* rgszNames,
2366 UINT cNames,
2367 LCID lcid,
2368 DISPID* rgDispId)
2370 ITypeInfo * pTInfo;
2371 HRESULT hres;
2373 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2374 rgszNames, cNames, (int)lcid, rgDispId);
2376 if (cNames == 0)
2378 return E_INVALIDARG;
2380 else
2382 /* retrieve type information */
2383 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2385 if (FAILED(hres))
2387 ERR("GetTypeInfo failed.\n");
2388 return hres;
2391 /* convert names to DISPIDs */
2392 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2393 ITypeInfo_Release(pTInfo);
2395 return hres;
2399 /************************************************************************
2400 * OLEPictureImpl_Invoke (IDispatch)
2402 * See Windows documentation for more details on IDispatch methods.
2404 static HRESULT WINAPI OLEPictureImpl_Invoke(
2405 IDispatch* iface,
2406 DISPID dispIdMember,
2407 REFIID riid,
2408 LCID lcid,
2409 WORD wFlags,
2410 DISPPARAMS* pDispParams,
2411 VARIANT* pVarResult,
2412 EXCEPINFO* pExepInfo,
2413 UINT* puArgErr)
2415 OLEPictureImpl *This = impl_from_IDispatch(iface);
2417 /* validate parameters */
2419 if (!IsEqualIID(riid, &IID_NULL))
2421 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2422 return DISP_E_UNKNOWNNAME;
2425 if (!pDispParams)
2427 ERR("null pDispParams not allowed\n");
2428 return DISP_E_PARAMNOTOPTIONAL;
2431 if (wFlags & DISPATCH_PROPERTYGET)
2433 if (pDispParams->cArgs != 0)
2435 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2436 return DISP_E_BADPARAMCOUNT;
2438 if (!pVarResult)
2440 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2441 return DISP_E_PARAMNOTOPTIONAL;
2444 else if (wFlags & DISPATCH_PROPERTYPUT)
2446 if (pDispParams->cArgs != 1)
2448 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2449 return DISP_E_BADPARAMCOUNT;
2453 switch (dispIdMember)
2455 case DISPID_PICT_HANDLE:
2456 if (wFlags & DISPATCH_PROPERTYGET)
2458 TRACE("DISPID_PICT_HANDLE\n");
2459 V_VT(pVarResult) = VT_I4;
2460 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2462 break;
2463 case DISPID_PICT_HPAL:
2464 if (wFlags & DISPATCH_PROPERTYGET)
2466 TRACE("DISPID_PICT_HPAL\n");
2467 V_VT(pVarResult) = VT_I4;
2468 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2470 else if (wFlags & DISPATCH_PROPERTYPUT)
2472 VARIANTARG vararg;
2473 HRESULT hr;
2474 TRACE("DISPID_PICT_HPAL\n");
2476 VariantInit(&vararg);
2477 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2478 if (FAILED(hr))
2479 return hr;
2481 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2483 VariantClear(&vararg);
2484 return hr;
2486 break;
2487 case DISPID_PICT_TYPE:
2488 if (wFlags & DISPATCH_PROPERTYGET)
2490 TRACE("DISPID_PICT_TYPE\n");
2491 V_VT(pVarResult) = VT_I2;
2492 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2494 break;
2495 case DISPID_PICT_WIDTH:
2496 if (wFlags & DISPATCH_PROPERTYGET)
2498 TRACE("DISPID_PICT_WIDTH\n");
2499 V_VT(pVarResult) = VT_I4;
2500 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2502 break;
2503 case DISPID_PICT_HEIGHT:
2504 if (wFlags & DISPATCH_PROPERTYGET)
2506 TRACE("DISPID_PICT_HEIGHT\n");
2507 V_VT(pVarResult) = VT_I4;
2508 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2510 break;
2513 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2514 return DISP_E_MEMBERNOTFOUND;
2518 static const IPictureVtbl OLEPictureImpl_VTable =
2520 OLEPictureImpl_QueryInterface,
2521 OLEPictureImpl_AddRef,
2522 OLEPictureImpl_Release,
2523 OLEPictureImpl_get_Handle,
2524 OLEPictureImpl_get_hPal,
2525 OLEPictureImpl_get_Type,
2526 OLEPictureImpl_get_Width,
2527 OLEPictureImpl_get_Height,
2528 OLEPictureImpl_Render,
2529 OLEPictureImpl_set_hPal,
2530 OLEPictureImpl_get_CurDC,
2531 OLEPictureImpl_SelectPicture,
2532 OLEPictureImpl_get_KeepOriginalFormat,
2533 OLEPictureImpl_put_KeepOriginalFormat,
2534 OLEPictureImpl_PictureChanged,
2535 OLEPictureImpl_SaveAsFile,
2536 OLEPictureImpl_get_Attributes
2539 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2541 OLEPictureImpl_IDispatch_QueryInterface,
2542 OLEPictureImpl_IDispatch_AddRef,
2543 OLEPictureImpl_IDispatch_Release,
2544 OLEPictureImpl_GetTypeInfoCount,
2545 OLEPictureImpl_GetTypeInfo,
2546 OLEPictureImpl_GetIDsOfNames,
2547 OLEPictureImpl_Invoke
2550 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2552 OLEPictureImpl_IPersistStream_QueryInterface,
2553 OLEPictureImpl_IPersistStream_AddRef,
2554 OLEPictureImpl_IPersistStream_Release,
2555 OLEPictureImpl_GetClassID,
2556 OLEPictureImpl_IsDirty,
2557 OLEPictureImpl_Load,
2558 OLEPictureImpl_Save,
2559 OLEPictureImpl_GetSizeMax
2562 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2564 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2565 OLEPictureImpl_IConnectionPointContainer_AddRef,
2566 OLEPictureImpl_IConnectionPointContainer_Release,
2567 OLEPictureImpl_EnumConnectionPoints,
2568 OLEPictureImpl_FindConnectionPoint
2571 /***********************************************************************
2572 * OleCreatePictureIndirect (OLEAUT32.419)
2574 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2575 BOOL fOwn, LPVOID *ppvObj )
2577 OLEPictureImpl* newPict = NULL;
2578 HRESULT hr = S_OK;
2580 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2583 * Sanity check
2585 if (ppvObj==0)
2586 return E_POINTER;
2588 *ppvObj = NULL;
2591 * Try to construct a new instance of the class.
2593 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2595 if (newPict == NULL)
2596 return E_OUTOFMEMORY;
2599 * Make sure it supports the interface required by the caller.
2601 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2604 * Release the reference obtained in the constructor. If
2605 * the QueryInterface was unsuccessful, it will free the class.
2607 IPicture_Release((IPicture*)newPict);
2609 return hr;
2613 /***********************************************************************
2614 * OleLoadPicture (OLEAUT32.418)
2616 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2617 REFIID riid, LPVOID *ppvObj )
2619 LPPERSISTSTREAM ps;
2620 IPicture *newpic;
2621 HRESULT hr;
2623 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2624 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2626 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2627 if (hr)
2628 return hr;
2629 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2630 if (hr) {
2631 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2632 IPicture_Release(newpic);
2633 *ppvObj = NULL;
2634 return hr;
2636 IPersistStream_Load(ps,lpstream);
2637 IPersistStream_Release(ps);
2638 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2639 if (hr)
2640 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2641 IPicture_Release(newpic);
2642 return hr;
2645 /***********************************************************************
2646 * OleLoadPictureEx (OLEAUT32.401)
2648 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2649 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2651 LPPERSISTSTREAM ps;
2652 IPicture *newpic;
2653 HRESULT hr;
2655 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2656 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2658 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2659 if (hr)
2660 return hr;
2661 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2662 if (hr) {
2663 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2664 IPicture_Release(newpic);
2665 *ppvObj = NULL;
2666 return hr;
2668 IPersistStream_Load(ps,lpstream);
2669 IPersistStream_Release(ps);
2670 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2671 if (hr)
2672 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2673 IPicture_Release(newpic);
2674 return hr;
2677 /***********************************************************************
2678 * OleLoadPicturePath (OLEAUT32.424)
2680 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2681 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2682 LPVOID *ppvRet )
2684 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2685 IPicture *ipicture;
2686 HANDLE hFile;
2687 DWORD dwFileSize;
2688 HGLOBAL hGlobal = NULL;
2689 DWORD dwBytesRead = 0;
2690 IStream *stream;
2691 BOOL bRead;
2692 IPersistStream *pStream;
2693 HRESULT hRes;
2695 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2696 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2697 debugstr_guid(riid), ppvRet);
2699 if (!ppvRet) return E_POINTER;
2701 if (strncmpW(szURLorPath, file, 7) == 0) {
2702 szURLorPath += 7;
2704 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2705 0, NULL);
2706 if (hFile == INVALID_HANDLE_VALUE)
2707 return E_UNEXPECTED;
2709 dwFileSize = GetFileSize(hFile, NULL);
2710 if (dwFileSize != INVALID_FILE_SIZE )
2712 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2713 if ( hGlobal)
2715 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2716 if (!bRead)
2718 GlobalFree(hGlobal);
2719 hGlobal = 0;
2723 CloseHandle(hFile);
2725 if (!hGlobal)
2726 return E_UNEXPECTED;
2728 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2729 if (FAILED(hRes))
2731 GlobalFree(hGlobal);
2732 return hRes;
2734 } else {
2735 IMoniker *pmnk;
2736 IBindCtx *pbc;
2738 hRes = CreateBindCtx(0, &pbc);
2739 if (SUCCEEDED(hRes))
2741 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2742 if (SUCCEEDED(hRes))
2744 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2745 IMoniker_Release(pmnk);
2747 IBindCtx_Release(pbc);
2749 if (FAILED(hRes))
2750 return hRes;
2753 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2754 &IID_IPicture, (LPVOID*)&ipicture);
2755 if (hRes != S_OK) {
2756 IStream_Release(stream);
2757 return hRes;
2760 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2761 if (hRes) {
2762 IStream_Release(stream);
2763 IPicture_Release(ipicture);
2764 return hRes;
2767 hRes = IPersistStream_Load(pStream, stream);
2768 IPersistStream_Release(pStream);
2769 IStream_Release(stream);
2771 if (hRes) {
2772 IPicture_Release(ipicture);
2773 return hRes;
2776 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2777 if (hRes)
2778 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2780 IPicture_Release(ipicture);
2781 return hRes;
2784 /*******************************************************************************
2785 * StdPic ClassFactory
2787 typedef struct
2789 /* IUnknown fields */
2790 const IClassFactoryVtbl *lpVtbl;
2791 LONG ref;
2792 } IClassFactoryImpl;
2794 static HRESULT WINAPI
2795 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2796 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2798 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2799 return E_NOINTERFACE;
2802 static ULONG WINAPI
2803 SPCF_AddRef(LPCLASSFACTORY iface) {
2804 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2805 return InterlockedIncrement(&This->ref);
2808 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2809 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2810 /* static class, won't be freed */
2811 return InterlockedDecrement(&This->ref);
2814 static HRESULT WINAPI SPCF_CreateInstance(
2815 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2817 /* Creates an uninitialized picture */
2818 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2822 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2823 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2824 FIXME("(%p)->(%d),stub!\n",This,dolock);
2825 return S_OK;
2828 static const IClassFactoryVtbl SPCF_Vtbl = {
2829 SPCF_QueryInterface,
2830 SPCF_AddRef,
2831 SPCF_Release,
2832 SPCF_CreateInstance,
2833 SPCF_LockServer
2835 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2837 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }