push bc3e5bf5ba806943a97979264a1f2e4a4dde5c94
[wine/hacks.git] / dlls / oleaut32 / olepicture.c
blobd8f01dbdafef50c0b73cd72418a6bd7f1e035d3c
1 /*
2 * OLE Picture object
4 * Implementation of OLE IPicture and related interfaces
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * BUGS
25 * Support PICTYPE_BITMAP and PICTYPE_ICON, altough only bitmaps very well..
26 * Lots of methods are just stubs.
29 * NOTES (or things that msdn doesn't tell you)
31 * The width and height properties are returned in HIMETRIC units (0.01mm)
32 * IPicture::Render also uses these to select a region of the src picture.
33 * A bitmap's size is converted into these units by using the screen resolution
34 * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
38 #include "config.h"
39 #include "wine/port.h"
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <string.h>
48 /* Must be before wine includes, the header has things conflicting with
49 * WINE headers.
51 #define COBJMACROS
52 #define NONAMELESSUNION
53 #define NONAMELESSSTRUCT
55 #include "winerror.h"
56 #include "windef.h"
57 #include "winbase.h"
58 #include "wingdi.h"
59 #include "winuser.h"
60 #include "ole2.h"
61 #include "olectl.h"
62 #include "oleauto.h"
63 #include "connpt.h"
64 #include "urlmon.h"
65 #include "wine/debug.h"
66 #include "wine/unicode.h"
68 #include "wine/wingdi16.h"
70 #ifdef SONAME_LIBJPEG
71 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
72 #define XMD_H
73 #define UINT8 JPEG_UINT8
74 #define UINT16 JPEG_UINT16
75 #undef FAR
76 #define boolean jpeg_boolean
77 # include <jpeglib.h>
78 #undef jpeg_boolean
79 #undef UINT16
80 #endif
82 #ifdef HAVE_PNG_H
83 #undef FAR
84 #include <png.h>
85 #endif
87 #include "ungif.h"
89 WINE_DEFAULT_DEBUG_CHANNEL(ole);
91 #include "pshpack1.h"
93 typedef struct {
94 BYTE bWidth;
95 BYTE bHeight;
96 BYTE bColorCount;
97 BYTE bReserved;
98 WORD xHotspot;
99 WORD yHotspot;
100 DWORD dwDIBSize;
101 DWORD dwDIBOffset;
102 } CURSORICONFILEDIRENTRY;
104 typedef struct
106 WORD idReserved;
107 WORD idType;
108 WORD idCount;
109 CURSORICONFILEDIRENTRY idEntries[1];
110 } CURSORICONFILEDIR;
112 #include "poppack.h"
114 /*************************************************************************
115 * Declaration of implementation class
118 typedef struct OLEPictureImpl {
121 * IPicture handles IUnknown
124 const IPictureVtbl *lpVtbl;
125 const IDispatchVtbl *lpvtblIDispatch;
126 const IPersistStreamVtbl *lpvtblIPersistStream;
127 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
129 /* Object reference count */
130 LONG ref;
132 /* We own the object and must destroy it ourselves */
133 BOOL fOwn;
135 /* Picture description */
136 PICTDESC desc;
138 /* These are the pixel size of a bitmap */
139 DWORD origWidth;
140 DWORD origHeight;
142 /* And these are the size of the picture converted into HIMETRIC units */
143 OLE_XSIZE_HIMETRIC himetricWidth;
144 OLE_YSIZE_HIMETRIC himetricHeight;
146 IConnectionPoint *pCP;
148 BOOL keepOrigFormat;
149 HDC hDCCur;
151 /* Bitmap transparency mask */
152 HBITMAP hbmMask;
153 HBITMAP hbmXor;
154 COLORREF rgbTrans;
156 /* data */
157 void* data;
158 int datalen;
159 BOOL bIsDirty; /* Set to TRUE if picture has changed */
160 unsigned int loadtime_magic; /* If a length header was found, saves value */
161 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
162 } OLEPictureImpl;
165 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
168 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
170 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
173 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
175 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
178 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
180 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
184 * Predeclare VTables. They get initialized at the end.
186 static const IPictureVtbl OLEPictureImpl_VTable;
187 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
188 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
189 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
191 /***********************************************************************
192 * Implementation of the OLEPictureImpl class.
195 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
196 BITMAP bm;
197 HDC hdcRef;
199 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
200 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
201 ERR("GetObject fails\n");
202 return;
204 This->origWidth = bm.bmWidth;
205 This->origHeight = bm.bmHeight;
206 /* The width and height are stored in HIMETRIC units (0.01 mm),
207 so we take our pixel width divide by pixels per inch and
208 multiply by 25.4 * 100 */
209 /* Should we use GetBitmapDimension if available? */
210 hdcRef = CreateCompatibleDC(0);
211 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
212 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
213 DeleteDC(hdcRef);
216 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
218 ICONINFO infoIcon;
220 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
221 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
222 HDC hdcRef;
223 BITMAP bm;
225 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
226 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
227 ERR("GetObject fails on icon bitmap\n");
228 return;
231 This->origWidth = bm.bmWidth;
232 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
233 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
234 hdcRef = GetDC(0);
235 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
236 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
237 ReleaseDC(0, hdcRef);
239 DeleteObject(infoIcon.hbmMask);
240 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
241 } else {
242 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
246 /************************************************************************
247 * OLEPictureImpl_Construct
249 * This method will construct a new instance of the OLEPictureImpl
250 * class.
252 * The caller of this method must release the object when it's
253 * done with it.
255 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
257 OLEPictureImpl* newObject = 0;
259 if (pictDesc)
260 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
263 * Allocate space for the object.
265 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
267 if (newObject==0)
268 return newObject;
271 * Initialize the virtual function table.
273 newObject->lpVtbl = &OLEPictureImpl_VTable;
274 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
275 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
276 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
278 newObject->pCP = NULL;
279 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
280 if (!newObject->pCP)
282 HeapFree(GetProcessHeap(), 0, newObject);
283 return NULL;
287 * Start with one reference count. The caller of this function
288 * must release the interface pointer when it is done.
290 newObject->ref = 1;
291 newObject->hDCCur = 0;
293 newObject->fOwn = fOwn;
295 /* dunno about original value */
296 newObject->keepOrigFormat = TRUE;
298 newObject->hbmMask = NULL;
299 newObject->hbmXor = NULL;
300 newObject->loadtime_magic = 0xdeadbeef;
301 newObject->loadtime_format = 0;
302 newObject->bIsDirty = FALSE;
304 if (pictDesc) {
305 memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC));
307 switch(pictDesc->picType) {
308 case PICTYPE_BITMAP:
309 OLEPictureImpl_SetBitmap(newObject);
310 break;
312 case PICTYPE_METAFILE:
313 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
314 newObject->himetricWidth = pictDesc->u.wmf.xExt;
315 newObject->himetricHeight = pictDesc->u.wmf.yExt;
316 break;
318 case PICTYPE_NONE:
319 /* not sure what to do here */
320 newObject->himetricWidth = newObject->himetricHeight = 0;
321 break;
323 case PICTYPE_ICON:
324 OLEPictureImpl_SetIcon(newObject);
325 break;
326 case PICTYPE_ENHMETAFILE:
327 default:
328 FIXME("Unsupported type %d\n", pictDesc->picType);
329 newObject->himetricWidth = newObject->himetricHeight = 0;
330 break;
332 } else {
333 newObject->desc.picType = PICTYPE_UNINITIALIZED;
336 TRACE("returning %p\n", newObject);
337 return newObject;
340 /************************************************************************
341 * OLEPictureImpl_Destroy
343 * This method is called by the Release method when the reference
344 * count goes down to 0. It will free all resources used by
345 * this object. */
346 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
348 TRACE("(%p)\n", Obj);
350 if (Obj->pCP)
351 IConnectionPoint_Release(Obj->pCP);
353 if(Obj->fOwn) { /* We need to destroy the picture */
354 switch(Obj->desc.picType) {
355 case PICTYPE_BITMAP:
356 DeleteObject(Obj->desc.u.bmp.hbitmap);
357 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
358 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
359 break;
360 case PICTYPE_METAFILE:
361 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
362 break;
363 case PICTYPE_ICON:
364 DestroyIcon(Obj->desc.u.icon.hicon);
365 break;
366 case PICTYPE_ENHMETAFILE:
367 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
368 break;
369 case PICTYPE_NONE:
370 case PICTYPE_UNINITIALIZED:
371 /* Nothing to do */
372 break;
373 default:
374 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
375 break;
378 HeapFree(GetProcessHeap(), 0, Obj->data);
379 HeapFree(GetProcessHeap(), 0, Obj);
383 /************************************************************************
384 * OLEPictureImpl_AddRef (IUnknown)
386 * See Windows documentation for more details on IUnknown methods.
388 static ULONG WINAPI OLEPictureImpl_AddRef(
389 IPicture* iface)
391 OLEPictureImpl *This = (OLEPictureImpl *)iface;
392 ULONG refCount = InterlockedIncrement(&This->ref);
394 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
396 return refCount;
399 /************************************************************************
400 * OLEPictureImpl_Release (IUnknown)
402 * See Windows documentation for more details on IUnknown methods.
404 static ULONG WINAPI OLEPictureImpl_Release(
405 IPicture* iface)
407 OLEPictureImpl *This = (OLEPictureImpl *)iface;
408 ULONG refCount = InterlockedDecrement(&This->ref);
410 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
413 * If the reference count goes down to 0, perform suicide.
415 if (!refCount) OLEPictureImpl_Destroy(This);
417 return refCount;
420 /************************************************************************
421 * OLEPictureImpl_QueryInterface (IUnknown)
423 * See Windows documentation for more details on IUnknown methods.
425 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
426 IPicture* iface,
427 REFIID riid,
428 void** ppvObject)
430 OLEPictureImpl *This = (OLEPictureImpl *)iface;
431 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
434 * Perform a sanity check on the parameters.
436 if ( (This==0) || (ppvObject==0) )
437 return E_INVALIDARG;
440 * Initialize the return parameter.
442 *ppvObject = 0;
445 * Compare the riid with the interface IDs implemented by this object.
447 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
448 *ppvObject = (IPicture*)This;
449 else if (IsEqualIID(&IID_IDispatch, riid))
450 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
451 else if (IsEqualIID(&IID_IPictureDisp, riid))
452 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
453 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
454 *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
455 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
456 *ppvObject = (IConnectionPointContainer*)&(This->lpvtblIConnectionPointContainer);
459 * Check that we obtained an interface.
461 if ((*ppvObject)==0)
463 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
464 return E_NOINTERFACE;
468 * Query Interface always increases the reference count by one when it is
469 * successful
471 OLEPictureImpl_AddRef((IPicture*)This);
473 return S_OK;
476 /***********************************************************************
477 * OLEPicture_SendNotify (internal)
479 * Sends notification messages of changed properties to any interested
480 * connections.
482 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
484 IEnumConnections *pEnum;
485 CONNECTDATA CD;
487 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
488 return;
489 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
490 IPropertyNotifySink *sink;
492 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
493 IPropertyNotifySink_OnChanged(sink, dispID);
494 IPropertyNotifySink_Release(sink);
495 IUnknown_Release(CD.pUnk);
497 IEnumConnections_Release(pEnum);
498 return;
501 /************************************************************************
502 * OLEPictureImpl_get_Handle
504 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
505 OLE_HANDLE *phandle)
507 OLEPictureImpl *This = (OLEPictureImpl *)iface;
508 TRACE("(%p)->(%p)\n", This, phandle);
509 switch(This->desc.picType) {
510 case PICTYPE_NONE:
511 case PICTYPE_UNINITIALIZED:
512 *phandle = 0;
513 break;
514 case PICTYPE_BITMAP:
515 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
516 break;
517 case PICTYPE_METAFILE:
518 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
519 break;
520 case PICTYPE_ICON:
521 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
522 break;
523 case PICTYPE_ENHMETAFILE:
524 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
525 break;
526 default:
527 FIXME("Unimplemented type %d\n", This->desc.picType);
528 return E_NOTIMPL;
530 TRACE("returning handle %08x\n", *phandle);
531 return S_OK;
534 /************************************************************************
535 * OLEPictureImpl_get_hPal
537 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
538 OLE_HANDLE *phandle)
540 OLEPictureImpl *This = (OLEPictureImpl *)iface;
541 HRESULT hres;
542 TRACE("(%p)->(%p)\n", This, phandle);
544 if (!phandle)
545 return E_POINTER;
547 switch (This->desc.picType) {
548 case (UINT)PICTYPE_UNINITIALIZED:
549 case PICTYPE_NONE:
550 *phandle = 0;
551 hres = S_FALSE;
552 break;
553 case PICTYPE_BITMAP:
554 *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
555 hres = S_OK;
556 break;
557 case PICTYPE_ICON:
558 case PICTYPE_METAFILE:
559 case PICTYPE_ENHMETAFILE:
560 default:
561 FIXME("unimplemented for type %d. Returning 0 palette.\n",
562 This->desc.picType);
563 *phandle = 0;
564 hres = S_OK;
567 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
568 return hres;
571 /************************************************************************
572 * OLEPictureImpl_get_Type
574 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
575 short *ptype)
577 OLEPictureImpl *This = (OLEPictureImpl *)iface;
578 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
579 *ptype = This->desc.picType;
580 return S_OK;
583 /************************************************************************
584 * OLEPictureImpl_get_Width
586 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
587 OLE_XSIZE_HIMETRIC *pwidth)
589 OLEPictureImpl *This = (OLEPictureImpl *)iface;
590 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
591 *pwidth = This->himetricWidth;
592 return S_OK;
595 /************************************************************************
596 * OLEPictureImpl_get_Height
598 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
599 OLE_YSIZE_HIMETRIC *pheight)
601 OLEPictureImpl *This = (OLEPictureImpl *)iface;
602 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
603 *pheight = This->himetricHeight;
604 return S_OK;
607 /************************************************************************
608 * OLEPictureImpl_Render
610 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
611 LONG x, LONG y, LONG cx, LONG cy,
612 OLE_XPOS_HIMETRIC xSrc,
613 OLE_YPOS_HIMETRIC ySrc,
614 OLE_XSIZE_HIMETRIC cxSrc,
615 OLE_YSIZE_HIMETRIC cySrc,
616 LPCRECT prcWBounds)
618 OLEPictureImpl *This = (OLEPictureImpl *)iface;
619 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
620 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
621 if(prcWBounds)
622 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
623 prcWBounds->right, prcWBounds->bottom);
626 * While the documentation suggests this to be here (or after rendering?)
627 * it does cause an endless recursion in my sample app. -MM 20010804
628 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
631 switch(This->desc.picType) {
632 case PICTYPE_BITMAP:
634 HBITMAP hbmpOld;
635 HDC hdcBmp;
637 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
638 NB y-axis gets flipped */
640 hdcBmp = CreateCompatibleDC(0);
641 SetMapMode(hdcBmp, MM_ANISOTROPIC);
642 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
643 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
644 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
645 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
647 if (This->hbmMask) {
648 HDC hdcMask = CreateCompatibleDC(0);
649 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
651 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
653 SetMapMode(hdcMask, MM_ANISOTROPIC);
654 SetWindowOrgEx(hdcMask, 0, 0, NULL);
655 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
656 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
657 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
659 SetBkColor(hdc, RGB(255, 255, 255));
660 SetTextColor(hdc, RGB(0, 0, 0));
661 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
662 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
664 SelectObject(hdcMask, hOldbm);
665 DeleteDC(hdcMask);
666 } else {
667 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
668 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
671 SelectObject(hdcBmp, hbmpOld);
672 DeleteDC(hdcBmp);
674 break;
675 case PICTYPE_ICON:
676 FIXME("Not quite correct implementation of rendering icons...\n");
677 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
678 break;
680 case PICTYPE_METAFILE:
681 PlayMetaFile(hdc, This->desc.u.wmf.hmeta);
682 break;
684 case PICTYPE_ENHMETAFILE:
686 RECT rc = { x, y, x + cx, y + cy };
687 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
688 break;
691 default:
692 FIXME("type %d not implemented\n", This->desc.picType);
693 return E_NOTIMPL;
695 return S_OK;
698 /************************************************************************
699 * OLEPictureImpl_set_hPal
701 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
702 OLE_HANDLE hpal)
704 OLEPictureImpl *This = (OLEPictureImpl *)iface;
705 FIXME("(%p)->(%08x): stub\n", This, hpal);
706 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
707 return E_NOTIMPL;
710 /************************************************************************
711 * OLEPictureImpl_get_CurDC
713 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
714 HDC *phdc)
716 OLEPictureImpl *This = (OLEPictureImpl *)iface;
717 TRACE("(%p), returning %p\n", This, This->hDCCur);
718 if (phdc) *phdc = This->hDCCur;
719 return S_OK;
722 /************************************************************************
723 * OLEPictureImpl_SelectPicture
725 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
726 HDC hdcIn,
727 HDC *phdcOut,
728 OLE_HANDLE *phbmpOut)
730 OLEPictureImpl *This = (OLEPictureImpl *)iface;
731 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
732 if (This->desc.picType == PICTYPE_BITMAP) {
733 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
735 if (phdcOut)
736 *phdcOut = This->hDCCur;
737 This->hDCCur = hdcIn;
738 if (phbmpOut)
739 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
740 return S_OK;
741 } else {
742 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
743 return E_FAIL;
747 /************************************************************************
748 * OLEPictureImpl_get_KeepOriginalFormat
750 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
751 BOOL *pfKeep)
753 OLEPictureImpl *This = (OLEPictureImpl *)iface;
754 TRACE("(%p)->(%p)\n", This, pfKeep);
755 if (!pfKeep)
756 return E_POINTER;
757 *pfKeep = This->keepOrigFormat;
758 return S_OK;
761 /************************************************************************
762 * OLEPictureImpl_put_KeepOriginalFormat
764 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
765 BOOL keep)
767 OLEPictureImpl *This = (OLEPictureImpl *)iface;
768 TRACE("(%p)->(%d)\n", This, keep);
769 This->keepOrigFormat = keep;
770 /* FIXME: what DISPID notification here? */
771 return S_OK;
774 /************************************************************************
775 * OLEPictureImpl_PictureChanged
777 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
779 OLEPictureImpl *This = (OLEPictureImpl *)iface;
780 TRACE("(%p)->()\n", This);
781 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
782 This->bIsDirty = TRUE;
783 return S_OK;
786 /************************************************************************
787 * OLEPictureImpl_SaveAsFile
789 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
790 IStream *pstream,
791 BOOL SaveMemCopy,
792 LONG *pcbSize)
794 OLEPictureImpl *This = (OLEPictureImpl *)iface;
795 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
796 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
799 /************************************************************************
800 * OLEPictureImpl_get_Attributes
802 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
803 DWORD *pdwAttr)
805 OLEPictureImpl *This = (OLEPictureImpl *)iface;
806 TRACE("(%p)->(%p).\n", This, pdwAttr);
807 *pdwAttr = 0;
808 switch (This->desc.picType) {
809 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
810 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
811 case PICTYPE_ENHMETAFILE: /* fall through */
812 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
813 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
815 return S_OK;
819 /************************************************************************
820 * IConnectionPointContainer
822 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
823 IConnectionPointContainer* iface,
824 REFIID riid,
825 VOID** ppvoid)
827 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
829 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
832 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
833 IConnectionPointContainer* iface)
835 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
837 return IPicture_AddRef((IPicture *)This);
840 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
841 IConnectionPointContainer* iface)
843 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
845 return IPicture_Release((IPicture *)This);
848 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
849 IConnectionPointContainer* iface,
850 IEnumConnectionPoints** ppEnum)
852 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
854 FIXME("(%p,%p), stub!\n",This,ppEnum);
855 return E_NOTIMPL;
858 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
859 IConnectionPointContainer* iface,
860 REFIID riid,
861 IConnectionPoint **ppCP)
863 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
864 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
865 if (!ppCP)
866 return E_POINTER;
867 *ppCP = NULL;
868 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
869 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
870 FIXME("no connection point for %s\n",debugstr_guid(riid));
871 return CONNECT_E_NOCONNECTION;
875 /************************************************************************
876 * IPersistStream
879 /************************************************************************
880 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
882 * See Windows documentation for more details on IUnknown methods.
884 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
885 IPersistStream* iface,
886 REFIID riid,
887 VOID** ppvoid)
889 OLEPictureImpl *This = impl_from_IPersistStream(iface);
891 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
894 /************************************************************************
895 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
897 * See Windows documentation for more details on IUnknown methods.
899 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
900 IPersistStream* iface)
902 OLEPictureImpl *This = impl_from_IPersistStream(iface);
904 return IPicture_AddRef((IPicture *)This);
907 /************************************************************************
908 * OLEPictureImpl_IPersistStream_Release (IUnknown)
910 * See Windows documentation for more details on IUnknown methods.
912 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
913 IPersistStream* iface)
915 OLEPictureImpl *This = impl_from_IPersistStream(iface);
917 return IPicture_Release((IPicture *)This);
920 /************************************************************************
921 * OLEPictureImpl_IPersistStream_GetClassID
923 static HRESULT WINAPI OLEPictureImpl_GetClassID(
924 IPersistStream* iface,CLSID* pClassID)
926 TRACE("(%p)\n", pClassID);
927 memcpy(pClassID, &CLSID_StdPicture, sizeof(*pClassID));
928 return S_OK;
931 /************************************************************************
932 * OLEPictureImpl_IPersistStream_IsDirty
934 static HRESULT WINAPI OLEPictureImpl_IsDirty(
935 IPersistStream* iface)
937 OLEPictureImpl *This = impl_from_IPersistStream(iface);
938 FIXME("(%p),stub!\n",This);
939 return E_NOTIMPL;
942 #ifdef SONAME_LIBJPEG
944 static void *libjpeg_handle;
945 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
946 MAKE_FUNCPTR(jpeg_std_error);
947 MAKE_FUNCPTR(jpeg_CreateDecompress);
948 MAKE_FUNCPTR(jpeg_read_header);
949 MAKE_FUNCPTR(jpeg_start_decompress);
950 MAKE_FUNCPTR(jpeg_read_scanlines);
951 MAKE_FUNCPTR(jpeg_finish_decompress);
952 MAKE_FUNCPTR(jpeg_destroy_decompress);
953 #undef MAKE_FUNCPTR
955 static void *load_libjpeg(void)
957 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
959 #define LOAD_FUNCPTR(f) \
960 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
961 libjpeg_handle = NULL; \
962 return NULL; \
965 LOAD_FUNCPTR(jpeg_std_error);
966 LOAD_FUNCPTR(jpeg_CreateDecompress);
967 LOAD_FUNCPTR(jpeg_read_header);
968 LOAD_FUNCPTR(jpeg_start_decompress);
969 LOAD_FUNCPTR(jpeg_read_scanlines);
970 LOAD_FUNCPTR(jpeg_finish_decompress);
971 LOAD_FUNCPTR(jpeg_destroy_decompress);
972 #undef LOAD_FUNCPTR
974 return libjpeg_handle;
977 /* for the jpeg decompressor source manager. */
978 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
980 static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
981 ERR("(), should not get here.\n");
982 return FALSE;
985 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
986 TRACE("Skipping %ld bytes...\n", num_bytes);
987 cinfo->src->next_input_byte += num_bytes;
988 cinfo->src->bytes_in_buffer -= num_bytes;
991 static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
992 ERR("(desired=%d), should not get here.\n",desired);
993 return FALSE;
995 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
996 #endif /* SONAME_LIBJPEG */
998 struct gifdata {
999 unsigned char *data;
1000 unsigned int curoff;
1001 unsigned int len;
1004 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1005 struct gifdata *gd = (struct gifdata*)gif->UserData;
1007 if (len+gd->curoff > gd->len) {
1008 FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1009 len = gd->len - gd->curoff;
1011 memcpy(data, gd->data+gd->curoff, len);
1012 gd->curoff += len;
1013 return len;
1017 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1019 struct gifdata gd;
1020 GifFileType *gif;
1021 BITMAPINFO *bmi;
1022 HDC hdcref;
1023 LPBYTE bytes;
1024 int i,j,ret;
1025 GifImageDesc *gid;
1026 SavedImage *si;
1027 ColorMapObject *cm;
1028 int transparent = -1;
1029 ExtensionBlock *eb;
1030 int padding;
1032 gd.data = xbuf;
1033 gd.curoff = 0;
1034 gd.len = xread;
1035 gif = DGifOpen((void*)&gd, _gif_inputfunc);
1036 ret = DGifSlurp(gif);
1037 if (ret == GIF_ERROR) {
1038 FIXME("Failed reading GIF using libgif.\n");
1039 return E_FAIL;
1041 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1042 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1043 TRACE("imgcnt %d\n", gif->ImageCount);
1044 if (gif->ImageCount<1) {
1045 FIXME("GIF stream does not have images inside?\n");
1046 return E_FAIL;
1048 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1049 gif->Image.Width, gif->Image.Height,
1050 gif->Image.Left, gif->Image.Top,
1051 gif->Image.Interlace
1053 /* */
1054 padding = (gif->SWidth+3) & ~3;
1055 si = gif->SavedImages+0;
1056 gid = &(si->ImageDesc);
1057 cm = gid->ColorMap;
1058 if (!cm) cm = gif->SColorMap;
1059 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1060 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1062 /* look for the transparent color extension */
1063 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1064 eb = si->ExtensionBlocks + i;
1065 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1066 if ((eb->Bytes[0] & 1) == 1) {
1067 transparent = (unsigned char)eb->Bytes[3];
1072 for (i = 0; i < cm->ColorCount; i++) {
1073 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1074 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1075 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1076 if (i == transparent) {
1077 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1078 bmi->bmiColors[i].rgbGreen,
1079 bmi->bmiColors[i].rgbBlue);
1083 /* Map to in picture coordinates */
1084 for (i = 0, j = 0; i < gid->Height; i++) {
1085 if (gif->Image.Interlace) {
1086 memcpy(
1087 bytes + (gid->Top + j) * padding + gid->Left,
1088 si->RasterBits + i * gid->Width,
1089 gid->Width);
1091 /* Lower bits of interlaced counter encode current interlace */
1092 if (j & 1) j += 2; /* Currently filling odd rows */
1093 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1094 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1096 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1097 /* End of current interlace, go to next interlace */
1098 if (j & 2) j = 1; /* Next iteration fills odd rows */
1099 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1100 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1102 } else {
1103 memcpy(
1104 bytes + (gid->Top + i) * padding + gid->Left,
1105 si->RasterBits + i * gid->Width,
1106 gid->Width);
1110 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1111 bmi->bmiHeader.biWidth = gif->SWidth;
1112 bmi->bmiHeader.biHeight = -gif->SHeight;
1113 bmi->bmiHeader.biPlanes = 1;
1114 bmi->bmiHeader.biBitCount = 8;
1115 bmi->bmiHeader.biCompression = BI_RGB;
1116 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1117 bmi->bmiHeader.biXPelsPerMeter = 0;
1118 bmi->bmiHeader.biYPelsPerMeter = 0;
1119 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1120 bmi->bmiHeader.biClrImportant = 0;
1122 hdcref = GetDC(0);
1123 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1124 hdcref,
1125 &bmi->bmiHeader,
1126 CBM_INIT,
1127 bytes,
1128 bmi,
1129 DIB_RGB_COLORS
1132 if (transparent > -1) {
1133 /* Create the Mask */
1134 HDC hdc = CreateCompatibleDC(0);
1135 HDC hdcMask = CreateCompatibleDC(0);
1136 HBITMAP hOldbitmap;
1137 HBITMAP hOldbitmapmask;
1139 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1140 HBITMAP hTempMask;
1142 This->hbmXor = CreateDIBitmap(
1143 hdcref,
1144 &bmi->bmiHeader,
1145 CBM_INIT,
1146 bytes,
1147 bmi,
1148 DIB_RGB_COLORS
1151 bmi->bmiColors[0].rgbRed = 0;
1152 bmi->bmiColors[0].rgbGreen = 0;
1153 bmi->bmiColors[0].rgbBlue = 0;
1154 bmi->bmiColors[1].rgbRed = 255;
1155 bmi->bmiColors[1].rgbGreen = 255;
1156 bmi->bmiColors[1].rgbBlue = 255;
1158 bmi->bmiHeader.biBitCount = 1;
1159 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1160 bmi->bmiHeader.biClrUsed = 2;
1162 for (i = 0; i < gif->SHeight; i++) {
1163 unsigned char * colorPointer = bytes + padding * i;
1164 unsigned char * monoPointer = bytes + monopadding * i;
1165 for (j = 0; j < gif->SWidth; j++) {
1166 unsigned char pixel = colorPointer[j];
1167 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1168 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1171 hdcref = GetDC(0);
1172 hTempMask = CreateDIBitmap(
1173 hdcref,
1174 &bmi->bmiHeader,
1175 CBM_INIT,
1176 bytes,
1177 bmi,
1178 DIB_RGB_COLORS
1180 DeleteDC(hdcref);
1182 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1183 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1184 hOldbitmap = SelectObject(hdc, hTempMask);
1185 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1187 SetBkColor(hdc, RGB(255, 255, 255));
1188 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1190 /* We no longer need the original bitmap, so we apply the first
1191 transformation with the mask to speed up the rendering */
1192 SelectObject(hdc, This->hbmXor);
1193 SetBkColor(hdc, RGB(0,0,0));
1194 SetTextColor(hdc, RGB(255,255,255));
1195 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1196 hdcMask, 0, 0, SRCAND);
1198 SelectObject(hdc, hOldbitmap);
1199 SelectObject(hdcMask, hOldbitmapmask);
1200 DeleteDC(hdcMask);
1201 DeleteDC(hdc);
1202 DeleteObject(hTempMask);
1205 DeleteDC(hdcref);
1206 This->desc.picType = PICTYPE_BITMAP;
1207 OLEPictureImpl_SetBitmap(This);
1208 DGifCloseFile(gif);
1209 HeapFree(GetProcessHeap(),0,bytes);
1210 return S_OK;
1213 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1215 #ifdef SONAME_LIBJPEG
1216 struct jpeg_decompress_struct jd;
1217 struct jpeg_error_mgr jerr;
1218 int ret;
1219 JDIMENSION x;
1220 JSAMPROW samprow,oldsamprow;
1221 BITMAPINFOHEADER bmi;
1222 LPBYTE bits;
1223 HDC hdcref;
1224 struct jpeg_source_mgr xjsm;
1225 LPBYTE oldbits;
1226 unsigned int i;
1228 if(!libjpeg_handle) {
1229 if(!load_libjpeg()) {
1230 FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1231 return E_FAIL;
1235 /* This is basically so we can use in-memory data for jpeg decompression.
1236 * We need to have all the functions.
1238 xjsm.next_input_byte = xbuf;
1239 xjsm.bytes_in_buffer = xread;
1240 xjsm.init_source = _jpeg_init_source;
1241 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1242 xjsm.skip_input_data = _jpeg_skip_input_data;
1243 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1244 xjsm.term_source = _jpeg_term_source;
1246 jd.err = pjpeg_std_error(&jerr);
1247 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1248 * jpeg_create_decompress(&jd); */
1249 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct));
1250 jd.src = &xjsm;
1251 ret=pjpeg_read_header(&jd,TRUE);
1252 jd.out_color_space = JCS_RGB;
1253 pjpeg_start_decompress(&jd);
1254 if (ret != JPEG_HEADER_OK) {
1255 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1256 HeapFree(GetProcessHeap(),0,xbuf);
1257 return E_FAIL;
1260 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1261 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1262 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1264 oldbits = bits;
1265 oldsamprow = samprow;
1266 while ( jd.output_scanline<jd.output_height ) {
1267 x = pjpeg_read_scanlines(&jd,&samprow,1);
1268 if (x != 1) {
1269 FIXME("failed to read current scanline?\n");
1270 break;
1272 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1273 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1274 *(bits++) = *(samprow+2);
1275 *(bits++) = *(samprow+1);
1276 *(bits++) = *(samprow);
1278 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1279 samprow = oldsamprow;
1281 bits = oldbits;
1283 bmi.biSize = sizeof(bmi);
1284 bmi.biWidth = jd.output_width;
1285 bmi.biHeight = -jd.output_height;
1286 bmi.biPlanes = 1;
1287 bmi.biBitCount = jd.output_components<<3;
1288 bmi.biCompression = BI_RGB;
1289 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1290 bmi.biXPelsPerMeter = 0;
1291 bmi.biYPelsPerMeter = 0;
1292 bmi.biClrUsed = 0;
1293 bmi.biClrImportant = 0;
1295 HeapFree(GetProcessHeap(),0,samprow);
1296 pjpeg_finish_decompress(&jd);
1297 pjpeg_destroy_decompress(&jd);
1298 hdcref = GetDC(0);
1299 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1300 hdcref,
1301 &bmi,
1302 CBM_INIT,
1303 bits,
1304 (BITMAPINFO*)&bmi,
1305 DIB_RGB_COLORS
1307 DeleteDC(hdcref);
1308 This->desc.picType = PICTYPE_BITMAP;
1309 OLEPictureImpl_SetBitmap(This);
1310 HeapFree(GetProcessHeap(),0,bits);
1311 return S_OK;
1312 #else
1313 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1314 return E_FAIL;
1315 #endif
1318 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1320 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1321 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1322 HDC hdcref;
1324 /* Does not matter whether this is a coreheader or not, we only use
1325 * components which are in both
1327 hdcref = GetDC(0);
1328 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1329 hdcref,
1330 &(bi->bmiHeader),
1331 CBM_INIT,
1332 xbuf+bfh->bfOffBits,
1334 DIB_RGB_COLORS
1336 DeleteDC(hdcref);
1337 This->desc.picType = PICTYPE_BITMAP;
1338 OLEPictureImpl_SetBitmap(This);
1339 return S_OK;
1342 /*****************************************************
1343 * start of PNG-specific code
1344 * currently only supports colortype PNG_COLOR_TYPE_RGB
1346 #ifdef SONAME_LIBPNG
1347 typedef struct{
1348 ULONG position;
1349 ULONG size;
1350 BYTE * buff;
1351 } png_io;
1353 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1354 png_size_t length)
1356 png_io * io_ptr = png_ptr->io_ptr;
1358 if(length + io_ptr->position > io_ptr->size){
1359 length = io_ptr->size - io_ptr->position;
1362 memcpy(data, io_ptr->buff + io_ptr->position, length);
1364 io_ptr->position += length;
1367 static void *libpng_handle;
1368 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1369 MAKE_FUNCPTR(png_create_read_struct);
1370 MAKE_FUNCPTR(png_create_info_struct);
1371 MAKE_FUNCPTR(png_set_read_fn);
1372 MAKE_FUNCPTR(png_read_info);
1373 MAKE_FUNCPTR(png_read_image);
1374 MAKE_FUNCPTR(png_get_rowbytes);
1375 MAKE_FUNCPTR(png_set_bgr);
1376 MAKE_FUNCPTR(png_destroy_read_struct);
1377 MAKE_FUNCPTR(png_set_palette_to_rgb);
1378 MAKE_FUNCPTR(png_read_update_info);
1379 MAKE_FUNCPTR(png_get_tRNS);
1380 MAKE_FUNCPTR(png_get_PLTE);
1381 MAKE_FUNCPTR(png_set_expand);
1382 #undef MAKE_FUNCPTR
1384 static void *load_libpng(void)
1386 if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1388 #define LOAD_FUNCPTR(f) \
1389 if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1390 libpng_handle = NULL; \
1391 return NULL; \
1393 LOAD_FUNCPTR(png_create_read_struct);
1394 LOAD_FUNCPTR(png_create_info_struct);
1395 LOAD_FUNCPTR(png_set_read_fn);
1396 LOAD_FUNCPTR(png_read_info);
1397 LOAD_FUNCPTR(png_read_image);
1398 LOAD_FUNCPTR(png_get_rowbytes);
1399 LOAD_FUNCPTR(png_set_bgr);
1400 LOAD_FUNCPTR(png_destroy_read_struct);
1401 LOAD_FUNCPTR(png_set_palette_to_rgb);
1402 LOAD_FUNCPTR(png_read_update_info);
1403 LOAD_FUNCPTR(png_get_tRNS);
1404 LOAD_FUNCPTR(png_get_PLTE);
1405 LOAD_FUNCPTR(png_set_expand);
1407 #undef LOAD_FUNCPTR
1409 return libpng_handle;
1411 #endif /* SONAME_LIBPNG */
1413 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1415 #ifdef SONAME_LIBPNG
1416 png_io io;
1417 png_structp png_ptr = NULL;
1418 png_infop info_ptr = NULL;
1419 INT row, rowsize, height, width, num_trans, i, j;
1420 png_bytep* row_pointers = NULL;
1421 png_bytep pngdata = NULL;
1422 BITMAPINFOHEADER bmi;
1423 HDC hdcref = NULL, hdcXor, hdcMask;
1424 HRESULT ret;
1425 BOOL transparency;
1426 png_bytep trans;
1427 png_color_16p trans_values;
1428 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1429 HBITMAP hbmoldXor, hbmoldMask, temp;
1431 if(!libpng_handle) {
1432 if(!load_libpng()) {
1433 ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1434 return E_FAIL;
1438 io.size = xread;
1439 io.position = 0;
1440 io.buff = xbuf;
1442 png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1443 NULL, NULL, NULL);
1445 if(setjmp(png_jmpbuf(png_ptr))){
1446 TRACE("Error in libpng\n");
1447 ret = E_FAIL;
1448 goto end;
1451 info_ptr = ppng_create_info_struct(png_ptr);
1452 ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1453 ppng_read_info(png_ptr, info_ptr);
1455 if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1456 png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1457 png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1458 FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1459 ret = E_FAIL;
1460 goto end;
1463 transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1464 == PNG_INFO_tRNS);
1466 /* sets format from anything to RGBA */
1467 ppng_set_expand(png_ptr);
1468 /* sets format to BGRA */
1469 ppng_set_bgr(png_ptr);
1471 ppng_read_update_info(png_ptr, info_ptr);
1473 rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1474 /* align rowsize to 4-byte boundary */
1475 rowsize = (rowsize + 3) & ~3;
1476 height = info_ptr->height;
1477 width = info_ptr->width;
1479 pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1480 row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1482 if(!pngdata || !row_pointers){
1483 ret = E_FAIL;
1484 goto end;
1487 for (row = 0; row < height; row++){
1488 row_pointers[row] = pngdata + row * rowsize;
1491 ppng_read_image(png_ptr, row_pointers);
1493 bmi.biSize = sizeof(bmi);
1494 bmi.biWidth = width;
1495 bmi.biHeight = -height;
1496 bmi.biPlanes = 1;
1497 bmi.biBitCount = info_ptr->channels * 8;
1498 bmi.biCompression = BI_RGB;
1499 bmi.biSizeImage = height * rowsize;
1500 bmi.biXPelsPerMeter = 0;
1501 bmi.biYPelsPerMeter = 0;
1502 bmi.biClrUsed = 0;
1503 bmi.biClrImportant = 0;
1505 hdcref = GetDC(0);
1506 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1507 hdcref,
1508 &bmi,
1509 CBM_INIT,
1510 pngdata,
1511 (BITMAPINFO*)&bmi,
1512 DIB_RGB_COLORS
1515 /* only fully-transparent alpha is handled */
1516 if((info_ptr->channels != 4) || !transparency){
1517 ReleaseDC(0, hdcref);
1518 goto succ;
1521 This->hbmXor = CreateDIBitmap(
1522 hdcref,
1523 &bmi,
1524 CBM_INIT,
1525 pngdata,
1526 (BITMAPINFO*)&bmi,
1527 DIB_RGB_COLORS
1530 /* set transparent pixels to black, all others to white */
1531 for(i = 0; i < height; i++){
1532 for(j = 3; j < rowsize; j += 4){
1533 if(row_pointers[i][j] == 0)
1534 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1535 else
1536 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1540 temp = CreateDIBitmap(
1541 hdcref,
1542 &bmi,
1543 CBM_INIT,
1544 pngdata,
1545 (BITMAPINFO*)&bmi,
1546 DIB_RGB_COLORS
1549 ReleaseDC(0, hdcref);
1551 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1552 hdcXor = CreateCompatibleDC(NULL);
1553 hdcMask = CreateCompatibleDC(NULL);
1555 hbmoldXor = SelectObject(hdcXor,temp);
1556 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1557 SetBkColor(hdcXor,black);
1558 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1560 SelectObject(hdcXor,This->hbmXor);
1561 DeleteObject(temp);
1563 SetTextColor(hdcXor,white);
1564 SetBkColor(hdcXor,black);
1565 BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1567 SelectObject(hdcXor,hbmoldXor);
1568 SelectObject(hdcMask,hbmoldMask);
1570 DeleteDC(hdcXor);
1571 DeleteDC(hdcMask);
1573 succ:
1574 This->desc.picType = PICTYPE_BITMAP;
1575 OLEPictureImpl_SetBitmap(This);
1576 ret = S_OK;
1578 end:
1579 if(png_ptr)
1580 ppng_destroy_read_struct(&png_ptr,
1581 (info_ptr ? &info_ptr : (png_infopp) NULL),
1582 (png_infopp)NULL);
1583 HeapFree(GetProcessHeap(), 0, row_pointers);
1584 HeapFree(GetProcessHeap(), 0, pngdata);
1585 return ret;
1586 #else /* SONAME_LIBPNG */
1587 ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1588 return E_FAIL;
1589 #endif
1592 /*****************************************************
1593 * start of Icon-specific code
1596 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1598 HICON hicon;
1599 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1600 HDC hdcRef;
1601 int i;
1604 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1605 FIXME("icon.idType=%d\n",cifd->idType);
1606 FIXME("icon.idCount=%d\n",cifd->idCount);
1608 for (i=0;i<cifd->idCount;i++) {
1609 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1610 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1611 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1612 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1613 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1614 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1615 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1616 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1619 i=0;
1620 /* If we have more than one icon, try to find the best.
1621 * this currently means '32 pixel wide'.
1623 if (cifd->idCount!=1) {
1624 for (i=0;i<cifd->idCount;i++) {
1625 if (cifd->idEntries[i].bWidth == 32)
1626 break;
1628 if (i==cifd->idCount) i=0;
1631 hicon = CreateIconFromResourceEx(
1632 xbuf+cifd->idEntries[i].dwDIBOffset,
1633 cifd->idEntries[i].dwDIBSize,
1634 TRUE, /* is icon */
1635 0x00030000,
1636 cifd->idEntries[i].bWidth,
1637 cifd->idEntries[i].bHeight,
1640 if (!hicon) {
1641 FIXME("CreateIcon failed.\n");
1642 return E_FAIL;
1643 } else {
1644 This->desc.picType = PICTYPE_ICON;
1645 This->desc.u.icon.hicon = hicon;
1646 This->origWidth = cifd->idEntries[i].bWidth;
1647 This->origHeight = cifd->idEntries[i].bHeight;
1648 hdcRef = CreateCompatibleDC(0);
1649 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1650 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1651 DeleteDC(hdcRef);
1652 return S_OK;
1656 static HRESULT OLEPictureImpl_LoadMetafile(OLEPictureImpl *This,
1657 const BYTE *data, ULONG size)
1659 HMETAFILE hmf;
1660 HENHMETAFILE hemf;
1662 /* SetMetaFileBitsEx performs data check on its own */
1663 hmf = SetMetaFileBitsEx(size, data);
1664 if (hmf)
1666 This->desc.picType = PICTYPE_METAFILE;
1667 This->desc.u.wmf.hmeta = hmf;
1668 This->desc.u.wmf.xExt = 0;
1669 This->desc.u.wmf.yExt = 0;
1671 This->origWidth = 0;
1672 This->origHeight = 0;
1673 This->himetricWidth = 0;
1674 This->himetricHeight = 0;
1676 return S_OK;
1679 hemf = SetEnhMetaFileBits(size, data);
1680 if (!hemf) return E_FAIL;
1682 This->desc.picType = PICTYPE_ENHMETAFILE;
1683 This->desc.u.emf.hemf = hemf;
1685 This->origWidth = 0;
1686 This->origHeight = 0;
1687 This->himetricWidth = 0;
1688 This->himetricHeight = 0;
1690 return S_OK;
1693 /************************************************************************
1694 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1696 * Loads the binary data from the IStream. Starts at current position.
1697 * There appears to be an 2 DWORD header:
1698 * DWORD magic;
1699 * DWORD len;
1701 * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1703 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1704 HRESULT hr = E_FAIL;
1705 BOOL headerisdata = FALSE;
1706 BOOL statfailed = FALSE;
1707 ULONG xread, toread;
1708 ULONG headerread;
1709 BYTE *xbuf;
1710 DWORD header[2];
1711 WORD magic;
1712 STATSTG statstg;
1713 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1715 TRACE("(%p,%p)\n",This,pStm);
1717 /****************************************************************************************
1718 * Part 1: Load the data
1720 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1721 * out whether we do.
1723 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1724 * compound file. This may explain most, if not all, of the cases of "no
1725 * header", and the header validation should take this into account.
1726 * At least in Visual Basic 6, resource streams, valid headers are
1727 * header[0] == "lt\0\0",
1728 * header[1] == length_of_stream.
1730 * Also handle streams where we do not have a working "Stat" method by
1731 * reading all data until the end of the stream.
1733 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1734 if (hr) {
1735 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1736 statfailed = TRUE;
1737 /* we will read at least 8 byte ... just right below */
1738 statstg.cbSize.QuadPart = 8;
1741 toread = 0;
1742 headerread = 0;
1743 headerisdata = FALSE;
1744 do {
1745 hr=IStream_Read(pStm,header,8,&xread);
1746 if (hr || xread!=8) {
1747 FIXME("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1748 return hr;
1750 headerread += xread;
1751 xread = 0;
1753 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1754 if (toread != 0 && toread != header[1])
1755 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1756 toread, header[1]);
1757 toread = header[1];
1758 if (toread == 0) break;
1759 } else {
1760 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1761 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1762 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1763 (header[0] == EMR_HEADER) || /* EMF header */
1764 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1765 (header[1]==0)
1766 ) {/* Found start of bitmap data */
1767 headerisdata = TRUE;
1768 if (toread == 0)
1769 toread = statstg.cbSize.QuadPart-8;
1770 else toread -= 8;
1771 xread = 8;
1772 } else {
1773 FIXME("Unknown stream header magic: %08x\n", header[0]);
1774 toread = header[1];
1777 } while (!headerisdata);
1779 if (statfailed) { /* we don't know the size ... read all we get */
1780 int sizeinc = 4096;
1781 int origsize = sizeinc;
1782 ULONG nread = 42;
1784 TRACE("Reading all data from stream.\n");
1785 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1786 if (headerisdata)
1787 memcpy (xbuf, &header, 8);
1788 while (1) {
1789 while (xread < origsize) {
1790 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1791 xread+=nread;
1792 if (hr || !nread)
1793 break;
1795 if (!nread || hr) /* done, or error */
1796 break;
1797 if (xread == origsize) {
1798 origsize += sizeinc;
1799 sizeinc = 2*sizeinc; /* exponential increase */
1800 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1803 if (hr)
1804 TRACE("hr in no-stat loader case is %08x\n", hr);
1805 TRACE("loaded %d bytes.\n", xread);
1806 This->datalen = xread;
1807 This->data = xbuf;
1808 } else {
1809 This->datalen = toread+(headerisdata?8:0);
1810 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1812 if (headerisdata)
1813 memcpy (xbuf, &header, 8);
1815 while (xread < This->datalen) {
1816 ULONG nread;
1817 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1818 xread+=nread;
1819 if (hr || !nread)
1820 break;
1822 if (xread != This->datalen)
1823 FIXME("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1825 if (This->datalen == 0) { /* Marks the "NONE" picture */
1826 This->desc.picType = PICTYPE_NONE;
1827 return S_OK;
1831 /****************************************************************************************
1832 * Part 2: Process the loaded data
1835 magic = xbuf[0] + (xbuf[1]<<8);
1836 This->loadtime_format = magic;
1838 switch (magic) {
1839 case 0x4947: /* GIF */
1840 hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1841 break;
1842 case 0xd8ff: /* JPEG */
1843 hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1844 break;
1845 case 0x4d42: /* Bitmap */
1846 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1847 break;
1848 case 0x5089: /* PNG */
1849 hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1850 break;
1851 case 0x0000: { /* ICON , first word is dwReserved */
1852 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1853 break;
1855 default:
1857 unsigned int i;
1859 /* let's see if it's a metafile */
1860 hr = OLEPictureImpl_LoadMetafile(This, xbuf, xread);
1861 if (hr == S_OK) break;
1863 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1864 hr=E_FAIL;
1865 for (i=0;i<xread+8;i++) {
1866 if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
1867 else MESSAGE("%02x ",xbuf[i-8]);
1868 if (i % 10 == 9) MESSAGE("\n");
1870 MESSAGE("\n");
1871 break;
1874 This->bIsDirty = FALSE;
1876 /* FIXME: this notify is not really documented */
1877 if (hr==S_OK)
1878 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1879 return hr;
1882 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1884 int iSuccess = 0;
1885 HDC hDC;
1886 BITMAPINFO * pInfoBitmap;
1887 int iNumPaletteEntries;
1888 unsigned char * pPixelData;
1889 BITMAPFILEHEADER * pFileHeader;
1890 BITMAPINFO * pInfoHeader;
1892 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1893 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1895 /* Find out bitmap size and padded length */
1896 hDC = GetDC(0);
1897 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1898 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1900 /* Fetch bitmap palette & pixel data */
1902 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1903 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1905 /* Calculate the total length required for the BMP data */
1906 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1907 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1908 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1909 } else {
1910 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1911 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1912 else
1913 iNumPaletteEntries = 0;
1915 *pLength =
1916 sizeof(BITMAPFILEHEADER) +
1917 sizeof(BITMAPINFOHEADER) +
1918 iNumPaletteEntries * sizeof(RGBQUAD) +
1919 pInfoBitmap->bmiHeader.biSizeImage;
1920 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1922 /* Fill the BITMAPFILEHEADER */
1923 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1924 pFileHeader->bfType = 0x4d42;
1925 pFileHeader->bfSize = *pLength;
1926 pFileHeader->bfOffBits =
1927 sizeof(BITMAPFILEHEADER) +
1928 sizeof(BITMAPINFOHEADER) +
1929 iNumPaletteEntries * sizeof(RGBQUAD);
1931 /* Fill the BITMAPINFOHEADER and the palette data */
1932 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1933 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1934 memcpy(
1935 (unsigned char *)(*ppBuffer) +
1936 sizeof(BITMAPFILEHEADER) +
1937 sizeof(BITMAPINFOHEADER) +
1938 iNumPaletteEntries * sizeof(RGBQUAD),
1939 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1940 iSuccess = 1;
1942 HeapFree(GetProcessHeap(), 0, pPixelData);
1943 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1944 return iSuccess;
1947 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1949 ICONINFO infoIcon;
1950 int iSuccess = 0;
1952 *ppBuffer = NULL; *pLength = 0;
1953 if (GetIconInfo(hIcon, &infoIcon)) {
1954 HDC hDC;
1955 BITMAPINFO * pInfoBitmap;
1956 unsigned char * pIconData = NULL;
1957 unsigned int iDataSize = 0;
1959 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1961 /* Find out icon size */
1962 hDC = GetDC(0);
1963 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1964 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1965 if (1) {
1966 /* Auxiliary pointers */
1967 CURSORICONFILEDIR * pIconDir;
1968 CURSORICONFILEDIRENTRY * pIconEntry;
1969 BITMAPINFOHEADER * pIconBitmapHeader;
1970 unsigned int iOffsetPalette;
1971 unsigned int iOffsetColorData;
1972 unsigned int iOffsetMaskData;
1974 unsigned int iLengthScanLineColor;
1975 unsigned int iLengthScanLineMask;
1976 unsigned int iNumEntriesPalette;
1978 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1979 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
1981 FIXME("DEBUG: bitmap size is %d x %d\n",
1982 pInfoBitmap->bmiHeader.biWidth,
1983 pInfoBitmap->bmiHeader.biHeight);
1984 FIXME("DEBUG: bitmap bpp is %d\n",
1985 pInfoBitmap->bmiHeader.biBitCount);
1986 FIXME("DEBUG: bitmap nplanes is %d\n",
1987 pInfoBitmap->bmiHeader.biPlanes);
1988 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1989 pInfoBitmap->bmiHeader.biSizeImage);
1991 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1992 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1993 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1995 /* Fill out the CURSORICONFILEDIR */
1996 pIconDir = (CURSORICONFILEDIR *)pIconData;
1997 pIconDir->idType = 1;
1998 pIconDir->idCount = 1;
2000 /* Fill out the CURSORICONFILEDIRENTRY */
2001 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2002 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2003 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2004 pIconEntry->bColorCount =
2005 (pInfoBitmap->bmiHeader.biBitCount < 8)
2006 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2007 : 0;
2008 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2009 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2010 pIconEntry->dwDIBSize = 0;
2011 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2013 /* Fill out the BITMAPINFOHEADER */
2014 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2015 memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
2017 /* Find out whether a palette exists for the bitmap */
2018 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2019 || (pInfoBitmap->bmiHeader.biBitCount == 24)
2020 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2021 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2022 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
2023 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2024 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2025 iNumEntriesPalette = 3;
2026 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2027 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2028 } else {
2029 iNumEntriesPalette = 0;
2032 /* Add bitmap size and header size to icon data size. */
2033 iOffsetPalette = iDataSize;
2034 iDataSize += iNumEntriesPalette * sizeof(DWORD);
2035 iOffsetColorData = iDataSize;
2036 iDataSize += pIconBitmapHeader->biSizeImage;
2037 iOffsetMaskData = iDataSize;
2038 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2039 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2040 pIconBitmapHeader->biHeight *= 2;
2041 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2042 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2043 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2044 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2046 /* Get the actual bitmap data from the icon bitmap */
2047 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2048 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2049 if (iNumEntriesPalette > 0) {
2050 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2051 iNumEntriesPalette * sizeof(RGBQUAD));
2054 /* Reset all values so that GetDIBits call succeeds */
2055 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2056 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2057 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2059 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2060 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2061 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2063 printf("ERROR: unable to get bitmap mask (error %u)\n",
2064 GetLastError());
2068 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2069 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2071 /* Write out everything produced so far to the stream */
2072 *ppBuffer = pIconData; *pLength = iDataSize;
2073 iSuccess = 1;
2074 } else {
2076 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2077 GetLastError());
2081 Remarks (from MSDN entry on GetIconInfo):
2083 GetIconInfo creates bitmaps for the hbmMask and hbmColor
2084 members of ICONINFO. The calling application must manage
2085 these bitmaps and delete them when they are no longer
2086 necessary.
2088 if (hDC) ReleaseDC(0, hDC);
2089 DeleteObject(infoIcon.hbmMask);
2090 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2091 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2092 } else {
2093 printf("ERROR: Unable to get icon information (error %u)\n",
2094 GetLastError());
2096 return iSuccess;
2099 static HRESULT WINAPI OLEPictureImpl_Save(
2100 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2102 HRESULT hResult = E_NOTIMPL;
2103 void * pIconData;
2104 unsigned int iDataSize;
2105 ULONG dummy;
2106 int iSerializeResult = 0;
2107 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2109 TRACE("%p %p %d\n", This, pStm, fClearDirty);
2111 switch (This->desc.picType) {
2112 case PICTYPE_ICON:
2113 if (This->bIsDirty || !This->data) {
2114 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2115 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2116 hResult = E_FAIL;
2117 break;
2119 HeapFree(GetProcessHeap(), 0, This->data);
2120 This->data = pIconData;
2121 This->datalen = iDataSize;
2123 if (This->loadtime_magic != 0xdeadbeef) {
2124 DWORD header[2];
2126 header[0] = This->loadtime_magic;
2127 header[1] = This->datalen;
2128 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2130 IStream_Write(pStm, This->data, This->datalen, &dummy);
2132 hResult = S_OK;
2133 break;
2134 case PICTYPE_BITMAP:
2135 if (This->bIsDirty) {
2136 switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) {
2137 case 0x4d42:
2138 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2139 break;
2140 case 0xd8ff:
2141 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2142 break;
2143 case 0x4947:
2144 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2145 break;
2146 case 0x5089:
2147 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2148 break;
2149 default:
2150 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2151 break;
2153 if (iSerializeResult) {
2155 if (This->loadtime_magic != 0xdeadbeef) {
2157 if (1) {
2158 DWORD header[2];
2160 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2161 header[1] = iDataSize;
2162 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2164 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2166 HeapFree(GetProcessHeap(), 0, This->data);
2167 This->data = pIconData;
2168 This->datalen = iDataSize;
2169 hResult = S_OK;
2171 } else {
2173 if (This->loadtime_magic != 0xdeadbeef) {
2175 if (1) {
2176 DWORD header[2];
2178 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2179 header[1] = This->datalen;
2180 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2182 IStream_Write(pStm, This->data, This->datalen, &dummy);
2183 hResult = S_OK;
2185 break;
2186 case PICTYPE_METAFILE:
2187 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2188 break;
2189 case PICTYPE_ENHMETAFILE:
2190 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2191 break;
2192 default:
2193 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2194 break;
2196 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2197 return hResult;
2200 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2201 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2203 OLEPictureImpl *This = impl_from_IPersistStream(iface);
2204 FIXME("(%p,%p),stub!\n",This,pcbSize);
2205 return E_NOTIMPL;
2209 /************************************************************************
2210 * IDispatch
2213 /************************************************************************
2214 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2216 * See Windows documentation for more details on IUnknown methods.
2218 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2219 IDispatch* iface,
2220 REFIID riid,
2221 VOID** ppvoid)
2223 OLEPictureImpl *This = impl_from_IDispatch(iface);
2225 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2228 /************************************************************************
2229 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2231 * See Windows documentation for more details on IUnknown methods.
2233 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2234 IDispatch* iface)
2236 OLEPictureImpl *This = impl_from_IDispatch(iface);
2238 return IPicture_AddRef((IPicture *)This);
2241 /************************************************************************
2242 * OLEPictureImpl_IDispatch_Release (IUnknown)
2244 * See Windows documentation for more details on IUnknown methods.
2246 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2247 IDispatch* iface)
2249 OLEPictureImpl *This = impl_from_IDispatch(iface);
2251 return IPicture_Release((IPicture *)This);
2254 /************************************************************************
2255 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2257 * See Windows documentation for more details on IDispatch methods.
2259 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2260 IDispatch* iface,
2261 unsigned int* pctinfo)
2263 TRACE("(%p)\n", pctinfo);
2265 *pctinfo = 1;
2267 return S_OK;
2270 /************************************************************************
2271 * OLEPictureImpl_GetTypeInfo (IDispatch)
2273 * See Windows documentation for more details on IDispatch methods.
2275 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2276 IDispatch* iface,
2277 UINT iTInfo,
2278 LCID lcid,
2279 ITypeInfo** ppTInfo)
2281 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2282 ITypeLib *tl;
2283 HRESULT hres;
2285 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2287 if (iTInfo != 0)
2288 return E_FAIL;
2290 hres = LoadTypeLib(stdole2tlb, &tl);
2291 if (FAILED(hres))
2293 ERR("Could not load stdole2.tlb\n");
2294 return hres;
2297 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2298 if (FAILED(hres))
2299 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2301 return hres;
2304 /************************************************************************
2305 * OLEPictureImpl_GetIDsOfNames (IDispatch)
2307 * See Windows documentation for more details on IDispatch methods.
2309 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2310 IDispatch* iface,
2311 REFIID riid,
2312 LPOLESTR* rgszNames,
2313 UINT cNames,
2314 LCID lcid,
2315 DISPID* rgDispId)
2317 FIXME("():Stub\n");
2319 return E_NOTIMPL;
2322 /************************************************************************
2323 * OLEPictureImpl_Invoke (IDispatch)
2325 * See Windows documentation for more details on IDispatch methods.
2327 static HRESULT WINAPI OLEPictureImpl_Invoke(
2328 IDispatch* iface,
2329 DISPID dispIdMember,
2330 REFIID riid,
2331 LCID lcid,
2332 WORD wFlags,
2333 DISPPARAMS* pDispParams,
2334 VARIANT* pVarResult,
2335 EXCEPINFO* pExepInfo,
2336 UINT* puArgErr)
2338 OLEPictureImpl *This = impl_from_IDispatch(iface);
2340 /* validate parameters */
2342 if (!IsEqualIID(riid, &IID_NULL))
2344 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2345 return DISP_E_UNKNOWNNAME;
2348 if (!pDispParams)
2350 ERR("null pDispParams not allowed\n");
2351 return DISP_E_PARAMNOTOPTIONAL;
2354 if (wFlags & DISPATCH_PROPERTYGET)
2356 if (pDispParams->cArgs != 0)
2358 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2359 return DISP_E_BADPARAMCOUNT;
2361 if (!pVarResult)
2363 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2364 return DISP_E_PARAMNOTOPTIONAL;
2367 else if (wFlags & DISPATCH_PROPERTYPUT)
2369 if (pDispParams->cArgs != 1)
2371 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2372 return DISP_E_BADPARAMCOUNT;
2376 switch (dispIdMember)
2378 case DISPID_PICT_HANDLE:
2379 if (wFlags & DISPATCH_PROPERTYGET)
2381 TRACE("DISPID_PICT_HANDLE\n");
2382 V_VT(pVarResult) = VT_I4;
2383 return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2385 break;
2386 case DISPID_PICT_HPAL:
2387 if (wFlags & DISPATCH_PROPERTYGET)
2389 TRACE("DISPID_PICT_HPAL\n");
2390 V_VT(pVarResult) = VT_I4;
2391 return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2393 else if (wFlags & DISPATCH_PROPERTYPUT)
2395 VARIANTARG vararg;
2396 HRESULT hr;
2397 TRACE("DISPID_PICT_HPAL\n");
2399 VariantInit(&vararg);
2400 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2401 if (FAILED(hr))
2402 return hr;
2404 hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2406 VariantClear(&vararg);
2407 return hr;
2409 break;
2410 case DISPID_PICT_TYPE:
2411 if (wFlags & DISPATCH_PROPERTYGET)
2413 TRACE("DISPID_PICT_TYPE\n");
2414 V_VT(pVarResult) = VT_I2;
2415 return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2417 break;
2418 case DISPID_PICT_WIDTH:
2419 if (wFlags & DISPATCH_PROPERTYGET)
2421 TRACE("DISPID_PICT_WIDTH\n");
2422 V_VT(pVarResult) = VT_I4;
2423 return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2425 break;
2426 case DISPID_PICT_HEIGHT:
2427 if (wFlags & DISPATCH_PROPERTYGET)
2429 TRACE("DISPID_PICT_HEIGHT\n");
2430 V_VT(pVarResult) = VT_I4;
2431 return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2433 break;
2436 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2437 return DISP_E_MEMBERNOTFOUND;
2441 static const IPictureVtbl OLEPictureImpl_VTable =
2443 OLEPictureImpl_QueryInterface,
2444 OLEPictureImpl_AddRef,
2445 OLEPictureImpl_Release,
2446 OLEPictureImpl_get_Handle,
2447 OLEPictureImpl_get_hPal,
2448 OLEPictureImpl_get_Type,
2449 OLEPictureImpl_get_Width,
2450 OLEPictureImpl_get_Height,
2451 OLEPictureImpl_Render,
2452 OLEPictureImpl_set_hPal,
2453 OLEPictureImpl_get_CurDC,
2454 OLEPictureImpl_SelectPicture,
2455 OLEPictureImpl_get_KeepOriginalFormat,
2456 OLEPictureImpl_put_KeepOriginalFormat,
2457 OLEPictureImpl_PictureChanged,
2458 OLEPictureImpl_SaveAsFile,
2459 OLEPictureImpl_get_Attributes
2462 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2464 OLEPictureImpl_IDispatch_QueryInterface,
2465 OLEPictureImpl_IDispatch_AddRef,
2466 OLEPictureImpl_IDispatch_Release,
2467 OLEPictureImpl_GetTypeInfoCount,
2468 OLEPictureImpl_GetTypeInfo,
2469 OLEPictureImpl_GetIDsOfNames,
2470 OLEPictureImpl_Invoke
2473 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2475 OLEPictureImpl_IPersistStream_QueryInterface,
2476 OLEPictureImpl_IPersistStream_AddRef,
2477 OLEPictureImpl_IPersistStream_Release,
2478 OLEPictureImpl_GetClassID,
2479 OLEPictureImpl_IsDirty,
2480 OLEPictureImpl_Load,
2481 OLEPictureImpl_Save,
2482 OLEPictureImpl_GetSizeMax
2485 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2487 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2488 OLEPictureImpl_IConnectionPointContainer_AddRef,
2489 OLEPictureImpl_IConnectionPointContainer_Release,
2490 OLEPictureImpl_EnumConnectionPoints,
2491 OLEPictureImpl_FindConnectionPoint
2494 /***********************************************************************
2495 * OleCreatePictureIndirect (OLEAUT32.419)
2497 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2498 BOOL fOwn, LPVOID *ppvObj )
2500 OLEPictureImpl* newPict = NULL;
2501 HRESULT hr = S_OK;
2503 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2506 * Sanity check
2508 if (ppvObj==0)
2509 return E_POINTER;
2511 *ppvObj = NULL;
2514 * Try to construct a new instance of the class.
2516 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2518 if (newPict == NULL)
2519 return E_OUTOFMEMORY;
2522 * Make sure it supports the interface required by the caller.
2524 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2527 * Release the reference obtained in the constructor. If
2528 * the QueryInterface was unsuccessful, it will free the class.
2530 IPicture_Release((IPicture*)newPict);
2532 return hr;
2536 /***********************************************************************
2537 * OleLoadPicture (OLEAUT32.418)
2539 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2540 REFIID riid, LPVOID *ppvObj )
2542 LPPERSISTSTREAM ps;
2543 IPicture *newpic;
2544 HRESULT hr;
2546 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2547 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2549 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2550 if (hr)
2551 return hr;
2552 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2553 if (hr) {
2554 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2555 IPicture_Release(newpic);
2556 *ppvObj = NULL;
2557 return hr;
2559 IPersistStream_Load(ps,lpstream);
2560 IPersistStream_Release(ps);
2561 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2562 if (hr)
2563 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2564 IPicture_Release(newpic);
2565 return hr;
2568 /***********************************************************************
2569 * OleLoadPictureEx (OLEAUT32.401)
2571 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2572 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2574 LPPERSISTSTREAM ps;
2575 IPicture *newpic;
2576 HRESULT hr;
2578 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2579 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2581 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2582 if (hr)
2583 return hr;
2584 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2585 if (hr) {
2586 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2587 IPicture_Release(newpic);
2588 *ppvObj = NULL;
2589 return hr;
2591 IPersistStream_Load(ps,lpstream);
2592 IPersistStream_Release(ps);
2593 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2594 if (hr)
2595 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2596 IPicture_Release(newpic);
2597 return hr;
2600 /***********************************************************************
2601 * OleLoadPicturePath (OLEAUT32.424)
2603 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2604 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2605 LPVOID *ppvRet )
2607 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2608 IPicture *ipicture;
2609 HANDLE hFile;
2610 DWORD dwFileSize;
2611 HGLOBAL hGlobal = NULL;
2612 DWORD dwBytesRead = 0;
2613 IStream *stream;
2614 BOOL bRead;
2615 IPersistStream *pStream;
2616 HRESULT hRes;
2618 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2619 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2620 debugstr_guid(riid), ppvRet);
2622 if (!ppvRet) return E_POINTER;
2624 if (strncmpW(szURLorPath, file, 7) == 0) {
2625 szURLorPath += 7;
2627 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2628 0, NULL);
2629 if (hFile == INVALID_HANDLE_VALUE)
2630 return E_UNEXPECTED;
2632 dwFileSize = GetFileSize(hFile, NULL);
2633 if (dwFileSize != INVALID_FILE_SIZE )
2635 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2636 if ( hGlobal)
2638 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2639 if (!bRead)
2641 GlobalFree(hGlobal);
2642 hGlobal = 0;
2646 CloseHandle(hFile);
2648 if (!hGlobal)
2649 return E_UNEXPECTED;
2651 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2652 if (FAILED(hRes))
2654 GlobalFree(hGlobal);
2655 return hRes;
2657 } else {
2658 IMoniker *pmnk;
2659 IBindCtx *pbc;
2661 hRes = CreateBindCtx(0, &pbc);
2662 if (SUCCEEDED(hRes))
2664 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2665 if (SUCCEEDED(hRes))
2667 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2668 IMoniker_Release(pmnk);
2670 IBindCtx_Release(pbc);
2672 if (FAILED(hRes))
2673 return hRes;
2676 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2677 &IID_IPicture, (LPVOID*)&ipicture);
2678 if (hRes != S_OK) {
2679 IStream_Release(stream);
2680 return hRes;
2683 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2684 if (hRes) {
2685 IStream_Release(stream);
2686 IPicture_Release(ipicture);
2687 return hRes;
2690 hRes = IPersistStream_Load(pStream, stream);
2691 IPersistStream_Release(pStream);
2692 IStream_Release(stream);
2694 if (hRes) {
2695 IPicture_Release(ipicture);
2696 return hRes;
2699 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2700 if (hRes)
2701 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2703 IPicture_Release(ipicture);
2704 return hRes;
2707 /*******************************************************************************
2708 * StdPic ClassFactory
2710 typedef struct
2712 /* IUnknown fields */
2713 const IClassFactoryVtbl *lpVtbl;
2714 LONG ref;
2715 } IClassFactoryImpl;
2717 static HRESULT WINAPI
2718 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2719 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2721 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2722 return E_NOINTERFACE;
2725 static ULONG WINAPI
2726 SPCF_AddRef(LPCLASSFACTORY iface) {
2727 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2728 return InterlockedIncrement(&This->ref);
2731 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2732 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2733 /* static class, won't be freed */
2734 return InterlockedDecrement(&This->ref);
2737 static HRESULT WINAPI SPCF_CreateInstance(
2738 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2740 /* Creates an uninitialized picture */
2741 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2745 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2746 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2747 FIXME("(%p)->(%d),stub!\n",This,dolock);
2748 return S_OK;
2751 static const IClassFactoryVtbl SPCF_Vtbl = {
2752 SPCF_QueryInterface,
2753 SPCF_AddRef,
2754 SPCF_Release,
2755 SPCF_CreateInstance,
2756 SPCF_LockServer
2758 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2760 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }