include: Add types to objidl.idl used by COM contexts.
[wine/testsucceed.git] / dlls / oleaut32 / olepicture.c
blob180d4d3a471701dd0b571b60ef43c760cee75f5d
1 /*
2 * OLE Picture object
4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * BUGS
25 * Support PICTYPE_BITMAP and PICTYPE_ICON, altough only bitmaps very well..
26 * Lots of methods are just stubs.
29 * NOTES (or things that msdn doesn't tell you)
31 * The width and height properties are returned in HIMETRIC units (0.01mm)
32 * IPicture::Render also uses these to select a region of the src picture.
33 * A bitmap's size is converted into these units by using the screen resolution
34 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
38 #include "config.h"
39 #include "wine/port.h"
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <string.h>
48 /* Must be before wine includes, the header has things conflicting with
49 * WINE headers.
51 #define COBJMACROS
52 #define NONAMELESSUNION
53 #define NONAMELESSSTRUCT
55 #include "winerror.h"
56 #include "windef.h"
57 #include "winbase.h"
58 #include "wingdi.h"
59 #include "winuser.h"
60 #include "ole2.h"
61 #include "olectl.h"
62 #include "oleauto.h"
63 #include "connpt.h"
64 #include "urlmon.h"
65 #include "wine/debug.h"
66 #include "wine/unicode.h"
68 #include "wine/wingdi16.h"
70 #ifdef HAVE_JPEGLIB_H
71 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
72 #define XMD_H
73 #define UINT8 JPEG_UINT8
74 #define UINT16 JPEG_UINT16
75 #undef FAR
76 #define boolean jpeg_boolean
77 # include <jpeglib.h>
78 #undef jpeg_boolean
79 #undef UINT16
80 #ifndef SONAME_LIBJPEG
81 #define SONAME_LIBJPEG "libjpeg.so"
82 #endif
83 #endif
85 #include "ungif.h"
87 WINE_DEFAULT_DEBUG_CHANNEL(ole);
89 #include "pshpack1.h"
91 typedef struct {
92 BYTE bWidth;
93 BYTE bHeight;
94 BYTE bColorCount;
95 BYTE bReserved;
96 WORD xHotspot;
97 WORD yHotspot;
98 DWORD dwDIBSize;
99 DWORD dwDIBOffset;
100 } CURSORICONFILEDIRENTRY;
102 typedef struct
104 WORD idReserved;
105 WORD idType;
106 WORD idCount;
107 CURSORICONFILEDIRENTRY idEntries[1];
108 } CURSORICONFILEDIR;
110 #include "poppack.h"
112 /*************************************************************************
113 * Declaration of implementation class
116 typedef struct OLEPictureImpl {
119 * IPicture handles IUnknown
122 const IPictureVtbl *lpVtbl;
123 const IDispatchVtbl *lpvtblIDispatch;
124 const IPersistStreamVtbl *lpvtblIPersistStream;
125 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
127 /* Object reference count */
128 LONG ref;
130 /* We own the object and must destroy it ourselves */
131 BOOL fOwn;
133 /* Picture description */
134 PICTDESC desc;
136 /* These are the pixel size of a bitmap */
137 DWORD origWidth;
138 DWORD origHeight;
140 /* And these are the size of the picture converted into HIMETRIC units */
141 OLE_XSIZE_HIMETRIC himetricWidth;
142 OLE_YSIZE_HIMETRIC himetricHeight;
144 IConnectionPoint *pCP;
146 BOOL keepOrigFormat;
147 HDC hDCCur;
149 /* Bitmap transparency mask */
150 HBITMAP hbmMask;
151 HBITMAP hbmXor;
152 COLORREF rgbTrans;
154 /* data */
155 void* data;
156 int datalen;
157 BOOL bIsDirty; /* Set to TRUE if picture has changed */
158 unsigned int loadtime_magic; /* If a length header was found, saves value */
159 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
160 } OLEPictureImpl;
163 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
166 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
168 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
171 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
173 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
176 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
178 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
182 * Predeclare VTables. They get initialized at the end.
184 static const IPictureVtbl OLEPictureImpl_VTable;
185 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
186 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
187 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
189 /***********************************************************************
190 * Implementation of the OLEPictureImpl class.
193 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
194 BITMAP bm;
195 HDC hdcRef;
197 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
198 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
199 ERR("GetObject fails\n");
200 return;
202 This->origWidth = bm.bmWidth;
203 This->origHeight = bm.bmHeight;
204 /* The width and height are stored in HIMETRIC units (0.01 mm),
205 so we take our pixel width divide by pixels per inch and
206 multiply by 25.4 * 100 */
207 /* Should we use GetBitmapDimension if available? */
208 hdcRef = CreateCompatibleDC(0);
209 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
210 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
211 DeleteDC(hdcRef);
214 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
216 ICONINFO infoIcon;
218 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
219 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
220 HDC hdcRef;
221 BITMAP bm;
223 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
224 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
225 ERR("GetObject fails on icon bitmap\n");
226 return;
229 This->origWidth = bm.bmWidth;
230 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
231 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
232 hdcRef = GetDC(0);
233 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
234 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
235 ReleaseDC(0, hdcRef);
237 DeleteObject(infoIcon.hbmMask);
238 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
239 } else {
240 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
244 /************************************************************************
245 * OLEPictureImpl_Construct
247 * This method will construct a new instance of the OLEPictureImpl
248 * class.
250 * The caller of this method must release the object when it's
251 * done with it.
253 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
255 OLEPictureImpl* newObject = 0;
257 if (pictDesc)
258 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
261 * Allocate space for the object.
263 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
265 if (newObject==0)
266 return newObject;
269 * Initialize the virtual function table.
271 newObject->lpVtbl = &OLEPictureImpl_VTable;
272 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
273 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
274 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
276 newObject->pCP = NULL;
277 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
278 if (!newObject->pCP)
280 HeapFree(GetProcessHeap(), 0, newObject);
281 return NULL;
285 * Start with one reference count. The caller of this function
286 * must release the interface pointer when it is done.
288 newObject->ref = 1;
289 newObject->hDCCur = 0;
291 newObject->fOwn = fOwn;
293 /* dunno about original value */
294 newObject->keepOrigFormat = TRUE;
296 newObject->hbmMask = NULL;
297 newObject->hbmXor = NULL;
298 newObject->loadtime_magic = 0xdeadbeef;
299 newObject->loadtime_format = 0;
300 newObject->bIsDirty = FALSE;
302 if (pictDesc) {
303 memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC));
305 switch(pictDesc->picType) {
306 case PICTYPE_BITMAP:
307 OLEPictureImpl_SetBitmap(newObject);
308 break;
310 case PICTYPE_METAFILE:
311 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
312 newObject->himetricWidth = pictDesc->u.wmf.xExt;
313 newObject->himetricHeight = pictDesc->u.wmf.yExt;
314 break;
316 case PICTYPE_NONE:
317 /* not sure what to do here */
318 newObject->himetricWidth = newObject->himetricHeight = 0;
319 break;
321 case PICTYPE_ICON:
322 OLEPictureImpl_SetIcon(newObject);
323 break;
324 case PICTYPE_ENHMETAFILE:
325 default:
326 FIXME("Unsupported type %d\n", pictDesc->picType);
327 newObject->himetricWidth = newObject->himetricHeight = 0;
328 break;
330 } else {
331 newObject->desc.picType = PICTYPE_UNINITIALIZED;
334 TRACE("returning %p\n", newObject);
335 return newObject;
338 /************************************************************************
339 * OLEPictureImpl_Destroy
341 * This method is called by the Release method when the reference
342 * count goes down to 0. It will free all resources used by
343 * this object. */
344 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
346 TRACE("(%p)\n", Obj);
348 if (Obj->pCP)
349 IConnectionPoint_Release(Obj->pCP);
351 if(Obj->fOwn) { /* We need to destroy the picture */
352 switch(Obj->desc.picType) {
353 case PICTYPE_BITMAP:
354 DeleteObject(Obj->desc.u.bmp.hbitmap);
355 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
356 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
357 break;
358 case PICTYPE_METAFILE:
359 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
360 break;
361 case PICTYPE_ICON:
362 DestroyIcon(Obj->desc.u.icon.hicon);
363 break;
364 case PICTYPE_ENHMETAFILE:
365 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
366 break;
367 case PICTYPE_NONE:
368 /* Nothing to do */
369 break;
370 default:
371 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
372 break;
375 HeapFree(GetProcessHeap(), 0, Obj->data);
376 HeapFree(GetProcessHeap(), 0, Obj);
380 /************************************************************************
381 * OLEPictureImpl_AddRef (IUnknown)
383 * See Windows documentation for more details on IUnknown methods.
385 static ULONG WINAPI OLEPictureImpl_AddRef(
386 IPicture* iface)
388 OLEPictureImpl *This = (OLEPictureImpl *)iface;
389 ULONG refCount = InterlockedIncrement(&This->ref);
391 TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1);
393 return refCount;
396 /************************************************************************
397 * OLEPictureImpl_Release (IUnknown)
399 * See Windows documentation for more details on IUnknown methods.
401 static ULONG WINAPI OLEPictureImpl_Release(
402 IPicture* iface)
404 OLEPictureImpl *This = (OLEPictureImpl *)iface;
405 ULONG refCount = InterlockedDecrement(&This->ref);
407 TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1);
410 * If the reference count goes down to 0, perform suicide.
412 if (!refCount) OLEPictureImpl_Destroy(This);
414 return refCount;
417 /************************************************************************
418 * OLEPictureImpl_QueryInterface (IUnknown)
420 * See Windows documentation for more details on IUnknown methods.
422 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
423 IPicture* iface,
424 REFIID riid,
425 void** ppvObject)
427 OLEPictureImpl *This = (OLEPictureImpl *)iface;
428 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
431 * Perform a sanity check on the parameters.
433 if ( (This==0) || (ppvObject==0) )
434 return E_INVALIDARG;
437 * Initialize the return parameter.
439 *ppvObject = 0;
442 * Compare the riid with the interface IDs implemented by this object.
444 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
445 *ppvObject = (IPicture*)This;
446 else if (IsEqualIID(&IID_IDispatch, riid))
447 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
448 else if (IsEqualIID(&IID_IPictureDisp, riid))
449 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
450 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
451 *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
452 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
453 *ppvObject = (IConnectionPointContainer*)&(This->lpvtblIConnectionPointContainer);
456 * Check that we obtained an interface.
458 if ((*ppvObject)==0)
460 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
461 return E_NOINTERFACE;
465 * Query Interface always increases the reference count by one when it is
466 * successful
468 OLEPictureImpl_AddRef((IPicture*)This);
470 return S_OK;
473 /***********************************************************************
474 * OLEPicture_SendNotify (internal)
476 * Sends notification messages of changed properties to any interested
477 * connections.
479 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
481 IEnumConnections *pEnum;
482 CONNECTDATA CD;
484 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
485 return;
486 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
487 IPropertyNotifySink *sink;
489 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
490 IPropertyNotifySink_OnChanged(sink, dispID);
491 IPropertyNotifySink_Release(sink);
492 IUnknown_Release(CD.pUnk);
494 IEnumConnections_Release(pEnum);
495 return;
498 /************************************************************************
499 * OLEPictureImpl_get_Handle
501 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
502 OLE_HANDLE *phandle)
504 OLEPictureImpl *This = (OLEPictureImpl *)iface;
505 TRACE("(%p)->(%p)\n", This, phandle);
506 switch(This->desc.picType) {
507 case PICTYPE_NONE:
508 *phandle = 0;
509 break;
510 case PICTYPE_BITMAP:
511 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
512 break;
513 case PICTYPE_METAFILE:
514 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
515 break;
516 case PICTYPE_ICON:
517 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
518 break;
519 case PICTYPE_ENHMETAFILE:
520 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
521 break;
522 default:
523 FIXME("Unimplemented type %d\n", This->desc.picType);
524 return E_NOTIMPL;
526 TRACE("returning handle %08x\n", *phandle);
527 return S_OK;
530 /************************************************************************
531 * OLEPictureImpl_get_hPal
533 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
534 OLE_HANDLE *phandle)
536 OLEPictureImpl *This = (OLEPictureImpl *)iface;
537 HRESULT hres;
538 TRACE("(%p)->(%p)\n", This, phandle);
540 if (!phandle)
541 return E_POINTER;
543 switch (This->desc.picType) {
544 case PICTYPE_UNINITIALIZED:
545 case PICTYPE_NONE:
546 *phandle = 0;
547 hres = S_FALSE;
548 break;
549 case PICTYPE_BITMAP:
550 *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
551 hres = S_OK;
552 break;
553 case PICTYPE_ICON:
554 case PICTYPE_METAFILE:
555 case PICTYPE_ENHMETAFILE:
556 default:
557 FIXME("unimplemented for type %d. Returning 0 palette.\n",
558 This->desc.picType);
559 *phandle = 0;
560 hres = S_OK;
563 TRACE("returning 0x%08lx, palette handle %08x\n", hres, *phandle);
564 return hres;
567 /************************************************************************
568 * OLEPictureImpl_get_Type
570 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
571 short *ptype)
573 OLEPictureImpl *This = (OLEPictureImpl *)iface;
574 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
575 *ptype = This->desc.picType;
576 return S_OK;
579 /************************************************************************
580 * OLEPictureImpl_get_Width
582 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
583 OLE_XSIZE_HIMETRIC *pwidth)
585 OLEPictureImpl *This = (OLEPictureImpl *)iface;
586 TRACE("(%p)->(%p): width is %ld\n", This, pwidth, This->himetricWidth);
587 *pwidth = This->himetricWidth;
588 return S_OK;
591 /************************************************************************
592 * OLEPictureImpl_get_Height
594 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
595 OLE_YSIZE_HIMETRIC *pheight)
597 OLEPictureImpl *This = (OLEPictureImpl *)iface;
598 TRACE("(%p)->(%p): height is %ld\n", This, pheight, This->himetricHeight);
599 *pheight = This->himetricHeight;
600 return S_OK;
603 /************************************************************************
604 * OLEPictureImpl_Render
606 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
607 LONG x, LONG y, LONG cx, LONG cy,
608 OLE_XPOS_HIMETRIC xSrc,
609 OLE_YPOS_HIMETRIC ySrc,
610 OLE_XSIZE_HIMETRIC cxSrc,
611 OLE_YSIZE_HIMETRIC cySrc,
612 LPCRECT prcWBounds)
614 OLEPictureImpl *This = (OLEPictureImpl *)iface;
615 TRACE("(%p)->(%p, (%ld,%ld), (%ld,%ld) <- (%ld,%ld), (%ld,%ld), %p)\n",
616 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
617 if(prcWBounds)
618 TRACE("prcWBounds (%ld,%ld) - (%ld,%ld)\n", prcWBounds->left, prcWBounds->top,
619 prcWBounds->right, prcWBounds->bottom);
622 * While the documentation suggests this to be here (or after rendering?)
623 * it does cause an endless recursion in my sample app. -MM 20010804
624 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
627 switch(This->desc.picType) {
628 case PICTYPE_BITMAP:
630 HBITMAP hbmpOld;
631 HDC hdcBmp;
633 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
634 NB y-axis gets flipped */
636 hdcBmp = CreateCompatibleDC(0);
637 SetMapMode(hdcBmp, MM_ANISOTROPIC);
638 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
639 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
640 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
641 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
643 if (This->hbmMask) {
644 HDC hdcMask = CreateCompatibleDC(0);
645 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
647 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
649 SetMapMode(hdcMask, MM_ANISOTROPIC);
650 SetWindowOrgEx(hdcMask, 0, 0, NULL);
651 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
652 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
653 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
655 SetBkColor(hdc, RGB(255, 255, 255));
656 SetTextColor(hdc, RGB(0, 0, 0));
657 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
658 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
660 SelectObject(hdcMask, hOldbm);
661 DeleteDC(hdcMask);
662 } else {
663 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
664 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
667 SelectObject(hdcBmp, hbmpOld);
668 DeleteDC(hdcBmp);
670 break;
671 case PICTYPE_ICON:
672 FIXME("Not quite correct implementation of rendering icons...\n");
673 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
674 break;
676 case PICTYPE_METAFILE:
677 case PICTYPE_ENHMETAFILE:
678 default:
679 FIXME("type %d not implemented\n", This->desc.picType);
680 return E_NOTIMPL;
682 return S_OK;
685 /************************************************************************
686 * OLEPictureImpl_set_hPal
688 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
689 OLE_HANDLE hpal)
691 OLEPictureImpl *This = (OLEPictureImpl *)iface;
692 FIXME("(%p)->(%08x): stub\n", This, hpal);
693 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
694 return E_NOTIMPL;
697 /************************************************************************
698 * OLEPictureImpl_get_CurDC
700 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
701 HDC *phdc)
703 OLEPictureImpl *This = (OLEPictureImpl *)iface;
704 TRACE("(%p), returning %p\n", This, This->hDCCur);
705 if (phdc) *phdc = This->hDCCur;
706 return S_OK;
709 /************************************************************************
710 * OLEPictureImpl_SelectPicture
712 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
713 HDC hdcIn,
714 HDC *phdcOut,
715 OLE_HANDLE *phbmpOut)
717 OLEPictureImpl *This = (OLEPictureImpl *)iface;
718 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
719 if (This->desc.picType == PICTYPE_BITMAP) {
720 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
722 if (phdcOut)
723 *phdcOut = This->hDCCur;
724 This->hDCCur = hdcIn;
725 if (phbmpOut)
726 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
727 return S_OK;
728 } else {
729 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
730 return E_FAIL;
734 /************************************************************************
735 * OLEPictureImpl_get_KeepOriginalFormat
737 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
738 BOOL *pfKeep)
740 OLEPictureImpl *This = (OLEPictureImpl *)iface;
741 TRACE("(%p)->(%p)\n", This, pfKeep);
742 if (!pfKeep)
743 return E_POINTER;
744 *pfKeep = This->keepOrigFormat;
745 return S_OK;
748 /************************************************************************
749 * OLEPictureImpl_put_KeepOriginalFormat
751 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
752 BOOL keep)
754 OLEPictureImpl *This = (OLEPictureImpl *)iface;
755 TRACE("(%p)->(%d)\n", This, keep);
756 This->keepOrigFormat = keep;
757 /* FIXME: what DISPID notification here? */
758 return S_OK;
761 /************************************************************************
762 * OLEPictureImpl_PictureChanged
764 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
766 OLEPictureImpl *This = (OLEPictureImpl *)iface;
767 TRACE("(%p)->()\n", This);
768 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
769 This->bIsDirty = TRUE;
770 return S_OK;
773 /************************************************************************
774 * OLEPictureImpl_SaveAsFile
776 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
777 IStream *pstream,
778 BOOL SaveMemCopy,
779 LONG *pcbSize)
781 OLEPictureImpl *This = (OLEPictureImpl *)iface;
782 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
783 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
786 /************************************************************************
787 * OLEPictureImpl_get_Attributes
789 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
790 DWORD *pdwAttr)
792 OLEPictureImpl *This = (OLEPictureImpl *)iface;
793 TRACE("(%p)->(%p).\n", This, pdwAttr);
794 *pdwAttr = 0;
795 switch (This->desc.picType) {
796 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
797 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
798 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
799 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
801 return S_OK;
805 /************************************************************************
806 * IConnectionPointContainer
808 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
809 IConnectionPointContainer* iface,
810 REFIID riid,
811 VOID** ppvoid)
813 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
815 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
818 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
819 IConnectionPointContainer* iface)
821 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
823 return IPicture_AddRef((IPicture *)This);
826 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
827 IConnectionPointContainer* iface)
829 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
831 return IPicture_Release((IPicture *)This);
834 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
835 IConnectionPointContainer* iface,
836 IEnumConnectionPoints** ppEnum)
838 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
840 FIXME("(%p,%p), stub!\n",This,ppEnum);
841 return E_NOTIMPL;
844 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
845 IConnectionPointContainer* iface,
846 REFIID riid,
847 IConnectionPoint **ppCP)
849 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
850 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
851 if (!ppCP)
852 return E_POINTER;
853 *ppCP = NULL;
854 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
855 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
856 FIXME("no connection point for %s\n",debugstr_guid(riid));
857 return CONNECT_E_NOCONNECTION;
861 /************************************************************************
862 * IPersistStream
865 /************************************************************************
866 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
868 * See Windows documentation for more details on IUnknown methods.
870 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
871 IPersistStream* iface,
872 REFIID riid,
873 VOID** ppvoid)
875 OLEPictureImpl *This = impl_from_IPersistStream(iface);
877 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
880 /************************************************************************
881 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
883 * See Windows documentation for more details on IUnknown methods.
885 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
886 IPersistStream* iface)
888 OLEPictureImpl *This = impl_from_IPersistStream(iface);
890 return IPicture_AddRef((IPicture *)This);
893 /************************************************************************
894 * OLEPictureImpl_IPersistStream_Release (IUnknown)
896 * See Windows documentation for more details on IUnknown methods.
898 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
899 IPersistStream* iface)
901 OLEPictureImpl *This = impl_from_IPersistStream(iface);
903 return IPicture_Release((IPicture *)This);
906 /************************************************************************
907 * OLEPictureImpl_IPersistStream_GetClassID
909 static HRESULT WINAPI OLEPictureImpl_GetClassID(
910 IPersistStream* iface,CLSID* pClassID)
912 TRACE("(%p)\n", pClassID);
913 memcpy(pClassID, &CLSID_StdPicture, sizeof(*pClassID));
914 return S_OK;
917 /************************************************************************
918 * OLEPictureImpl_IPersistStream_IsDirty
920 static HRESULT WINAPI OLEPictureImpl_IsDirty(
921 IPersistStream* iface)
923 OLEPictureImpl *This = impl_from_IPersistStream(iface);
924 FIXME("(%p),stub!\n",This);
925 return E_NOTIMPL;
928 #ifdef HAVE_JPEGLIB_H
930 static void *libjpeg_handle;
931 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
932 MAKE_FUNCPTR(jpeg_std_error);
933 MAKE_FUNCPTR(jpeg_CreateDecompress);
934 MAKE_FUNCPTR(jpeg_read_header);
935 MAKE_FUNCPTR(jpeg_start_decompress);
936 MAKE_FUNCPTR(jpeg_read_scanlines);
937 MAKE_FUNCPTR(jpeg_finish_decompress);
938 MAKE_FUNCPTR(jpeg_destroy_decompress);
939 #undef MAKE_FUNCPTR
941 static void *load_libjpeg(void)
943 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
945 #define LOAD_FUNCPTR(f) \
946 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
947 libjpeg_handle = NULL; \
948 return NULL; \
951 LOAD_FUNCPTR(jpeg_std_error);
952 LOAD_FUNCPTR(jpeg_CreateDecompress);
953 LOAD_FUNCPTR(jpeg_read_header);
954 LOAD_FUNCPTR(jpeg_start_decompress);
955 LOAD_FUNCPTR(jpeg_read_scanlines);
956 LOAD_FUNCPTR(jpeg_finish_decompress);
957 LOAD_FUNCPTR(jpeg_destroy_decompress);
958 #undef LOAD_FUNCPTR
960 return libjpeg_handle;
963 /* for the jpeg decompressor source manager. */
964 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
966 static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
967 ERR("(), should not get here.\n");
968 return FALSE;
971 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
972 TRACE("Skipping %ld bytes...\n", num_bytes);
973 cinfo->src->next_input_byte += num_bytes;
974 cinfo->src->bytes_in_buffer -= num_bytes;
977 static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
978 ERR("(desired=%d), should not get here.\n",desired);
979 return FALSE;
981 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
982 #endif /* HAVE_JPEGLIB_H */
984 struct gifdata {
985 unsigned char *data;
986 unsigned int curoff;
987 unsigned int len;
990 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
991 struct gifdata *gd = (struct gifdata*)gif->UserData;
993 if (len+gd->curoff > gd->len) {
994 FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
995 len = gd->len - gd->curoff;
997 memcpy(data, gd->data+gd->curoff, len);
998 gd->curoff += len;
999 return len;
1003 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1005 struct gifdata gd;
1006 GifFileType *gif;
1007 BITMAPINFO *bmi;
1008 HDC hdcref;
1009 LPBYTE bytes;
1010 int i,j,ret;
1011 GifImageDesc *gid;
1012 SavedImage *si;
1013 ColorMapObject *cm;
1014 int transparent = -1;
1015 ExtensionBlock *eb;
1016 int padding;
1018 gd.data = xbuf;
1019 gd.curoff = 0;
1020 gd.len = xread;
1021 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1022 ret = DGifSlurp(gif);
1023 if (ret == GIF_ERROR) {
1024 FIXME("Failed reading GIF using libgif.\n");
1025 return E_FAIL;
1027 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1028 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1029 TRACE("imgcnt %d\n", gif->ImageCount);
1030 if (gif->ImageCount<1) {
1031 FIXME("GIF stream does not have images inside?\n");
1032 return E_FAIL;
1034 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1035 gif->Image.Width, gif->Image.Height,
1036 gif->Image.Left, gif->Image.Top,
1037 gif->Image.Interlace
1039 /* */
1040 padding = (gif->SWidth+3) & ~3;
1041 si = gif->SavedImages+0;
1042 gid = &(si->ImageDesc);
1043 cm = gid->ColorMap;
1044 if (!cm) cm = gif->SColorMap;
1045 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1046 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1048 /* look for the transparent color extension */
1049 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1050 eb = si->ExtensionBlocks + i;
1051 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1052 if ((eb->Bytes[0] & 1) == 1) {
1053 transparent = (unsigned char)eb->Bytes[3];
1058 for (i = 0; i < cm->ColorCount; i++) {
1059 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1060 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1061 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1062 if (i == transparent) {
1063 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1064 bmi->bmiColors[i].rgbGreen,
1065 bmi->bmiColors[i].rgbBlue);
1069 /* Map to in picture coordinates */
1070 for (i = 0, j = 0; i < gid->Height; i++) {
1071 if (gif->Image.Interlace) {
1072 memcpy(
1073 bytes + (gid->Top + j) * padding + gid->Left,
1074 si->RasterBits + i * gid->Width,
1075 gid->Width);
1077 /* Lower bits of interlaced counter encode current interlace */
1078 if (j & 1) j += 2; /* Currently filling odd rows */
1079 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1080 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1082 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1083 /* End of current interlace, go to next interlace */
1084 if (j & 2) j = 1; /* Next iteration fills odd rows */
1085 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1086 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1088 } else {
1089 memcpy(
1090 bytes + (gid->Top + i) * padding + gid->Left,
1091 si->RasterBits + i * gid->Width,
1092 gid->Width);
1096 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1097 bmi->bmiHeader.biWidth = gif->SWidth;
1098 bmi->bmiHeader.biHeight = -gif->SHeight;
1099 bmi->bmiHeader.biPlanes = 1;
1100 bmi->bmiHeader.biBitCount = 8;
1101 bmi->bmiHeader.biCompression = BI_RGB;
1102 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1103 bmi->bmiHeader.biXPelsPerMeter = 0;
1104 bmi->bmiHeader.biYPelsPerMeter = 0;
1105 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1106 bmi->bmiHeader.biClrImportant = 0;
1108 hdcref = GetDC(0);
1109 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1110 hdcref,
1111 &bmi->bmiHeader,
1112 CBM_INIT,
1113 bytes,
1114 bmi,
1115 DIB_RGB_COLORS
1118 if (transparent > -1) {
1119 /* Create the Mask */
1120 HDC hdc = CreateCompatibleDC(0);
1121 HDC hdcMask = CreateCompatibleDC(0);
1122 HBITMAP hOldbitmap;
1123 HBITMAP hOldbitmapmask;
1125 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1126 HBITMAP hTempMask;
1128 This->hbmXor = CreateDIBitmap(
1129 hdcref,
1130 &bmi->bmiHeader,
1131 CBM_INIT,
1132 bytes,
1133 bmi,
1134 DIB_RGB_COLORS
1137 bmi->bmiColors[0].rgbRed = 0;
1138 bmi->bmiColors[0].rgbGreen = 0;
1139 bmi->bmiColors[0].rgbBlue = 0;
1140 bmi->bmiColors[1].rgbRed = 255;
1141 bmi->bmiColors[1].rgbGreen = 255;
1142 bmi->bmiColors[1].rgbBlue = 255;
1144 bmi->bmiHeader.biBitCount = 1;
1145 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1146 bmi->bmiHeader.biClrUsed = 2;
1148 for (i = 0; i < gif->SHeight; i++) {
1149 unsigned char * colorPointer = bytes + padding * i;
1150 unsigned char * monoPointer = bytes + monopadding * i;
1151 for (j = 0; j < gif->SWidth; j++) {
1152 unsigned char pixel = colorPointer[j];
1153 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1154 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1157 hdcref = GetDC(0);
1158 hTempMask = CreateDIBitmap(
1159 hdcref,
1160 &bmi->bmiHeader,
1161 CBM_INIT,
1162 bytes,
1163 bmi,
1164 DIB_RGB_COLORS
1166 DeleteDC(hdcref);
1168 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1169 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1170 hOldbitmap = SelectObject(hdc, hTempMask);
1171 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1173 SetBkColor(hdc, RGB(255, 255, 255));
1174 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1176 /* We no longer need the original bitmap, so we apply the first
1177 transformation with the mask to speed up the rendering */
1178 SelectObject(hdc, This->hbmXor);
1179 SetBkColor(hdc, RGB(0,0,0));
1180 SetTextColor(hdc, RGB(255,255,255));
1181 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1182 hdcMask, 0, 0, SRCAND);
1184 SelectObject(hdc, hOldbitmap);
1185 SelectObject(hdcMask, hOldbitmapmask);
1186 DeleteDC(hdcMask);
1187 DeleteDC(hdc);
1188 DeleteObject(hTempMask);
1191 DeleteDC(hdcref);
1192 This->desc.picType = PICTYPE_BITMAP;
1193 OLEPictureImpl_SetBitmap(This);
1194 DGifCloseFile(gif);
1195 HeapFree(GetProcessHeap(),0,bytes);
1196 return S_OK;
1199 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1201 #ifdef HAVE_JPEGLIB_H
1202 struct jpeg_decompress_struct jd;
1203 struct jpeg_error_mgr jerr;
1204 int ret;
1205 JDIMENSION x;
1206 JSAMPROW samprow,oldsamprow;
1207 BITMAPINFOHEADER bmi;
1208 LPBYTE bits;
1209 HDC hdcref;
1210 struct jpeg_source_mgr xjsm;
1211 LPBYTE oldbits;
1212 unsigned int i;
1214 if(!libjpeg_handle) {
1215 if(!load_libjpeg()) {
1216 FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1217 return E_FAIL;
1221 /* This is basically so we can use in-memory data for jpeg decompression.
1222 * We need to have all the functions.
1224 xjsm.next_input_byte = xbuf;
1225 xjsm.bytes_in_buffer = xread;
1226 xjsm.init_source = _jpeg_init_source;
1227 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1228 xjsm.skip_input_data = _jpeg_skip_input_data;
1229 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1230 xjsm.term_source = _jpeg_term_source;
1232 jd.err = pjpeg_std_error(&jerr);
1233 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1234 * jpeg_create_decompress(&jd); */
1235 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct));
1236 jd.src = &xjsm;
1237 ret=pjpeg_read_header(&jd,TRUE);
1238 jd.out_color_space = JCS_RGB;
1239 pjpeg_start_decompress(&jd);
1240 if (ret != JPEG_HEADER_OK) {
1241 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1242 HeapFree(GetProcessHeap(),0,xbuf);
1243 return E_FAIL;
1246 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1247 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1248 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1250 oldbits = bits;
1251 oldsamprow = samprow;
1252 while ( jd.output_scanline<jd.output_height ) {
1253 x = pjpeg_read_scanlines(&jd,&samprow,1);
1254 if (x != 1) {
1255 FIXME("failed to read current scanline?\n");
1256 break;
1258 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1259 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1260 *(bits++) = *(samprow+2);
1261 *(bits++) = *(samprow+1);
1262 *(bits++) = *(samprow);
1264 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1265 samprow = oldsamprow;
1267 bits = oldbits;
1269 bmi.biSize = sizeof(bmi);
1270 bmi.biWidth = jd.output_width;
1271 bmi.biHeight = -jd.output_height;
1272 bmi.biPlanes = 1;
1273 bmi.biBitCount = jd.output_components<<3;
1274 bmi.biCompression = BI_RGB;
1275 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1276 bmi.biXPelsPerMeter = 0;
1277 bmi.biYPelsPerMeter = 0;
1278 bmi.biClrUsed = 0;
1279 bmi.biClrImportant = 0;
1281 HeapFree(GetProcessHeap(),0,samprow);
1282 pjpeg_finish_decompress(&jd);
1283 pjpeg_destroy_decompress(&jd);
1284 hdcref = GetDC(0);
1285 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1286 hdcref,
1287 &bmi,
1288 CBM_INIT,
1289 bits,
1290 (BITMAPINFO*)&bmi,
1291 DIB_RGB_COLORS
1293 DeleteDC(hdcref);
1294 This->desc.picType = PICTYPE_BITMAP;
1295 OLEPictureImpl_SetBitmap(This);
1296 HeapFree(GetProcessHeap(),0,bits);
1297 return S_OK;
1298 #else
1299 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1300 return E_FAIL;
1301 #endif
1304 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1306 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1307 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1308 HDC hdcref;
1310 /* Does not matter whether this is a coreheader or not, we only use
1311 * components which are in both
1313 hdcref = GetDC(0);
1314 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1315 hdcref,
1316 &(bi->bmiHeader),
1317 CBM_INIT,
1318 xbuf+bfh->bfOffBits,
1320 DIB_RGB_COLORS
1322 DeleteDC(hdcref);
1323 This->desc.picType = PICTYPE_BITMAP;
1324 OLEPictureImpl_SetBitmap(This);
1325 return S_OK;
1328 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1330 HICON hicon;
1331 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1332 HDC hdcRef;
1333 int i;
1336 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1337 FIXME("icon.idType=%d\n",cifd->idType);
1338 FIXME("icon.idCount=%d\n",cifd->idCount);
1340 for (i=0;i<cifd->idCount;i++) {
1341 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1342 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1343 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1344 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1345 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1346 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1347 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1348 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1351 i=0;
1352 /* If we have more than one icon, try to find the best.
1353 * this currently means '32 pixel wide'.
1355 if (cifd->idCount!=1) {
1356 for (i=0;i<cifd->idCount;i++) {
1357 if (cifd->idEntries[i].bWidth == 32)
1358 break;
1360 if (i==cifd->idCount) i=0;
1363 hicon = CreateIconFromResourceEx(
1364 xbuf+cifd->idEntries[i].dwDIBOffset,
1365 cifd->idEntries[i].dwDIBSize,
1366 TRUE, /* is icon */
1367 0x00030000,
1368 cifd->idEntries[i].bWidth,
1369 cifd->idEntries[i].bHeight,
1372 if (!hicon) {
1373 FIXME("CreateIcon failed.\n");
1374 return E_FAIL;
1375 } else {
1376 This->desc.picType = PICTYPE_ICON;
1377 This->desc.u.icon.hicon = hicon;
1378 This->origWidth = cifd->idEntries[i].bWidth;
1379 This->origHeight = cifd->idEntries[i].bHeight;
1380 hdcRef = CreateCompatibleDC(0);
1381 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1382 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1383 DeleteDC(hdcRef);
1384 return S_OK;
1388 /************************************************************************
1389 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1391 * Loads the binary data from the IStream. Starts at current position.
1392 * There appears to be an 2 DWORD header:
1393 * DWORD magic;
1394 * DWORD len;
1396 * Currently implemented: BITMAP, ICON, JPEG, GIF
1398 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1399 HRESULT hr = E_FAIL;
1400 BOOL headerisdata = FALSE;
1401 BOOL statfailed = FALSE;
1402 ULONG xread, toread;
1403 BYTE *xbuf;
1404 DWORD header[2];
1405 WORD magic;
1406 STATSTG statstg;
1407 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1409 TRACE("(%p,%p)\n",This,pStm);
1411 /****************************************************************************************
1412 * Part 1: Load the data
1414 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1415 * out whether we do.
1417 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1418 * compound file. This may explain most, if not all, of the cases of "no
1419 * header", and the header validation should take this into account.
1420 * At least in Visual Basic 6, resource streams, valid headers are
1421 * header[0] == "lt\0\0",
1422 * header[1] == length_of_stream.
1424 * Also handle streams where we do not have a working "Stat" method by
1425 * reading all data until the end of the stream.
1427 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1428 if (hr) {
1429 TRACE("stat failed with hres %lx, proceeding to read all data.\n",hr);
1430 statfailed = TRUE;
1431 /* we will read at least 8 byte ... just right below */
1432 statstg.cbSize.QuadPart = 8;
1434 hr=IStream_Read(pStm,header,8,&xread);
1435 if (hr || xread!=8) {
1436 FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
1437 return hr;
1440 headerisdata = FALSE;
1441 xread = 0;
1442 if (!memcmp(&(header[0]),"lt\0\0", 4) && (header[1] <= statstg.cbSize.QuadPart-8)) {
1443 toread = header[1];
1444 } else {
1445 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1446 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1447 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1448 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1449 (header[1]==0)
1450 ) {/* Incorrect header, assume none. */
1451 headerisdata = TRUE;
1452 toread = statstg.cbSize.QuadPart-8;
1453 xread = 8;
1454 } else {
1455 FIXME("Unknown stream header magic: %08lx\n", header[0]);
1456 toread = header[1];
1460 if (statfailed) { /* we don't know the size ... read all we get */
1461 int sizeinc = 4096;
1462 int origsize = sizeinc;
1463 ULONG nread = 42;
1465 TRACE("Reading all data from stream.\n");
1466 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1467 if (headerisdata)
1468 memcpy (xbuf, &header, 8);
1469 while (1) {
1470 while (xread < origsize) {
1471 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1472 xread+=nread;
1473 if (hr || !nread)
1474 break;
1476 if (!nread || hr) /* done, or error */
1477 break;
1478 if (xread == origsize) {
1479 origsize += sizeinc;
1480 sizeinc = 2*sizeinc; /* exponential increase */
1481 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1484 if (hr)
1485 TRACE("hr in no-stat loader case is %08lx\n", hr);
1486 TRACE("loaded %ld bytes.\n", xread);
1487 This->datalen = xread;
1488 This->data = xbuf;
1489 } else {
1490 This->datalen = toread+(headerisdata?8:0);
1491 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1493 if (headerisdata)
1494 memcpy (xbuf, &header, 8);
1496 while (xread < This->datalen) {
1497 ULONG nread;
1498 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1499 xread+=nread;
1500 if (hr || !nread)
1501 break;
1503 if (xread != This->datalen)
1504 FIXME("Could only read %ld of %d bytes out of stream?\n",xread,This->datalen);
1506 if (This->datalen == 0) { /* Marks the "NONE" picture */
1507 This->desc.picType = PICTYPE_NONE;
1508 return S_OK;
1512 /****************************************************************************************
1513 * Part 2: Process the loaded data
1516 magic = xbuf[0] + (xbuf[1]<<8);
1517 switch (magic) {
1518 case 0x4947: /* GIF */
1519 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1520 break;
1521 case 0xd8ff: /* JPEG */
1522 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1523 break;
1524 case 0x4d42: /* Bitmap */
1525 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1526 break;
1527 case 0x0000: { /* ICON , first word is dwReserved */
1528 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1529 break;
1531 default:
1533 unsigned int i;
1534 FIXME("Unknown magic %04x, %ld read bytes:\n",magic,xread);
1535 hr=E_FAIL;
1536 for (i=0;i<xread+8;i++) {
1537 if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
1538 else MESSAGE("%02x ",xbuf[i-8]);
1539 if (i % 10 == 9) MESSAGE("\n");
1541 MESSAGE("\n");
1542 break;
1545 This->bIsDirty = FALSE;
1547 /* FIXME: this notify is not really documented */
1548 if (hr==S_OK)
1549 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1550 return hr;
1553 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1555 int iSuccess = 0;
1556 HDC hDC;
1557 BITMAPINFO * pInfoBitmap;
1558 int iNumPaletteEntries;
1559 unsigned char * pPixelData;
1560 BITMAPFILEHEADER * pFileHeader;
1561 BITMAPINFO * pInfoHeader;
1563 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1564 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1566 /* Find out bitmap size and padded length */
1567 hDC = GetDC(0);
1568 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1569 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1571 /* Fetch bitmap palette & pixel data */
1573 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1574 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1576 /* Calculate the total length required for the BMP data */
1577 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1578 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1579 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1580 } else {
1581 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1582 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1583 else
1584 iNumPaletteEntries = 0;
1586 *pLength =
1587 sizeof(BITMAPFILEHEADER) +
1588 sizeof(BITMAPINFOHEADER) +
1589 iNumPaletteEntries * sizeof(RGBQUAD) +
1590 pInfoBitmap->bmiHeader.biSizeImage;
1591 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1593 /* Fill the BITMAPFILEHEADER */
1594 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1595 pFileHeader->bfType = 0x4d42;
1596 pFileHeader->bfSize = *pLength;
1597 pFileHeader->bfOffBits =
1598 sizeof(BITMAPFILEHEADER) +
1599 sizeof(BITMAPINFOHEADER) +
1600 iNumPaletteEntries * sizeof(RGBQUAD);
1602 /* Fill the BITMAPINFOHEADER and the palette data */
1603 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1604 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1605 memcpy(
1606 (unsigned char *)(*ppBuffer) +
1607 sizeof(BITMAPFILEHEADER) +
1608 sizeof(BITMAPINFOHEADER) +
1609 iNumPaletteEntries * sizeof(RGBQUAD),
1610 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1611 iSuccess = 1;
1613 HeapFree(GetProcessHeap(), 0, pPixelData);
1614 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1615 return iSuccess;
1618 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1620 ICONINFO infoIcon;
1621 int iSuccess = 0;
1623 *ppBuffer = NULL; *pLength = 0;
1624 if (GetIconInfo(hIcon, &infoIcon)) {
1625 HDC hDC;
1626 BITMAPINFO * pInfoBitmap;
1627 unsigned char * pIconData = NULL;
1628 unsigned int iDataSize = 0;
1630 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1632 /* Find out icon size */
1633 hDC = GetDC(0);
1634 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1635 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1636 if (1) {
1637 /* Auxiliary pointers */
1638 CURSORICONFILEDIR * pIconDir;
1639 CURSORICONFILEDIRENTRY * pIconEntry;
1640 BITMAPINFOHEADER * pIconBitmapHeader;
1641 unsigned int iOffsetPalette;
1642 unsigned int iOffsetColorData;
1643 unsigned int iOffsetMaskData;
1645 unsigned int iLengthScanLineColor;
1646 unsigned int iLengthScanLineMask;
1647 unsigned int iNumEntriesPalette;
1649 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1650 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
1652 FIXME("DEBUG: bitmap size is %d x %d\n",
1653 pInfoBitmap->bmiHeader.biWidth,
1654 pInfoBitmap->bmiHeader.biHeight);
1655 FIXME("DEBUG: bitmap bpp is %d\n",
1656 pInfoBitmap->bmiHeader.biBitCount);
1657 FIXME("DEBUG: bitmap nplanes is %d\n",
1658 pInfoBitmap->bmiHeader.biPlanes);
1659 FIXME("DEBUG: bitmap biSizeImage is %lu\n",
1660 pInfoBitmap->bmiHeader.biSizeImage);
1662 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1663 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1664 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1666 /* Fill out the CURSORICONFILEDIR */
1667 pIconDir = (CURSORICONFILEDIR *)pIconData;
1668 pIconDir->idType = 1;
1669 pIconDir->idCount = 1;
1671 /* Fill out the CURSORICONFILEDIRENTRY */
1672 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1673 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1674 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1675 pIconEntry->bColorCount =
1676 (pInfoBitmap->bmiHeader.biBitCount < 8)
1677 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1678 : 0;
1679 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1680 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1681 pIconEntry->dwDIBSize = 0;
1682 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1684 /* Fill out the BITMAPINFOHEADER */
1685 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1686 memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
1688 /* Find out whether a palette exists for the bitmap */
1689 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1690 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1691 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1692 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1693 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1694 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1695 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1696 iNumEntriesPalette = 3;
1697 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1698 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1699 } else {
1700 iNumEntriesPalette = 0;
1703 /* Add bitmap size and header size to icon data size. */
1704 iOffsetPalette = iDataSize;
1705 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1706 iOffsetColorData = iDataSize;
1707 iDataSize += pIconBitmapHeader->biSizeImage;
1708 iOffsetMaskData = iDataSize;
1709 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1710 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1711 pIconBitmapHeader->biHeight *= 2;
1712 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1713 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1714 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1715 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1717 /* Get the actual bitmap data from the icon bitmap */
1718 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1719 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1720 if (iNumEntriesPalette > 0) {
1721 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1722 iNumEntriesPalette * sizeof(RGBQUAD));
1725 /* Reset all values so that GetDIBits call succeeds */
1726 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1727 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1728 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1730 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1731 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1732 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1734 printf("ERROR: unable to get bitmap mask (error %lu)\n",
1735 GetLastError());
1739 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1740 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1742 /* Write out everything produced so far to the stream */
1743 *ppBuffer = pIconData; *pLength = iDataSize;
1744 iSuccess = 1;
1745 } else {
1747 printf("ERROR: unable to get bitmap information via GetDIBits() (error %lu)\n",
1748 GetLastError());
1752 Remarks (from MSDN entry on GetIconInfo):
1754 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1755 members of ICONINFO. The calling application must manage
1756 these bitmaps and delete them when they are no longer
1757 necessary.
1759 if (hDC) ReleaseDC(0, hDC);
1760 DeleteObject(infoIcon.hbmMask);
1761 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1762 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1763 } else {
1764 printf("ERROR: Unable to get icon information (error %lu)\n",
1765 GetLastError());
1767 return iSuccess;
1770 static HRESULT WINAPI OLEPictureImpl_Save(
1771 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1773 HRESULT hResult = E_NOTIMPL;
1774 void * pIconData;
1775 unsigned int iDataSize;
1776 ULONG dummy;
1777 int iSerializeResult = 0;
1778 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1780 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1782 switch (This->desc.picType) {
1783 case PICTYPE_ICON:
1784 if (This->bIsDirty || !This->data) {
1785 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1786 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1787 hResult = E_FAIL;
1788 break;
1790 HeapFree(GetProcessHeap(), 0, This->data);
1791 This->data = pIconData;
1792 This->datalen = iDataSize;
1794 if (This->loadtime_magic != 0xdeadbeef) {
1795 DWORD header[2];
1797 header[0] = This->loadtime_magic;
1798 header[1] = This->datalen;
1799 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1801 IStream_Write(pStm, This->data, This->datalen, &dummy);
1803 hResult = S_OK;
1804 break;
1805 case PICTYPE_BITMAP:
1806 if (This->bIsDirty) {
1807 switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) {
1808 case 0x4d42:
1809 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1810 break;
1811 case 0xd8ff:
1812 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1813 break;
1814 case 0x4947:
1815 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1816 break;
1817 default:
1818 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1819 break;
1821 if (iSerializeResult) {
1823 if (This->loadtime_magic != 0xdeadbeef) {
1825 if (1) {
1826 DWORD header[2];
1828 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1829 header[1] = iDataSize;
1830 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1832 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1834 HeapFree(GetProcessHeap(), 0, This->data);
1835 This->data = pIconData;
1836 This->datalen = iDataSize;
1837 hResult = S_OK;
1839 } else {
1841 if (This->loadtime_magic != 0xdeadbeef) {
1843 if (1) {
1844 DWORD header[2];
1846 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1847 header[1] = This->datalen;
1848 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1850 IStream_Write(pStm, This->data, This->datalen, &dummy);
1851 hResult = S_OK;
1853 break;
1854 case PICTYPE_METAFILE:
1855 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1856 break;
1857 case PICTYPE_ENHMETAFILE:
1858 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1859 break;
1860 default:
1861 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1862 break;
1864 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1865 return hResult;
1868 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1869 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1871 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1872 FIXME("(%p,%p),stub!\n",This,pcbSize);
1873 return E_NOTIMPL;
1877 /************************************************************************
1878 * IDispatch
1881 /************************************************************************
1882 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1884 * See Windows documentation for more details on IUnknown methods.
1886 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1887 IDispatch* iface,
1888 REFIID riid,
1889 VOID** ppvoid)
1891 OLEPictureImpl *This = impl_from_IDispatch(iface);
1893 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
1896 /************************************************************************
1897 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1899 * See Windows documentation for more details on IUnknown methods.
1901 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1902 IDispatch* iface)
1904 OLEPictureImpl *This = impl_from_IDispatch(iface);
1906 return IPicture_AddRef((IPicture *)This);
1909 /************************************************************************
1910 * OLEPictureImpl_IDispatch_Release (IUnknown)
1912 * See Windows documentation for more details on IUnknown methods.
1914 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1915 IDispatch* iface)
1917 OLEPictureImpl *This = impl_from_IDispatch(iface);
1919 return IPicture_Release((IPicture *)This);
1922 /************************************************************************
1923 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1925 * See Windows documentation for more details on IDispatch methods.
1927 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1928 IDispatch* iface,
1929 unsigned int* pctinfo)
1931 TRACE("(%p)", pctinfo);
1933 *pctinfo = 1;
1935 return S_OK;
1938 /************************************************************************
1939 * OLEPictureImpl_GetTypeInfo (IDispatch)
1941 * See Windows documentation for more details on IDispatch methods.
1943 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1944 IDispatch* iface,
1945 UINT iTInfo,
1946 LCID lcid,
1947 ITypeInfo** ppTInfo)
1949 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1950 ITypeLib *tl;
1951 HRESULT hres;
1953 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1955 if (iTInfo != 0)
1956 return E_FAIL;
1958 hres = LoadTypeLib(stdole2tlb, &tl);
1959 if (FAILED(hres))
1961 ERR("Could not load stdole2.tlb\n");
1962 return hres;
1965 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1966 if (FAILED(hres))
1967 ERR("Did not get IPictureDisp typeinfo from typelib, hres %lx\n", hres);
1969 return hres;
1972 /************************************************************************
1973 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1975 * See Windows documentation for more details on IDispatch methods.
1977 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1978 IDispatch* iface,
1979 REFIID riid,
1980 LPOLESTR* rgszNames,
1981 UINT cNames,
1982 LCID lcid,
1983 DISPID* rgDispId)
1985 FIXME("():Stub\n");
1987 return E_NOTIMPL;
1990 /************************************************************************
1991 * OLEPictureImpl_Invoke (IDispatch)
1993 * See Windows documentation for more details on IDispatch methods.
1995 static HRESULT WINAPI OLEPictureImpl_Invoke(
1996 IDispatch* iface,
1997 DISPID dispIdMember,
1998 REFIID riid,
1999 LCID lcid,
2000 WORD wFlags,
2001 DISPPARAMS* pDispParams,
2002 VARIANT* pVarResult,
2003 EXCEPINFO* pExepInfo,
2004 UINT* puArgErr)
2006 OLEPictureImpl *This = impl_from_IDispatch(iface);
2008 /* validate parameters */
2010 if (!IsEqualIID(riid, &IID_NULL))
2012 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2013 return DISP_E_UNKNOWNNAME;
2016 if (!pDispParams)
2018 ERR("null pDispParams not allowed\n");
2019 return DISP_E_PARAMNOTOPTIONAL;
2022 if (wFlags & DISPATCH_PROPERTYGET)
2024 if (pDispParams->cArgs != 0)
2026 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2027 return DISP_E_BADPARAMCOUNT;
2029 if (!pVarResult)
2031 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2032 return DISP_E_PARAMNOTOPTIONAL;
2035 else if (wFlags & DISPATCH_PROPERTYPUT)
2037 if (pDispParams->cArgs != 1)
2039 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2040 return DISP_E_BADPARAMCOUNT;
2044 switch (dispIdMember)
2046 case DISPID_PICT_HANDLE:
2047 if (wFlags & DISPATCH_PROPERTYGET)
2049 TRACE("DISPID_PICT_HANDLE\n");
2050 V_VT(pVarResult) = VT_I4;
2051 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2053 break;
2054 case DISPID_PICT_HPAL:
2055 if (wFlags & DISPATCH_PROPERTYGET)
2057 TRACE("DISPID_PICT_HPAL\n");
2058 V_VT(pVarResult) = VT_I4;
2059 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2061 else if (wFlags & DISPATCH_PROPERTYPUT)
2063 VARIANTARG vararg;
2064 HRESULT hr;
2065 TRACE("DISPID_PICT_HPAL\n");
2067 VariantInit(&vararg);
2068 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2069 if (FAILED(hr))
2070 return hr;
2072 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2074 VariantClear(&vararg);
2075 return hr;
2077 break;
2078 case DISPID_PICT_TYPE:
2079 if (wFlags & DISPATCH_PROPERTYGET)
2081 TRACE("DISPID_PICT_TYPE\n");
2082 V_VT(pVarResult) = VT_I2;
2083 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2085 break;
2086 case DISPID_PICT_WIDTH:
2087 if (wFlags & DISPATCH_PROPERTYGET)
2089 TRACE("DISPID_PICT_WIDTH\n");
2090 V_VT(pVarResult) = VT_I4;
2091 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2093 break;
2094 case DISPID_PICT_HEIGHT:
2095 if (wFlags & DISPATCH_PROPERTYGET)
2097 TRACE("DISPID_PICT_HEIGHT\n");
2098 V_VT(pVarResult) = VT_I4;
2099 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2101 break;
2104 ERR("invalid dispid 0x%lx or wFlags 0x%x\n", dispIdMember, wFlags);
2105 return DISP_E_MEMBERNOTFOUND;
2109 static const IPictureVtbl OLEPictureImpl_VTable =
2111 OLEPictureImpl_QueryInterface,
2112 OLEPictureImpl_AddRef,
2113 OLEPictureImpl_Release,
2114 OLEPictureImpl_get_Handle,
2115 OLEPictureImpl_get_hPal,
2116 OLEPictureImpl_get_Type,
2117 OLEPictureImpl_get_Width,
2118 OLEPictureImpl_get_Height,
2119 OLEPictureImpl_Render,
2120 OLEPictureImpl_set_hPal,
2121 OLEPictureImpl_get_CurDC,
2122 OLEPictureImpl_SelectPicture,
2123 OLEPictureImpl_get_KeepOriginalFormat,
2124 OLEPictureImpl_put_KeepOriginalFormat,
2125 OLEPictureImpl_PictureChanged,
2126 OLEPictureImpl_SaveAsFile,
2127 OLEPictureImpl_get_Attributes
2130 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2132 OLEPictureImpl_IDispatch_QueryInterface,
2133 OLEPictureImpl_IDispatch_AddRef,
2134 OLEPictureImpl_IDispatch_Release,
2135 OLEPictureImpl_GetTypeInfoCount,
2136 OLEPictureImpl_GetTypeInfo,
2137 OLEPictureImpl_GetIDsOfNames,
2138 OLEPictureImpl_Invoke
2141 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2143 OLEPictureImpl_IPersistStream_QueryInterface,
2144 OLEPictureImpl_IPersistStream_AddRef,
2145 OLEPictureImpl_IPersistStream_Release,
2146 OLEPictureImpl_GetClassID,
2147 OLEPictureImpl_IsDirty,
2148 OLEPictureImpl_Load,
2149 OLEPictureImpl_Save,
2150 OLEPictureImpl_GetSizeMax
2153 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2155 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2156 OLEPictureImpl_IConnectionPointContainer_AddRef,
2157 OLEPictureImpl_IConnectionPointContainer_Release,
2158 OLEPictureImpl_EnumConnectionPoints,
2159 OLEPictureImpl_FindConnectionPoint
2162 /***********************************************************************
2163 * OleCreatePictureIndirect (OLEAUT32.419)
2165 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2166 BOOL fOwn, LPVOID *ppvObj )
2168 OLEPictureImpl* newPict = NULL;
2169 HRESULT hr = S_OK;
2171 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2174 * Sanity check
2176 if (ppvObj==0)
2177 return E_POINTER;
2179 *ppvObj = NULL;
2182 * Try to construct a new instance of the class.
2184 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2186 if (newPict == NULL)
2187 return E_OUTOFMEMORY;
2190 * Make sure it supports the interface required by the caller.
2192 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2195 * Release the reference obtained in the constructor. If
2196 * the QueryInterface was unsuccessful, it will free the class.
2198 IPicture_Release((IPicture*)newPict);
2200 return hr;
2204 /***********************************************************************
2205 * OleLoadPicture (OLEAUT32.418)
2207 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2208 REFIID riid, LPVOID *ppvObj )
2210 LPPERSISTSTREAM ps;
2211 IPicture *newpic;
2212 HRESULT hr;
2214 TRACE("(%p,%ld,%d,%s,%p), partially implemented.\n",
2215 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2217 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2218 if (hr)
2219 return hr;
2220 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2221 if (hr) {
2222 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2223 IPicture_Release(newpic);
2224 *ppvObj = NULL;
2225 return hr;
2227 IPersistStream_Load(ps,lpstream);
2228 IPersistStream_Release(ps);
2229 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2230 if (hr)
2231 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2232 IPicture_Release(newpic);
2233 return hr;
2236 /***********************************************************************
2237 * OleLoadPictureEx (OLEAUT32.401)
2239 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2240 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2242 LPPERSISTSTREAM ps;
2243 IPicture *newpic;
2244 HRESULT hr;
2246 FIXME("(%p,%ld,%d,%s,x=%ld,y=%ld,f=%lx,%p), partially implemented.\n",
2247 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2249 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2250 if (hr)
2251 return hr;
2252 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2253 if (hr) {
2254 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2255 IPicture_Release(newpic);
2256 *ppvObj = NULL;
2257 return hr;
2259 IPersistStream_Load(ps,lpstream);
2260 IPersistStream_Release(ps);
2261 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2262 if (hr)
2263 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2264 IPicture_Release(newpic);
2265 return hr;
2268 /***********************************************************************
2269 * OleLoadPicturePath (OLEAUT32.424)
2271 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2272 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2273 LPVOID *ppvRet )
2275 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2276 IPicture *ipicture;
2277 HANDLE hFile;
2278 DWORD dwFileSize;
2279 HGLOBAL hGlobal = NULL;
2280 DWORD dwBytesRead = 0;
2281 IStream *stream;
2282 BOOL bRead;
2283 IPersistStream *pStream;
2284 HRESULT hRes;
2286 TRACE("(%s,%p,%ld,%08lx,%s,%p): stub\n",
2287 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2288 debugstr_guid(riid), ppvRet);
2290 if (!ppvRet) return E_POINTER;
2292 if (strncmpW(szURLorPath, file, 7) == 0) {
2293 szURLorPath += 7;
2295 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2296 0, NULL);
2297 if (hFile == INVALID_HANDLE_VALUE)
2298 return E_UNEXPECTED;
2300 dwFileSize = GetFileSize(hFile, NULL);
2301 if (dwFileSize != INVALID_FILE_SIZE )
2303 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2304 if ( hGlobal)
2306 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2307 if (!bRead)
2309 GlobalFree(hGlobal);
2310 hGlobal = 0;
2314 CloseHandle(hFile);
2316 if (!hGlobal)
2317 return E_UNEXPECTED;
2319 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2320 if (FAILED(hRes))
2322 GlobalFree(hGlobal);
2323 return hRes;
2325 } else {
2326 IMoniker *pmnk;
2327 IBindCtx *pbc;
2329 hRes = CreateBindCtx(0, &pbc);
2330 if (SUCCEEDED(hRes))
2332 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2333 if (SUCCEEDED(hRes))
2335 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2336 IMoniker_Release(pmnk);
2338 IBindCtx_Release(pbc);
2340 if (FAILED(hRes))
2341 return hRes;
2344 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2345 &IID_IPicture, (LPVOID*)&ipicture);
2346 if (hRes != S_OK) {
2347 IStream_Release(stream);
2348 return hRes;
2351 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2352 if (hRes) {
2353 IStream_Release(stream);
2354 IPicture_Release(ipicture);
2355 return hRes;
2358 hRes = IPersistStream_Load(pStream, stream);
2359 IPersistStream_Release(pStream);
2360 IStream_Release(stream);
2362 if (hRes) {
2363 IPicture_Release(ipicture);
2364 return hRes;
2367 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2368 if (hRes)
2369 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2371 IPicture_Release(ipicture);
2372 return hRes;
2375 /*******************************************************************************
2376 * StdPic ClassFactory
2378 typedef struct
2380 /* IUnknown fields */
2381 const IClassFactoryVtbl *lpVtbl;
2382 LONG ref;
2383 } IClassFactoryImpl;
2385 static HRESULT WINAPI
2386 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2387 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2389 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2390 return E_NOINTERFACE;
2393 static ULONG WINAPI
2394 SPCF_AddRef(LPCLASSFACTORY iface) {
2395 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2396 return InterlockedIncrement(&This->ref);
2399 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2400 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2401 /* static class, won't be freed */
2402 return InterlockedDecrement(&This->ref);
2405 static HRESULT WINAPI SPCF_CreateInstance(
2406 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2408 /* Creates an uninitialized picture */
2409 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2413 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2414 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2415 FIXME("(%p)->(%d),stub!\n",This,dolock);
2416 return S_OK;
2419 static const IClassFactoryVtbl SPCF_Vtbl = {
2420 SPCF_QueryInterface,
2421 SPCF_AddRef,
2422 SPCF_Release,
2423 SPCF_CreateInstance,
2424 SPCF_LockServer
2426 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2428 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }