d3d10core: Implement ID3D10Texture2D::GetType().
[wine/multimedia.git] / dlls / oleaut32 / olepicture.c
blobf05501d5cf4e30bf28927565deec0a093efea918
1 /*
2 * OLE Picture object
4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
8 * Copyright 2008 Kirill K. Smirnov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * BUGS
26 * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
27 * Lots of methods are just stubs.
30 * NOTES (or things that msdn doesn't tell you)
32 * The width and height properties are returned in HIMETRIC units (0.01mm)
33 * IPicture::Render also uses these to select a region of the src picture.
34 * A bitmap's size is converted into these units by using the screen resolution
35 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
39 #include "config.h"
40 #include "wine/port.h"
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <string.h>
49 #ifdef SONAME_LIBJPEG
50 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
51 #define XMD_H
52 #define UINT8 JPEG_UINT8
53 #define UINT16 JPEG_UINT16
54 #define boolean jpeg_boolean
55 # include <jpeglib.h>
56 #undef UINT8
57 #undef UINT16
58 #undef boolean
59 #endif
61 #ifdef HAVE_PNG_H
62 #include <png.h>
63 #endif
65 /* Must be before wine includes, the header has things conflicting with
66 * WINE headers.
68 #define COBJMACROS
69 #define NONAMELESSUNION
70 #define NONAMELESSSTRUCT
72 #include "winerror.h"
73 #include "windef.h"
74 #include "winbase.h"
75 #include "wingdi.h"
76 #include "winuser.h"
77 #include "ole2.h"
78 #include "olectl.h"
79 #include "oleauto.h"
80 #include "connpt.h"
81 #include "urlmon.h"
82 #include "wine/debug.h"
83 #include "wine/unicode.h"
85 #include "wine/wingdi16.h"
87 #include "ungif.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(ole);
91 #include "pshpack1.h"
93 /* Header for Aldus Placable Metafiles - a standard metafile follows */
94 typedef struct _APM_HEADER
96 DWORD key;
97 WORD handle;
98 SHORT left;
99 SHORT top;
100 SHORT right;
101 SHORT bottom;
102 WORD inch;
103 DWORD reserved;
104 WORD checksum;
105 } APM_HEADER;
107 typedef struct {
108 BYTE bWidth;
109 BYTE bHeight;
110 BYTE bColorCount;
111 BYTE bReserved;
112 WORD xHotspot;
113 WORD yHotspot;
114 DWORD dwDIBSize;
115 DWORD dwDIBOffset;
116 } CURSORICONFILEDIRENTRY;
118 typedef struct
120 WORD idReserved;
121 WORD idType;
122 WORD idCount;
123 CURSORICONFILEDIRENTRY idEntries[1];
124 } CURSORICONFILEDIR;
126 #include "poppack.h"
128 /*************************************************************************
129 * Declaration of implementation class
132 typedef struct OLEPictureImpl {
135 * IPicture handles IUnknown
138 const IPictureVtbl *lpVtbl;
139 const IDispatchVtbl *lpvtblIDispatch;
140 const IPersistStreamVtbl *lpvtblIPersistStream;
141 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
143 /* Object reference count */
144 LONG ref;
146 /* We own the object and must destroy it ourselves */
147 BOOL fOwn;
149 /* Picture description */
150 PICTDESC desc;
152 /* These are the pixel size of a bitmap */
153 DWORD origWidth;
154 DWORD origHeight;
156 /* And these are the size of the picture converted into HIMETRIC units */
157 OLE_XSIZE_HIMETRIC himetricWidth;
158 OLE_YSIZE_HIMETRIC himetricHeight;
160 IConnectionPoint *pCP;
162 BOOL keepOrigFormat;
163 HDC hDCCur;
165 /* Bitmap transparency mask */
166 HBITMAP hbmMask;
167 HBITMAP hbmXor;
168 COLORREF rgbTrans;
170 /* data */
171 void* data;
172 int datalen;
173 BOOL bIsDirty; /* Set to TRUE if picture has changed */
174 unsigned int loadtime_magic; /* If a length header was found, saves value */
175 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
176 } OLEPictureImpl;
179 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
182 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
184 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
187 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
189 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
192 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
194 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
198 * Predeclare VTables. They get initialized at the end.
200 static const IPictureVtbl OLEPictureImpl_VTable;
201 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
202 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
203 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
205 /***********************************************************************
206 * Implementation of the OLEPictureImpl class.
209 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
210 BITMAP bm;
211 HDC hdcRef;
213 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
214 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
215 ERR("GetObject fails\n");
216 return;
218 This->origWidth = bm.bmWidth;
219 This->origHeight = bm.bmHeight;
220 /* The width and height are stored in HIMETRIC units (0.01 mm),
221 so we take our pixel width divide by pixels per inch and
222 multiply by 25.4 * 100 */
223 /* Should we use GetBitmapDimension if available? */
224 hdcRef = CreateCompatibleDC(0);
225 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
226 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
227 DeleteDC(hdcRef);
230 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
232 ICONINFO infoIcon;
234 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
235 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
236 HDC hdcRef;
237 BITMAP bm;
239 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
240 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
241 ERR("GetObject fails on icon bitmap\n");
242 return;
245 This->origWidth = bm.bmWidth;
246 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
247 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
248 hdcRef = GetDC(0);
249 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
250 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
251 ReleaseDC(0, hdcRef);
253 DeleteObject(infoIcon.hbmMask);
254 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
255 } else {
256 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
260 /************************************************************************
261 * OLEPictureImpl_Construct
263 * This method will construct a new instance of the OLEPictureImpl
264 * class.
266 * The caller of this method must release the object when it's
267 * done with it.
269 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
271 OLEPictureImpl* newObject = 0;
273 if (pictDesc)
274 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
277 * Allocate space for the object.
279 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
281 if (newObject==0)
282 return newObject;
285 * Initialize the virtual function table.
287 newObject->lpVtbl = &OLEPictureImpl_VTable;
288 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
289 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
290 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
292 newObject->pCP = NULL;
293 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
294 if (!newObject->pCP)
296 HeapFree(GetProcessHeap(), 0, newObject);
297 return NULL;
301 * Start with one reference count. The caller of this function
302 * must release the interface pointer when it is done.
304 newObject->ref = 1;
305 newObject->hDCCur = 0;
307 newObject->fOwn = fOwn;
309 /* dunno about original value */
310 newObject->keepOrigFormat = TRUE;
312 newObject->hbmMask = NULL;
313 newObject->hbmXor = NULL;
314 newObject->loadtime_magic = 0xdeadbeef;
315 newObject->loadtime_format = 0;
316 newObject->bIsDirty = FALSE;
318 if (pictDesc) {
319 newObject->desc = *pictDesc;
321 switch(pictDesc->picType) {
322 case PICTYPE_BITMAP:
323 OLEPictureImpl_SetBitmap(newObject);
324 break;
326 case PICTYPE_METAFILE:
327 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
328 newObject->himetricWidth = pictDesc->u.wmf.xExt;
329 newObject->himetricHeight = pictDesc->u.wmf.yExt;
330 break;
332 case PICTYPE_NONE:
333 /* not sure what to do here */
334 newObject->himetricWidth = newObject->himetricHeight = 0;
335 break;
337 case PICTYPE_ICON:
338 OLEPictureImpl_SetIcon(newObject);
339 break;
340 case PICTYPE_ENHMETAFILE:
341 default:
342 FIXME("Unsupported type %d\n", pictDesc->picType);
343 newObject->himetricWidth = newObject->himetricHeight = 0;
344 break;
346 } else {
347 newObject->desc.picType = PICTYPE_UNINITIALIZED;
350 TRACE("returning %p\n", newObject);
351 return newObject;
354 /************************************************************************
355 * OLEPictureImpl_Destroy
357 * This method is called by the Release method when the reference
358 * count goes down to 0. It will free all resources used by
359 * this object. */
360 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
362 TRACE("(%p)\n", Obj);
364 if (Obj->pCP)
365 IConnectionPoint_Release(Obj->pCP);
367 if(Obj->fOwn) { /* We need to destroy the picture */
368 switch(Obj->desc.picType) {
369 case PICTYPE_BITMAP:
370 DeleteObject(Obj->desc.u.bmp.hbitmap);
371 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
372 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
373 break;
374 case PICTYPE_METAFILE:
375 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
376 break;
377 case PICTYPE_ICON:
378 DestroyIcon(Obj->desc.u.icon.hicon);
379 break;
380 case PICTYPE_ENHMETAFILE:
381 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
382 break;
383 case PICTYPE_NONE:
384 case PICTYPE_UNINITIALIZED:
385 /* Nothing to do */
386 break;
387 default:
388 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
389 break;
392 HeapFree(GetProcessHeap(), 0, Obj->data);
393 HeapFree(GetProcessHeap(), 0, Obj);
397 /************************************************************************
398 * OLEPictureImpl_AddRef (IUnknown)
400 * See Windows documentation for more details on IUnknown methods.
402 static ULONG WINAPI OLEPictureImpl_AddRef(
403 IPicture* iface)
405 OLEPictureImpl *This = (OLEPictureImpl *)iface;
406 ULONG refCount = InterlockedIncrement(&This->ref);
408 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
410 return refCount;
413 /************************************************************************
414 * OLEPictureImpl_Release (IUnknown)
416 * See Windows documentation for more details on IUnknown methods.
418 static ULONG WINAPI OLEPictureImpl_Release(
419 IPicture* iface)
421 OLEPictureImpl *This = (OLEPictureImpl *)iface;
422 ULONG refCount = InterlockedDecrement(&This->ref);
424 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
427 * If the reference count goes down to 0, perform suicide.
429 if (!refCount) OLEPictureImpl_Destroy(This);
431 return refCount;
434 /************************************************************************
435 * OLEPictureImpl_QueryInterface (IUnknown)
437 * See Windows documentation for more details on IUnknown methods.
439 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
440 IPicture* iface,
441 REFIID riid,
442 void** ppvObject)
444 OLEPictureImpl *This = (OLEPictureImpl *)iface;
445 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
448 * Perform a sanity check on the parameters.
450 if ( (This==0) || (ppvObject==0) )
451 return E_INVALIDARG;
454 * Initialize the return parameter.
456 *ppvObject = 0;
459 * Compare the riid with the interface IDs implemented by this object.
461 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
462 *ppvObject = (IPicture*)This;
463 else if (IsEqualIID(&IID_IDispatch, riid))
464 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
465 else if (IsEqualIID(&IID_IPictureDisp, riid))
466 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
467 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
468 *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
469 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
470 *ppvObject = (IConnectionPointContainer*)&(This->lpvtblIConnectionPointContainer);
473 * Check that we obtained an interface.
475 if ((*ppvObject)==0)
477 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
478 return E_NOINTERFACE;
482 * Query Interface always increases the reference count by one when it is
483 * successful
485 OLEPictureImpl_AddRef((IPicture*)This);
487 return S_OK;
490 /***********************************************************************
491 * OLEPicture_SendNotify (internal)
493 * Sends notification messages of changed properties to any interested
494 * connections.
496 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
498 IEnumConnections *pEnum;
499 CONNECTDATA CD;
501 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
502 return;
503 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
504 IPropertyNotifySink *sink;
506 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
507 IPropertyNotifySink_OnChanged(sink, dispID);
508 IPropertyNotifySink_Release(sink);
509 IUnknown_Release(CD.pUnk);
511 IEnumConnections_Release(pEnum);
514 /************************************************************************
515 * OLEPictureImpl_get_Handle
517 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
518 OLE_HANDLE *phandle)
520 OLEPictureImpl *This = (OLEPictureImpl *)iface;
521 TRACE("(%p)->(%p)\n", This, phandle);
523 if(!phandle)
524 return E_POINTER;
526 switch(This->desc.picType) {
527 case PICTYPE_NONE:
528 case PICTYPE_UNINITIALIZED:
529 *phandle = 0;
530 break;
531 case PICTYPE_BITMAP:
532 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
533 break;
534 case PICTYPE_METAFILE:
535 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
536 break;
537 case PICTYPE_ICON:
538 *phandle = HandleToUlong(This->desc.u.icon.hicon);
539 break;
540 case PICTYPE_ENHMETAFILE:
541 *phandle = HandleToUlong(This->desc.u.emf.hemf);
542 break;
543 default:
544 FIXME("Unimplemented type %d\n", This->desc.picType);
545 return E_NOTIMPL;
547 TRACE("returning handle %08x\n", *phandle);
548 return S_OK;
551 /************************************************************************
552 * OLEPictureImpl_get_hPal
554 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
555 OLE_HANDLE *phandle)
557 OLEPictureImpl *This = (OLEPictureImpl *)iface;
558 HRESULT hres;
559 TRACE("(%p)->(%p)\n", This, phandle);
561 if (!phandle)
562 return E_POINTER;
564 switch (This->desc.picType) {
565 case (UINT)PICTYPE_UNINITIALIZED:
566 case PICTYPE_NONE:
567 *phandle = 0;
568 hres = S_FALSE;
569 break;
570 case PICTYPE_BITMAP:
571 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
572 hres = S_OK;
573 break;
574 case PICTYPE_METAFILE:
575 hres = E_FAIL;
576 break;
577 case PICTYPE_ICON:
578 case PICTYPE_ENHMETAFILE:
579 default:
580 FIXME("unimplemented for type %d. Returning 0 palette.\n",
581 This->desc.picType);
582 *phandle = 0;
583 hres = S_OK;
586 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
587 return hres;
590 /************************************************************************
591 * OLEPictureImpl_get_Type
593 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
594 short *ptype)
596 OLEPictureImpl *This = (OLEPictureImpl *)iface;
597 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
599 if(!ptype)
600 return E_POINTER;
602 *ptype = This->desc.picType;
603 return S_OK;
606 /************************************************************************
607 * OLEPictureImpl_get_Width
609 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
610 OLE_XSIZE_HIMETRIC *pwidth)
612 OLEPictureImpl *This = (OLEPictureImpl *)iface;
613 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
614 *pwidth = This->himetricWidth;
615 return S_OK;
618 /************************************************************************
619 * OLEPictureImpl_get_Height
621 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
622 OLE_YSIZE_HIMETRIC *pheight)
624 OLEPictureImpl *This = (OLEPictureImpl *)iface;
625 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
626 *pheight = This->himetricHeight;
627 return S_OK;
630 /************************************************************************
631 * OLEPictureImpl_Render
633 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
634 LONG x, LONG y, LONG cx, LONG cy,
635 OLE_XPOS_HIMETRIC xSrc,
636 OLE_YPOS_HIMETRIC ySrc,
637 OLE_XSIZE_HIMETRIC cxSrc,
638 OLE_YSIZE_HIMETRIC cySrc,
639 LPCRECT prcWBounds)
641 OLEPictureImpl *This = (OLEPictureImpl *)iface;
642 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
643 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
644 if(prcWBounds)
645 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
646 prcWBounds->right, prcWBounds->bottom);
648 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
649 return CTL_E_INVALIDPROPERTYVALUE;
653 * While the documentation suggests this to be here (or after rendering?)
654 * it does cause an endless recursion in my sample app. -MM 20010804
655 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
658 switch(This->desc.picType) {
659 case PICTYPE_UNINITIALIZED:
660 case PICTYPE_NONE:
661 /* nothing to do */
662 return S_OK;
663 case PICTYPE_BITMAP:
665 HBITMAP hbmpOld;
666 HDC hdcBmp;
668 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
669 NB y-axis gets flipped */
671 hdcBmp = CreateCompatibleDC(0);
672 SetMapMode(hdcBmp, MM_ANISOTROPIC);
673 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
674 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
675 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
676 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
678 if (This->hbmMask) {
679 HDC hdcMask = CreateCompatibleDC(0);
680 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
682 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
684 SetMapMode(hdcMask, MM_ANISOTROPIC);
685 SetWindowOrgEx(hdcMask, 0, 0, NULL);
686 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
687 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
688 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
690 SetBkColor(hdc, RGB(255, 255, 255));
691 SetTextColor(hdc, RGB(0, 0, 0));
692 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
693 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
695 SelectObject(hdcMask, hOldbm);
696 DeleteDC(hdcMask);
697 } else {
698 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
699 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
702 SelectObject(hdcBmp, hbmpOld);
703 DeleteDC(hdcBmp);
705 break;
706 case PICTYPE_ICON:
707 FIXME("Not quite correct implementation of rendering icons...\n");
708 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
709 break;
711 case PICTYPE_METAFILE:
713 POINT prevOrg, prevWndOrg;
714 SIZE prevExt, prevWndExt;
715 int oldmode;
717 /* Render the WMF to the appropriate location by setting the
718 appropriate ratio between "device units" and "logical units" */
719 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
720 /* For the "source rectangle" the y-axis must be inverted */
721 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
722 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
723 /* For the "destination rectangle" no inversion is necessary */
724 SetViewportOrgEx(hdc, x, y, &prevOrg);
725 SetViewportExtEx(hdc, cx, cy, &prevExt);
727 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
728 ERR("PlayMetaFile failed!\n");
730 /* We're done, restore the DC to the previous settings for converting
731 logical units to device units */
732 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
733 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
734 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
735 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
736 SetMapMode(hdc, oldmode);
737 break;
740 case PICTYPE_ENHMETAFILE:
742 RECT rc = { x, y, x + cx, y + cy };
743 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
744 break;
747 default:
748 FIXME("type %d not implemented\n", This->desc.picType);
749 return E_NOTIMPL;
751 return S_OK;
754 /************************************************************************
755 * OLEPictureImpl_set_hPal
757 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
758 OLE_HANDLE hpal)
760 OLEPictureImpl *This = (OLEPictureImpl *)iface;
761 FIXME("(%p)->(%08x): stub\n", This, hpal);
762 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
763 return E_NOTIMPL;
766 /************************************************************************
767 * OLEPictureImpl_get_CurDC
769 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
770 HDC *phdc)
772 OLEPictureImpl *This = (OLEPictureImpl *)iface;
773 TRACE("(%p), returning %p\n", This, This->hDCCur);
774 if (phdc) *phdc = This->hDCCur;
775 return S_OK;
778 /************************************************************************
779 * OLEPictureImpl_SelectPicture
781 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
782 HDC hdcIn,
783 HDC *phdcOut,
784 OLE_HANDLE *phbmpOut)
786 OLEPictureImpl *This = (OLEPictureImpl *)iface;
787 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
788 if (This->desc.picType == PICTYPE_BITMAP) {
789 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
791 if (phdcOut)
792 *phdcOut = This->hDCCur;
793 This->hDCCur = hdcIn;
794 if (phbmpOut)
795 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
796 return S_OK;
797 } else {
798 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
799 return E_FAIL;
803 /************************************************************************
804 * OLEPictureImpl_get_KeepOriginalFormat
806 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
807 BOOL *pfKeep)
809 OLEPictureImpl *This = (OLEPictureImpl *)iface;
810 TRACE("(%p)->(%p)\n", This, pfKeep);
811 if (!pfKeep)
812 return E_POINTER;
813 *pfKeep = This->keepOrigFormat;
814 return S_OK;
817 /************************************************************************
818 * OLEPictureImpl_put_KeepOriginalFormat
820 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
821 BOOL keep)
823 OLEPictureImpl *This = (OLEPictureImpl *)iface;
824 TRACE("(%p)->(%d)\n", This, keep);
825 This->keepOrigFormat = keep;
826 /* FIXME: what DISPID notification here? */
827 return S_OK;
830 /************************************************************************
831 * OLEPictureImpl_PictureChanged
833 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
835 OLEPictureImpl *This = (OLEPictureImpl *)iface;
836 TRACE("(%p)->()\n", This);
837 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
838 This->bIsDirty = TRUE;
839 return S_OK;
842 /************************************************************************
843 * OLEPictureImpl_SaveAsFile
845 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
846 IStream *pstream,
847 BOOL SaveMemCopy,
848 LONG *pcbSize)
850 OLEPictureImpl *This = (OLEPictureImpl *)iface;
851 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
852 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
855 /************************************************************************
856 * OLEPictureImpl_get_Attributes
858 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
859 DWORD *pdwAttr)
861 OLEPictureImpl *This = (OLEPictureImpl *)iface;
862 TRACE("(%p)->(%p).\n", This, pdwAttr);
864 if(!pdwAttr)
865 return E_POINTER;
867 *pdwAttr = 0;
868 switch (This->desc.picType) {
869 case PICTYPE_UNINITIALIZED:
870 case PICTYPE_NONE: break;
871 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
872 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
873 case PICTYPE_ENHMETAFILE: /* fall through */
874 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
875 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
877 return S_OK;
881 /************************************************************************
882 * IConnectionPointContainer
884 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
885 IConnectionPointContainer* iface,
886 REFIID riid,
887 VOID** ppvoid)
889 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
891 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
894 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
895 IConnectionPointContainer* iface)
897 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
899 return IPicture_AddRef((IPicture *)This);
902 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
903 IConnectionPointContainer* iface)
905 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
907 return IPicture_Release((IPicture *)This);
910 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
911 IConnectionPointContainer* iface,
912 IEnumConnectionPoints** ppEnum)
914 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
916 FIXME("(%p,%p), stub!\n",This,ppEnum);
917 return E_NOTIMPL;
920 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
921 IConnectionPointContainer* iface,
922 REFIID riid,
923 IConnectionPoint **ppCP)
925 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
926 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
927 if (!ppCP)
928 return E_POINTER;
929 *ppCP = NULL;
930 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
931 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
932 FIXME("no connection point for %s\n",debugstr_guid(riid));
933 return CONNECT_E_NOCONNECTION;
937 /************************************************************************
938 * IPersistStream
941 /************************************************************************
942 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
944 * See Windows documentation for more details on IUnknown methods.
946 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
947 IPersistStream* iface,
948 REFIID riid,
949 VOID** ppvoid)
951 OLEPictureImpl *This = impl_from_IPersistStream(iface);
953 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
956 /************************************************************************
957 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
959 * See Windows documentation for more details on IUnknown methods.
961 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
962 IPersistStream* iface)
964 OLEPictureImpl *This = impl_from_IPersistStream(iface);
966 return IPicture_AddRef((IPicture *)This);
969 /************************************************************************
970 * OLEPictureImpl_IPersistStream_Release (IUnknown)
972 * See Windows documentation for more details on IUnknown methods.
974 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
975 IPersistStream* iface)
977 OLEPictureImpl *This = impl_from_IPersistStream(iface);
979 return IPicture_Release((IPicture *)This);
982 /************************************************************************
983 * OLEPictureImpl_IPersistStream_GetClassID
985 static HRESULT WINAPI OLEPictureImpl_GetClassID(
986 IPersistStream* iface,CLSID* pClassID)
988 TRACE("(%p)\n", pClassID);
989 *pClassID = CLSID_StdPicture;
990 return S_OK;
993 /************************************************************************
994 * OLEPictureImpl_IPersistStream_IsDirty
996 static HRESULT WINAPI OLEPictureImpl_IsDirty(
997 IPersistStream* iface)
999 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1000 FIXME("(%p),stub!\n",This);
1001 return E_NOTIMPL;
1004 #ifdef SONAME_LIBJPEG
1006 static void *libjpeg_handle;
1007 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1008 MAKE_FUNCPTR(jpeg_std_error);
1009 MAKE_FUNCPTR(jpeg_CreateDecompress);
1010 MAKE_FUNCPTR(jpeg_read_header);
1011 MAKE_FUNCPTR(jpeg_start_decompress);
1012 MAKE_FUNCPTR(jpeg_read_scanlines);
1013 MAKE_FUNCPTR(jpeg_finish_decompress);
1014 MAKE_FUNCPTR(jpeg_destroy_decompress);
1015 #undef MAKE_FUNCPTR
1017 static void *load_libjpeg(void)
1019 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
1021 #define LOAD_FUNCPTR(f) \
1022 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
1023 libjpeg_handle = NULL; \
1024 return NULL; \
1027 LOAD_FUNCPTR(jpeg_std_error);
1028 LOAD_FUNCPTR(jpeg_CreateDecompress);
1029 LOAD_FUNCPTR(jpeg_read_header);
1030 LOAD_FUNCPTR(jpeg_start_decompress);
1031 LOAD_FUNCPTR(jpeg_read_scanlines);
1032 LOAD_FUNCPTR(jpeg_finish_decompress);
1033 LOAD_FUNCPTR(jpeg_destroy_decompress);
1034 #undef LOAD_FUNCPTR
1036 return libjpeg_handle;
1039 /* for the jpeg decompressor source manager. */
1040 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1042 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1043 ERR("(), should not get here.\n");
1044 return FALSE;
1047 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1048 TRACE("Skipping %ld bytes...\n", num_bytes);
1049 cinfo->src->next_input_byte += num_bytes;
1050 cinfo->src->bytes_in_buffer -= num_bytes;
1053 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1054 ERR("(desired=%d), should not get here.\n",desired);
1055 return FALSE;
1057 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1058 #endif /* SONAME_LIBJPEG */
1060 struct gifdata {
1061 unsigned char *data;
1062 unsigned int curoff;
1063 unsigned int len;
1066 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1067 struct gifdata *gd = (struct gifdata*)gif->UserData;
1069 if (len+gd->curoff > gd->len) {
1070 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1071 len = gd->len - gd->curoff;
1073 memcpy(data, gd->data+gd->curoff, len);
1074 gd->curoff += len;
1075 return len;
1079 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1081 struct gifdata gd;
1082 GifFileType *gif;
1083 BITMAPINFO *bmi;
1084 HDC hdcref;
1085 LPBYTE bytes;
1086 int i,j,ret;
1087 GifImageDesc *gid;
1088 SavedImage *si;
1089 ColorMapObject *cm;
1090 int transparent = -1;
1091 ExtensionBlock *eb;
1092 int padding;
1094 gd.data = xbuf;
1095 gd.curoff = 0;
1096 gd.len = xread;
1097 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1098 ret = DGifSlurp(gif);
1099 if (ret == GIF_ERROR) {
1100 ERR("Failed reading GIF using libgif.\n");
1101 return E_FAIL;
1103 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1104 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1105 TRACE("imgcnt %d\n", gif->ImageCount);
1106 if (gif->ImageCount<1) {
1107 ERR("GIF stream does not have images inside?\n");
1108 return E_FAIL;
1110 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1111 gif->Image.Width, gif->Image.Height,
1112 gif->Image.Left, gif->Image.Top,
1113 gif->Image.Interlace
1115 /* */
1116 padding = (gif->SWidth+3) & ~3;
1117 si = gif->SavedImages+0;
1118 gid = &(si->ImageDesc);
1119 cm = gid->ColorMap;
1120 if (!cm) cm = gif->SColorMap;
1121 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1122 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1124 /* look for the transparent color extension */
1125 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1126 eb = si->ExtensionBlocks + i;
1127 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1128 if ((eb->Bytes[0] & 1) == 1) {
1129 transparent = (unsigned char)eb->Bytes[3];
1134 for (i = 0; i < cm->ColorCount; i++) {
1135 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1136 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1137 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1138 if (i == transparent) {
1139 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1140 bmi->bmiColors[i].rgbGreen,
1141 bmi->bmiColors[i].rgbBlue);
1145 /* Map to in picture coordinates */
1146 for (i = 0, j = 0; i < gid->Height; i++) {
1147 if (gif->Image.Interlace) {
1148 memcpy(
1149 bytes + (gid->Top + j) * padding + gid->Left,
1150 si->RasterBits + i * gid->Width,
1151 gid->Width);
1153 /* Lower bits of interlaced counter encode current interlace */
1154 if (j & 1) j += 2; /* Currently filling odd rows */
1155 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1156 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1158 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1159 /* End of current interlace, go to next interlace */
1160 if (j & 2) j = 1; /* Next iteration fills odd rows */
1161 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1162 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1164 } else {
1165 memcpy(
1166 bytes + (gid->Top + i) * padding + gid->Left,
1167 si->RasterBits + i * gid->Width,
1168 gid->Width);
1172 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1173 bmi->bmiHeader.biWidth = gif->SWidth;
1174 bmi->bmiHeader.biHeight = -gif->SHeight;
1175 bmi->bmiHeader.biPlanes = 1;
1176 bmi->bmiHeader.biBitCount = 8;
1177 bmi->bmiHeader.biCompression = BI_RGB;
1178 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1179 bmi->bmiHeader.biXPelsPerMeter = 0;
1180 bmi->bmiHeader.biYPelsPerMeter = 0;
1181 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1182 bmi->bmiHeader.biClrImportant = 0;
1184 hdcref = GetDC(0);
1185 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1186 hdcref,
1187 &bmi->bmiHeader,
1188 CBM_INIT,
1189 bytes,
1190 bmi,
1191 DIB_RGB_COLORS
1194 if (transparent > -1) {
1195 /* Create the Mask */
1196 HDC hdc = CreateCompatibleDC(0);
1197 HDC hdcMask = CreateCompatibleDC(0);
1198 HBITMAP hOldbitmap;
1199 HBITMAP hOldbitmapmask;
1201 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1202 HBITMAP hTempMask;
1204 This->hbmXor = CreateDIBitmap(
1205 hdcref,
1206 &bmi->bmiHeader,
1207 CBM_INIT,
1208 bytes,
1209 bmi,
1210 DIB_RGB_COLORS
1213 bmi->bmiColors[0].rgbRed = 0;
1214 bmi->bmiColors[0].rgbGreen = 0;
1215 bmi->bmiColors[0].rgbBlue = 0;
1216 bmi->bmiColors[1].rgbRed = 255;
1217 bmi->bmiColors[1].rgbGreen = 255;
1218 bmi->bmiColors[1].rgbBlue = 255;
1220 bmi->bmiHeader.biBitCount = 1;
1221 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1222 bmi->bmiHeader.biClrUsed = 2;
1224 for (i = 0; i < gif->SHeight; i++) {
1225 unsigned char * colorPointer = bytes + padding * i;
1226 unsigned char * monoPointer = bytes + monopadding * i;
1227 for (j = 0; j < gif->SWidth; j++) {
1228 unsigned char pixel = colorPointer[j];
1229 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1230 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1233 hdcref = GetDC(0);
1234 hTempMask = CreateDIBitmap(
1235 hdcref,
1236 &bmi->bmiHeader,
1237 CBM_INIT,
1238 bytes,
1239 bmi,
1240 DIB_RGB_COLORS
1242 DeleteDC(hdcref);
1244 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1245 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1246 hOldbitmap = SelectObject(hdc, hTempMask);
1247 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1249 SetBkColor(hdc, RGB(255, 255, 255));
1250 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1252 /* We no longer need the original bitmap, so we apply the first
1253 transformation with the mask to speed up the rendering */
1254 SelectObject(hdc, This->hbmXor);
1255 SetBkColor(hdc, RGB(0,0,0));
1256 SetTextColor(hdc, RGB(255,255,255));
1257 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1258 hdcMask, 0, 0, SRCAND);
1260 SelectObject(hdc, hOldbitmap);
1261 SelectObject(hdcMask, hOldbitmapmask);
1262 DeleteDC(hdcMask);
1263 DeleteDC(hdc);
1264 DeleteObject(hTempMask);
1267 DeleteDC(hdcref);
1268 This->desc.picType = PICTYPE_BITMAP;
1269 OLEPictureImpl_SetBitmap(This);
1270 DGifCloseFile(gif);
1271 HeapFree(GetProcessHeap(),0,bmi);
1272 HeapFree(GetProcessHeap(),0,bytes);
1273 return S_OK;
1276 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1278 #ifdef SONAME_LIBJPEG
1279 struct jpeg_decompress_struct jd;
1280 struct jpeg_error_mgr jerr;
1281 int ret;
1282 JDIMENSION x;
1283 JSAMPROW samprow,oldsamprow;
1284 BITMAPINFOHEADER bmi;
1285 LPBYTE bits;
1286 HDC hdcref;
1287 struct jpeg_source_mgr xjsm;
1288 LPBYTE oldbits;
1289 unsigned int i;
1291 if(!libjpeg_handle) {
1292 if(!load_libjpeg()) {
1293 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1294 return E_FAIL;
1298 /* This is basically so we can use in-memory data for jpeg decompression.
1299 * We need to have all the functions.
1301 xjsm.next_input_byte = xbuf;
1302 xjsm.bytes_in_buffer = xread;
1303 xjsm.init_source = _jpeg_init_source;
1304 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1305 xjsm.skip_input_data = _jpeg_skip_input_data;
1306 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1307 xjsm.term_source = _jpeg_term_source;
1309 jd.err = pjpeg_std_error(&jerr);
1310 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1311 * jpeg_create_decompress(&jd); */
1312 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1313 jd.src = &xjsm;
1314 ret=pjpeg_read_header(&jd,TRUE);
1315 jd.out_color_space = JCS_RGB;
1316 pjpeg_start_decompress(&jd);
1317 if (ret != JPEG_HEADER_OK) {
1318 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1319 HeapFree(GetProcessHeap(),0,xbuf);
1320 return E_FAIL;
1323 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1324 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1325 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1327 oldbits = bits;
1328 oldsamprow = samprow;
1329 while ( jd.output_scanline<jd.output_height ) {
1330 x = pjpeg_read_scanlines(&jd,&samprow,1);
1331 if (x != 1) {
1332 ERR("failed to read current scanline?\n");
1333 break;
1335 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1336 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1337 *(bits++) = *(samprow+2);
1338 *(bits++) = *(samprow+1);
1339 *(bits++) = *(samprow);
1341 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1342 samprow = oldsamprow;
1344 bits = oldbits;
1346 bmi.biSize = sizeof(bmi);
1347 bmi.biWidth = jd.output_width;
1348 bmi.biHeight = -jd.output_height;
1349 bmi.biPlanes = 1;
1350 bmi.biBitCount = jd.output_components<<3;
1351 bmi.biCompression = BI_RGB;
1352 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1353 bmi.biXPelsPerMeter = 0;
1354 bmi.biYPelsPerMeter = 0;
1355 bmi.biClrUsed = 0;
1356 bmi.biClrImportant = 0;
1358 HeapFree(GetProcessHeap(),0,samprow);
1359 pjpeg_finish_decompress(&jd);
1360 pjpeg_destroy_decompress(&jd);
1361 hdcref = GetDC(0);
1362 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1363 hdcref,
1364 &bmi,
1365 CBM_INIT,
1366 bits,
1367 (BITMAPINFO*)&bmi,
1368 DIB_RGB_COLORS
1370 DeleteDC(hdcref);
1371 This->desc.picType = PICTYPE_BITMAP;
1372 OLEPictureImpl_SetBitmap(This);
1373 HeapFree(GetProcessHeap(),0,bits);
1374 return S_OK;
1375 #else
1376 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1377 return E_FAIL;
1378 #endif
1381 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1383 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1384 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1385 HDC hdcref;
1387 /* Does not matter whether this is a coreheader or not, we only use
1388 * components which are in both
1390 hdcref = GetDC(0);
1391 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1392 hdcref,
1393 &(bi->bmiHeader),
1394 CBM_INIT,
1395 xbuf+bfh->bfOffBits,
1397 DIB_RGB_COLORS
1399 DeleteDC(hdcref);
1400 if (This->desc.u.bmp.hbitmap == 0)
1401 return E_FAIL;
1402 This->desc.picType = PICTYPE_BITMAP;
1403 OLEPictureImpl_SetBitmap(This);
1404 return S_OK;
1407 /*****************************************************
1408 * start of PNG-specific code
1409 * currently only supports colortype PNG_COLOR_TYPE_RGB
1411 #ifdef SONAME_LIBPNG
1412 typedef struct{
1413 ULONG position;
1414 ULONG size;
1415 BYTE * buff;
1416 } png_io;
1418 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1419 png_size_t length)
1421 png_io * io_ptr = png_ptr->io_ptr;
1423 if(length + io_ptr->position > io_ptr->size){
1424 length = io_ptr->size - io_ptr->position;
1427 memcpy(data, io_ptr->buff + io_ptr->position, length);
1429 io_ptr->position += length;
1432 static void *libpng_handle;
1433 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1434 MAKE_FUNCPTR(png_create_read_struct);
1435 MAKE_FUNCPTR(png_create_info_struct);
1436 MAKE_FUNCPTR(png_set_read_fn);
1437 MAKE_FUNCPTR(png_read_info);
1438 MAKE_FUNCPTR(png_read_image);
1439 MAKE_FUNCPTR(png_get_rowbytes);
1440 MAKE_FUNCPTR(png_set_bgr);
1441 MAKE_FUNCPTR(png_destroy_read_struct);
1442 MAKE_FUNCPTR(png_set_palette_to_rgb);
1443 MAKE_FUNCPTR(png_read_update_info);
1444 MAKE_FUNCPTR(png_get_tRNS);
1445 MAKE_FUNCPTR(png_get_PLTE);
1446 MAKE_FUNCPTR(png_set_expand);
1447 #undef MAKE_FUNCPTR
1449 static void *load_libpng(void)
1451 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1453 #define LOAD_FUNCPTR(f) \
1454 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1455 libpng_handle = NULL; \
1456 return NULL; \
1458 LOAD_FUNCPTR(png_create_read_struct);
1459 LOAD_FUNCPTR(png_create_info_struct);
1460 LOAD_FUNCPTR(png_set_read_fn);
1461 LOAD_FUNCPTR(png_read_info);
1462 LOAD_FUNCPTR(png_read_image);
1463 LOAD_FUNCPTR(png_get_rowbytes);
1464 LOAD_FUNCPTR(png_set_bgr);
1465 LOAD_FUNCPTR(png_destroy_read_struct);
1466 LOAD_FUNCPTR(png_set_palette_to_rgb);
1467 LOAD_FUNCPTR(png_read_update_info);
1468 LOAD_FUNCPTR(png_get_tRNS);
1469 LOAD_FUNCPTR(png_get_PLTE);
1470 LOAD_FUNCPTR(png_set_expand);
1472 #undef LOAD_FUNCPTR
1474 return libpng_handle;
1476 #endif /* SONAME_LIBPNG */
1478 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1480 #ifdef SONAME_LIBPNG
1481 png_io io;
1482 png_structp png_ptr = NULL;
1483 png_infop info_ptr = NULL;
1484 INT row, rowsize, height, width, num_trans, i, j;
1485 png_bytep* row_pointers = NULL;
1486 png_bytep pngdata = NULL;
1487 BITMAPINFOHEADER bmi;
1488 HDC hdcref = NULL, hdcXor, hdcMask;
1489 HRESULT ret;
1490 BOOL transparency;
1491 png_bytep trans;
1492 png_color_16p trans_values;
1493 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1494 HBITMAP hbmoldXor, hbmoldMask, temp;
1496 if(!libpng_handle) {
1497 if(!load_libpng()) {
1498 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1499 return E_FAIL;
1503 io.size = xread;
1504 io.position = 0;
1505 io.buff = xbuf;
1507 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1508 NULL, NULL, NULL);
1510 if(setjmp(png_jmpbuf(png_ptr))){
1511 TRACE("Error in libpng\n");
1512 ret = E_FAIL;
1513 goto end;
1516 info_ptr = ppng_create_info_struct(png_ptr);
1517 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1518 ppng_read_info(png_ptr, info_ptr);
1520 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1521 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1522 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1523 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1524 ret = E_FAIL;
1525 goto end;
1528 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1529 == PNG_INFO_tRNS);
1531 /* sets format from anything to RGBA */
1532 ppng_set_expand(png_ptr);
1533 /* sets format to BGRA */
1534 ppng_set_bgr(png_ptr);
1536 ppng_read_update_info(png_ptr, info_ptr);
1538 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1539 /* align rowsize to 4-byte boundary */
1540 rowsize = (rowsize + 3) & ~3;
1541 height = info_ptr->height;
1542 width = info_ptr->width;
1544 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1545 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1547 if(!pngdata || !row_pointers){
1548 ret = E_FAIL;
1549 goto end;
1552 for (row = 0; row < height; row++){
1553 row_pointers[row] = pngdata + row * rowsize;
1556 ppng_read_image(png_ptr, row_pointers);
1558 bmi.biSize = sizeof(bmi);
1559 bmi.biWidth = width;
1560 bmi.biHeight = -height;
1561 bmi.biPlanes = 1;
1562 bmi.biBitCount = info_ptr->channels * 8;
1563 bmi.biCompression = BI_RGB;
1564 bmi.biSizeImage = height * rowsize;
1565 bmi.biXPelsPerMeter = 0;
1566 bmi.biYPelsPerMeter = 0;
1567 bmi.biClrUsed = 0;
1568 bmi.biClrImportant = 0;
1570 hdcref = GetDC(0);
1571 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1572 hdcref,
1573 &bmi,
1574 CBM_INIT,
1575 pngdata,
1576 (BITMAPINFO*)&bmi,
1577 DIB_RGB_COLORS
1580 /* only fully-transparent alpha is handled */
1581 if((info_ptr->channels != 4) || !transparency){
1582 ReleaseDC(0, hdcref);
1583 goto succ;
1586 This->hbmXor = CreateDIBitmap(
1587 hdcref,
1588 &bmi,
1589 CBM_INIT,
1590 pngdata,
1591 (BITMAPINFO*)&bmi,
1592 DIB_RGB_COLORS
1595 /* set transparent pixels to black, all others to white */
1596 for(i = 0; i < height; i++){
1597 for(j = 3; j < rowsize; j += 4){
1598 if(row_pointers[i][j] == 0)
1599 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1600 else
1601 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1605 temp = CreateDIBitmap(
1606 hdcref,
1607 &bmi,
1608 CBM_INIT,
1609 pngdata,
1610 (BITMAPINFO*)&bmi,
1611 DIB_RGB_COLORS
1614 ReleaseDC(0, hdcref);
1616 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1617 hdcXor = CreateCompatibleDC(NULL);
1618 hdcMask = CreateCompatibleDC(NULL);
1620 hbmoldXor = SelectObject(hdcXor,temp);
1621 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1622 SetBkColor(hdcXor,black);
1623 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1625 SelectObject(hdcXor,This->hbmXor);
1626 DeleteObject(temp);
1628 SetTextColor(hdcXor,white);
1629 SetBkColor(hdcXor,black);
1630 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1632 SelectObject(hdcXor,hbmoldXor);
1633 SelectObject(hdcMask,hbmoldMask);
1635 DeleteDC(hdcXor);
1636 DeleteDC(hdcMask);
1638 succ:
1639 This->desc.picType = PICTYPE_BITMAP;
1640 OLEPictureImpl_SetBitmap(This);
1641 ret = S_OK;
1643 end:
1644 if(png_ptr)
1645 ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1646 HeapFree(GetProcessHeap(), 0, row_pointers);
1647 HeapFree(GetProcessHeap(), 0, pngdata);
1648 return ret;
1649 #else /* SONAME_LIBPNG */
1650 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1651 return E_FAIL;
1652 #endif
1655 /*****************************************************
1656 * start of Icon-specific code
1659 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1661 HICON hicon;
1662 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1663 HDC hdcRef;
1664 int i;
1667 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1668 FIXME("icon.idType=%d\n",cifd->idType);
1669 FIXME("icon.idCount=%d\n",cifd->idCount);
1671 for (i=0;i<cifd->idCount;i++) {
1672 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1673 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1674 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1675 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1676 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1677 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1678 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1679 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1682 i=0;
1683 /* If we have more than one icon, try to find the best.
1684 * this currently means '32 pixel wide'.
1686 if (cifd->idCount!=1) {
1687 for (i=0;i<cifd->idCount;i++) {
1688 if (cifd->idEntries[i].bWidth == 32)
1689 break;
1691 if (i==cifd->idCount) i=0;
1694 hicon = CreateIconFromResourceEx(
1695 xbuf+cifd->idEntries[i].dwDIBOffset,
1696 cifd->idEntries[i].dwDIBSize,
1697 TRUE, /* is icon */
1698 0x00030000,
1699 cifd->idEntries[i].bWidth,
1700 cifd->idEntries[i].bHeight,
1703 if (!hicon) {
1704 ERR("CreateIcon failed.\n");
1705 return E_FAIL;
1706 } else {
1707 This->desc.picType = PICTYPE_ICON;
1708 This->desc.u.icon.hicon = hicon;
1709 This->origWidth = cifd->idEntries[i].bWidth;
1710 This->origHeight = cifd->idEntries[i].bHeight;
1711 hdcRef = CreateCompatibleDC(0);
1712 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1713 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1714 DeleteDC(hdcRef);
1715 return S_OK;
1719 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1720 const BYTE *data, ULONG size)
1722 HENHMETAFILE hemf;
1723 ENHMETAHEADER hdr;
1725 hemf = SetEnhMetaFileBits(size, data);
1726 if (!hemf) return E_FAIL;
1728 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1730 This->desc.picType = PICTYPE_ENHMETAFILE;
1731 This->desc.u.emf.hemf = hemf;
1733 This->origWidth = 0;
1734 This->origHeight = 0;
1735 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1736 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1738 return S_OK;
1741 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1742 const BYTE *data, ULONG size)
1744 APM_HEADER *header = (APM_HEADER *)data;
1745 HMETAFILE hmf;
1747 if (size < sizeof(APM_HEADER))
1748 return E_FAIL;
1749 if (header->key != 0x9ac6cdd7)
1750 return E_FAIL;
1752 /* SetMetaFileBitsEx performs data check on its own */
1753 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1754 if (!hmf) return E_FAIL;
1756 This->desc.picType = PICTYPE_METAFILE;
1757 This->desc.u.wmf.hmeta = hmf;
1758 This->desc.u.wmf.xExt = 0;
1759 This->desc.u.wmf.yExt = 0;
1761 This->origWidth = 0;
1762 This->origHeight = 0;
1763 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1764 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1765 return S_OK;
1768 /************************************************************************
1769 * BITMAP FORMAT FLAGS -
1770 * Flags that differentiate between different types of bitmaps.
1773 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1774 #define BITMAP_FORMAT_JPEG 0xd8ff
1775 #define BITMAP_FORMAT_GIF 0x4947
1776 #define BITMAP_FORMAT_PNG 0x5089
1777 #define BITMAP_FORMAT_APM 0xcdd7
1779 /************************************************************************
1780 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1782 * Loads the binary data from the IStream. Starts at current position.
1783 * There appears to be an 2 DWORD header:
1784 * DWORD magic;
1785 * DWORD len;
1787 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1789 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1790 HRESULT hr = E_FAIL;
1791 BOOL headerisdata = FALSE;
1792 BOOL statfailed = FALSE;
1793 ULONG xread, toread;
1794 ULONG headerread;
1795 BYTE *xbuf;
1796 DWORD header[2];
1797 WORD magic;
1798 STATSTG statstg;
1799 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1801 TRACE("(%p,%p)\n",This,pStm);
1803 /****************************************************************************************
1804 * Part 1: Load the data
1806 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1807 * out whether we do.
1809 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1810 * compound file. This may explain most, if not all, of the cases of "no
1811 * header", and the header validation should take this into account.
1812 * At least in Visual Basic 6, resource streams, valid headers are
1813 * header[0] == "lt\0\0",
1814 * header[1] == length_of_stream.
1816 * Also handle streams where we do not have a working "Stat" method by
1817 * reading all data until the end of the stream.
1819 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1820 if (hr) {
1821 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1822 statfailed = TRUE;
1823 /* we will read at least 8 byte ... just right below */
1824 statstg.cbSize.QuadPart = 8;
1827 toread = 0;
1828 headerread = 0;
1829 headerisdata = FALSE;
1830 do {
1831 hr=IStream_Read(pStm,header,8,&xread);
1832 if (hr || xread!=8) {
1833 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1834 return (hr?hr:E_FAIL);
1836 headerread += xread;
1837 xread = 0;
1839 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1840 if (toread != 0 && toread != header[1])
1841 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1842 toread, header[1]);
1843 toread = header[1];
1844 if (toread == 0) break;
1845 } else {
1846 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1847 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1848 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1849 (header[0] == EMR_HEADER) || /* EMF header */
1850 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1851 (header[1]==0)
1852 ) {/* Found start of bitmap data */
1853 headerisdata = TRUE;
1854 if (toread == 0)
1855 toread = statstg.cbSize.QuadPart-8;
1856 else toread -= 8;
1857 xread = 8;
1858 } else {
1859 FIXME("Unknown stream header magic: %08x\n", header[0]);
1860 toread = header[1];
1863 } while (!headerisdata);
1865 if (statfailed) { /* we don't know the size ... read all we get */
1866 int sizeinc = 4096;
1867 int origsize = sizeinc;
1868 ULONG nread = 42;
1870 TRACE("Reading all data from stream.\n");
1871 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1872 if (headerisdata)
1873 memcpy (xbuf, header, 8);
1874 while (1) {
1875 while (xread < origsize) {
1876 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1877 xread+=nread;
1878 if (hr || !nread)
1879 break;
1881 if (!nread || hr) /* done, or error */
1882 break;
1883 if (xread == origsize) {
1884 origsize += sizeinc;
1885 sizeinc = 2*sizeinc; /* exponential increase */
1886 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1889 if (hr)
1890 TRACE("hr in no-stat loader case is %08x\n", hr);
1891 TRACE("loaded %d bytes.\n", xread);
1892 This->datalen = xread;
1893 This->data = xbuf;
1894 } else {
1895 This->datalen = toread+(headerisdata?8:0);
1896 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1897 if (!xbuf)
1898 return E_OUTOFMEMORY;
1900 if (headerisdata)
1901 memcpy (xbuf, header, 8);
1903 while (xread < This->datalen) {
1904 ULONG nread;
1905 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1906 xread+=nread;
1907 if (hr || !nread)
1908 break;
1910 if (xread != This->datalen)
1911 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1913 if (This->datalen == 0) { /* Marks the "NONE" picture */
1914 This->desc.picType = PICTYPE_NONE;
1915 return S_OK;
1919 /****************************************************************************************
1920 * Part 2: Process the loaded data
1923 magic = xbuf[0] + (xbuf[1]<<8);
1924 This->loadtime_format = magic;
1926 switch (magic) {
1927 case BITMAP_FORMAT_GIF: /* GIF */
1928 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1929 break;
1930 case BITMAP_FORMAT_JPEG: /* JPEG */
1931 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1932 break;
1933 case BITMAP_FORMAT_BMP: /* Bitmap */
1934 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1935 break;
1936 case BITMAP_FORMAT_PNG: /* PNG */
1937 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1938 break;
1939 case BITMAP_FORMAT_APM: /* APM */
1940 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1941 break;
1942 case 0x0000: { /* ICON , first word is dwReserved */
1943 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1944 break;
1946 default:
1948 unsigned int i;
1950 /* let's see if it's a EMF */
1951 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1952 if (hr == S_OK) break;
1954 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1955 hr=E_FAIL;
1956 for (i=0;i<xread+8;i++) {
1957 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1958 else MESSAGE("%02x ",xbuf[i-8]);
1959 if (i % 10 == 9) MESSAGE("\n");
1961 MESSAGE("\n");
1962 break;
1965 This->bIsDirty = FALSE;
1967 /* FIXME: this notify is not really documented */
1968 if (hr==S_OK)
1969 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1970 return hr;
1973 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1975 int iSuccess = 0;
1976 HDC hDC;
1977 BITMAPINFO * pInfoBitmap;
1978 int iNumPaletteEntries;
1979 unsigned char * pPixelData;
1980 BITMAPFILEHEADER * pFileHeader;
1981 BITMAPINFO * pInfoHeader;
1983 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1984 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1986 /* Find out bitmap size and padded length */
1987 hDC = GetDC(0);
1988 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1989 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1991 /* Fetch bitmap palette & pixel data */
1993 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1994 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1996 /* Calculate the total length required for the BMP data */
1997 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1998 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1999 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
2000 } else {
2001 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
2002 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
2003 else
2004 iNumPaletteEntries = 0;
2006 *pLength =
2007 sizeof(BITMAPFILEHEADER) +
2008 sizeof(BITMAPINFOHEADER) +
2009 iNumPaletteEntries * sizeof(RGBQUAD) +
2010 pInfoBitmap->bmiHeader.biSizeImage;
2011 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
2013 /* Fill the BITMAPFILEHEADER */
2014 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
2015 pFileHeader->bfType = BITMAP_FORMAT_BMP;
2016 pFileHeader->bfSize = *pLength;
2017 pFileHeader->bfOffBits =
2018 sizeof(BITMAPFILEHEADER) +
2019 sizeof(BITMAPINFOHEADER) +
2020 iNumPaletteEntries * sizeof(RGBQUAD);
2022 /* Fill the BITMAPINFOHEADER and the palette data */
2023 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
2024 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
2025 memcpy(
2026 (unsigned char *)(*ppBuffer) +
2027 sizeof(BITMAPFILEHEADER) +
2028 sizeof(BITMAPINFOHEADER) +
2029 iNumPaletteEntries * sizeof(RGBQUAD),
2030 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2031 iSuccess = 1;
2033 HeapFree(GetProcessHeap(), 0, pPixelData);
2034 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2035 return iSuccess;
2038 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2040 ICONINFO infoIcon;
2041 int iSuccess = 0;
2043 *ppBuffer = NULL; *pLength = 0;
2044 if (GetIconInfo(hIcon, &infoIcon)) {
2045 HDC hDC;
2046 BITMAPINFO * pInfoBitmap;
2047 unsigned char * pIconData = NULL;
2048 unsigned int iDataSize = 0;
2050 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2052 /* Find out icon size */
2053 hDC = GetDC(0);
2054 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2055 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2056 if (1) {
2057 /* Auxiliary pointers */
2058 CURSORICONFILEDIR * pIconDir;
2059 CURSORICONFILEDIRENTRY * pIconEntry;
2060 BITMAPINFOHEADER * pIconBitmapHeader;
2061 unsigned int iOffsetPalette;
2062 unsigned int iOffsetColorData;
2063 unsigned int iOffsetMaskData;
2065 unsigned int iLengthScanLineColor;
2066 unsigned int iLengthScanLineMask;
2067 unsigned int iNumEntriesPalette;
2069 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2070 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2072 FIXME("DEBUG: bitmap size is %d x %d\n",
2073 pInfoBitmap->bmiHeader.biWidth,
2074 pInfoBitmap->bmiHeader.biHeight);
2075 FIXME("DEBUG: bitmap bpp is %d\n",
2076 pInfoBitmap->bmiHeader.biBitCount);
2077 FIXME("DEBUG: bitmap nplanes is %d\n",
2078 pInfoBitmap->bmiHeader.biPlanes);
2079 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2080 pInfoBitmap->bmiHeader.biSizeImage);
2082 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2083 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2084 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2086 /* Fill out the CURSORICONFILEDIR */
2087 pIconDir = (CURSORICONFILEDIR *)pIconData;
2088 pIconDir->idType = 1;
2089 pIconDir->idCount = 1;
2091 /* Fill out the CURSORICONFILEDIRENTRY */
2092 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2093 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2094 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2095 pIconEntry->bColorCount =
2096 (pInfoBitmap->bmiHeader.biBitCount < 8)
2097 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2098 : 0;
2099 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2100 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2101 pIconEntry->dwDIBSize = 0;
2102 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2104 /* Fill out the BITMAPINFOHEADER */
2105 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2106 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2108 /* Find out whether a palette exists for the bitmap */
2109 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2110 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2111 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2112 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2113 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2114 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2115 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2116 iNumEntriesPalette = 3;
2117 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2118 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2119 } else {
2120 iNumEntriesPalette = 0;
2123 /* Add bitmap size and header size to icon data size. */
2124 iOffsetPalette = iDataSize;
2125 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2126 iOffsetColorData = iDataSize;
2127 iDataSize += pIconBitmapHeader->biSizeImage;
2128 iOffsetMaskData = iDataSize;
2129 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2130 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2131 pIconBitmapHeader->biHeight *= 2;
2132 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2133 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2134 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2135 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2137 /* Get the actual bitmap data from the icon bitmap */
2138 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2139 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2140 if (iNumEntriesPalette > 0) {
2141 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2142 iNumEntriesPalette * sizeof(RGBQUAD));
2145 /* Reset all values so that GetDIBits call succeeds */
2146 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2147 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2148 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2150 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2151 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2152 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2154 printf("ERROR: unable to get bitmap mask (error %u)\n",
2155 GetLastError());
2159 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2160 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2162 /* Write out everything produced so far to the stream */
2163 *ppBuffer = pIconData; *pLength = iDataSize;
2164 iSuccess = 1;
2165 } else {
2167 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2168 GetLastError());
2172 Remarks (from MSDN entry on GetIconInfo):
2174 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2175 members of ICONINFO. The calling application must manage
2176 these bitmaps and delete them when they are no longer
2177 necessary.
2179 if (hDC) ReleaseDC(0, hDC);
2180 DeleteObject(infoIcon.hbmMask);
2181 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2182 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2183 } else {
2184 printf("ERROR: Unable to get icon information (error %u)\n",
2185 GetLastError());
2187 return iSuccess;
2190 static HRESULT WINAPI OLEPictureImpl_Save(
2191 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2193 HRESULT hResult = E_NOTIMPL;
2194 void * pIconData;
2195 unsigned int iDataSize;
2196 ULONG dummy;
2197 int iSerializeResult = 0;
2198 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2200 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2202 switch (This->desc.picType) {
2203 case PICTYPE_ICON:
2204 if (This->bIsDirty || !This->data) {
2205 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2206 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2207 hResult = E_FAIL;
2208 break;
2210 HeapFree(GetProcessHeap(), 0, This->data);
2211 This->data = pIconData;
2212 This->datalen = iDataSize;
2214 if (This->loadtime_magic != 0xdeadbeef) {
2215 DWORD header[2];
2217 header[0] = This->loadtime_magic;
2218 header[1] = This->datalen;
2219 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2221 IStream_Write(pStm, This->data, This->datalen, &dummy);
2223 hResult = S_OK;
2224 break;
2225 case PICTYPE_BITMAP:
2226 if (This->bIsDirty) {
2227 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2228 case BITMAP_FORMAT_BMP:
2229 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2230 break;
2231 case BITMAP_FORMAT_JPEG:
2232 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2233 break;
2234 case BITMAP_FORMAT_GIF:
2235 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2236 break;
2237 case BITMAP_FORMAT_PNG:
2238 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2239 break;
2240 default:
2241 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2242 break;
2244 if (iSerializeResult) {
2246 if (This->loadtime_magic != 0xdeadbeef) {
2248 if (1) {
2249 DWORD header[2];
2251 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2252 header[1] = iDataSize;
2253 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2255 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2257 HeapFree(GetProcessHeap(), 0, This->data);
2258 This->data = pIconData;
2259 This->datalen = iDataSize;
2260 hResult = S_OK;
2262 } else {
2264 if (This->loadtime_magic != 0xdeadbeef) {
2266 if (1) {
2267 DWORD header[2];
2269 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2270 header[1] = This->datalen;
2271 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2273 IStream_Write(pStm, This->data, This->datalen, &dummy);
2274 hResult = S_OK;
2276 break;
2277 case PICTYPE_METAFILE:
2278 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2279 break;
2280 case PICTYPE_ENHMETAFILE:
2281 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2282 break;
2283 default:
2284 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2285 break;
2287 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2288 return hResult;
2291 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2292 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2294 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2295 FIXME("(%p,%p),stub!\n",This,pcbSize);
2296 return E_NOTIMPL;
2300 /************************************************************************
2301 * IDispatch
2304 /************************************************************************
2305 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2307 * See Windows documentation for more details on IUnknown methods.
2309 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2310 IDispatch* iface,
2311 REFIID riid,
2312 VOID** ppvoid)
2314 OLEPictureImpl *This = impl_from_IDispatch(iface);
2316 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2319 /************************************************************************
2320 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2322 * See Windows documentation for more details on IUnknown methods.
2324 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2325 IDispatch* iface)
2327 OLEPictureImpl *This = impl_from_IDispatch(iface);
2329 return IPicture_AddRef((IPicture *)This);
2332 /************************************************************************
2333 * OLEPictureImpl_IDispatch_Release (IUnknown)
2335 * See Windows documentation for more details on IUnknown methods.
2337 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2338 IDispatch* iface)
2340 OLEPictureImpl *This = impl_from_IDispatch(iface);
2342 return IPicture_Release((IPicture *)This);
2345 /************************************************************************
2346 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2348 * See Windows documentation for more details on IDispatch methods.
2350 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2351 IDispatch* iface,
2352 unsigned int* pctinfo)
2354 TRACE("(%p)\n", pctinfo);
2356 *pctinfo = 1;
2358 return S_OK;
2361 /************************************************************************
2362 * OLEPictureImpl_GetTypeInfo (IDispatch)
2364 * See Windows documentation for more details on IDispatch methods.
2366 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2367 IDispatch* iface,
2368 UINT iTInfo,
2369 LCID lcid,
2370 ITypeInfo** ppTInfo)
2372 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2373 ITypeLib *tl;
2374 HRESULT hres;
2376 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2378 if (iTInfo != 0)
2379 return E_FAIL;
2381 hres = LoadTypeLib(stdole2tlb, &tl);
2382 if (FAILED(hres))
2384 ERR("Could not load stdole2.tlb\n");
2385 return hres;
2388 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2389 if (FAILED(hres))
2390 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2392 return hres;
2395 /************************************************************************
2396 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2398 * See Windows documentation for more details on IDispatch methods.
2400 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2401 IDispatch* iface,
2402 REFIID riid,
2403 LPOLESTR* rgszNames,
2404 UINT cNames,
2405 LCID lcid,
2406 DISPID* rgDispId)
2408 ITypeInfo * pTInfo;
2409 HRESULT hres;
2411 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2412 rgszNames, cNames, (int)lcid, rgDispId);
2414 if (cNames == 0)
2416 return E_INVALIDARG;
2418 else
2420 /* retrieve type information */
2421 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2423 if (FAILED(hres))
2425 ERR("GetTypeInfo failed.\n");
2426 return hres;
2429 /* convert names to DISPIDs */
2430 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2431 ITypeInfo_Release(pTInfo);
2433 return hres;
2437 /************************************************************************
2438 * OLEPictureImpl_Invoke (IDispatch)
2440 * See Windows documentation for more details on IDispatch methods.
2442 static HRESULT WINAPI OLEPictureImpl_Invoke(
2443 IDispatch* iface,
2444 DISPID dispIdMember,
2445 REFIID riid,
2446 LCID lcid,
2447 WORD wFlags,
2448 DISPPARAMS* pDispParams,
2449 VARIANT* pVarResult,
2450 EXCEPINFO* pExepInfo,
2451 UINT* puArgErr)
2453 OLEPictureImpl *This = impl_from_IDispatch(iface);
2455 /* validate parameters */
2457 if (!IsEqualIID(riid, &IID_NULL))
2459 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2460 return DISP_E_UNKNOWNNAME;
2463 if (!pDispParams)
2465 ERR("null pDispParams not allowed\n");
2466 return DISP_E_PARAMNOTOPTIONAL;
2469 if (wFlags & DISPATCH_PROPERTYGET)
2471 if (pDispParams->cArgs != 0)
2473 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2474 return DISP_E_BADPARAMCOUNT;
2476 if (!pVarResult)
2478 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2479 return DISP_E_PARAMNOTOPTIONAL;
2482 else if (wFlags & DISPATCH_PROPERTYPUT)
2484 if (pDispParams->cArgs != 1)
2486 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2487 return DISP_E_BADPARAMCOUNT;
2491 switch (dispIdMember)
2493 case DISPID_PICT_HANDLE:
2494 if (wFlags & DISPATCH_PROPERTYGET)
2496 TRACE("DISPID_PICT_HANDLE\n");
2497 V_VT(pVarResult) = VT_I4;
2498 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2500 break;
2501 case DISPID_PICT_HPAL:
2502 if (wFlags & DISPATCH_PROPERTYGET)
2504 TRACE("DISPID_PICT_HPAL\n");
2505 V_VT(pVarResult) = VT_I4;
2506 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2508 else if (wFlags & DISPATCH_PROPERTYPUT)
2510 VARIANTARG vararg;
2511 HRESULT hr;
2512 TRACE("DISPID_PICT_HPAL\n");
2514 VariantInit(&vararg);
2515 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2516 if (FAILED(hr))
2517 return hr;
2519 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2521 VariantClear(&vararg);
2522 return hr;
2524 break;
2525 case DISPID_PICT_TYPE:
2526 if (wFlags & DISPATCH_PROPERTYGET)
2528 TRACE("DISPID_PICT_TYPE\n");
2529 V_VT(pVarResult) = VT_I2;
2530 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2532 break;
2533 case DISPID_PICT_WIDTH:
2534 if (wFlags & DISPATCH_PROPERTYGET)
2536 TRACE("DISPID_PICT_WIDTH\n");
2537 V_VT(pVarResult) = VT_I4;
2538 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2540 break;
2541 case DISPID_PICT_HEIGHT:
2542 if (wFlags & DISPATCH_PROPERTYGET)
2544 TRACE("DISPID_PICT_HEIGHT\n");
2545 V_VT(pVarResult) = VT_I4;
2546 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2548 break;
2551 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2552 return DISP_E_MEMBERNOTFOUND;
2556 static const IPictureVtbl OLEPictureImpl_VTable =
2558 OLEPictureImpl_QueryInterface,
2559 OLEPictureImpl_AddRef,
2560 OLEPictureImpl_Release,
2561 OLEPictureImpl_get_Handle,
2562 OLEPictureImpl_get_hPal,
2563 OLEPictureImpl_get_Type,
2564 OLEPictureImpl_get_Width,
2565 OLEPictureImpl_get_Height,
2566 OLEPictureImpl_Render,
2567 OLEPictureImpl_set_hPal,
2568 OLEPictureImpl_get_CurDC,
2569 OLEPictureImpl_SelectPicture,
2570 OLEPictureImpl_get_KeepOriginalFormat,
2571 OLEPictureImpl_put_KeepOriginalFormat,
2572 OLEPictureImpl_PictureChanged,
2573 OLEPictureImpl_SaveAsFile,
2574 OLEPictureImpl_get_Attributes
2577 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2579 OLEPictureImpl_IDispatch_QueryInterface,
2580 OLEPictureImpl_IDispatch_AddRef,
2581 OLEPictureImpl_IDispatch_Release,
2582 OLEPictureImpl_GetTypeInfoCount,
2583 OLEPictureImpl_GetTypeInfo,
2584 OLEPictureImpl_GetIDsOfNames,
2585 OLEPictureImpl_Invoke
2588 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2590 OLEPictureImpl_IPersistStream_QueryInterface,
2591 OLEPictureImpl_IPersistStream_AddRef,
2592 OLEPictureImpl_IPersistStream_Release,
2593 OLEPictureImpl_GetClassID,
2594 OLEPictureImpl_IsDirty,
2595 OLEPictureImpl_Load,
2596 OLEPictureImpl_Save,
2597 OLEPictureImpl_GetSizeMax
2600 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2602 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2603 OLEPictureImpl_IConnectionPointContainer_AddRef,
2604 OLEPictureImpl_IConnectionPointContainer_Release,
2605 OLEPictureImpl_EnumConnectionPoints,
2606 OLEPictureImpl_FindConnectionPoint
2609 /***********************************************************************
2610 * OleCreatePictureIndirect (OLEAUT32.419)
2612 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2613 BOOL fOwn, LPVOID *ppvObj )
2615 OLEPictureImpl* newPict = NULL;
2616 HRESULT hr = S_OK;
2618 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2621 * Sanity check
2623 if (ppvObj==0)
2624 return E_POINTER;
2626 *ppvObj = NULL;
2629 * Try to construct a new instance of the class.
2631 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2633 if (newPict == NULL)
2634 return E_OUTOFMEMORY;
2637 * Make sure it supports the interface required by the caller.
2639 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2642 * Release the reference obtained in the constructor. If
2643 * the QueryInterface was unsuccessful, it will free the class.
2645 IPicture_Release((IPicture*)newPict);
2647 return hr;
2651 /***********************************************************************
2652 * OleLoadPicture (OLEAUT32.418)
2654 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2655 REFIID riid, LPVOID *ppvObj )
2657 LPPERSISTSTREAM ps;
2658 IPicture *newpic;
2659 HRESULT hr;
2661 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2662 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2664 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2665 if (hr)
2666 return hr;
2667 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2668 if (hr) {
2669 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2670 IPicture_Release(newpic);
2671 *ppvObj = NULL;
2672 return hr;
2674 hr = IPersistStream_Load(ps,lpstream);
2675 IPersistStream_Release(ps);
2676 if (FAILED(hr))
2678 ERR("IPersistStream_Load failed\n");
2679 IPicture_Release(newpic);
2680 *ppvObj = NULL;
2681 return hr;
2683 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2684 if (hr)
2685 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2686 IPicture_Release(newpic);
2687 return hr;
2690 /***********************************************************************
2691 * OleLoadPictureEx (OLEAUT32.401)
2693 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2694 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2696 LPPERSISTSTREAM ps;
2697 IPicture *newpic;
2698 HRESULT hr;
2700 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2701 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2703 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2704 if (hr)
2705 return hr;
2706 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2707 if (hr) {
2708 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2709 IPicture_Release(newpic);
2710 *ppvObj = NULL;
2711 return hr;
2713 hr = IPersistStream_Load(ps,lpstream);
2714 IPersistStream_Release(ps);
2715 if (FAILED(hr))
2717 ERR("IPersistStream_Load failed\n");
2718 IPicture_Release(newpic);
2719 *ppvObj = NULL;
2720 return hr;
2722 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2723 if (hr)
2724 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2725 IPicture_Release(newpic);
2726 return hr;
2729 /***********************************************************************
2730 * OleLoadPicturePath (OLEAUT32.424)
2732 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2733 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2734 LPVOID *ppvRet )
2736 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2737 IPicture *ipicture;
2738 HANDLE hFile;
2739 DWORD dwFileSize;
2740 HGLOBAL hGlobal = NULL;
2741 DWORD dwBytesRead = 0;
2742 IStream *stream;
2743 BOOL bRead;
2744 IPersistStream *pStream;
2745 HRESULT hRes;
2747 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2748 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2749 debugstr_guid(riid), ppvRet);
2751 if (!ppvRet) return E_POINTER;
2753 if (strncmpW(szURLorPath, file, 7) == 0) {
2754 szURLorPath += 7;
2756 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2757 0, NULL);
2758 if (hFile == INVALID_HANDLE_VALUE)
2759 return E_UNEXPECTED;
2761 dwFileSize = GetFileSize(hFile, NULL);
2762 if (dwFileSize != INVALID_FILE_SIZE )
2764 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2765 if ( hGlobal)
2767 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2768 if (!bRead)
2770 GlobalFree(hGlobal);
2771 hGlobal = 0;
2775 CloseHandle(hFile);
2777 if (!hGlobal)
2778 return E_UNEXPECTED;
2780 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2781 if (FAILED(hRes))
2783 GlobalFree(hGlobal);
2784 return hRes;
2786 } else {
2787 IMoniker *pmnk;
2788 IBindCtx *pbc;
2790 hRes = CreateBindCtx(0, &pbc);
2791 if (SUCCEEDED(hRes))
2793 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2794 if (SUCCEEDED(hRes))
2796 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2797 IMoniker_Release(pmnk);
2799 IBindCtx_Release(pbc);
2801 if (FAILED(hRes))
2802 return hRes;
2805 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2806 &IID_IPicture, (LPVOID*)&ipicture);
2807 if (hRes != S_OK) {
2808 IStream_Release(stream);
2809 return hRes;
2812 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2813 if (hRes) {
2814 IStream_Release(stream);
2815 IPicture_Release(ipicture);
2816 return hRes;
2819 hRes = IPersistStream_Load(pStream, stream);
2820 IPersistStream_Release(pStream);
2821 IStream_Release(stream);
2823 if (hRes) {
2824 IPicture_Release(ipicture);
2825 return hRes;
2828 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2829 if (hRes)
2830 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2832 IPicture_Release(ipicture);
2833 return hRes;
2836 /*******************************************************************************
2837 * StdPic ClassFactory
2839 typedef struct
2841 /* IUnknown fields */
2842 const IClassFactoryVtbl *lpVtbl;
2843 LONG ref;
2844 } IClassFactoryImpl;
2846 static HRESULT WINAPI
2847 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2848 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2850 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2851 return E_NOINTERFACE;
2854 static ULONG WINAPI
2855 SPCF_AddRef(LPCLASSFACTORY iface) {
2856 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2857 return InterlockedIncrement(&This->ref);
2860 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2861 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2862 /* static class, won't be freed */
2863 return InterlockedDecrement(&This->ref);
2866 static HRESULT WINAPI SPCF_CreateInstance(
2867 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2869 /* Creates an uninitialized picture */
2870 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2874 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2875 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2876 FIXME("(%p)->(%d),stub!\n",This,dolock);
2877 return S_OK;
2880 static const IClassFactoryVtbl SPCF_Vtbl = {
2881 SPCF_QueryInterface,
2882 SPCF_AddRef,
2883 SPCF_Release,
2884 SPCF_CreateInstance,
2885 SPCF_LockServer
2887 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2889 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }