push 36f87734b677b59a60e8d0f7daaece38a167639b
[wine/hacks.git] / dlls / oleaut32 / olepicture.c
blob09d2c32b2b6824e3a829b497ab1d99bbf5e3baa1
1 /*
2 * OLE Picture object
4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
8 * Copyright 2008 Kirill K. Smirnov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * BUGS
26 * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
27 * Lots of methods are just stubs.
30 * NOTES (or things that msdn doesn't tell you)
32 * The width and height properties are returned in HIMETRIC units (0.01mm)
33 * IPicture::Render also uses these to select a region of the src picture.
34 * A bitmap's size is converted into these units by using the screen resolution
35 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
39 #include "config.h"
40 #include "wine/port.h"
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <string.h>
49 #ifdef SONAME_LIBJPEG
50 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
51 #define XMD_H
52 #define UINT8 JPEG_UINT8
53 #define UINT16 JPEG_UINT16
54 #define boolean jpeg_boolean
55 # include <jpeglib.h>
56 #undef UINT8
57 #undef UINT16
58 #undef boolean
59 #endif
61 #ifdef HAVE_PNG_H
62 #include <png.h>
63 #endif
65 /* Must be before wine includes, the header has things conflicting with
66 * WINE headers.
68 #define COBJMACROS
69 #define NONAMELESSUNION
70 #define NONAMELESSSTRUCT
72 #include "winerror.h"
73 #include "windef.h"
74 #include "winbase.h"
75 #include "wingdi.h"
76 #include "winuser.h"
77 #include "ole2.h"
78 #include "olectl.h"
79 #include "oleauto.h"
80 #include "connpt.h"
81 #include "urlmon.h"
82 #include "wine/debug.h"
83 #include "wine/unicode.h"
85 #include "wine/wingdi16.h"
87 #include "ungif.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(ole);
91 #include "pshpack1.h"
93 /* Header for Aldus Placable Metafiles - a standard metafile follows */
94 typedef struct _APM_HEADER
96 DWORD key;
97 WORD handle;
98 SHORT left;
99 SHORT top;
100 SHORT right;
101 SHORT bottom;
102 WORD inch;
103 DWORD reserved;
104 WORD checksum;
105 } APM_HEADER;
107 typedef struct {
108 BYTE bWidth;
109 BYTE bHeight;
110 BYTE bColorCount;
111 BYTE bReserved;
112 WORD xHotspot;
113 WORD yHotspot;
114 DWORD dwDIBSize;
115 DWORD dwDIBOffset;
116 } CURSORICONFILEDIRENTRY;
118 typedef struct
120 WORD idReserved;
121 WORD idType;
122 WORD idCount;
123 CURSORICONFILEDIRENTRY idEntries[1];
124 } CURSORICONFILEDIR;
126 #include "poppack.h"
128 /*************************************************************************
129 * Declaration of implementation class
132 typedef struct OLEPictureImpl {
135 * IPicture handles IUnknown
138 const IPictureVtbl *lpVtbl;
139 const IDispatchVtbl *lpvtblIDispatch;
140 const IPersistStreamVtbl *lpvtblIPersistStream;
141 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
143 /* Object reference count */
144 LONG ref;
146 /* We own the object and must destroy it ourselves */
147 BOOL fOwn;
149 /* Picture description */
150 PICTDESC desc;
152 /* These are the pixel size of a bitmap */
153 DWORD origWidth;
154 DWORD origHeight;
156 /* And these are the size of the picture converted into HIMETRIC units */
157 OLE_XSIZE_HIMETRIC himetricWidth;
158 OLE_YSIZE_HIMETRIC himetricHeight;
160 IConnectionPoint *pCP;
162 BOOL keepOrigFormat;
163 HDC hDCCur;
165 /* Bitmap transparency mask */
166 HBITMAP hbmMask;
167 HBITMAP hbmXor;
168 COLORREF rgbTrans;
170 /* data */
171 void* data;
172 int datalen;
173 BOOL bIsDirty; /* Set to TRUE if picture has changed */
174 unsigned int loadtime_magic; /* If a length header was found, saves value */
175 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
176 } OLEPictureImpl;
179 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
182 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
184 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
187 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
189 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
192 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
194 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
198 * Predeclare VTables. They get initialized at the end.
200 static const IPictureVtbl OLEPictureImpl_VTable;
201 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
202 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
203 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
205 /***********************************************************************
206 * Implementation of the OLEPictureImpl class.
209 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
210 BITMAP bm;
211 HDC hdcRef;
213 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
214 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
215 ERR("GetObject fails\n");
216 return;
218 This->origWidth = bm.bmWidth;
219 This->origHeight = bm.bmHeight;
220 /* The width and height are stored in HIMETRIC units (0.01 mm),
221 so we take our pixel width divide by pixels per inch and
222 multiply by 25.4 * 100 */
223 /* Should we use GetBitmapDimension if available? */
224 hdcRef = CreateCompatibleDC(0);
225 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
226 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
227 DeleteDC(hdcRef);
230 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
232 ICONINFO infoIcon;
234 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
235 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
236 HDC hdcRef;
237 BITMAP bm;
239 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
240 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
241 ERR("GetObject fails on icon bitmap\n");
242 return;
245 This->origWidth = bm.bmWidth;
246 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
247 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
248 hdcRef = GetDC(0);
249 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
250 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
251 ReleaseDC(0, hdcRef);
253 DeleteObject(infoIcon.hbmMask);
254 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
255 } else {
256 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
260 /************************************************************************
261 * OLEPictureImpl_Construct
263 * This method will construct a new instance of the OLEPictureImpl
264 * class.
266 * The caller of this method must release the object when it's
267 * done with it.
269 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
271 OLEPictureImpl* newObject = 0;
273 if (pictDesc)
274 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
277 * Allocate space for the object.
279 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
281 if (newObject==0)
282 return newObject;
285 * Initialize the virtual function table.
287 newObject->lpVtbl = &OLEPictureImpl_VTable;
288 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
289 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
290 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
292 newObject->pCP = NULL;
293 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
294 if (!newObject->pCP)
296 HeapFree(GetProcessHeap(), 0, newObject);
297 return NULL;
301 * Start with one reference count. The caller of this function
302 * must release the interface pointer when it is done.
304 newObject->ref = 1;
305 newObject->hDCCur = 0;
307 newObject->fOwn = fOwn;
309 /* dunno about original value */
310 newObject->keepOrigFormat = TRUE;
312 newObject->hbmMask = NULL;
313 newObject->hbmXor = NULL;
314 newObject->loadtime_magic = 0xdeadbeef;
315 newObject->loadtime_format = 0;
316 newObject->bIsDirty = FALSE;
318 if (pictDesc) {
319 newObject->desc = *pictDesc;
321 switch(pictDesc->picType) {
322 case PICTYPE_BITMAP:
323 OLEPictureImpl_SetBitmap(newObject);
324 break;
326 case PICTYPE_METAFILE:
327 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
328 newObject->himetricWidth = pictDesc->u.wmf.xExt;
329 newObject->himetricHeight = pictDesc->u.wmf.yExt;
330 break;
332 case PICTYPE_NONE:
333 /* not sure what to do here */
334 newObject->himetricWidth = newObject->himetricHeight = 0;
335 break;
337 case PICTYPE_ICON:
338 OLEPictureImpl_SetIcon(newObject);
339 break;
340 case PICTYPE_ENHMETAFILE:
341 default:
342 FIXME("Unsupported type %d\n", pictDesc->picType);
343 newObject->himetricWidth = newObject->himetricHeight = 0;
344 break;
346 } else {
347 newObject->desc.picType = PICTYPE_UNINITIALIZED;
350 TRACE("returning %p\n", newObject);
351 return newObject;
354 /************************************************************************
355 * OLEPictureImpl_Destroy
357 * This method is called by the Release method when the reference
358 * count goes down to 0. It will free all resources used by
359 * this object. */
360 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
362 TRACE("(%p)\n", Obj);
364 if (Obj->pCP)
365 IConnectionPoint_Release(Obj->pCP);
367 if(Obj->fOwn) { /* We need to destroy the picture */
368 switch(Obj->desc.picType) {
369 case PICTYPE_BITMAP:
370 DeleteObject(Obj->desc.u.bmp.hbitmap);
371 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
372 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
373 break;
374 case PICTYPE_METAFILE:
375 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
376 break;
377 case PICTYPE_ICON:
378 DestroyIcon(Obj->desc.u.icon.hicon);
379 break;
380 case PICTYPE_ENHMETAFILE:
381 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
382 break;
383 case PICTYPE_NONE:
384 case PICTYPE_UNINITIALIZED:
385 /* Nothing to do */
386 break;
387 default:
388 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
389 break;
392 HeapFree(GetProcessHeap(), 0, Obj->data);
393 HeapFree(GetProcessHeap(), 0, Obj);
397 /************************************************************************
398 * OLEPictureImpl_AddRef (IUnknown)
400 * See Windows documentation for more details on IUnknown methods.
402 static ULONG WINAPI OLEPictureImpl_AddRef(
403 IPicture* iface)
405 OLEPictureImpl *This = (OLEPictureImpl *)iface;
406 ULONG refCount = InterlockedIncrement(&This->ref);
408 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
410 return refCount;
413 /************************************************************************
414 * OLEPictureImpl_Release (IUnknown)
416 * See Windows documentation for more details on IUnknown methods.
418 static ULONG WINAPI OLEPictureImpl_Release(
419 IPicture* iface)
421 OLEPictureImpl *This = (OLEPictureImpl *)iface;
422 ULONG refCount = InterlockedDecrement(&This->ref);
424 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
427 * If the reference count goes down to 0, perform suicide.
429 if (!refCount) OLEPictureImpl_Destroy(This);
431 return refCount;
434 /************************************************************************
435 * OLEPictureImpl_QueryInterface (IUnknown)
437 * See Windows documentation for more details on IUnknown methods.
439 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
440 IPicture* iface,
441 REFIID riid,
442 void** ppvObject)
444 OLEPictureImpl *This = (OLEPictureImpl *)iface;
445 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
448 * Perform a sanity check on the parameters.
450 if ( (This==0) || (ppvObject==0) )
451 return E_INVALIDARG;
454 * Initialize the return parameter.
456 *ppvObject = 0;
459 * Compare the riid with the interface IDs implemented by this object.
461 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
462 *ppvObject = (IPicture*)This;
463 else if (IsEqualIID(&IID_IDispatch, riid))
464 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
465 else if (IsEqualIID(&IID_IPictureDisp, riid))
466 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
467 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
468 *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
469 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
470 *ppvObject = (IConnectionPointContainer*)&(This->lpvtblIConnectionPointContainer);
473 * Check that we obtained an interface.
475 if ((*ppvObject)==0)
477 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
478 return E_NOINTERFACE;
482 * Query Interface always increases the reference count by one when it is
483 * successful
485 OLEPictureImpl_AddRef((IPicture*)This);
487 return S_OK;
490 /***********************************************************************
491 * OLEPicture_SendNotify (internal)
493 * Sends notification messages of changed properties to any interested
494 * connections.
496 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
498 IEnumConnections *pEnum;
499 CONNECTDATA CD;
501 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
502 return;
503 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
504 IPropertyNotifySink *sink;
506 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
507 IPropertyNotifySink_OnChanged(sink, dispID);
508 IPropertyNotifySink_Release(sink);
509 IUnknown_Release(CD.pUnk);
511 IEnumConnections_Release(pEnum);
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 *pClassID = CLSID_StdPicture;
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 jpeg_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 jpeg_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,bmi);
1241 HeapFree(GetProcessHeap(),0,bytes);
1242 return S_OK;
1245 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1247 #ifdef SONAME_LIBJPEG
1248 struct jpeg_decompress_struct jd;
1249 struct jpeg_error_mgr jerr;
1250 int ret;
1251 JDIMENSION x;
1252 JSAMPROW samprow,oldsamprow;
1253 BITMAPINFOHEADER bmi;
1254 LPBYTE bits;
1255 HDC hdcref;
1256 struct jpeg_source_mgr xjsm;
1257 LPBYTE oldbits;
1258 unsigned int i;
1260 if(!libjpeg_handle) {
1261 if(!load_libjpeg()) {
1262 FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1263 return E_FAIL;
1267 /* This is basically so we can use in-memory data for jpeg decompression.
1268 * We need to have all the functions.
1270 xjsm.next_input_byte = xbuf;
1271 xjsm.bytes_in_buffer = xread;
1272 xjsm.init_source = _jpeg_init_source;
1273 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1274 xjsm.skip_input_data = _jpeg_skip_input_data;
1275 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1276 xjsm.term_source = _jpeg_term_source;
1278 jd.err = pjpeg_std_error(&jerr);
1279 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1280 * jpeg_create_decompress(&jd); */
1281 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1282 jd.src = &xjsm;
1283 ret=pjpeg_read_header(&jd,TRUE);
1284 jd.out_color_space = JCS_RGB;
1285 pjpeg_start_decompress(&jd);
1286 if (ret != JPEG_HEADER_OK) {
1287 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1288 HeapFree(GetProcessHeap(),0,xbuf);
1289 return E_FAIL;
1292 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1293 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1294 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1296 oldbits = bits;
1297 oldsamprow = samprow;
1298 while ( jd.output_scanline<jd.output_height ) {
1299 x = pjpeg_read_scanlines(&jd,&samprow,1);
1300 if (x != 1) {
1301 FIXME("failed to read current scanline?\n");
1302 break;
1304 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1305 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1306 *(bits++) = *(samprow+2);
1307 *(bits++) = *(samprow+1);
1308 *(bits++) = *(samprow);
1310 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1311 samprow = oldsamprow;
1313 bits = oldbits;
1315 bmi.biSize = sizeof(bmi);
1316 bmi.biWidth = jd.output_width;
1317 bmi.biHeight = -jd.output_height;
1318 bmi.biPlanes = 1;
1319 bmi.biBitCount = jd.output_components<<3;
1320 bmi.biCompression = BI_RGB;
1321 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1322 bmi.biXPelsPerMeter = 0;
1323 bmi.biYPelsPerMeter = 0;
1324 bmi.biClrUsed = 0;
1325 bmi.biClrImportant = 0;
1327 HeapFree(GetProcessHeap(),0,samprow);
1328 pjpeg_finish_decompress(&jd);
1329 pjpeg_destroy_decompress(&jd);
1330 hdcref = GetDC(0);
1331 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1332 hdcref,
1333 &bmi,
1334 CBM_INIT,
1335 bits,
1336 (BITMAPINFO*)&bmi,
1337 DIB_RGB_COLORS
1339 DeleteDC(hdcref);
1340 This->desc.picType = PICTYPE_BITMAP;
1341 OLEPictureImpl_SetBitmap(This);
1342 HeapFree(GetProcessHeap(),0,bits);
1343 return S_OK;
1344 #else
1345 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1346 return E_FAIL;
1347 #endif
1350 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1352 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1353 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1354 HDC hdcref;
1356 /* Does not matter whether this is a coreheader or not, we only use
1357 * components which are in both
1359 hdcref = GetDC(0);
1360 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1361 hdcref,
1362 &(bi->bmiHeader),
1363 CBM_INIT,
1364 xbuf+bfh->bfOffBits,
1366 DIB_RGB_COLORS
1368 DeleteDC(hdcref);
1369 if (This->desc.u.bmp.hbitmap == 0)
1370 return E_FAIL;
1371 This->desc.picType = PICTYPE_BITMAP;
1372 OLEPictureImpl_SetBitmap(This);
1373 return S_OK;
1376 /*****************************************************
1377 * start of PNG-specific code
1378 * currently only supports colortype PNG_COLOR_TYPE_RGB
1380 #ifdef SONAME_LIBPNG
1381 typedef struct{
1382 ULONG position;
1383 ULONG size;
1384 BYTE * buff;
1385 } png_io;
1387 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1388 png_size_t length)
1390 png_io * io_ptr = png_ptr->io_ptr;
1392 if(length + io_ptr->position > io_ptr->size){
1393 length = io_ptr->size - io_ptr->position;
1396 memcpy(data, io_ptr->buff + io_ptr->position, length);
1398 io_ptr->position += length;
1401 static void *libpng_handle;
1402 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1403 MAKE_FUNCPTR(png_create_read_struct);
1404 MAKE_FUNCPTR(png_create_info_struct);
1405 MAKE_FUNCPTR(png_set_read_fn);
1406 MAKE_FUNCPTR(png_read_info);
1407 MAKE_FUNCPTR(png_read_image);
1408 MAKE_FUNCPTR(png_get_rowbytes);
1409 MAKE_FUNCPTR(png_set_bgr);
1410 MAKE_FUNCPTR(png_destroy_read_struct);
1411 MAKE_FUNCPTR(png_set_palette_to_rgb);
1412 MAKE_FUNCPTR(png_read_update_info);
1413 MAKE_FUNCPTR(png_get_tRNS);
1414 MAKE_FUNCPTR(png_get_PLTE);
1415 MAKE_FUNCPTR(png_set_expand);
1416 #undef MAKE_FUNCPTR
1418 static void *load_libpng(void)
1420 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1422 #define LOAD_FUNCPTR(f) \
1423 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1424 libpng_handle = NULL; \
1425 return NULL; \
1427 LOAD_FUNCPTR(png_create_read_struct);
1428 LOAD_FUNCPTR(png_create_info_struct);
1429 LOAD_FUNCPTR(png_set_read_fn);
1430 LOAD_FUNCPTR(png_read_info);
1431 LOAD_FUNCPTR(png_read_image);
1432 LOAD_FUNCPTR(png_get_rowbytes);
1433 LOAD_FUNCPTR(png_set_bgr);
1434 LOAD_FUNCPTR(png_destroy_read_struct);
1435 LOAD_FUNCPTR(png_set_palette_to_rgb);
1436 LOAD_FUNCPTR(png_read_update_info);
1437 LOAD_FUNCPTR(png_get_tRNS);
1438 LOAD_FUNCPTR(png_get_PLTE);
1439 LOAD_FUNCPTR(png_set_expand);
1441 #undef LOAD_FUNCPTR
1443 return libpng_handle;
1445 #endif /* SONAME_LIBPNG */
1447 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1449 #ifdef SONAME_LIBPNG
1450 png_io io;
1451 png_structp png_ptr = NULL;
1452 png_infop info_ptr = NULL;
1453 INT row, rowsize, height, width, num_trans, i, j;
1454 png_bytep* row_pointers = NULL;
1455 png_bytep pngdata = NULL;
1456 BITMAPINFOHEADER bmi;
1457 HDC hdcref = NULL, hdcXor, hdcMask;
1458 HRESULT ret;
1459 BOOL transparency;
1460 png_bytep trans;
1461 png_color_16p trans_values;
1462 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1463 HBITMAP hbmoldXor, hbmoldMask, temp;
1465 if(!libpng_handle) {
1466 if(!load_libpng()) {
1467 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1468 return E_FAIL;
1472 io.size = xread;
1473 io.position = 0;
1474 io.buff = xbuf;
1476 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1477 NULL, NULL, NULL);
1479 if(setjmp(png_jmpbuf(png_ptr))){
1480 TRACE("Error in libpng\n");
1481 ret = E_FAIL;
1482 goto end;
1485 info_ptr = ppng_create_info_struct(png_ptr);
1486 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1487 ppng_read_info(png_ptr, info_ptr);
1489 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1490 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1491 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1492 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1493 ret = E_FAIL;
1494 goto end;
1497 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1498 == PNG_INFO_tRNS);
1500 /* sets format from anything to RGBA */
1501 ppng_set_expand(png_ptr);
1502 /* sets format to BGRA */
1503 ppng_set_bgr(png_ptr);
1505 ppng_read_update_info(png_ptr, info_ptr);
1507 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1508 /* align rowsize to 4-byte boundary */
1509 rowsize = (rowsize + 3) & ~3;
1510 height = info_ptr->height;
1511 width = info_ptr->width;
1513 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1514 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1516 if(!pngdata || !row_pointers){
1517 ret = E_FAIL;
1518 goto end;
1521 for (row = 0; row < height; row++){
1522 row_pointers[row] = pngdata + row * rowsize;
1525 ppng_read_image(png_ptr, row_pointers);
1527 bmi.biSize = sizeof(bmi);
1528 bmi.biWidth = width;
1529 bmi.biHeight = -height;
1530 bmi.biPlanes = 1;
1531 bmi.biBitCount = info_ptr->channels * 8;
1532 bmi.biCompression = BI_RGB;
1533 bmi.biSizeImage = height * rowsize;
1534 bmi.biXPelsPerMeter = 0;
1535 bmi.biYPelsPerMeter = 0;
1536 bmi.biClrUsed = 0;
1537 bmi.biClrImportant = 0;
1539 hdcref = GetDC(0);
1540 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1541 hdcref,
1542 &bmi,
1543 CBM_INIT,
1544 pngdata,
1545 (BITMAPINFO*)&bmi,
1546 DIB_RGB_COLORS
1549 /* only fully-transparent alpha is handled */
1550 if((info_ptr->channels != 4) || !transparency){
1551 ReleaseDC(0, hdcref);
1552 goto succ;
1555 This->hbmXor = CreateDIBitmap(
1556 hdcref,
1557 &bmi,
1558 CBM_INIT,
1559 pngdata,
1560 (BITMAPINFO*)&bmi,
1561 DIB_RGB_COLORS
1564 /* set transparent pixels to black, all others to white */
1565 for(i = 0; i < height; i++){
1566 for(j = 3; j < rowsize; j += 4){
1567 if(row_pointers[i][j] == 0)
1568 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1569 else
1570 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1574 temp = CreateDIBitmap(
1575 hdcref,
1576 &bmi,
1577 CBM_INIT,
1578 pngdata,
1579 (BITMAPINFO*)&bmi,
1580 DIB_RGB_COLORS
1583 ReleaseDC(0, hdcref);
1585 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1586 hdcXor = CreateCompatibleDC(NULL);
1587 hdcMask = CreateCompatibleDC(NULL);
1589 hbmoldXor = SelectObject(hdcXor,temp);
1590 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1591 SetBkColor(hdcXor,black);
1592 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1594 SelectObject(hdcXor,This->hbmXor);
1595 DeleteObject(temp);
1597 SetTextColor(hdcXor,white);
1598 SetBkColor(hdcXor,black);
1599 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1601 SelectObject(hdcXor,hbmoldXor);
1602 SelectObject(hdcMask,hbmoldMask);
1604 DeleteDC(hdcXor);
1605 DeleteDC(hdcMask);
1607 succ:
1608 This->desc.picType = PICTYPE_BITMAP;
1609 OLEPictureImpl_SetBitmap(This);
1610 ret = S_OK;
1612 end:
1613 if(png_ptr)
1614 ppng_destroy_read_struct(&png_ptr,
1615 (info_ptr ? &info_ptr : (png_infopp) NULL),
1616 (png_infopp)NULL);
1617 HeapFree(GetProcessHeap(), 0, row_pointers);
1618 HeapFree(GetProcessHeap(), 0, pngdata);
1619 return ret;
1620 #else /* SONAME_LIBPNG */
1621 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1622 return E_FAIL;
1623 #endif
1626 /*****************************************************
1627 * start of Icon-specific code
1630 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1632 HICON hicon;
1633 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1634 HDC hdcRef;
1635 int i;
1638 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1639 FIXME("icon.idType=%d\n",cifd->idType);
1640 FIXME("icon.idCount=%d\n",cifd->idCount);
1642 for (i=0;i<cifd->idCount;i++) {
1643 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1644 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1645 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1646 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1647 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1648 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1649 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1650 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1653 i=0;
1654 /* If we have more than one icon, try to find the best.
1655 * this currently means '32 pixel wide'.
1657 if (cifd->idCount!=1) {
1658 for (i=0;i<cifd->idCount;i++) {
1659 if (cifd->idEntries[i].bWidth == 32)
1660 break;
1662 if (i==cifd->idCount) i=0;
1665 hicon = CreateIconFromResourceEx(
1666 xbuf+cifd->idEntries[i].dwDIBOffset,
1667 cifd->idEntries[i].dwDIBSize,
1668 TRUE, /* is icon */
1669 0x00030000,
1670 cifd->idEntries[i].bWidth,
1671 cifd->idEntries[i].bHeight,
1674 if (!hicon) {
1675 FIXME("CreateIcon failed.\n");
1676 return E_FAIL;
1677 } else {
1678 This->desc.picType = PICTYPE_ICON;
1679 This->desc.u.icon.hicon = hicon;
1680 This->origWidth = cifd->idEntries[i].bWidth;
1681 This->origHeight = cifd->idEntries[i].bHeight;
1682 hdcRef = CreateCompatibleDC(0);
1683 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1684 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1685 DeleteDC(hdcRef);
1686 return S_OK;
1690 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1691 const BYTE *data, ULONG size)
1693 HENHMETAFILE hemf;
1694 ENHMETAHEADER hdr;
1696 hemf = SetEnhMetaFileBits(size, data);
1697 if (!hemf) return E_FAIL;
1699 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1701 This->desc.picType = PICTYPE_ENHMETAFILE;
1702 This->desc.u.emf.hemf = hemf;
1704 This->origWidth = 0;
1705 This->origHeight = 0;
1706 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1707 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1709 return S_OK;
1712 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1713 const BYTE *data, ULONG size)
1715 APM_HEADER *header = (APM_HEADER *)data;
1716 HMETAFILE hmf;
1718 if (size < sizeof(APM_HEADER))
1719 return E_FAIL;
1720 if (header->key != 0x9ac6cdd7)
1721 return E_FAIL;
1723 /* SetMetaFileBitsEx performs data check on its own */
1724 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1725 if (!hmf) return E_FAIL;
1727 This->desc.picType = PICTYPE_METAFILE;
1728 This->desc.u.wmf.hmeta = hmf;
1729 This->desc.u.wmf.xExt = 0;
1730 This->desc.u.wmf.yExt = 0;
1732 This->origWidth = 0;
1733 This->origHeight = 0;
1734 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1735 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1736 return S_OK;
1739 /************************************************************************
1740 * BITMAP FORMAT FLAGS -
1741 * Flags that differentiate between different types of bitmaps.
1744 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1745 #define BITMAP_FORMAT_JPEG 0xd8ff
1746 #define BITMAP_FORMAT_GIF 0x4947
1747 #define BITMAP_FORMAT_PNG 0x5089
1748 #define BITMAP_FORMAT_APM 0xcdd7
1750 /************************************************************************
1751 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1753 * Loads the binary data from the IStream. Starts at current position.
1754 * There appears to be an 2 DWORD header:
1755 * DWORD magic;
1756 * DWORD len;
1758 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1760 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1761 HRESULT hr = E_FAIL;
1762 BOOL headerisdata = FALSE;
1763 BOOL statfailed = FALSE;
1764 ULONG xread, toread;
1765 ULONG headerread;
1766 BYTE *xbuf;
1767 DWORD header[2];
1768 WORD magic;
1769 STATSTG statstg;
1770 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1772 TRACE("(%p,%p)\n",This,pStm);
1774 /****************************************************************************************
1775 * Part 1: Load the data
1777 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1778 * out whether we do.
1780 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1781 * compound file. This may explain most, if not all, of the cases of "no
1782 * header", and the header validation should take this into account.
1783 * At least in Visual Basic 6, resource streams, valid headers are
1784 * header[0] == "lt\0\0",
1785 * header[1] == length_of_stream.
1787 * Also handle streams where we do not have a working "Stat" method by
1788 * reading all data until the end of the stream.
1790 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1791 if (hr) {
1792 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1793 statfailed = TRUE;
1794 /* we will read at least 8 byte ... just right below */
1795 statstg.cbSize.QuadPart = 8;
1798 toread = 0;
1799 headerread = 0;
1800 headerisdata = FALSE;
1801 do {
1802 hr=IStream_Read(pStm,header,8,&xread);
1803 if (hr || xread!=8) {
1804 FIXME("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1805 return hr;
1807 headerread += xread;
1808 xread = 0;
1810 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1811 if (toread != 0 && toread != header[1])
1812 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1813 toread, header[1]);
1814 toread = header[1];
1815 if (toread == 0) break;
1816 } else {
1817 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1818 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1819 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1820 (header[0] == EMR_HEADER) || /* EMF header */
1821 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1822 (header[1]==0)
1823 ) {/* Found start of bitmap data */
1824 headerisdata = TRUE;
1825 if (toread == 0)
1826 toread = statstg.cbSize.QuadPart-8;
1827 else toread -= 8;
1828 xread = 8;
1829 } else {
1830 FIXME("Unknown stream header magic: %08x\n", header[0]);
1831 toread = header[1];
1834 } while (!headerisdata);
1836 if (statfailed) { /* we don't know the size ... read all we get */
1837 int sizeinc = 4096;
1838 int origsize = sizeinc;
1839 ULONG nread = 42;
1841 TRACE("Reading all data from stream.\n");
1842 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1843 if (headerisdata)
1844 memcpy (xbuf, header, 8);
1845 while (1) {
1846 while (xread < origsize) {
1847 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1848 xread+=nread;
1849 if (hr || !nread)
1850 break;
1852 if (!nread || hr) /* done, or error */
1853 break;
1854 if (xread == origsize) {
1855 origsize += sizeinc;
1856 sizeinc = 2*sizeinc; /* exponential increase */
1857 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1860 if (hr)
1861 TRACE("hr in no-stat loader case is %08x\n", hr);
1862 TRACE("loaded %d bytes.\n", xread);
1863 This->datalen = xread;
1864 This->data = xbuf;
1865 } else {
1866 This->datalen = toread+(headerisdata?8:0);
1867 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1868 if (!xbuf)
1869 return E_OUTOFMEMORY;
1871 if (headerisdata)
1872 memcpy (xbuf, header, 8);
1874 while (xread < This->datalen) {
1875 ULONG nread;
1876 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1877 xread+=nread;
1878 if (hr || !nread)
1879 break;
1881 if (xread != This->datalen)
1882 FIXME("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1884 if (This->datalen == 0) { /* Marks the "NONE" picture */
1885 This->desc.picType = PICTYPE_NONE;
1886 return S_OK;
1890 /****************************************************************************************
1891 * Part 2: Process the loaded data
1894 magic = xbuf[0] + (xbuf[1]<<8);
1895 This->loadtime_format = magic;
1897 switch (magic) {
1898 case BITMAP_FORMAT_GIF: /* GIF */
1899 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1900 break;
1901 case BITMAP_FORMAT_JPEG: /* JPEG */
1902 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1903 break;
1904 case BITMAP_FORMAT_BMP: /* Bitmap */
1905 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1906 break;
1907 case BITMAP_FORMAT_PNG: /* PNG */
1908 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1909 break;
1910 case BITMAP_FORMAT_APM: /* APM */
1911 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1912 break;
1913 case 0x0000: { /* ICON , first word is dwReserved */
1914 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1915 break;
1917 default:
1919 unsigned int i;
1921 /* let's see if it's a EMF */
1922 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1923 if (hr == S_OK) break;
1925 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1926 hr=E_FAIL;
1927 for (i=0;i<xread+8;i++) {
1928 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1929 else MESSAGE("%02x ",xbuf[i-8]);
1930 if (i % 10 == 9) MESSAGE("\n");
1932 MESSAGE("\n");
1933 break;
1936 This->bIsDirty = FALSE;
1938 /* FIXME: this notify is not really documented */
1939 if (hr==S_OK)
1940 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1941 return hr;
1944 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1946 int iSuccess = 0;
1947 HDC hDC;
1948 BITMAPINFO * pInfoBitmap;
1949 int iNumPaletteEntries;
1950 unsigned char * pPixelData;
1951 BITMAPFILEHEADER * pFileHeader;
1952 BITMAPINFO * pInfoHeader;
1954 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1955 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1957 /* Find out bitmap size and padded length */
1958 hDC = GetDC(0);
1959 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1960 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1962 /* Fetch bitmap palette & pixel data */
1964 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1965 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1967 /* Calculate the total length required for the BMP data */
1968 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1969 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1970 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1971 } else {
1972 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1973 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1974 else
1975 iNumPaletteEntries = 0;
1977 *pLength =
1978 sizeof(BITMAPFILEHEADER) +
1979 sizeof(BITMAPINFOHEADER) +
1980 iNumPaletteEntries * sizeof(RGBQUAD) +
1981 pInfoBitmap->bmiHeader.biSizeImage;
1982 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1984 /* Fill the BITMAPFILEHEADER */
1985 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1986 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1987 pFileHeader->bfSize = *pLength;
1988 pFileHeader->bfOffBits =
1989 sizeof(BITMAPFILEHEADER) +
1990 sizeof(BITMAPINFOHEADER) +
1991 iNumPaletteEntries * sizeof(RGBQUAD);
1993 /* Fill the BITMAPINFOHEADER and the palette data */
1994 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1995 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1996 memcpy(
1997 (unsigned char *)(*ppBuffer) +
1998 sizeof(BITMAPFILEHEADER) +
1999 sizeof(BITMAPINFOHEADER) +
2000 iNumPaletteEntries * sizeof(RGBQUAD),
2001 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2002 iSuccess = 1;
2004 HeapFree(GetProcessHeap(), 0, pPixelData);
2005 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2006 return iSuccess;
2009 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2011 ICONINFO infoIcon;
2012 int iSuccess = 0;
2014 *ppBuffer = NULL; *pLength = 0;
2015 if (GetIconInfo(hIcon, &infoIcon)) {
2016 HDC hDC;
2017 BITMAPINFO * pInfoBitmap;
2018 unsigned char * pIconData = NULL;
2019 unsigned int iDataSize = 0;
2021 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2023 /* Find out icon size */
2024 hDC = GetDC(0);
2025 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2026 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2027 if (1) {
2028 /* Auxiliary pointers */
2029 CURSORICONFILEDIR * pIconDir;
2030 CURSORICONFILEDIRENTRY * pIconEntry;
2031 BITMAPINFOHEADER * pIconBitmapHeader;
2032 unsigned int iOffsetPalette;
2033 unsigned int iOffsetColorData;
2034 unsigned int iOffsetMaskData;
2036 unsigned int iLengthScanLineColor;
2037 unsigned int iLengthScanLineMask;
2038 unsigned int iNumEntriesPalette;
2040 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2041 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2043 FIXME("DEBUG: bitmap size is %d x %d\n",
2044 pInfoBitmap->bmiHeader.biWidth,
2045 pInfoBitmap->bmiHeader.biHeight);
2046 FIXME("DEBUG: bitmap bpp is %d\n",
2047 pInfoBitmap->bmiHeader.biBitCount);
2048 FIXME("DEBUG: bitmap nplanes is %d\n",
2049 pInfoBitmap->bmiHeader.biPlanes);
2050 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2051 pInfoBitmap->bmiHeader.biSizeImage);
2053 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2054 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2055 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2057 /* Fill out the CURSORICONFILEDIR */
2058 pIconDir = (CURSORICONFILEDIR *)pIconData;
2059 pIconDir->idType = 1;
2060 pIconDir->idCount = 1;
2062 /* Fill out the CURSORICONFILEDIRENTRY */
2063 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2064 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2065 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2066 pIconEntry->bColorCount =
2067 (pInfoBitmap->bmiHeader.biBitCount < 8)
2068 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2069 : 0;
2070 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2071 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2072 pIconEntry->dwDIBSize = 0;
2073 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2075 /* Fill out the BITMAPINFOHEADER */
2076 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2077 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2079 /* Find out whether a palette exists for the bitmap */
2080 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2081 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2082 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2083 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2084 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2085 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2086 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2087 iNumEntriesPalette = 3;
2088 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2089 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2090 } else {
2091 iNumEntriesPalette = 0;
2094 /* Add bitmap size and header size to icon data size. */
2095 iOffsetPalette = iDataSize;
2096 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2097 iOffsetColorData = iDataSize;
2098 iDataSize += pIconBitmapHeader->biSizeImage;
2099 iOffsetMaskData = iDataSize;
2100 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2101 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2102 pIconBitmapHeader->biHeight *= 2;
2103 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2104 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2105 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2106 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2108 /* Get the actual bitmap data from the icon bitmap */
2109 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2110 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2111 if (iNumEntriesPalette > 0) {
2112 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2113 iNumEntriesPalette * sizeof(RGBQUAD));
2116 /* Reset all values so that GetDIBits call succeeds */
2117 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2118 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2119 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2121 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2122 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2123 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2125 printf("ERROR: unable to get bitmap mask (error %u)\n",
2126 GetLastError());
2130 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2131 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2133 /* Write out everything produced so far to the stream */
2134 *ppBuffer = pIconData; *pLength = iDataSize;
2135 iSuccess = 1;
2136 } else {
2138 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2139 GetLastError());
2143 Remarks (from MSDN entry on GetIconInfo):
2145 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2146 members of ICONINFO. The calling application must manage
2147 these bitmaps and delete them when they are no longer
2148 necessary.
2150 if (hDC) ReleaseDC(0, hDC);
2151 DeleteObject(infoIcon.hbmMask);
2152 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2153 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2154 } else {
2155 printf("ERROR: Unable to get icon information (error %u)\n",
2156 GetLastError());
2158 return iSuccess;
2161 static HRESULT WINAPI OLEPictureImpl_Save(
2162 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2164 HRESULT hResult = E_NOTIMPL;
2165 void * pIconData;
2166 unsigned int iDataSize;
2167 ULONG dummy;
2168 int iSerializeResult = 0;
2169 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2171 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2173 switch (This->desc.picType) {
2174 case PICTYPE_ICON:
2175 if (This->bIsDirty || !This->data) {
2176 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2177 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2178 hResult = E_FAIL;
2179 break;
2181 HeapFree(GetProcessHeap(), 0, This->data);
2182 This->data = pIconData;
2183 This->datalen = iDataSize;
2185 if (This->loadtime_magic != 0xdeadbeef) {
2186 DWORD header[2];
2188 header[0] = This->loadtime_magic;
2189 header[1] = This->datalen;
2190 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2192 IStream_Write(pStm, This->data, This->datalen, &dummy);
2194 hResult = S_OK;
2195 break;
2196 case PICTYPE_BITMAP:
2197 if (This->bIsDirty) {
2198 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2199 case BITMAP_FORMAT_BMP:
2200 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2201 break;
2202 case BITMAP_FORMAT_JPEG:
2203 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2204 break;
2205 case BITMAP_FORMAT_GIF:
2206 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2207 break;
2208 case BITMAP_FORMAT_PNG:
2209 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2210 break;
2211 default:
2212 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2213 break;
2215 if (iSerializeResult) {
2217 if (This->loadtime_magic != 0xdeadbeef) {
2219 if (1) {
2220 DWORD header[2];
2222 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2223 header[1] = iDataSize;
2224 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2226 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2228 HeapFree(GetProcessHeap(), 0, This->data);
2229 This->data = pIconData;
2230 This->datalen = iDataSize;
2231 hResult = S_OK;
2233 } else {
2235 if (This->loadtime_magic != 0xdeadbeef) {
2237 if (1) {
2238 DWORD header[2];
2240 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2241 header[1] = This->datalen;
2242 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2244 IStream_Write(pStm, This->data, This->datalen, &dummy);
2245 hResult = S_OK;
2247 break;
2248 case PICTYPE_METAFILE:
2249 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2250 break;
2251 case PICTYPE_ENHMETAFILE:
2252 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2253 break;
2254 default:
2255 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2256 break;
2258 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2259 return hResult;
2262 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2263 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2265 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2266 FIXME("(%p,%p),stub!\n",This,pcbSize);
2267 return E_NOTIMPL;
2271 /************************************************************************
2272 * IDispatch
2275 /************************************************************************
2276 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2278 * See Windows documentation for more details on IUnknown methods.
2280 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2281 IDispatch* iface,
2282 REFIID riid,
2283 VOID** ppvoid)
2285 OLEPictureImpl *This = impl_from_IDispatch(iface);
2287 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2290 /************************************************************************
2291 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2293 * See Windows documentation for more details on IUnknown methods.
2295 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2296 IDispatch* iface)
2298 OLEPictureImpl *This = impl_from_IDispatch(iface);
2300 return IPicture_AddRef((IPicture *)This);
2303 /************************************************************************
2304 * OLEPictureImpl_IDispatch_Release (IUnknown)
2306 * See Windows documentation for more details on IUnknown methods.
2308 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2309 IDispatch* iface)
2311 OLEPictureImpl *This = impl_from_IDispatch(iface);
2313 return IPicture_Release((IPicture *)This);
2316 /************************************************************************
2317 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2319 * See Windows documentation for more details on IDispatch methods.
2321 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2322 IDispatch* iface,
2323 unsigned int* pctinfo)
2325 TRACE("(%p)\n", pctinfo);
2327 *pctinfo = 1;
2329 return S_OK;
2332 /************************************************************************
2333 * OLEPictureImpl_GetTypeInfo (IDispatch)
2335 * See Windows documentation for more details on IDispatch methods.
2337 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2338 IDispatch* iface,
2339 UINT iTInfo,
2340 LCID lcid,
2341 ITypeInfo** ppTInfo)
2343 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2344 ITypeLib *tl;
2345 HRESULT hres;
2347 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2349 if (iTInfo != 0)
2350 return E_FAIL;
2352 hres = LoadTypeLib(stdole2tlb, &tl);
2353 if (FAILED(hres))
2355 ERR("Could not load stdole2.tlb\n");
2356 return hres;
2359 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2360 if (FAILED(hres))
2361 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2363 return hres;
2366 /************************************************************************
2367 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2369 * See Windows documentation for more details on IDispatch methods.
2371 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2372 IDispatch* iface,
2373 REFIID riid,
2374 LPOLESTR* rgszNames,
2375 UINT cNames,
2376 LCID lcid,
2377 DISPID* rgDispId)
2379 ITypeInfo * pTInfo;
2380 HRESULT hres;
2382 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2383 rgszNames, cNames, (int)lcid, rgDispId);
2385 if (cNames == 0)
2387 return E_INVALIDARG;
2389 else
2391 /* retrieve type information */
2392 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2394 if (FAILED(hres))
2396 ERR("GetTypeInfo failed.\n");
2397 return hres;
2400 /* convert names to DISPIDs */
2401 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2402 ITypeInfo_Release(pTInfo);
2404 return hres;
2408 /************************************************************************
2409 * OLEPictureImpl_Invoke (IDispatch)
2411 * See Windows documentation for more details on IDispatch methods.
2413 static HRESULT WINAPI OLEPictureImpl_Invoke(
2414 IDispatch* iface,
2415 DISPID dispIdMember,
2416 REFIID riid,
2417 LCID lcid,
2418 WORD wFlags,
2419 DISPPARAMS* pDispParams,
2420 VARIANT* pVarResult,
2421 EXCEPINFO* pExepInfo,
2422 UINT* puArgErr)
2424 OLEPictureImpl *This = impl_from_IDispatch(iface);
2426 /* validate parameters */
2428 if (!IsEqualIID(riid, &IID_NULL))
2430 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2431 return DISP_E_UNKNOWNNAME;
2434 if (!pDispParams)
2436 ERR("null pDispParams not allowed\n");
2437 return DISP_E_PARAMNOTOPTIONAL;
2440 if (wFlags & DISPATCH_PROPERTYGET)
2442 if (pDispParams->cArgs != 0)
2444 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2445 return DISP_E_BADPARAMCOUNT;
2447 if (!pVarResult)
2449 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2450 return DISP_E_PARAMNOTOPTIONAL;
2453 else if (wFlags & DISPATCH_PROPERTYPUT)
2455 if (pDispParams->cArgs != 1)
2457 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2458 return DISP_E_BADPARAMCOUNT;
2462 switch (dispIdMember)
2464 case DISPID_PICT_HANDLE:
2465 if (wFlags & DISPATCH_PROPERTYGET)
2467 TRACE("DISPID_PICT_HANDLE\n");
2468 V_VT(pVarResult) = VT_I4;
2469 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2471 break;
2472 case DISPID_PICT_HPAL:
2473 if (wFlags & DISPATCH_PROPERTYGET)
2475 TRACE("DISPID_PICT_HPAL\n");
2476 V_VT(pVarResult) = VT_I4;
2477 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2479 else if (wFlags & DISPATCH_PROPERTYPUT)
2481 VARIANTARG vararg;
2482 HRESULT hr;
2483 TRACE("DISPID_PICT_HPAL\n");
2485 VariantInit(&vararg);
2486 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2487 if (FAILED(hr))
2488 return hr;
2490 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2492 VariantClear(&vararg);
2493 return hr;
2495 break;
2496 case DISPID_PICT_TYPE:
2497 if (wFlags & DISPATCH_PROPERTYGET)
2499 TRACE("DISPID_PICT_TYPE\n");
2500 V_VT(pVarResult) = VT_I2;
2501 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2503 break;
2504 case DISPID_PICT_WIDTH:
2505 if (wFlags & DISPATCH_PROPERTYGET)
2507 TRACE("DISPID_PICT_WIDTH\n");
2508 V_VT(pVarResult) = VT_I4;
2509 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2511 break;
2512 case DISPID_PICT_HEIGHT:
2513 if (wFlags & DISPATCH_PROPERTYGET)
2515 TRACE("DISPID_PICT_HEIGHT\n");
2516 V_VT(pVarResult) = VT_I4;
2517 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2519 break;
2522 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2523 return DISP_E_MEMBERNOTFOUND;
2527 static const IPictureVtbl OLEPictureImpl_VTable =
2529 OLEPictureImpl_QueryInterface,
2530 OLEPictureImpl_AddRef,
2531 OLEPictureImpl_Release,
2532 OLEPictureImpl_get_Handle,
2533 OLEPictureImpl_get_hPal,
2534 OLEPictureImpl_get_Type,
2535 OLEPictureImpl_get_Width,
2536 OLEPictureImpl_get_Height,
2537 OLEPictureImpl_Render,
2538 OLEPictureImpl_set_hPal,
2539 OLEPictureImpl_get_CurDC,
2540 OLEPictureImpl_SelectPicture,
2541 OLEPictureImpl_get_KeepOriginalFormat,
2542 OLEPictureImpl_put_KeepOriginalFormat,
2543 OLEPictureImpl_PictureChanged,
2544 OLEPictureImpl_SaveAsFile,
2545 OLEPictureImpl_get_Attributes
2548 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2550 OLEPictureImpl_IDispatch_QueryInterface,
2551 OLEPictureImpl_IDispatch_AddRef,
2552 OLEPictureImpl_IDispatch_Release,
2553 OLEPictureImpl_GetTypeInfoCount,
2554 OLEPictureImpl_GetTypeInfo,
2555 OLEPictureImpl_GetIDsOfNames,
2556 OLEPictureImpl_Invoke
2559 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2561 OLEPictureImpl_IPersistStream_QueryInterface,
2562 OLEPictureImpl_IPersistStream_AddRef,
2563 OLEPictureImpl_IPersistStream_Release,
2564 OLEPictureImpl_GetClassID,
2565 OLEPictureImpl_IsDirty,
2566 OLEPictureImpl_Load,
2567 OLEPictureImpl_Save,
2568 OLEPictureImpl_GetSizeMax
2571 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2573 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2574 OLEPictureImpl_IConnectionPointContainer_AddRef,
2575 OLEPictureImpl_IConnectionPointContainer_Release,
2576 OLEPictureImpl_EnumConnectionPoints,
2577 OLEPictureImpl_FindConnectionPoint
2580 /***********************************************************************
2581 * OleCreatePictureIndirect (OLEAUT32.419)
2583 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2584 BOOL fOwn, LPVOID *ppvObj )
2586 OLEPictureImpl* newPict = NULL;
2587 HRESULT hr = S_OK;
2589 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2592 * Sanity check
2594 if (ppvObj==0)
2595 return E_POINTER;
2597 *ppvObj = NULL;
2600 * Try to construct a new instance of the class.
2602 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2604 if (newPict == NULL)
2605 return E_OUTOFMEMORY;
2608 * Make sure it supports the interface required by the caller.
2610 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2613 * Release the reference obtained in the constructor. If
2614 * the QueryInterface was unsuccessful, it will free the class.
2616 IPicture_Release((IPicture*)newPict);
2618 return hr;
2622 /***********************************************************************
2623 * OleLoadPicture (OLEAUT32.418)
2625 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2626 REFIID riid, LPVOID *ppvObj )
2628 LPPERSISTSTREAM ps;
2629 IPicture *newpic;
2630 HRESULT hr;
2632 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2633 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2635 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2636 if (hr)
2637 return hr;
2638 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2639 if (hr) {
2640 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2641 IPicture_Release(newpic);
2642 *ppvObj = NULL;
2643 return hr;
2645 hr = IPersistStream_Load(ps,lpstream);
2646 IPersistStream_Release(ps);
2647 if (FAILED(hr))
2649 ERR("IPersistStream_Load failed\n");
2650 IPicture_Release(newpic);
2651 *ppvObj = NULL;
2652 return hr;
2654 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2655 if (hr)
2656 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2657 IPicture_Release(newpic);
2658 return hr;
2661 /***********************************************************************
2662 * OleLoadPictureEx (OLEAUT32.401)
2664 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2665 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2667 LPPERSISTSTREAM ps;
2668 IPicture *newpic;
2669 HRESULT hr;
2671 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2672 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2674 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2675 if (hr)
2676 return hr;
2677 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2678 if (hr) {
2679 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2680 IPicture_Release(newpic);
2681 *ppvObj = NULL;
2682 return hr;
2684 hr = IPersistStream_Load(ps,lpstream);
2685 IPersistStream_Release(ps);
2686 if (FAILED(hr))
2688 ERR("IPersistStream_Load failed\n");
2689 IPicture_Release(newpic);
2690 *ppvObj = NULL;
2691 return hr;
2693 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2694 if (hr)
2695 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2696 IPicture_Release(newpic);
2697 return hr;
2700 /***********************************************************************
2701 * OleLoadPicturePath (OLEAUT32.424)
2703 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2704 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2705 LPVOID *ppvRet )
2707 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2708 IPicture *ipicture;
2709 HANDLE hFile;
2710 DWORD dwFileSize;
2711 HGLOBAL hGlobal = NULL;
2712 DWORD dwBytesRead = 0;
2713 IStream *stream;
2714 BOOL bRead;
2715 IPersistStream *pStream;
2716 HRESULT hRes;
2718 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2719 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2720 debugstr_guid(riid), ppvRet);
2722 if (!ppvRet) return E_POINTER;
2724 if (strncmpW(szURLorPath, file, 7) == 0) {
2725 szURLorPath += 7;
2727 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2728 0, NULL);
2729 if (hFile == INVALID_HANDLE_VALUE)
2730 return E_UNEXPECTED;
2732 dwFileSize = GetFileSize(hFile, NULL);
2733 if (dwFileSize != INVALID_FILE_SIZE )
2735 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2736 if ( hGlobal)
2738 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2739 if (!bRead)
2741 GlobalFree(hGlobal);
2742 hGlobal = 0;
2746 CloseHandle(hFile);
2748 if (!hGlobal)
2749 return E_UNEXPECTED;
2751 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2752 if (FAILED(hRes))
2754 GlobalFree(hGlobal);
2755 return hRes;
2757 } else {
2758 IMoniker *pmnk;
2759 IBindCtx *pbc;
2761 hRes = CreateBindCtx(0, &pbc);
2762 if (SUCCEEDED(hRes))
2764 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2765 if (SUCCEEDED(hRes))
2767 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2768 IMoniker_Release(pmnk);
2770 IBindCtx_Release(pbc);
2772 if (FAILED(hRes))
2773 return hRes;
2776 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2777 &IID_IPicture, (LPVOID*)&ipicture);
2778 if (hRes != S_OK) {
2779 IStream_Release(stream);
2780 return hRes;
2783 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2784 if (hRes) {
2785 IStream_Release(stream);
2786 IPicture_Release(ipicture);
2787 return hRes;
2790 hRes = IPersistStream_Load(pStream, stream);
2791 IPersistStream_Release(pStream);
2792 IStream_Release(stream);
2794 if (hRes) {
2795 IPicture_Release(ipicture);
2796 return hRes;
2799 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2800 if (hRes)
2801 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2803 IPicture_Release(ipicture);
2804 return hRes;
2807 /*******************************************************************************
2808 * StdPic ClassFactory
2810 typedef struct
2812 /* IUnknown fields */
2813 const IClassFactoryVtbl *lpVtbl;
2814 LONG ref;
2815 } IClassFactoryImpl;
2817 static HRESULT WINAPI
2818 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2819 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2821 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2822 return E_NOINTERFACE;
2825 static ULONG WINAPI
2826 SPCF_AddRef(LPCLASSFACTORY iface) {
2827 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2828 return InterlockedIncrement(&This->ref);
2831 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2832 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2833 /* static class, won't be freed */
2834 return InterlockedDecrement(&This->ref);
2837 static HRESULT WINAPI SPCF_CreateInstance(
2838 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2840 /* Creates an uninitialized picture */
2841 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2845 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2846 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2847 FIXME("(%p)->(%d),stub!\n",This,dolock);
2848 return S_OK;
2851 static const IClassFactoryVtbl SPCF_Vtbl = {
2852 SPCF_QueryInterface,
2853 SPCF_AddRef,
2854 SPCF_Release,
2855 SPCF_CreateInstance,
2856 SPCF_LockServer
2858 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2860 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }