push 390edd058cbebc9f7cb21f639a52f5acd36a8bf3
[wine/hacks.git] / dlls / oleaut32 / olepicture.c
blob4409a15032640f88f4ac01222cc359c397746210
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 #undef HAVE_STDLIB_H
56 # include <jpeglib.h>
57 #undef HAVE_STDLIB_H
58 #define HAVE_STDLIB_H 1
59 #undef UINT8
60 #undef UINT16
61 #undef boolean
62 #endif
64 #ifdef HAVE_PNG_H
65 #include <png.h>
66 #endif
68 /* Must be before wine includes, the header has things conflicting with
69 * WINE headers.
71 #define COBJMACROS
72 #define NONAMELESSUNION
73 #define NONAMELESSSTRUCT
75 #include "winerror.h"
76 #include "windef.h"
77 #include "winbase.h"
78 #include "wingdi.h"
79 #include "winuser.h"
80 #include "ole2.h"
81 #include "olectl.h"
82 #include "oleauto.h"
83 #include "connpt.h"
84 #include "urlmon.h"
85 #include "wine/debug.h"
86 #include "wine/unicode.h"
87 #include "wine/library.h"
89 #include "ungif.h"
91 WINE_DEFAULT_DEBUG_CHANNEL(ole);
93 #include "pshpack1.h"
95 /* Header for Aldus Placable Metafiles - a standard metafile follows */
96 typedef struct _APM_HEADER
98 DWORD key;
99 WORD handle;
100 SHORT left;
101 SHORT top;
102 SHORT right;
103 SHORT bottom;
104 WORD inch;
105 DWORD reserved;
106 WORD checksum;
107 } APM_HEADER;
109 typedef struct {
110 BYTE bWidth;
111 BYTE bHeight;
112 BYTE bColorCount;
113 BYTE bReserved;
114 WORD xHotspot;
115 WORD yHotspot;
116 DWORD dwDIBSize;
117 DWORD dwDIBOffset;
118 } CURSORICONFILEDIRENTRY;
120 typedef struct
122 WORD idReserved;
123 WORD idType;
124 WORD idCount;
125 CURSORICONFILEDIRENTRY idEntries[1];
126 } CURSORICONFILEDIR;
128 #include "poppack.h"
130 /*************************************************************************
131 * Declaration of implementation class
134 typedef struct OLEPictureImpl {
137 * IPicture handles IUnknown
140 const IPictureVtbl *lpVtbl;
141 const IDispatchVtbl *lpvtblIDispatch;
142 const IPersistStreamVtbl *lpvtblIPersistStream;
143 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
145 /* Object reference count */
146 LONG ref;
148 /* We own the object and must destroy it ourselves */
149 BOOL fOwn;
151 /* Picture description */
152 PICTDESC desc;
154 /* These are the pixel size of a bitmap */
155 DWORD origWidth;
156 DWORD origHeight;
158 /* And these are the size of the picture converted into HIMETRIC units */
159 OLE_XSIZE_HIMETRIC himetricWidth;
160 OLE_YSIZE_HIMETRIC himetricHeight;
162 IConnectionPoint *pCP;
164 BOOL keepOrigFormat;
165 HDC hDCCur;
167 /* Bitmap transparency mask */
168 HBITMAP hbmMask;
169 HBITMAP hbmXor;
170 COLORREF rgbTrans;
172 /* data */
173 void* data;
174 int datalen;
175 BOOL bIsDirty; /* Set to TRUE if picture has changed */
176 unsigned int loadtime_magic; /* If a length header was found, saves value */
177 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
178 } OLEPictureImpl;
181 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
184 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
186 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
189 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
191 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
194 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
196 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
200 * Predeclare VTables. They get initialized at the end.
202 static const IPictureVtbl OLEPictureImpl_VTable;
203 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
204 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
205 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
207 /***********************************************************************
208 * Implementation of the OLEPictureImpl class.
211 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
212 BITMAP bm;
213 HDC hdcRef;
215 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
216 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
217 ERR("GetObject fails\n");
218 return;
220 This->origWidth = bm.bmWidth;
221 This->origHeight = bm.bmHeight;
222 /* The width and height are stored in HIMETRIC units (0.01 mm),
223 so we take our pixel width divide by pixels per inch and
224 multiply by 25.4 * 100 */
225 /* Should we use GetBitmapDimension if available? */
226 hdcRef = CreateCompatibleDC(0);
227 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
228 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
229 DeleteDC(hdcRef);
232 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
234 ICONINFO infoIcon;
236 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
237 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
238 HDC hdcRef;
239 BITMAP bm;
241 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
242 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
243 ERR("GetObject fails on icon bitmap\n");
244 return;
247 This->origWidth = bm.bmWidth;
248 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
249 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
250 hdcRef = GetDC(0);
251 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
252 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
253 ReleaseDC(0, hdcRef);
255 DeleteObject(infoIcon.hbmMask);
256 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
257 } else {
258 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
262 /************************************************************************
263 * OLEPictureImpl_Construct
265 * This method will construct a new instance of the OLEPictureImpl
266 * class.
268 * The caller of this method must release the object when it's
269 * done with it.
271 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
273 OLEPictureImpl* newObject = 0;
275 if (pictDesc)
276 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
279 * Allocate space for the object.
281 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
283 if (newObject==0)
284 return newObject;
287 * Initialize the virtual function table.
289 newObject->lpVtbl = &OLEPictureImpl_VTable;
290 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
291 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
292 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
294 newObject->pCP = NULL;
295 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
296 if (!newObject->pCP)
298 HeapFree(GetProcessHeap(), 0, newObject);
299 return NULL;
303 * Start with one reference count. The caller of this function
304 * must release the interface pointer when it is done.
306 newObject->ref = 1;
307 newObject->hDCCur = 0;
309 newObject->fOwn = fOwn;
311 /* dunno about original value */
312 newObject->keepOrigFormat = TRUE;
314 newObject->hbmMask = NULL;
315 newObject->hbmXor = NULL;
316 newObject->loadtime_magic = 0xdeadbeef;
317 newObject->loadtime_format = 0;
318 newObject->bIsDirty = FALSE;
320 if (pictDesc) {
321 newObject->desc = *pictDesc;
323 switch(pictDesc->picType) {
324 case PICTYPE_BITMAP:
325 OLEPictureImpl_SetBitmap(newObject);
326 break;
328 case PICTYPE_METAFILE:
329 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
330 newObject->himetricWidth = pictDesc->u.wmf.xExt;
331 newObject->himetricHeight = pictDesc->u.wmf.yExt;
332 break;
334 case PICTYPE_NONE:
335 /* not sure what to do here */
336 newObject->himetricWidth = newObject->himetricHeight = 0;
337 break;
339 case PICTYPE_ICON:
340 OLEPictureImpl_SetIcon(newObject);
341 break;
342 case PICTYPE_ENHMETAFILE:
343 default:
344 FIXME("Unsupported type %d\n", pictDesc->picType);
345 newObject->himetricWidth = newObject->himetricHeight = 0;
346 break;
348 } else {
349 newObject->desc.picType = PICTYPE_UNINITIALIZED;
352 TRACE("returning %p\n", newObject);
353 return newObject;
356 /************************************************************************
357 * OLEPictureImpl_Destroy
359 * This method is called by the Release method when the reference
360 * count goes down to 0. It will free all resources used by
361 * this object. */
362 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
364 TRACE("(%p)\n", Obj);
366 if (Obj->pCP)
367 IConnectionPoint_Release(Obj->pCP);
369 if(Obj->fOwn) { /* We need to destroy the picture */
370 switch(Obj->desc.picType) {
371 case PICTYPE_BITMAP:
372 DeleteObject(Obj->desc.u.bmp.hbitmap);
373 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
374 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
375 break;
376 case PICTYPE_METAFILE:
377 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
378 break;
379 case PICTYPE_ICON:
380 DestroyIcon(Obj->desc.u.icon.hicon);
381 break;
382 case PICTYPE_ENHMETAFILE:
383 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
384 break;
385 case PICTYPE_NONE:
386 case PICTYPE_UNINITIALIZED:
387 /* Nothing to do */
388 break;
389 default:
390 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
391 break;
394 HeapFree(GetProcessHeap(), 0, Obj->data);
395 HeapFree(GetProcessHeap(), 0, Obj);
399 /************************************************************************
400 * OLEPictureImpl_AddRef (IUnknown)
402 * See Windows documentation for more details on IUnknown methods.
404 static ULONG WINAPI OLEPictureImpl_AddRef(
405 IPicture* iface)
407 OLEPictureImpl *This = (OLEPictureImpl *)iface;
408 ULONG refCount = InterlockedIncrement(&This->ref);
410 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
412 return refCount;
415 /************************************************************************
416 * OLEPictureImpl_Release (IUnknown)
418 * See Windows documentation for more details on IUnknown methods.
420 static ULONG WINAPI OLEPictureImpl_Release(
421 IPicture* iface)
423 OLEPictureImpl *This = (OLEPictureImpl *)iface;
424 ULONG refCount = InterlockedDecrement(&This->ref);
426 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
429 * If the reference count goes down to 0, perform suicide.
431 if (!refCount) OLEPictureImpl_Destroy(This);
433 return refCount;
436 /************************************************************************
437 * OLEPictureImpl_QueryInterface (IUnknown)
439 * See Windows documentation for more details on IUnknown methods.
441 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
442 IPicture* iface,
443 REFIID riid,
444 void** ppvObject)
446 OLEPictureImpl *This = (OLEPictureImpl *)iface;
447 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
450 * Perform a sanity check on the parameters.
452 if ( (This==0) || (ppvObject==0) )
453 return E_INVALIDARG;
456 * Initialize the return parameter.
458 *ppvObject = 0;
461 * Compare the riid with the interface IDs implemented by this object.
463 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
464 *ppvObject = This;
465 else if (IsEqualIID(&IID_IDispatch, riid))
466 *ppvObject = &This->lpvtblIDispatch;
467 else if (IsEqualIID(&IID_IPictureDisp, riid))
468 *ppvObject = &This->lpvtblIDispatch;
469 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
470 *ppvObject = &This->lpvtblIPersistStream;
471 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
472 *ppvObject = &This->lpvtblIConnectionPointContainer;
475 * Check that we obtained an interface.
477 if ((*ppvObject)==0)
479 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
480 return E_NOINTERFACE;
484 * Query Interface always increases the reference count by one when it is
485 * successful
487 OLEPictureImpl_AddRef((IPicture*)This);
489 return S_OK;
492 /***********************************************************************
493 * OLEPicture_SendNotify (internal)
495 * Sends notification messages of changed properties to any interested
496 * connections.
498 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
500 IEnumConnections *pEnum;
501 CONNECTDATA CD;
503 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
504 return;
505 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
506 IPropertyNotifySink *sink;
508 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
509 IPropertyNotifySink_OnChanged(sink, dispID);
510 IPropertyNotifySink_Release(sink);
511 IUnknown_Release(CD.pUnk);
513 IEnumConnections_Release(pEnum);
516 /************************************************************************
517 * OLEPictureImpl_get_Handle
519 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
520 OLE_HANDLE *phandle)
522 OLEPictureImpl *This = (OLEPictureImpl *)iface;
523 TRACE("(%p)->(%p)\n", This, phandle);
525 if(!phandle)
526 return E_POINTER;
528 switch(This->desc.picType) {
529 case PICTYPE_NONE:
530 case PICTYPE_UNINITIALIZED:
531 *phandle = 0;
532 break;
533 case PICTYPE_BITMAP:
534 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
535 break;
536 case PICTYPE_METAFILE:
537 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
538 break;
539 case PICTYPE_ICON:
540 *phandle = HandleToUlong(This->desc.u.icon.hicon);
541 break;
542 case PICTYPE_ENHMETAFILE:
543 *phandle = HandleToUlong(This->desc.u.emf.hemf);
544 break;
545 default:
546 FIXME("Unimplemented type %d\n", This->desc.picType);
547 return E_NOTIMPL;
549 TRACE("returning handle %08x\n", *phandle);
550 return S_OK;
553 /************************************************************************
554 * OLEPictureImpl_get_hPal
556 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
557 OLE_HANDLE *phandle)
559 OLEPictureImpl *This = (OLEPictureImpl *)iface;
560 HRESULT hres;
561 TRACE("(%p)->(%p)\n", This, phandle);
563 if (!phandle)
564 return E_POINTER;
566 switch (This->desc.picType) {
567 case (UINT)PICTYPE_UNINITIALIZED:
568 case PICTYPE_NONE:
569 *phandle = 0;
570 hres = S_FALSE;
571 break;
572 case PICTYPE_BITMAP:
573 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
574 hres = S_OK;
575 break;
576 case PICTYPE_METAFILE:
577 hres = E_FAIL;
578 break;
579 case PICTYPE_ICON:
580 case PICTYPE_ENHMETAFILE:
581 default:
582 FIXME("unimplemented for type %d. Returning 0 palette.\n",
583 This->desc.picType);
584 *phandle = 0;
585 hres = S_OK;
588 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
589 return hres;
592 /************************************************************************
593 * OLEPictureImpl_get_Type
595 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
596 short *ptype)
598 OLEPictureImpl *This = (OLEPictureImpl *)iface;
599 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
601 if(!ptype)
602 return E_POINTER;
604 *ptype = This->desc.picType;
605 return S_OK;
608 /************************************************************************
609 * OLEPictureImpl_get_Width
611 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
612 OLE_XSIZE_HIMETRIC *pwidth)
614 OLEPictureImpl *This = (OLEPictureImpl *)iface;
615 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
616 *pwidth = This->himetricWidth;
617 return S_OK;
620 /************************************************************************
621 * OLEPictureImpl_get_Height
623 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
624 OLE_YSIZE_HIMETRIC *pheight)
626 OLEPictureImpl *This = (OLEPictureImpl *)iface;
627 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
628 *pheight = This->himetricHeight;
629 return S_OK;
632 /************************************************************************
633 * OLEPictureImpl_Render
635 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
636 LONG x, LONG y, LONG cx, LONG cy,
637 OLE_XPOS_HIMETRIC xSrc,
638 OLE_YPOS_HIMETRIC ySrc,
639 OLE_XSIZE_HIMETRIC cxSrc,
640 OLE_YSIZE_HIMETRIC cySrc,
641 LPCRECT prcWBounds)
643 OLEPictureImpl *This = (OLEPictureImpl *)iface;
644 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
645 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
646 if(prcWBounds)
647 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
648 prcWBounds->right, prcWBounds->bottom);
650 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
651 return CTL_E_INVALIDPROPERTYVALUE;
655 * While the documentation suggests this to be here (or after rendering?)
656 * it does cause an endless recursion in my sample app. -MM 20010804
657 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
660 switch(This->desc.picType) {
661 case PICTYPE_UNINITIALIZED:
662 case PICTYPE_NONE:
663 /* nothing to do */
664 return S_OK;
665 case PICTYPE_BITMAP:
667 HBITMAP hbmpOld;
668 HDC hdcBmp;
670 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
671 NB y-axis gets flipped */
673 hdcBmp = CreateCompatibleDC(0);
674 SetMapMode(hdcBmp, MM_ANISOTROPIC);
675 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
676 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
677 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
678 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
680 if (This->hbmMask) {
681 HDC hdcMask = CreateCompatibleDC(0);
682 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
684 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
686 SetMapMode(hdcMask, MM_ANISOTROPIC);
687 SetWindowOrgEx(hdcMask, 0, 0, NULL);
688 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
689 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
690 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
692 SetBkColor(hdc, RGB(255, 255, 255));
693 SetTextColor(hdc, RGB(0, 0, 0));
694 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
695 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
697 SelectObject(hdcMask, hOldbm);
698 DeleteDC(hdcMask);
699 } else {
700 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
701 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
704 SelectObject(hdcBmp, hbmpOld);
705 DeleteDC(hdcBmp);
707 break;
708 case PICTYPE_ICON:
709 FIXME("Not quite correct implementation of rendering icons...\n");
710 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
711 break;
713 case PICTYPE_METAFILE:
715 POINT prevOrg, prevWndOrg;
716 SIZE prevExt, prevWndExt;
717 int oldmode;
719 /* Render the WMF to the appropriate location by setting the
720 appropriate ratio between "device units" and "logical units" */
721 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
722 /* For the "source rectangle" the y-axis must be inverted */
723 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
724 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
725 /* For the "destination rectangle" no inversion is necessary */
726 SetViewportOrgEx(hdc, x, y, &prevOrg);
727 SetViewportExtEx(hdc, cx, cy, &prevExt);
729 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
730 ERR("PlayMetaFile failed!\n");
732 /* We're done, restore the DC to the previous settings for converting
733 logical units to device units */
734 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
735 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
736 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
737 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
738 SetMapMode(hdc, oldmode);
739 break;
742 case PICTYPE_ENHMETAFILE:
744 RECT rc = { x, y, x + cx, y + cy };
745 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
746 break;
749 default:
750 FIXME("type %d not implemented\n", This->desc.picType);
751 return E_NOTIMPL;
753 return S_OK;
756 /************************************************************************
757 * OLEPictureImpl_set_hPal
759 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
760 OLE_HANDLE hpal)
762 OLEPictureImpl *This = (OLEPictureImpl *)iface;
763 FIXME("(%p)->(%08x): stub\n", This, hpal);
764 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
765 return E_NOTIMPL;
768 /************************************************************************
769 * OLEPictureImpl_get_CurDC
771 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
772 HDC *phdc)
774 OLEPictureImpl *This = (OLEPictureImpl *)iface;
775 TRACE("(%p), returning %p\n", This, This->hDCCur);
776 if (phdc) *phdc = This->hDCCur;
777 return S_OK;
780 /************************************************************************
781 * OLEPictureImpl_SelectPicture
783 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
784 HDC hdcIn,
785 HDC *phdcOut,
786 OLE_HANDLE *phbmpOut)
788 OLEPictureImpl *This = (OLEPictureImpl *)iface;
789 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
790 if (This->desc.picType == PICTYPE_BITMAP) {
791 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
793 if (phdcOut)
794 *phdcOut = This->hDCCur;
795 This->hDCCur = hdcIn;
796 if (phbmpOut)
797 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
798 return S_OK;
799 } else {
800 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
801 return E_FAIL;
805 /************************************************************************
806 * OLEPictureImpl_get_KeepOriginalFormat
808 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
809 BOOL *pfKeep)
811 OLEPictureImpl *This = (OLEPictureImpl *)iface;
812 TRACE("(%p)->(%p)\n", This, pfKeep);
813 if (!pfKeep)
814 return E_POINTER;
815 *pfKeep = This->keepOrigFormat;
816 return S_OK;
819 /************************************************************************
820 * OLEPictureImpl_put_KeepOriginalFormat
822 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
823 BOOL keep)
825 OLEPictureImpl *This = (OLEPictureImpl *)iface;
826 TRACE("(%p)->(%d)\n", This, keep);
827 This->keepOrigFormat = keep;
828 /* FIXME: what DISPID notification here? */
829 return S_OK;
832 /************************************************************************
833 * OLEPictureImpl_PictureChanged
835 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
837 OLEPictureImpl *This = (OLEPictureImpl *)iface;
838 TRACE("(%p)->()\n", This);
839 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
840 This->bIsDirty = TRUE;
841 return S_OK;
844 /************************************************************************
845 * OLEPictureImpl_SaveAsFile
847 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
848 IStream *pstream,
849 BOOL SaveMemCopy,
850 LONG *pcbSize)
852 OLEPictureImpl *This = (OLEPictureImpl *)iface;
853 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
854 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
857 /************************************************************************
858 * OLEPictureImpl_get_Attributes
860 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
861 DWORD *pdwAttr)
863 OLEPictureImpl *This = (OLEPictureImpl *)iface;
864 TRACE("(%p)->(%p).\n", This, pdwAttr);
866 if(!pdwAttr)
867 return E_POINTER;
869 *pdwAttr = 0;
870 switch (This->desc.picType) {
871 case PICTYPE_UNINITIALIZED:
872 case PICTYPE_NONE: break;
873 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
874 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
875 case PICTYPE_ENHMETAFILE: /* fall through */
876 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
877 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
879 return S_OK;
883 /************************************************************************
884 * IConnectionPointContainer
886 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
887 IConnectionPointContainer* iface,
888 REFIID riid,
889 VOID** ppvoid)
891 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
893 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
896 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
897 IConnectionPointContainer* iface)
899 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
901 return IPicture_AddRef((IPicture *)This);
904 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
905 IConnectionPointContainer* iface)
907 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
909 return IPicture_Release((IPicture *)This);
912 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
913 IConnectionPointContainer* iface,
914 IEnumConnectionPoints** ppEnum)
916 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
918 FIXME("(%p,%p), stub!\n",This,ppEnum);
919 return E_NOTIMPL;
922 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
923 IConnectionPointContainer* iface,
924 REFIID riid,
925 IConnectionPoint **ppCP)
927 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
928 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
929 if (!ppCP)
930 return E_POINTER;
931 *ppCP = NULL;
932 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
933 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
934 FIXME("no connection point for %s\n",debugstr_guid(riid));
935 return CONNECT_E_NOCONNECTION;
939 /************************************************************************
940 * IPersistStream
943 /************************************************************************
944 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
946 * See Windows documentation for more details on IUnknown methods.
948 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
949 IPersistStream* iface,
950 REFIID riid,
951 VOID** ppvoid)
953 OLEPictureImpl *This = impl_from_IPersistStream(iface);
955 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
958 /************************************************************************
959 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
961 * See Windows documentation for more details on IUnknown methods.
963 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
964 IPersistStream* iface)
966 OLEPictureImpl *This = impl_from_IPersistStream(iface);
968 return IPicture_AddRef((IPicture *)This);
971 /************************************************************************
972 * OLEPictureImpl_IPersistStream_Release (IUnknown)
974 * See Windows documentation for more details on IUnknown methods.
976 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
977 IPersistStream* iface)
979 OLEPictureImpl *This = impl_from_IPersistStream(iface);
981 return IPicture_Release((IPicture *)This);
984 /************************************************************************
985 * OLEPictureImpl_IPersistStream_GetClassID
987 static HRESULT WINAPI OLEPictureImpl_GetClassID(
988 IPersistStream* iface,CLSID* pClassID)
990 TRACE("(%p)\n", pClassID);
991 *pClassID = CLSID_StdPicture;
992 return S_OK;
995 /************************************************************************
996 * OLEPictureImpl_IPersistStream_IsDirty
998 static HRESULT WINAPI OLEPictureImpl_IsDirty(
999 IPersistStream* iface)
1001 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1002 FIXME("(%p),stub!\n",This);
1003 return E_NOTIMPL;
1006 #ifdef SONAME_LIBJPEG
1008 static void *libjpeg_handle;
1009 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1010 MAKE_FUNCPTR(jpeg_std_error);
1011 MAKE_FUNCPTR(jpeg_CreateDecompress);
1012 MAKE_FUNCPTR(jpeg_read_header);
1013 MAKE_FUNCPTR(jpeg_start_decompress);
1014 MAKE_FUNCPTR(jpeg_read_scanlines);
1015 MAKE_FUNCPTR(jpeg_finish_decompress);
1016 MAKE_FUNCPTR(jpeg_destroy_decompress);
1017 #undef MAKE_FUNCPTR
1019 static void *load_libjpeg(void)
1021 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
1023 #define LOAD_FUNCPTR(f) \
1024 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
1025 libjpeg_handle = NULL; \
1026 return NULL; \
1029 LOAD_FUNCPTR(jpeg_std_error);
1030 LOAD_FUNCPTR(jpeg_CreateDecompress);
1031 LOAD_FUNCPTR(jpeg_read_header);
1032 LOAD_FUNCPTR(jpeg_start_decompress);
1033 LOAD_FUNCPTR(jpeg_read_scanlines);
1034 LOAD_FUNCPTR(jpeg_finish_decompress);
1035 LOAD_FUNCPTR(jpeg_destroy_decompress);
1036 #undef LOAD_FUNCPTR
1038 return libjpeg_handle;
1041 /* for the jpeg decompressor source manager. */
1042 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1044 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1045 ERR("(), should not get here.\n");
1046 return FALSE;
1049 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1050 TRACE("Skipping %ld bytes...\n", num_bytes);
1051 cinfo->src->next_input_byte += num_bytes;
1052 cinfo->src->bytes_in_buffer -= num_bytes;
1055 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1056 ERR("(desired=%d), should not get here.\n",desired);
1057 return FALSE;
1059 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1060 #endif /* SONAME_LIBJPEG */
1062 struct gifdata {
1063 unsigned char *data;
1064 unsigned int curoff;
1065 unsigned int len;
1068 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1069 struct gifdata *gd = gif->UserData;
1071 if (len+gd->curoff > gd->len) {
1072 ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1073 len = gd->len - gd->curoff;
1075 memcpy(data, gd->data+gd->curoff, len);
1076 gd->curoff += len;
1077 return len;
1081 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1083 struct gifdata gd;
1084 GifFileType *gif;
1085 BITMAPINFO *bmi;
1086 HDC hdcref;
1087 LPBYTE bytes;
1088 int i,j,ret;
1089 GifImageDesc *gid;
1090 SavedImage *si;
1091 ColorMapObject *cm;
1092 int transparent = -1;
1093 ExtensionBlock *eb;
1094 int padding;
1096 gd.data = xbuf;
1097 gd.curoff = 0;
1098 gd.len = xread;
1099 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1100 ret = DGifSlurp(gif);
1101 if (ret == GIF_ERROR) {
1102 ERR("Failed reading GIF using libgif.\n");
1103 return E_FAIL;
1105 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1106 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1107 TRACE("imgcnt %d\n", gif->ImageCount);
1108 if (gif->ImageCount<1) {
1109 ERR("GIF stream does not have images inside?\n");
1110 return E_FAIL;
1112 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1113 gif->Image.Width, gif->Image.Height,
1114 gif->Image.Left, gif->Image.Top,
1115 gif->Image.Interlace
1117 /* */
1118 padding = (gif->SWidth+3) & ~3;
1119 si = gif->SavedImages+0;
1120 gid = &(si->ImageDesc);
1121 cm = gid->ColorMap;
1122 if (!cm) cm = gif->SColorMap;
1123 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1124 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1126 /* look for the transparent color extension */
1127 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1128 eb = si->ExtensionBlocks + i;
1129 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1130 if ((eb->Bytes[0] & 1) == 1) {
1131 transparent = (unsigned char)eb->Bytes[3];
1136 for (i = 0; i < cm->ColorCount; i++) {
1137 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1138 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1139 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1140 if (i == transparent) {
1141 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1142 bmi->bmiColors[i].rgbGreen,
1143 bmi->bmiColors[i].rgbBlue);
1147 /* Map to in picture coordinates */
1148 for (i = 0, j = 0; i < gid->Height; i++) {
1149 if (gif->Image.Interlace) {
1150 memcpy(
1151 bytes + (gid->Top + j) * padding + gid->Left,
1152 si->RasterBits + i * gid->Width,
1153 gid->Width);
1155 /* Lower bits of interlaced counter encode current interlace */
1156 if (j & 1) j += 2; /* Currently filling odd rows */
1157 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1158 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1160 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1161 /* End of current interlace, go to next interlace */
1162 if (j & 2) j = 1; /* Next iteration fills odd rows */
1163 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1164 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1166 } else {
1167 memcpy(
1168 bytes + (gid->Top + i) * padding + gid->Left,
1169 si->RasterBits + i * gid->Width,
1170 gid->Width);
1174 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1175 bmi->bmiHeader.biWidth = gif->SWidth;
1176 bmi->bmiHeader.biHeight = -gif->SHeight;
1177 bmi->bmiHeader.biPlanes = 1;
1178 bmi->bmiHeader.biBitCount = 8;
1179 bmi->bmiHeader.biCompression = BI_RGB;
1180 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1181 bmi->bmiHeader.biXPelsPerMeter = 0;
1182 bmi->bmiHeader.biYPelsPerMeter = 0;
1183 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1184 bmi->bmiHeader.biClrImportant = 0;
1186 hdcref = GetDC(0);
1187 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1188 hdcref,
1189 &bmi->bmiHeader,
1190 CBM_INIT,
1191 bytes,
1192 bmi,
1193 DIB_RGB_COLORS
1196 if (transparent > -1) {
1197 /* Create the Mask */
1198 HDC hdc = CreateCompatibleDC(0);
1199 HDC hdcMask = CreateCompatibleDC(0);
1200 HBITMAP hOldbitmap;
1201 HBITMAP hOldbitmapmask;
1203 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1204 HBITMAP hTempMask;
1206 This->hbmXor = CreateDIBitmap(
1207 hdcref,
1208 &bmi->bmiHeader,
1209 CBM_INIT,
1210 bytes,
1211 bmi,
1212 DIB_RGB_COLORS
1215 bmi->bmiColors[0].rgbRed = 0;
1216 bmi->bmiColors[0].rgbGreen = 0;
1217 bmi->bmiColors[0].rgbBlue = 0;
1218 bmi->bmiColors[1].rgbRed = 255;
1219 bmi->bmiColors[1].rgbGreen = 255;
1220 bmi->bmiColors[1].rgbBlue = 255;
1222 bmi->bmiHeader.biBitCount = 1;
1223 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1224 bmi->bmiHeader.biClrUsed = 2;
1226 for (i = 0; i < gif->SHeight; i++) {
1227 unsigned char * colorPointer = bytes + padding * i;
1228 unsigned char * monoPointer = bytes + monopadding * i;
1229 for (j = 0; j < gif->SWidth; j++) {
1230 unsigned char pixel = colorPointer[j];
1231 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1232 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1235 hdcref = GetDC(0);
1236 hTempMask = CreateDIBitmap(
1237 hdcref,
1238 &bmi->bmiHeader,
1239 CBM_INIT,
1240 bytes,
1241 bmi,
1242 DIB_RGB_COLORS
1244 DeleteDC(hdcref);
1246 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1247 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1248 hOldbitmap = SelectObject(hdc, hTempMask);
1249 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1251 SetBkColor(hdc, RGB(255, 255, 255));
1252 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1254 /* We no longer need the original bitmap, so we apply the first
1255 transformation with the mask to speed up the rendering */
1256 SelectObject(hdc, This->hbmXor);
1257 SetBkColor(hdc, RGB(0,0,0));
1258 SetTextColor(hdc, RGB(255,255,255));
1259 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1260 hdcMask, 0, 0, SRCAND);
1262 SelectObject(hdc, hOldbitmap);
1263 SelectObject(hdcMask, hOldbitmapmask);
1264 DeleteDC(hdcMask);
1265 DeleteDC(hdc);
1266 DeleteObject(hTempMask);
1269 DeleteDC(hdcref);
1270 This->desc.picType = PICTYPE_BITMAP;
1271 OLEPictureImpl_SetBitmap(This);
1272 DGifCloseFile(gif);
1273 HeapFree(GetProcessHeap(),0,bmi);
1274 HeapFree(GetProcessHeap(),0,bytes);
1275 return S_OK;
1278 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1280 #ifdef SONAME_LIBJPEG
1281 struct jpeg_decompress_struct jd;
1282 struct jpeg_error_mgr jerr;
1283 int ret;
1284 JDIMENSION x;
1285 JSAMPROW samprow,oldsamprow;
1286 BITMAPINFOHEADER bmi;
1287 LPBYTE bits;
1288 HDC hdcref;
1289 struct jpeg_source_mgr xjsm;
1290 LPBYTE oldbits;
1291 unsigned int i;
1293 if(!libjpeg_handle) {
1294 if(!load_libjpeg()) {
1295 ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1296 return E_FAIL;
1300 /* This is basically so we can use in-memory data for jpeg decompression.
1301 * We need to have all the functions.
1303 xjsm.next_input_byte = xbuf;
1304 xjsm.bytes_in_buffer = xread;
1305 xjsm.init_source = _jpeg_init_source;
1306 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1307 xjsm.skip_input_data = _jpeg_skip_input_data;
1308 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1309 xjsm.term_source = _jpeg_term_source;
1311 jd.err = pjpeg_std_error(&jerr);
1312 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1313 * jpeg_create_decompress(&jd); */
1314 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1315 jd.src = &xjsm;
1316 ret=pjpeg_read_header(&jd,TRUE);
1317 jd.out_color_space = JCS_RGB;
1318 pjpeg_start_decompress(&jd);
1319 if (ret != JPEG_HEADER_OK) {
1320 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1321 HeapFree(GetProcessHeap(),0,xbuf);
1322 return E_FAIL;
1325 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1326 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1327 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1329 oldbits = bits;
1330 oldsamprow = samprow;
1331 while ( jd.output_scanline<jd.output_height ) {
1332 x = pjpeg_read_scanlines(&jd,&samprow,1);
1333 if (x != 1) {
1334 ERR("failed to read current scanline?\n");
1335 break;
1337 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1338 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1339 *(bits++) = *(samprow+2);
1340 *(bits++) = *(samprow+1);
1341 *(bits++) = *(samprow);
1343 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1344 samprow = oldsamprow;
1346 bits = oldbits;
1348 bmi.biSize = sizeof(bmi);
1349 bmi.biWidth = jd.output_width;
1350 bmi.biHeight = -jd.output_height;
1351 bmi.biPlanes = 1;
1352 bmi.biBitCount = jd.output_components<<3;
1353 bmi.biCompression = BI_RGB;
1354 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1355 bmi.biXPelsPerMeter = 0;
1356 bmi.biYPelsPerMeter = 0;
1357 bmi.biClrUsed = 0;
1358 bmi.biClrImportant = 0;
1360 HeapFree(GetProcessHeap(),0,samprow);
1361 pjpeg_finish_decompress(&jd);
1362 pjpeg_destroy_decompress(&jd);
1363 hdcref = GetDC(0);
1364 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1365 hdcref,
1366 &bmi,
1367 CBM_INIT,
1368 bits,
1369 (BITMAPINFO*)&bmi,
1370 DIB_RGB_COLORS
1372 DeleteDC(hdcref);
1373 This->desc.picType = PICTYPE_BITMAP;
1374 OLEPictureImpl_SetBitmap(This);
1375 HeapFree(GetProcessHeap(),0,bits);
1376 return S_OK;
1377 #else
1378 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1379 return E_FAIL;
1380 #endif
1383 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1385 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1386 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1387 HDC hdcref;
1389 /* Does not matter whether this is a coreheader or not, we only use
1390 * components which are in both
1392 hdcref = GetDC(0);
1393 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1394 hdcref,
1395 &(bi->bmiHeader),
1396 CBM_INIT,
1397 xbuf+bfh->bfOffBits,
1399 DIB_RGB_COLORS
1401 DeleteDC(hdcref);
1402 if (This->desc.u.bmp.hbitmap == 0)
1403 return E_FAIL;
1404 This->desc.picType = PICTYPE_BITMAP;
1405 OLEPictureImpl_SetBitmap(This);
1406 return S_OK;
1409 /*****************************************************
1410 * start of PNG-specific code
1411 * currently only supports colortype PNG_COLOR_TYPE_RGB
1413 #ifdef SONAME_LIBPNG
1414 typedef struct{
1415 ULONG position;
1416 ULONG size;
1417 BYTE * buff;
1418 } png_io;
1420 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1421 png_size_t length)
1423 png_io * io_ptr = png_ptr->io_ptr;
1425 if(length + io_ptr->position > io_ptr->size){
1426 length = io_ptr->size - io_ptr->position;
1429 memcpy(data, io_ptr->buff + io_ptr->position, length);
1431 io_ptr->position += length;
1434 static void *libpng_handle;
1435 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1436 MAKE_FUNCPTR(png_create_read_struct);
1437 MAKE_FUNCPTR(png_create_info_struct);
1438 MAKE_FUNCPTR(png_set_read_fn);
1439 MAKE_FUNCPTR(png_read_info);
1440 MAKE_FUNCPTR(png_read_image);
1441 MAKE_FUNCPTR(png_get_rowbytes);
1442 MAKE_FUNCPTR(png_set_bgr);
1443 MAKE_FUNCPTR(png_destroy_read_struct);
1444 MAKE_FUNCPTR(png_set_palette_to_rgb);
1445 MAKE_FUNCPTR(png_read_update_info);
1446 MAKE_FUNCPTR(png_get_tRNS);
1447 MAKE_FUNCPTR(png_get_PLTE);
1448 MAKE_FUNCPTR(png_set_expand);
1449 #undef MAKE_FUNCPTR
1451 static void *load_libpng(void)
1453 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1455 #define LOAD_FUNCPTR(f) \
1456 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1457 libpng_handle = NULL; \
1458 return NULL; \
1460 LOAD_FUNCPTR(png_create_read_struct);
1461 LOAD_FUNCPTR(png_create_info_struct);
1462 LOAD_FUNCPTR(png_set_read_fn);
1463 LOAD_FUNCPTR(png_read_info);
1464 LOAD_FUNCPTR(png_read_image);
1465 LOAD_FUNCPTR(png_get_rowbytes);
1466 LOAD_FUNCPTR(png_set_bgr);
1467 LOAD_FUNCPTR(png_destroy_read_struct);
1468 LOAD_FUNCPTR(png_set_palette_to_rgb);
1469 LOAD_FUNCPTR(png_read_update_info);
1470 LOAD_FUNCPTR(png_get_tRNS);
1471 LOAD_FUNCPTR(png_get_PLTE);
1472 LOAD_FUNCPTR(png_set_expand);
1474 #undef LOAD_FUNCPTR
1476 return libpng_handle;
1478 #endif /* SONAME_LIBPNG */
1480 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1482 #ifdef SONAME_LIBPNG
1483 png_io io;
1484 png_structp png_ptr = NULL;
1485 png_infop info_ptr = NULL;
1486 INT row, rowsize, height, width, num_trans, i, j;
1487 png_bytep* row_pointers = NULL;
1488 png_bytep pngdata = NULL;
1489 BITMAPINFOHEADER bmi;
1490 HDC hdcref = NULL, hdcXor, hdcMask;
1491 HRESULT ret;
1492 BOOL transparency;
1493 png_bytep trans;
1494 png_color_16p trans_values;
1495 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1496 HBITMAP hbmoldXor, hbmoldMask, temp;
1498 if(!libpng_handle) {
1499 if(!load_libpng()) {
1500 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1501 return E_FAIL;
1505 io.size = xread;
1506 io.position = 0;
1507 io.buff = xbuf;
1509 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1510 NULL, NULL, NULL);
1512 if(setjmp(png_jmpbuf(png_ptr))){
1513 TRACE("Error in libpng\n");
1514 ret = E_FAIL;
1515 goto end;
1518 info_ptr = ppng_create_info_struct(png_ptr);
1519 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1520 ppng_read_info(png_ptr, info_ptr);
1522 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1523 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1524 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1525 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1526 ret = E_FAIL;
1527 goto end;
1530 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1531 == PNG_INFO_tRNS);
1533 /* sets format from anything to RGBA */
1534 ppng_set_expand(png_ptr);
1535 /* sets format to BGRA */
1536 ppng_set_bgr(png_ptr);
1538 ppng_read_update_info(png_ptr, info_ptr);
1540 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1541 /* align rowsize to 4-byte boundary */
1542 rowsize = (rowsize + 3) & ~3;
1543 height = info_ptr->height;
1544 width = info_ptr->width;
1546 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1547 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1549 if(!pngdata || !row_pointers){
1550 ret = E_FAIL;
1551 goto end;
1554 for (row = 0; row < height; row++){
1555 row_pointers[row] = pngdata + row * rowsize;
1558 ppng_read_image(png_ptr, row_pointers);
1560 bmi.biSize = sizeof(bmi);
1561 bmi.biWidth = width;
1562 bmi.biHeight = -height;
1563 bmi.biPlanes = 1;
1564 bmi.biBitCount = info_ptr->channels * 8;
1565 bmi.biCompression = BI_RGB;
1566 bmi.biSizeImage = height * rowsize;
1567 bmi.biXPelsPerMeter = 0;
1568 bmi.biYPelsPerMeter = 0;
1569 bmi.biClrUsed = 0;
1570 bmi.biClrImportant = 0;
1572 hdcref = GetDC(0);
1573 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1574 hdcref,
1575 &bmi,
1576 CBM_INIT,
1577 pngdata,
1578 (BITMAPINFO*)&bmi,
1579 DIB_RGB_COLORS
1582 /* only fully-transparent alpha is handled */
1583 if((info_ptr->channels != 4) || !transparency){
1584 ReleaseDC(0, hdcref);
1585 goto succ;
1588 This->hbmXor = CreateDIBitmap(
1589 hdcref,
1590 &bmi,
1591 CBM_INIT,
1592 pngdata,
1593 (BITMAPINFO*)&bmi,
1594 DIB_RGB_COLORS
1597 /* set transparent pixels to black, all others to white */
1598 for(i = 0; i < height; i++){
1599 for(j = 3; j < rowsize; j += 4){
1600 if(row_pointers[i][j] == 0)
1601 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1602 else
1603 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1607 temp = CreateDIBitmap(
1608 hdcref,
1609 &bmi,
1610 CBM_INIT,
1611 pngdata,
1612 (BITMAPINFO*)&bmi,
1613 DIB_RGB_COLORS
1616 ReleaseDC(0, hdcref);
1618 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1619 hdcXor = CreateCompatibleDC(NULL);
1620 hdcMask = CreateCompatibleDC(NULL);
1622 hbmoldXor = SelectObject(hdcXor,temp);
1623 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1624 SetBkColor(hdcXor,black);
1625 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1627 SelectObject(hdcXor,This->hbmXor);
1628 DeleteObject(temp);
1630 SetTextColor(hdcXor,white);
1631 SetBkColor(hdcXor,black);
1632 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1634 SelectObject(hdcXor,hbmoldXor);
1635 SelectObject(hdcMask,hbmoldMask);
1637 DeleteDC(hdcXor);
1638 DeleteDC(hdcMask);
1640 succ:
1641 This->desc.picType = PICTYPE_BITMAP;
1642 OLEPictureImpl_SetBitmap(This);
1643 ret = S_OK;
1645 end:
1646 if(png_ptr)
1647 ppng_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : NULL, NULL);
1648 HeapFree(GetProcessHeap(), 0, row_pointers);
1649 HeapFree(GetProcessHeap(), 0, pngdata);
1650 return ret;
1651 #else /* SONAME_LIBPNG */
1652 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1653 return E_FAIL;
1654 #endif
1657 /*****************************************************
1658 * start of Icon-specific code
1661 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1663 HICON hicon;
1664 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1665 HDC hdcRef;
1666 int i;
1669 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1670 FIXME("icon.idType=%d\n",cifd->idType);
1671 FIXME("icon.idCount=%d\n",cifd->idCount);
1673 for (i=0;i<cifd->idCount;i++) {
1674 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1675 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1676 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1677 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1678 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1679 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1680 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1681 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1684 i=0;
1685 /* If we have more than one icon, try to find the best.
1686 * this currently means '32 pixel wide'.
1688 if (cifd->idCount!=1) {
1689 for (i=0;i<cifd->idCount;i++) {
1690 if (cifd->idEntries[i].bWidth == 32)
1691 break;
1693 if (i==cifd->idCount) i=0;
1696 hicon = CreateIconFromResourceEx(
1697 xbuf+cifd->idEntries[i].dwDIBOffset,
1698 cifd->idEntries[i].dwDIBSize,
1699 TRUE, /* is icon */
1700 0x00030000,
1701 cifd->idEntries[i].bWidth,
1702 cifd->idEntries[i].bHeight,
1705 if (!hicon) {
1706 ERR("CreateIcon failed.\n");
1707 return E_FAIL;
1708 } else {
1709 This->desc.picType = PICTYPE_ICON;
1710 This->desc.u.icon.hicon = hicon;
1711 This->origWidth = cifd->idEntries[i].bWidth;
1712 This->origHeight = cifd->idEntries[i].bHeight;
1713 hdcRef = CreateCompatibleDC(0);
1714 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1715 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1716 DeleteDC(hdcRef);
1717 return S_OK;
1721 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1722 const BYTE *data, ULONG size)
1724 HENHMETAFILE hemf;
1725 ENHMETAHEADER hdr;
1727 hemf = SetEnhMetaFileBits(size, data);
1728 if (!hemf) return E_FAIL;
1730 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1732 This->desc.picType = PICTYPE_ENHMETAFILE;
1733 This->desc.u.emf.hemf = hemf;
1735 This->origWidth = 0;
1736 This->origHeight = 0;
1737 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1738 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1740 return S_OK;
1743 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1744 const BYTE *data, ULONG size)
1746 APM_HEADER *header = (APM_HEADER *)data;
1747 HMETAFILE hmf;
1749 if (size < sizeof(APM_HEADER))
1750 return E_FAIL;
1751 if (header->key != 0x9ac6cdd7)
1752 return E_FAIL;
1754 /* SetMetaFileBitsEx performs data check on its own */
1755 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1756 if (!hmf) return E_FAIL;
1758 This->desc.picType = PICTYPE_METAFILE;
1759 This->desc.u.wmf.hmeta = hmf;
1760 This->desc.u.wmf.xExt = 0;
1761 This->desc.u.wmf.yExt = 0;
1763 This->origWidth = 0;
1764 This->origHeight = 0;
1765 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1766 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1767 return S_OK;
1770 /************************************************************************
1771 * BITMAP FORMAT FLAGS -
1772 * Flags that differentiate between different types of bitmaps.
1775 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
1776 #define BITMAP_FORMAT_JPEG 0xd8ff
1777 #define BITMAP_FORMAT_GIF 0x4947
1778 #define BITMAP_FORMAT_PNG 0x5089
1779 #define BITMAP_FORMAT_APM 0xcdd7
1781 /************************************************************************
1782 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1784 * Loads the binary data from the IStream. Starts at current position.
1785 * There appears to be an 2 DWORD header:
1786 * DWORD magic;
1787 * DWORD len;
1789 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1791 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1792 HRESULT hr = E_FAIL;
1793 BOOL headerisdata = FALSE;
1794 BOOL statfailed = FALSE;
1795 ULONG xread, toread;
1796 ULONG headerread;
1797 BYTE *xbuf;
1798 DWORD header[2];
1799 WORD magic;
1800 STATSTG statstg;
1801 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1803 TRACE("(%p,%p)\n",This,pStm);
1805 /****************************************************************************************
1806 * Part 1: Load the data
1808 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1809 * out whether we do.
1811 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1812 * compound file. This may explain most, if not all, of the cases of "no
1813 * header", and the header validation should take this into account.
1814 * At least in Visual Basic 6, resource streams, valid headers are
1815 * header[0] == "lt\0\0",
1816 * header[1] == length_of_stream.
1818 * Also handle streams where we do not have a working "Stat" method by
1819 * reading all data until the end of the stream.
1821 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1822 if (hr) {
1823 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1824 statfailed = TRUE;
1825 /* we will read at least 8 byte ... just right below */
1826 statstg.cbSize.QuadPart = 8;
1829 toread = 0;
1830 headerread = 0;
1831 headerisdata = FALSE;
1832 do {
1833 hr=IStream_Read(pStm,header,8,&xread);
1834 if (hr || xread!=8) {
1835 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1836 return (hr?hr:E_FAIL);
1838 headerread += xread;
1839 xread = 0;
1841 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1842 if (toread != 0 && toread != header[1])
1843 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1844 toread, header[1]);
1845 toread = header[1];
1846 if (toread == 0) break;
1847 } else {
1848 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1849 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1850 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1851 (header[0] == EMR_HEADER) || /* EMF header */
1852 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1853 (header[1]==0)
1854 ) {/* Found start of bitmap data */
1855 headerisdata = TRUE;
1856 if (toread == 0)
1857 toread = statstg.cbSize.QuadPart-8;
1858 else toread -= 8;
1859 xread = 8;
1860 } else {
1861 FIXME("Unknown stream header magic: %08x\n", header[0]);
1862 toread = header[1];
1865 } while (!headerisdata);
1867 if (statfailed) { /* we don't know the size ... read all we get */
1868 int sizeinc = 4096;
1869 int origsize = sizeinc;
1870 ULONG nread = 42;
1872 TRACE("Reading all data from stream.\n");
1873 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1874 if (headerisdata)
1875 memcpy (xbuf, header, 8);
1876 while (1) {
1877 while (xread < origsize) {
1878 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1879 xread+=nread;
1880 if (hr || !nread)
1881 break;
1883 if (!nread || hr) /* done, or error */
1884 break;
1885 if (xread == origsize) {
1886 origsize += sizeinc;
1887 sizeinc = 2*sizeinc; /* exponential increase */
1888 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1891 if (hr)
1892 TRACE("hr in no-stat loader case is %08x\n", hr);
1893 TRACE("loaded %d bytes.\n", xread);
1894 This->datalen = xread;
1895 This->data = xbuf;
1896 } else {
1897 This->datalen = toread+(headerisdata?8:0);
1898 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1899 if (!xbuf)
1900 return E_OUTOFMEMORY;
1902 if (headerisdata)
1903 memcpy (xbuf, header, 8);
1905 while (xread < This->datalen) {
1906 ULONG nread;
1907 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1908 xread+=nread;
1909 if (hr || !nread)
1910 break;
1912 if (xread != This->datalen)
1913 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1915 if (This->datalen == 0) { /* Marks the "NONE" picture */
1916 This->desc.picType = PICTYPE_NONE;
1917 return S_OK;
1921 /****************************************************************************************
1922 * Part 2: Process the loaded data
1925 magic = xbuf[0] + (xbuf[1]<<8);
1926 This->loadtime_format = magic;
1928 switch (magic) {
1929 case BITMAP_FORMAT_GIF: /* GIF */
1930 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1931 break;
1932 case BITMAP_FORMAT_JPEG: /* JPEG */
1933 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1934 break;
1935 case BITMAP_FORMAT_BMP: /* Bitmap */
1936 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1937 break;
1938 case BITMAP_FORMAT_PNG: /* PNG */
1939 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1940 break;
1941 case BITMAP_FORMAT_APM: /* APM */
1942 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1943 break;
1944 case 0x0000: { /* ICON , first word is dwReserved */
1945 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1946 break;
1948 default:
1950 unsigned int i;
1952 /* let's see if it's a EMF */
1953 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1954 if (hr == S_OK) break;
1956 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1957 hr=E_FAIL;
1958 for (i=0;i<xread+8;i++) {
1959 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1960 else MESSAGE("%02x ",xbuf[i-8]);
1961 if (i % 10 == 9) MESSAGE("\n");
1963 MESSAGE("\n");
1964 break;
1967 This->bIsDirty = FALSE;
1969 /* FIXME: this notify is not really documented */
1970 if (hr==S_OK)
1971 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1972 return hr;
1975 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1977 int iSuccess = 0;
1978 HDC hDC;
1979 BITMAPINFO * pInfoBitmap;
1980 int iNumPaletteEntries;
1981 unsigned char * pPixelData;
1982 BITMAPFILEHEADER * pFileHeader;
1983 BITMAPINFO * pInfoHeader;
1985 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1986 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1988 /* Find out bitmap size and padded length */
1989 hDC = GetDC(0);
1990 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1991 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1993 /* Fetch bitmap palette & pixel data */
1995 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1996 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1998 /* Calculate the total length required for the BMP data */
1999 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
2000 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
2001 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
2002 } else {
2003 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
2004 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
2005 else
2006 iNumPaletteEntries = 0;
2008 *pLength =
2009 sizeof(BITMAPFILEHEADER) +
2010 sizeof(BITMAPINFOHEADER) +
2011 iNumPaletteEntries * sizeof(RGBQUAD) +
2012 pInfoBitmap->bmiHeader.biSizeImage;
2013 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
2015 /* Fill the BITMAPFILEHEADER */
2016 pFileHeader = *ppBuffer;
2017 pFileHeader->bfType = BITMAP_FORMAT_BMP;
2018 pFileHeader->bfSize = *pLength;
2019 pFileHeader->bfOffBits =
2020 sizeof(BITMAPFILEHEADER) +
2021 sizeof(BITMAPINFOHEADER) +
2022 iNumPaletteEntries * sizeof(RGBQUAD);
2024 /* Fill the BITMAPINFOHEADER and the palette data */
2025 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
2026 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
2027 memcpy(
2028 (unsigned char *)(*ppBuffer) +
2029 sizeof(BITMAPFILEHEADER) +
2030 sizeof(BITMAPINFOHEADER) +
2031 iNumPaletteEntries * sizeof(RGBQUAD),
2032 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2033 iSuccess = 1;
2035 HeapFree(GetProcessHeap(), 0, pPixelData);
2036 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2037 return iSuccess;
2040 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2042 ICONINFO infoIcon;
2043 int iSuccess = 0;
2045 *ppBuffer = NULL; *pLength = 0;
2046 if (GetIconInfo(hIcon, &infoIcon)) {
2047 HDC hDC;
2048 BITMAPINFO * pInfoBitmap;
2049 unsigned char * pIconData = NULL;
2050 unsigned int iDataSize = 0;
2052 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2054 /* Find out icon size */
2055 hDC = GetDC(0);
2056 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2057 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2058 if (1) {
2059 /* Auxiliary pointers */
2060 CURSORICONFILEDIR * pIconDir;
2061 CURSORICONFILEDIRENTRY * pIconEntry;
2062 BITMAPINFOHEADER * pIconBitmapHeader;
2063 unsigned int iOffsetPalette;
2064 unsigned int iOffsetColorData;
2065 unsigned int iOffsetMaskData;
2067 unsigned int iLengthScanLineColor;
2068 unsigned int iLengthScanLineMask;
2069 unsigned int iNumEntriesPalette;
2071 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2072 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2074 FIXME("DEBUG: bitmap size is %d x %d\n",
2075 pInfoBitmap->bmiHeader.biWidth,
2076 pInfoBitmap->bmiHeader.biHeight);
2077 FIXME("DEBUG: bitmap bpp is %d\n",
2078 pInfoBitmap->bmiHeader.biBitCount);
2079 FIXME("DEBUG: bitmap nplanes is %d\n",
2080 pInfoBitmap->bmiHeader.biPlanes);
2081 FIXME("DEBUG: bitmap biSizeImage is %u\n",
2082 pInfoBitmap->bmiHeader.biSizeImage);
2084 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2085 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2086 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2088 /* Fill out the CURSORICONFILEDIR */
2089 pIconDir = (CURSORICONFILEDIR *)pIconData;
2090 pIconDir->idType = 1;
2091 pIconDir->idCount = 1;
2093 /* Fill out the CURSORICONFILEDIRENTRY */
2094 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2095 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2096 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2097 pIconEntry->bColorCount =
2098 (pInfoBitmap->bmiHeader.biBitCount < 8)
2099 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2100 : 0;
2101 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2102 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2103 pIconEntry->dwDIBSize = 0;
2104 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2106 /* Fill out the BITMAPINFOHEADER */
2107 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2108 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2110 /* Find out whether a palette exists for the bitmap */
2111 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2112 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2113 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2114 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2115 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2116 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2117 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2118 iNumEntriesPalette = 3;
2119 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2120 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2121 } else {
2122 iNumEntriesPalette = 0;
2125 /* Add bitmap size and header size to icon data size. */
2126 iOffsetPalette = iDataSize;
2127 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2128 iOffsetColorData = iDataSize;
2129 iDataSize += pIconBitmapHeader->biSizeImage;
2130 iOffsetMaskData = iDataSize;
2131 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2132 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2133 pIconBitmapHeader->biHeight *= 2;
2134 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2135 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2136 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2137 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2139 /* Get the actual bitmap data from the icon bitmap */
2140 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2141 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2142 if (iNumEntriesPalette > 0) {
2143 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2144 iNumEntriesPalette * sizeof(RGBQUAD));
2147 /* Reset all values so that GetDIBits call succeeds */
2148 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2149 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2150 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2152 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2153 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2154 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2156 printf("ERROR: unable to get bitmap mask (error %u)\n",
2157 GetLastError());
2161 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2162 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2164 /* Write out everything produced so far to the stream */
2165 *ppBuffer = pIconData; *pLength = iDataSize;
2166 iSuccess = 1;
2167 } else {
2169 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2170 GetLastError());
2174 Remarks (from MSDN entry on GetIconInfo):
2176 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2177 members of ICONINFO. The calling application must manage
2178 these bitmaps and delete them when they are no longer
2179 necessary.
2181 if (hDC) ReleaseDC(0, hDC);
2182 DeleteObject(infoIcon.hbmMask);
2183 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2184 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2185 } else {
2186 printf("ERROR: Unable to get icon information (error %u)\n",
2187 GetLastError());
2189 return iSuccess;
2192 static HRESULT WINAPI OLEPictureImpl_Save(
2193 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2195 HRESULT hResult = E_NOTIMPL;
2196 void * pIconData;
2197 unsigned int iDataSize;
2198 ULONG dummy;
2199 int iSerializeResult = 0;
2200 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2202 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2204 switch (This->desc.picType) {
2205 case PICTYPE_ICON:
2206 if (This->bIsDirty || !This->data) {
2207 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2208 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2209 hResult = E_FAIL;
2210 break;
2212 HeapFree(GetProcessHeap(), 0, This->data);
2213 This->data = pIconData;
2214 This->datalen = iDataSize;
2216 if (This->loadtime_magic != 0xdeadbeef) {
2217 DWORD header[2];
2219 header[0] = This->loadtime_magic;
2220 header[1] = This->datalen;
2221 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2223 IStream_Write(pStm, This->data, This->datalen, &dummy);
2225 hResult = S_OK;
2226 break;
2227 case PICTYPE_BITMAP:
2228 if (This->bIsDirty) {
2229 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2230 case BITMAP_FORMAT_BMP:
2231 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2232 break;
2233 case BITMAP_FORMAT_JPEG:
2234 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2235 break;
2236 case BITMAP_FORMAT_GIF:
2237 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2238 break;
2239 case BITMAP_FORMAT_PNG:
2240 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2241 break;
2242 default:
2243 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2244 break;
2246 if (iSerializeResult) {
2248 if (This->loadtime_magic != 0xdeadbeef) {
2250 if (1) {
2251 DWORD header[2];
2253 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2254 header[1] = iDataSize;
2255 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2257 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2259 HeapFree(GetProcessHeap(), 0, This->data);
2260 This->data = pIconData;
2261 This->datalen = iDataSize;
2262 hResult = S_OK;
2264 } else {
2266 if (This->loadtime_magic != 0xdeadbeef) {
2268 if (1) {
2269 DWORD header[2];
2271 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2272 header[1] = This->datalen;
2273 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2275 IStream_Write(pStm, This->data, This->datalen, &dummy);
2276 hResult = S_OK;
2278 break;
2279 case PICTYPE_METAFILE:
2280 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2281 break;
2282 case PICTYPE_ENHMETAFILE:
2283 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2284 break;
2285 default:
2286 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2287 break;
2289 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2290 return hResult;
2293 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2294 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2296 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2297 FIXME("(%p,%p),stub!\n",This,pcbSize);
2298 return E_NOTIMPL;
2302 /************************************************************************
2303 * IDispatch
2306 /************************************************************************
2307 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2309 * See Windows documentation for more details on IUnknown methods.
2311 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2312 IDispatch* iface,
2313 REFIID riid,
2314 VOID** ppvoid)
2316 OLEPictureImpl *This = impl_from_IDispatch(iface);
2318 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2321 /************************************************************************
2322 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2324 * See Windows documentation for more details on IUnknown methods.
2326 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2327 IDispatch* iface)
2329 OLEPictureImpl *This = impl_from_IDispatch(iface);
2331 return IPicture_AddRef((IPicture *)This);
2334 /************************************************************************
2335 * OLEPictureImpl_IDispatch_Release (IUnknown)
2337 * See Windows documentation for more details on IUnknown methods.
2339 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2340 IDispatch* iface)
2342 OLEPictureImpl *This = impl_from_IDispatch(iface);
2344 return IPicture_Release((IPicture *)This);
2347 /************************************************************************
2348 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2350 * See Windows documentation for more details on IDispatch methods.
2352 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2353 IDispatch* iface,
2354 unsigned int* pctinfo)
2356 TRACE("(%p)\n", pctinfo);
2358 *pctinfo = 1;
2360 return S_OK;
2363 /************************************************************************
2364 * OLEPictureImpl_GetTypeInfo (IDispatch)
2366 * See Windows documentation for more details on IDispatch methods.
2368 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2369 IDispatch* iface,
2370 UINT iTInfo,
2371 LCID lcid,
2372 ITypeInfo** ppTInfo)
2374 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2375 ITypeLib *tl;
2376 HRESULT hres;
2378 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2380 if (iTInfo != 0)
2381 return E_FAIL;
2383 hres = LoadTypeLib(stdole2tlb, &tl);
2384 if (FAILED(hres))
2386 ERR("Could not load stdole2.tlb\n");
2387 return hres;
2390 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2391 if (FAILED(hres))
2392 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2394 return hres;
2397 /************************************************************************
2398 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2400 * See Windows documentation for more details on IDispatch methods.
2402 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2403 IDispatch* iface,
2404 REFIID riid,
2405 LPOLESTR* rgszNames,
2406 UINT cNames,
2407 LCID lcid,
2408 DISPID* rgDispId)
2410 ITypeInfo * pTInfo;
2411 HRESULT hres;
2413 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2414 rgszNames, cNames, (int)lcid, rgDispId);
2416 if (cNames == 0)
2418 return E_INVALIDARG;
2420 else
2422 /* retrieve type information */
2423 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2425 if (FAILED(hres))
2427 ERR("GetTypeInfo failed.\n");
2428 return hres;
2431 /* convert names to DISPIDs */
2432 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2433 ITypeInfo_Release(pTInfo);
2435 return hres;
2439 /************************************************************************
2440 * OLEPictureImpl_Invoke (IDispatch)
2442 * See Windows documentation for more details on IDispatch methods.
2444 static HRESULT WINAPI OLEPictureImpl_Invoke(
2445 IDispatch* iface,
2446 DISPID dispIdMember,
2447 REFIID riid,
2448 LCID lcid,
2449 WORD wFlags,
2450 DISPPARAMS* pDispParams,
2451 VARIANT* pVarResult,
2452 EXCEPINFO* pExepInfo,
2453 UINT* puArgErr)
2455 OLEPictureImpl *This = impl_from_IDispatch(iface);
2457 /* validate parameters */
2459 if (!IsEqualIID(riid, &IID_NULL))
2461 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2462 return DISP_E_UNKNOWNNAME;
2465 if (!pDispParams)
2467 ERR("null pDispParams not allowed\n");
2468 return DISP_E_PARAMNOTOPTIONAL;
2471 if (wFlags & DISPATCH_PROPERTYGET)
2473 if (pDispParams->cArgs != 0)
2475 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2476 return DISP_E_BADPARAMCOUNT;
2478 if (!pVarResult)
2480 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2481 return DISP_E_PARAMNOTOPTIONAL;
2484 else if (wFlags & DISPATCH_PROPERTYPUT)
2486 if (pDispParams->cArgs != 1)
2488 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2489 return DISP_E_BADPARAMCOUNT;
2493 switch (dispIdMember)
2495 case DISPID_PICT_HANDLE:
2496 if (wFlags & DISPATCH_PROPERTYGET)
2498 TRACE("DISPID_PICT_HANDLE\n");
2499 V_VT(pVarResult) = VT_I4;
2500 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2502 break;
2503 case DISPID_PICT_HPAL:
2504 if (wFlags & DISPATCH_PROPERTYGET)
2506 TRACE("DISPID_PICT_HPAL\n");
2507 V_VT(pVarResult) = VT_I4;
2508 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2510 else if (wFlags & DISPATCH_PROPERTYPUT)
2512 VARIANTARG vararg;
2513 HRESULT hr;
2514 TRACE("DISPID_PICT_HPAL\n");
2516 VariantInit(&vararg);
2517 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2518 if (FAILED(hr))
2519 return hr;
2521 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2523 VariantClear(&vararg);
2524 return hr;
2526 break;
2527 case DISPID_PICT_TYPE:
2528 if (wFlags & DISPATCH_PROPERTYGET)
2530 TRACE("DISPID_PICT_TYPE\n");
2531 V_VT(pVarResult) = VT_I2;
2532 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2534 break;
2535 case DISPID_PICT_WIDTH:
2536 if (wFlags & DISPATCH_PROPERTYGET)
2538 TRACE("DISPID_PICT_WIDTH\n");
2539 V_VT(pVarResult) = VT_I4;
2540 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2542 break;
2543 case DISPID_PICT_HEIGHT:
2544 if (wFlags & DISPATCH_PROPERTYGET)
2546 TRACE("DISPID_PICT_HEIGHT\n");
2547 V_VT(pVarResult) = VT_I4;
2548 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2550 break;
2553 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2554 return DISP_E_MEMBERNOTFOUND;
2558 static const IPictureVtbl OLEPictureImpl_VTable =
2560 OLEPictureImpl_QueryInterface,
2561 OLEPictureImpl_AddRef,
2562 OLEPictureImpl_Release,
2563 OLEPictureImpl_get_Handle,
2564 OLEPictureImpl_get_hPal,
2565 OLEPictureImpl_get_Type,
2566 OLEPictureImpl_get_Width,
2567 OLEPictureImpl_get_Height,
2568 OLEPictureImpl_Render,
2569 OLEPictureImpl_set_hPal,
2570 OLEPictureImpl_get_CurDC,
2571 OLEPictureImpl_SelectPicture,
2572 OLEPictureImpl_get_KeepOriginalFormat,
2573 OLEPictureImpl_put_KeepOriginalFormat,
2574 OLEPictureImpl_PictureChanged,
2575 OLEPictureImpl_SaveAsFile,
2576 OLEPictureImpl_get_Attributes
2579 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2581 OLEPictureImpl_IDispatch_QueryInterface,
2582 OLEPictureImpl_IDispatch_AddRef,
2583 OLEPictureImpl_IDispatch_Release,
2584 OLEPictureImpl_GetTypeInfoCount,
2585 OLEPictureImpl_GetTypeInfo,
2586 OLEPictureImpl_GetIDsOfNames,
2587 OLEPictureImpl_Invoke
2590 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2592 OLEPictureImpl_IPersistStream_QueryInterface,
2593 OLEPictureImpl_IPersistStream_AddRef,
2594 OLEPictureImpl_IPersistStream_Release,
2595 OLEPictureImpl_GetClassID,
2596 OLEPictureImpl_IsDirty,
2597 OLEPictureImpl_Load,
2598 OLEPictureImpl_Save,
2599 OLEPictureImpl_GetSizeMax
2602 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2604 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2605 OLEPictureImpl_IConnectionPointContainer_AddRef,
2606 OLEPictureImpl_IConnectionPointContainer_Release,
2607 OLEPictureImpl_EnumConnectionPoints,
2608 OLEPictureImpl_FindConnectionPoint
2611 /***********************************************************************
2612 * OleCreatePictureIndirect (OLEAUT32.419)
2614 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2615 BOOL fOwn, LPVOID *ppvObj )
2617 OLEPictureImpl* newPict = NULL;
2618 HRESULT hr = S_OK;
2620 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2623 * Sanity check
2625 if (ppvObj==0)
2626 return E_POINTER;
2628 *ppvObj = NULL;
2631 * Try to construct a new instance of the class.
2633 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2635 if (newPict == NULL)
2636 return E_OUTOFMEMORY;
2639 * Make sure it supports the interface required by the caller.
2641 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2644 * Release the reference obtained in the constructor. If
2645 * the QueryInterface was unsuccessful, it will free the class.
2647 IPicture_Release((IPicture*)newPict);
2649 return hr;
2653 /***********************************************************************
2654 * OleLoadPicture (OLEAUT32.418)
2656 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2657 REFIID riid, LPVOID *ppvObj )
2659 LPPERSISTSTREAM ps;
2660 IPicture *newpic;
2661 HRESULT hr;
2663 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2664 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2666 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2667 if (hr)
2668 return hr;
2669 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2670 if (hr) {
2671 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2672 IPicture_Release(newpic);
2673 *ppvObj = NULL;
2674 return hr;
2676 hr = IPersistStream_Load(ps,lpstream);
2677 IPersistStream_Release(ps);
2678 if (FAILED(hr))
2680 ERR("IPersistStream_Load failed\n");
2681 IPicture_Release(newpic);
2682 *ppvObj = NULL;
2683 return hr;
2685 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2686 if (hr)
2687 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2688 IPicture_Release(newpic);
2689 return hr;
2692 /***********************************************************************
2693 * OleLoadPictureEx (OLEAUT32.401)
2695 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2696 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2698 LPPERSISTSTREAM ps;
2699 IPicture *newpic;
2700 HRESULT hr;
2702 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2703 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2705 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2706 if (hr)
2707 return hr;
2708 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2709 if (hr) {
2710 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2711 IPicture_Release(newpic);
2712 *ppvObj = NULL;
2713 return hr;
2715 hr = IPersistStream_Load(ps,lpstream);
2716 IPersistStream_Release(ps);
2717 if (FAILED(hr))
2719 ERR("IPersistStream_Load failed\n");
2720 IPicture_Release(newpic);
2721 *ppvObj = NULL;
2722 return hr;
2724 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2725 if (hr)
2726 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2727 IPicture_Release(newpic);
2728 return hr;
2731 /***********************************************************************
2732 * OleLoadPicturePath (OLEAUT32.424)
2734 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2735 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2736 LPVOID *ppvRet )
2738 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2739 IPicture *ipicture;
2740 HANDLE hFile;
2741 DWORD dwFileSize;
2742 HGLOBAL hGlobal = NULL;
2743 DWORD dwBytesRead = 0;
2744 IStream *stream;
2745 BOOL bRead;
2746 IPersistStream *pStream;
2747 HRESULT hRes;
2749 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2750 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2751 debugstr_guid(riid), ppvRet);
2753 if (!ppvRet) return E_POINTER;
2755 if (strncmpW(szURLorPath, file, 7) == 0) {
2756 szURLorPath += 7;
2758 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2759 0, NULL);
2760 if (hFile == INVALID_HANDLE_VALUE)
2761 return E_UNEXPECTED;
2763 dwFileSize = GetFileSize(hFile, NULL);
2764 if (dwFileSize != INVALID_FILE_SIZE )
2766 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2767 if ( hGlobal)
2769 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2770 if (!bRead)
2772 GlobalFree(hGlobal);
2773 hGlobal = 0;
2777 CloseHandle(hFile);
2779 if (!hGlobal)
2780 return E_UNEXPECTED;
2782 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2783 if (FAILED(hRes))
2785 GlobalFree(hGlobal);
2786 return hRes;
2788 } else {
2789 IMoniker *pmnk;
2790 IBindCtx *pbc;
2792 hRes = CreateBindCtx(0, &pbc);
2793 if (SUCCEEDED(hRes))
2795 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2796 if (SUCCEEDED(hRes))
2798 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2799 IMoniker_Release(pmnk);
2801 IBindCtx_Release(pbc);
2803 if (FAILED(hRes))
2804 return hRes;
2807 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2808 &IID_IPicture, (LPVOID*)&ipicture);
2809 if (hRes != S_OK) {
2810 IStream_Release(stream);
2811 return hRes;
2814 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2815 if (hRes) {
2816 IStream_Release(stream);
2817 IPicture_Release(ipicture);
2818 return hRes;
2821 hRes = IPersistStream_Load(pStream, stream);
2822 IPersistStream_Release(pStream);
2823 IStream_Release(stream);
2825 if (hRes) {
2826 IPicture_Release(ipicture);
2827 return hRes;
2830 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2831 if (hRes)
2832 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2834 IPicture_Release(ipicture);
2835 return hRes;
2838 /*******************************************************************************
2839 * StdPic ClassFactory
2841 typedef struct
2843 /* IUnknown fields */
2844 const IClassFactoryVtbl *lpVtbl;
2845 LONG ref;
2846 } IClassFactoryImpl;
2848 static HRESULT WINAPI
2849 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2850 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2852 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2853 return E_NOINTERFACE;
2856 static ULONG WINAPI
2857 SPCF_AddRef(LPCLASSFACTORY iface) {
2858 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2859 return InterlockedIncrement(&This->ref);
2862 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2863 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2864 /* static class, won't be freed */
2865 return InterlockedDecrement(&This->ref);
2868 static HRESULT WINAPI SPCF_CreateInstance(
2869 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2871 /* Creates an uninitialized picture */
2872 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2876 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2877 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2878 FIXME("(%p)->(%d),stub!\n",This,dolock);
2879 return S_OK;
2882 static const IClassFactoryVtbl SPCF_Vtbl = {
2883 SPCF_QueryInterface,
2884 SPCF_AddRef,
2885 SPCF_Release,
2886 SPCF_CreateInstance,
2887 SPCF_LockServer
2889 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2891 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }