Added IHlinkTarget interface.
[wine/testsucceed.git] / dlls / oleaut32 / olepicture.c
blobe1e4024031dda1b63f1797444df922e600738300
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 #ifdef HAVE_GIF_LIB_H
52 # include <gif_lib.h>
53 # ifndef SONAME_LIBUNGIF
54 # define SONAME_LIBUNGIF "libungif.so"
55 # endif
56 # ifndef SONAME_LIBGIF
57 # define SONAME_LIBGIF "libgif.so"
58 # endif
59 #endif
61 #define COBJMACROS
62 #define NONAMELESSUNION
63 #define NONAMELESSSTRUCT
65 #include "winerror.h"
66 #include "windef.h"
67 #include "winbase.h"
68 #include "wingdi.h"
69 #include "winuser.h"
70 #include "ole2.h"
71 #include "olectl.h"
72 #include "oleauto.h"
73 #include "connpt.h"
74 #include "urlmon.h"
75 #include "wine/debug.h"
76 #include "wine/unicode.h"
78 #include "wine/wingdi16.h"
80 #ifdef HAVE_JPEGLIB_H
81 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
82 #define XMD_H
83 #define UINT8 JPEG_UINT8
84 #define UINT16 JPEG_UINT16
85 #undef FAR
86 # include <jpeglib.h>
87 #undef UINT16
88 #ifndef SONAME_LIBJPEG
89 #define SONAME_LIBJPEG "libjpeg.so"
90 #endif
91 #endif
93 WINE_DEFAULT_DEBUG_CHANNEL(ole);
95 #include "pshpack1.h"
97 typedef struct {
98 BYTE bWidth;
99 BYTE bHeight;
100 BYTE bColorCount;
101 BYTE bReserved;
102 WORD xHotspot;
103 WORD yHotspot;
104 DWORD dwDIBSize;
105 DWORD dwDIBOffset;
106 } CURSORICONFILEDIRENTRY;
108 typedef struct
110 WORD idReserved;
111 WORD idType;
112 WORD idCount;
113 CURSORICONFILEDIRENTRY idEntries[1];
114 } CURSORICONFILEDIR;
116 #include "poppack.h"
118 /*************************************************************************
119 * Declaration of implementation class
122 typedef struct OLEPictureImpl {
125 * IPicture handles IUnknown
128 const IPictureVtbl *lpVtbl;
129 const IDispatchVtbl *lpvtblIDispatch;
130 const IPersistStreamVtbl *lpvtblIPersistStream;
131 const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
133 /* Object reference count */
134 LONG ref;
136 /* We own the object and must destroy it ourselves */
137 BOOL fOwn;
139 /* Picture description */
140 PICTDESC desc;
142 /* These are the pixel size of a bitmap */
143 DWORD origWidth;
144 DWORD origHeight;
146 /* And these are the size of the picture converted into HIMETRIC units */
147 OLE_XSIZE_HIMETRIC himetricWidth;
148 OLE_YSIZE_HIMETRIC himetricHeight;
150 IConnectionPoint *pCP;
152 BOOL keepOrigFormat;
153 HDC hDCCur;
155 /* Bitmap transparency mask */
156 HBITMAP hbmMask;
157 HBITMAP hbmXor;
158 COLORREF rgbTrans;
160 /* data */
161 void* data;
162 int datalen;
163 BOOL bIsDirty; /* Set to TRUE if picture has changed */
164 unsigned int loadtime_magic; /* If a length header was found, saves value */
165 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
166 } OLEPictureImpl;
169 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
172 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
174 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
177 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
179 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
182 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
184 return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
188 * Predeclare VTables. They get initialized at the end.
190 static const IPictureVtbl OLEPictureImpl_VTable;
191 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
192 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
193 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
195 /***********************************************************************
196 * Implementation of the OLEPictureImpl class.
199 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
200 BITMAP bm;
201 HDC hdcRef;
203 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
204 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
205 ERR("GetObject fails\n");
206 return;
208 This->origWidth = bm.bmWidth;
209 This->origHeight = bm.bmHeight;
210 /* The width and height are stored in HIMETRIC units (0.01 mm),
211 so we take our pixel width divide by pixels per inch and
212 multiply by 25.4 * 100 */
213 /* Should we use GetBitmapDimension if available? */
214 hdcRef = CreateCompatibleDC(0);
215 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
216 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
217 DeleteDC(hdcRef);
220 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
222 ICONINFO infoIcon;
224 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
225 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
226 HDC hdcRef;
227 BITMAP bm;
229 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
230 if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
231 ERR("GetObject fails on icon bitmap\n");
232 return;
235 This->origWidth = bm.bmWidth;
236 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
237 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
238 hdcRef = GetDC(0);
239 This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
240 This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
241 ReleaseDC(0, hdcRef);
243 DeleteObject(infoIcon.hbmMask);
244 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
245 } else {
246 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
250 /************************************************************************
251 * OLEPictureImpl_Construct
253 * This method will construct a new instance of the OLEPictureImpl
254 * class.
256 * The caller of this method must release the object when it's
257 * done with it.
259 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
261 OLEPictureImpl* newObject = 0;
263 if (pictDesc)
264 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
267 * Allocate space for the object.
269 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
271 if (newObject==0)
272 return newObject;
275 * Initialize the virtual function table.
277 newObject->lpVtbl = &OLEPictureImpl_VTable;
278 newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
279 newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
280 newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
282 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
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 if(pictDesc->cbSizeofstruct != sizeof(PICTDESC)) {
304 FIXME("struct size = %d\n", pictDesc->cbSizeofstruct);
306 memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC));
309 switch(pictDesc->picType) {
310 case PICTYPE_BITMAP:
311 OLEPictureImpl_SetBitmap(newObject);
312 break;
314 case PICTYPE_METAFILE:
315 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
316 newObject->himetricWidth = pictDesc->u.wmf.xExt;
317 newObject->himetricHeight = pictDesc->u.wmf.yExt;
318 break;
320 case PICTYPE_NONE:
321 /* not sure what to do here */
322 newObject->himetricWidth = newObject->himetricHeight = 0;
323 break;
325 case PICTYPE_ICON:
326 OLEPictureImpl_SetIcon(newObject);
327 break;
328 case PICTYPE_ENHMETAFILE:
329 default:
330 FIXME("Unsupported type %d\n", pictDesc->picType);
331 newObject->himetricWidth = newObject->himetricHeight = 0;
332 break;
334 } else {
335 newObject->desc.picType = PICTYPE_UNINITIALIZED;
338 TRACE("returning %p\n", newObject);
339 return newObject;
342 /************************************************************************
343 * OLEPictureImpl_Destroy
345 * This method is called by the Release method when the reference
346 * count goes down to 0. It will free all resources used by
347 * this object. */
348 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
350 TRACE("(%p)\n", Obj);
352 if(Obj->fOwn) { /* We need to destroy the picture */
353 switch(Obj->desc.picType) {
354 case PICTYPE_BITMAP:
355 DeleteObject(Obj->desc.u.bmp.hbitmap);
356 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
357 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
358 break;
359 case PICTYPE_METAFILE:
360 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
361 break;
362 case PICTYPE_ICON:
363 DestroyIcon(Obj->desc.u.icon.hicon);
364 break;
365 case PICTYPE_ENHMETAFILE:
366 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
367 break;
368 case PICTYPE_NONE:
369 /* Nothing to do */
370 break;
371 default:
372 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
373 break;
376 HeapFree(GetProcessHeap(), 0, Obj->data);
377 HeapFree(GetProcessHeap(), 0, Obj);
380 static ULONG WINAPI OLEPictureImpl_AddRef(IPicture* iface);
382 /************************************************************************
383 * OLEPictureImpl_QueryInterface (IUnknown)
385 * See Windows documentation for more details on IUnknown methods.
387 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
388 IPicture* iface,
389 REFIID riid,
390 void** ppvObject)
392 OLEPictureImpl *This = (OLEPictureImpl *)iface;
393 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
396 * Perform a sanity check on the parameters.
398 if ( (This==0) || (ppvObject==0) )
399 return E_INVALIDARG;
402 * Initialize the return parameter.
404 *ppvObject = 0;
407 * Compare the riid with the interface IDs implemented by this object.
409 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
411 *ppvObject = (IPicture*)This;
413 else if (memcmp(&IID_IPicture, riid, sizeof(IID_IPicture)) == 0)
415 *ppvObject = (IPicture*)This;
417 else if (memcmp(&IID_IDispatch, riid, sizeof(IID_IDispatch)) == 0)
419 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
421 else if (memcmp(&IID_IPictureDisp, riid, sizeof(IID_IPictureDisp)) == 0)
423 *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
425 else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0)
427 *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
429 else if (memcmp(&IID_IConnectionPointContainer, riid, sizeof(IID_IConnectionPointContainer)) == 0)
431 *ppvObject = (IConnectionPointContainer*)&(This->lpvtblIConnectionPointContainer);
434 * Check that we obtained an interface.
436 if ((*ppvObject)==0)
438 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
439 return E_NOINTERFACE;
443 * Query Interface always increases the reference count by one when it is
444 * successful
446 OLEPictureImpl_AddRef((IPicture*)This);
448 return S_OK;
450 /***********************************************************************
451 * OLEPicture_SendNotify (internal)
453 * Sends notification messages of changed properties to any interested
454 * connections.
456 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
458 IEnumConnections *pEnum;
459 CONNECTDATA CD;
461 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
462 return;
463 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
464 IPropertyNotifySink *sink;
466 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
467 IPropertyNotifySink_OnChanged(sink, dispID);
468 IPropertyNotifySink_Release(sink);
469 IUnknown_Release(CD.pUnk);
471 IEnumConnections_Release(pEnum);
472 return;
475 /************************************************************************
476 * OLEPictureImpl_AddRef (IUnknown)
478 * See Windows documentation for more details on IUnknown methods.
480 static ULONG WINAPI OLEPictureImpl_AddRef(
481 IPicture* iface)
483 OLEPictureImpl *This = (OLEPictureImpl *)iface;
484 ULONG refCount = InterlockedIncrement(&This->ref);
486 TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1);
488 return refCount;
491 /************************************************************************
492 * OLEPictureImpl_Release (IUnknown)
494 * See Windows documentation for more details on IUnknown methods.
496 static ULONG WINAPI OLEPictureImpl_Release(
497 IPicture* iface)
499 OLEPictureImpl *This = (OLEPictureImpl *)iface;
500 ULONG refCount = InterlockedDecrement(&This->ref);
502 TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1);
505 * If the reference count goes down to 0, perform suicide.
507 if (!refCount) OLEPictureImpl_Destroy(This);
509 return refCount;
513 /************************************************************************
514 * OLEPictureImpl_get_Handle
516 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
517 OLE_HANDLE *phandle)
519 OLEPictureImpl *This = (OLEPictureImpl *)iface;
520 TRACE("(%p)->(%p)\n", This, phandle);
521 switch(This->desc.picType) {
522 case PICTYPE_NONE:
523 *phandle = 0;
524 break;
525 case PICTYPE_BITMAP:
526 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
527 break;
528 case PICTYPE_METAFILE:
529 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
530 break;
531 case PICTYPE_ICON:
532 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
533 break;
534 case PICTYPE_ENHMETAFILE:
535 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
536 break;
537 default:
538 FIXME("Unimplemented type %d\n", This->desc.picType);
539 return E_NOTIMPL;
541 TRACE("returning handle %08x\n", *phandle);
542 return S_OK;
545 /************************************************************************
546 * OLEPictureImpl_get_hPal
548 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
549 OLE_HANDLE *phandle)
551 OLEPictureImpl *This = (OLEPictureImpl *)iface;
552 HRESULT hres;
553 TRACE("(%p)->(%p)\n", This, phandle);
555 if (!phandle)
556 return E_POINTER;
558 switch (This->desc.picType) {
559 case PICTYPE_UNINITIALIZED:
560 case PICTYPE_NONE:
561 *phandle = 0;
562 hres = S_FALSE;
563 break;
564 case PICTYPE_BITMAP:
565 *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
566 hres = S_OK;
567 break;
568 case PICTYPE_ICON:
569 case PICTYPE_METAFILE:
570 case PICTYPE_ENHMETAFILE:
571 default:
572 FIXME("unimplemented for type %d. Returning 0 palette.\n",
573 This->desc.picType);
574 *phandle = 0;
575 hres = S_OK;
578 TRACE("returning 0x%08lx, palette handle %08x\n", hres, *phandle);
579 return hres;
582 /************************************************************************
583 * OLEPictureImpl_get_Type
585 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
586 short *ptype)
588 OLEPictureImpl *This = (OLEPictureImpl *)iface;
589 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
590 *ptype = This->desc.picType;
591 return S_OK;
594 /************************************************************************
595 * OLEPictureImpl_get_Width
597 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
598 OLE_XSIZE_HIMETRIC *pwidth)
600 OLEPictureImpl *This = (OLEPictureImpl *)iface;
601 TRACE("(%p)->(%p): width is %ld\n", This, pwidth, This->himetricWidth);
602 *pwidth = This->himetricWidth;
603 return S_OK;
606 /************************************************************************
607 * OLEPictureImpl_get_Height
609 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
610 OLE_YSIZE_HIMETRIC *pheight)
612 OLEPictureImpl *This = (OLEPictureImpl *)iface;
613 TRACE("(%p)->(%p): height is %ld\n", This, pheight, This->himetricHeight);
614 *pheight = This->himetricHeight;
615 return S_OK;
618 /************************************************************************
619 * OLEPictureImpl_Render
621 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
622 LONG x, LONG y, LONG cx, LONG cy,
623 OLE_XPOS_HIMETRIC xSrc,
624 OLE_YPOS_HIMETRIC ySrc,
625 OLE_XSIZE_HIMETRIC cxSrc,
626 OLE_YSIZE_HIMETRIC cySrc,
627 LPCRECT prcWBounds)
629 OLEPictureImpl *This = (OLEPictureImpl *)iface;
630 TRACE("(%p)->(%p, (%ld,%ld), (%ld,%ld) <- (%ld,%ld), (%ld,%ld), %p)\n",
631 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
632 if(prcWBounds)
633 TRACE("prcWBounds (%ld,%ld) - (%ld,%ld)\n", prcWBounds->left, prcWBounds->top,
634 prcWBounds->right, prcWBounds->bottom);
637 * While the documentation suggests this to be here (or after rendering?)
638 * it does cause an endless recursion in my sample app. -MM 20010804
639 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
642 switch(This->desc.picType) {
643 case PICTYPE_BITMAP:
645 HBITMAP hbmpOld;
646 HDC hdcBmp;
648 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
649 NB y-axis gets flipped */
651 hdcBmp = CreateCompatibleDC(0);
652 SetMapMode(hdcBmp, MM_ANISOTROPIC);
653 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
654 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
655 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
656 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
658 if (This->hbmMask) {
659 HDC hdcMask = CreateCompatibleDC(0);
660 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
662 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
664 SetMapMode(hdcMask, MM_ANISOTROPIC);
665 SetWindowOrgEx(hdcMask, 0, 0, NULL);
666 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
667 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
668 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
670 SetBkColor(hdc, RGB(255, 255, 255));
671 SetTextColor(hdc, RGB(0, 0, 0));
672 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
673 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
675 SelectObject(hdcMask, hOldbm);
676 DeleteDC(hdcMask);
677 } else {
678 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
679 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
682 SelectObject(hdcBmp, hbmpOld);
683 DeleteDC(hdcBmp);
685 break;
686 case PICTYPE_ICON:
687 FIXME("Not quite correct implementation of rendering icons...\n");
688 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
689 break;
691 case PICTYPE_METAFILE:
692 case PICTYPE_ENHMETAFILE:
693 default:
694 FIXME("type %d not implemented\n", This->desc.picType);
695 return E_NOTIMPL;
697 return S_OK;
700 /************************************************************************
701 * OLEPictureImpl_set_hPal
703 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
704 OLE_HANDLE hpal)
706 OLEPictureImpl *This = (OLEPictureImpl *)iface;
707 FIXME("(%p)->(%08x): stub\n", This, hpal);
708 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
709 return E_NOTIMPL;
712 /************************************************************************
713 * OLEPictureImpl_get_CurDC
715 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
716 HDC *phdc)
718 OLEPictureImpl *This = (OLEPictureImpl *)iface;
719 TRACE("(%p), returning %p\n", This, This->hDCCur);
720 if (phdc) *phdc = This->hDCCur;
721 return S_OK;
724 /************************************************************************
725 * OLEPictureImpl_SelectPicture
727 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
728 HDC hdcIn,
729 HDC *phdcOut,
730 OLE_HANDLE *phbmpOut)
732 OLEPictureImpl *This = (OLEPictureImpl *)iface;
733 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
734 if (This->desc.picType == PICTYPE_BITMAP) {
735 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
737 if (phdcOut)
738 *phdcOut = This->hDCCur;
739 This->hDCCur = hdcIn;
740 if (phbmpOut)
741 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
742 return S_OK;
743 } else {
744 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
745 return E_FAIL;
749 /************************************************************************
750 * OLEPictureImpl_get_KeepOriginalFormat
752 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
753 BOOL *pfKeep)
755 OLEPictureImpl *This = (OLEPictureImpl *)iface;
756 TRACE("(%p)->(%p)\n", This, pfKeep);
757 if (!pfKeep)
758 return E_POINTER;
759 *pfKeep = This->keepOrigFormat;
760 return S_OK;
763 /************************************************************************
764 * OLEPictureImpl_put_KeepOriginalFormat
766 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
767 BOOL keep)
769 OLEPictureImpl *This = (OLEPictureImpl *)iface;
770 TRACE("(%p)->(%d)\n", This, keep);
771 This->keepOrigFormat = keep;
772 /* FIXME: what DISPID notification here? */
773 return S_OK;
776 /************************************************************************
777 * OLEPictureImpl_PictureChanged
779 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
781 OLEPictureImpl *This = (OLEPictureImpl *)iface;
782 TRACE("(%p)->()\n", This);
783 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
784 This->bIsDirty = TRUE;
785 return S_OK;
788 /************************************************************************
789 * OLEPictureImpl_SaveAsFile
791 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
792 IStream *pstream,
793 BOOL SaveMemCopy,
794 LONG *pcbSize)
796 OLEPictureImpl *This = (OLEPictureImpl *)iface;
797 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
798 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
801 /************************************************************************
802 * OLEPictureImpl_get_Attributes
804 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
805 DWORD *pdwAttr)
807 OLEPictureImpl *This = (OLEPictureImpl *)iface;
808 TRACE("(%p)->(%p).\n", This, pdwAttr);
809 *pdwAttr = 0;
810 switch (This->desc.picType) {
811 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
812 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
813 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
814 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
816 return S_OK;
820 /************************************************************************
821 * IConnectionPointContainer
824 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
825 IConnectionPointContainer* iface,
826 REFIID riid,
827 VOID** ppvoid)
829 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
831 return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
834 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
835 IConnectionPointContainer* iface)
837 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
839 return IPicture_AddRef((IPicture *)This);
842 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
843 IConnectionPointContainer* iface)
845 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
847 return IPicture_Release((IPicture *)This);
850 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
851 IConnectionPointContainer* iface,
852 IEnumConnectionPoints** ppEnum)
854 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
856 FIXME("(%p,%p), stub!\n",This,ppEnum);
857 return E_NOTIMPL;
860 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
861 IConnectionPointContainer* iface,
862 REFIID riid,
863 IConnectionPoint **ppCP)
865 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
866 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
867 if (!ppCP)
868 return E_POINTER;
869 *ppCP = NULL;
870 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
871 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
872 FIXME("tried to find connection point on %s?\n",debugstr_guid(riid));
873 return 0x80040200;
875 /************************************************************************
876 * IPersistStream
878 /************************************************************************
879 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
881 * See Windows documentation for more details on IUnknown methods.
883 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
884 IPersistStream* iface,
885 REFIID riid,
886 VOID** ppvoid)
888 OLEPictureImpl *This = impl_from_IPersistStream(iface);
890 return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
893 /************************************************************************
894 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
896 * See Windows documentation for more details on IUnknown methods.
898 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
899 IPersistStream* iface)
901 OLEPictureImpl *This = impl_from_IPersistStream(iface);
903 return IPicture_AddRef((IPicture *)This);
906 /************************************************************************
907 * OLEPictureImpl_IPersistStream_Release (IUnknown)
909 * See Windows documentation for more details on IUnknown methods.
911 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
912 IPersistStream* iface)
914 OLEPictureImpl *This = impl_from_IPersistStream(iface);
916 return IPicture_Release((IPicture *)This);
919 /************************************************************************
920 * OLEPictureImpl_IPersistStream_GetClassID
922 static HRESULT WINAPI OLEPictureImpl_GetClassID(
923 IPersistStream* iface,CLSID* pClassID)
925 OLEPictureImpl *This = impl_from_IPersistStream(iface);
926 FIXME("(%p),stub!\n",This);
927 return E_FAIL;
930 /************************************************************************
931 * OLEPictureImpl_IPersistStream_IsDirty
933 static HRESULT WINAPI OLEPictureImpl_IsDirty(
934 IPersistStream* iface)
936 OLEPictureImpl *This = impl_from_IPersistStream(iface);
937 FIXME("(%p),stub!\n",This);
938 return E_NOTIMPL;
941 #ifdef HAVE_JPEGLIB_H
943 static void *libjpeg_handle;
944 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
945 MAKE_FUNCPTR(jpeg_std_error);
946 MAKE_FUNCPTR(jpeg_CreateDecompress);
947 MAKE_FUNCPTR(jpeg_read_header);
948 MAKE_FUNCPTR(jpeg_start_decompress);
949 MAKE_FUNCPTR(jpeg_read_scanlines);
950 MAKE_FUNCPTR(jpeg_finish_decompress);
951 MAKE_FUNCPTR(jpeg_destroy_decompress);
952 #undef MAKE_FUNCPTR
954 static void *load_libjpeg(void)
956 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
958 #define LOAD_FUNCPTR(f) \
959 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
960 libjpeg_handle = NULL; \
961 return NULL; \
964 LOAD_FUNCPTR(jpeg_std_error);
965 LOAD_FUNCPTR(jpeg_CreateDecompress);
966 LOAD_FUNCPTR(jpeg_read_header);
967 LOAD_FUNCPTR(jpeg_start_decompress);
968 LOAD_FUNCPTR(jpeg_read_scanlines);
969 LOAD_FUNCPTR(jpeg_finish_decompress);
970 LOAD_FUNCPTR(jpeg_destroy_decompress);
971 #undef LOAD_FUNCPTR
973 return libjpeg_handle;
976 /* for the jpeg decompressor source manager. */
977 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
979 static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
980 ERR("(), should not get here.\n");
981 return FALSE;
984 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
985 TRACE("Skipping %ld bytes...\n", num_bytes);
986 cinfo->src->next_input_byte += num_bytes;
987 cinfo->src->bytes_in_buffer -= num_bytes;
990 static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
991 ERR("(desired=%d), should not get here.\n",desired);
992 return FALSE;
994 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
995 #endif /* HAVE_JPEGLIB_H */
997 #ifdef HAVE_GIF_LIB_H
999 static void *libungif_handle;
1000 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1001 MAKE_FUNCPTR(DGifOpen);
1002 MAKE_FUNCPTR(DGifSlurp);
1003 MAKE_FUNCPTR(DGifCloseFile);
1004 #undef MAKE_FUNCPTR
1006 struct gifdata {
1007 unsigned char *data;
1008 unsigned int curoff;
1009 unsigned int len;
1012 static void *load_libungif(void)
1014 if(((libungif_handle = wine_dlopen(SONAME_LIBUNGIF, RTLD_NOW, NULL, 0)) != NULL) ||
1015 ((libungif_handle = wine_dlopen(SONAME_LIBGIF , RTLD_NOW, NULL, 0)) != NULL)
1018 #define LOAD_FUNCPTR(f) \
1019 if((p##f = wine_dlsym(libungif_handle, #f, NULL, 0)) == NULL) { \
1020 libungif_handle = NULL; \
1021 return NULL; \
1024 LOAD_FUNCPTR(DGifOpen);
1025 LOAD_FUNCPTR(DGifSlurp);
1026 LOAD_FUNCPTR(DGifCloseFile);
1027 #undef LOAD_FUNCPTR
1029 return libungif_handle;
1032 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1033 struct gifdata *gd = (struct gifdata*)gif->UserData;
1035 if (len+gd->curoff > gd->len) {
1036 FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1037 len = gd->len - gd->curoff;
1039 memcpy(data, gd->data+gd->curoff, len);
1040 gd->curoff += len;
1041 return len;
1044 #endif /* HAVE_GIF_LIB_H */
1046 /************************************************************************
1047 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1049 * Loads the binary data from the IStream. Starts at current position.
1050 * There appears to be an 2 DWORD header:
1051 * DWORD magic;
1052 * DWORD len;
1054 * Currently implemented: BITMAP, ICON, JPEG, GIF
1056 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1057 HRESULT hr = E_FAIL;
1058 BOOL headerisdata = FALSE;
1059 ULONG xread, toread;
1060 BYTE *xbuf;
1061 DWORD header[2];
1062 WORD magic;
1063 STATSTG statstg;
1064 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1066 TRACE("(%p,%p)\n",This,pStm);
1068 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1069 * out whether we do.
1071 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1072 * compound file. This may explain most, if not all, of the cases of "no header",
1073 * and the header validation should take this into account. At least in Visual Basic 6,
1074 * resource streams, valid headers are
1075 * header[0] == "lt\0\0",
1076 * header[1] == length_of_stream.
1078 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1079 if (hr)
1080 FIXME("Stat failed with hres %lx\n",hr);
1081 hr=IStream_Read(pStm,header,8,&xread);
1082 if (hr || xread!=8) {
1083 FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
1084 return hr;
1087 headerisdata = FALSE;
1088 xread = 0;
1089 if (!memcmp(&(header[0]),"lt\0\0", 4) && (header[1] <= statstg.cbSize.QuadPart-8)) {
1090 toread = header[1];
1091 } else {
1092 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1093 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1094 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1095 (header[1] > statstg.cbSize.QuadPart) || /* invalid size */
1096 (header[1]==0)
1097 ) {/* Incorrect header, assume none. */
1098 headerisdata = TRUE;
1099 toread = statstg.cbSize.QuadPart-8;
1100 xread = 8;
1101 } else {
1102 FIXME("Unknown stream header magic: %08lx\n", header[0]);
1103 toread = header[1];
1107 This->datalen = toread+(headerisdata?8:0);
1108 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1110 if (headerisdata)
1111 memcpy (xbuf, &header, 8);
1113 while (xread < This->datalen) {
1114 ULONG nread;
1115 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1116 xread+=nread;
1117 if (hr || !nread)
1118 break;
1120 if (xread != This->datalen)
1121 FIXME("Could only read %ld of %d bytes out of stream?\n",xread,This->datalen);
1123 if (This->datalen == 0) { /* Marks the "NONE" picture */
1124 This->desc.picType = PICTYPE_NONE;
1125 return S_OK;
1128 magic = xbuf[0] + (xbuf[1]<<8);
1129 switch (magic) {
1130 case 0x4947: { /* GIF */
1131 #ifdef HAVE_GIF_LIB_H
1132 struct gifdata gd;
1133 GifFileType *gif;
1134 BITMAPINFO *bmi;
1135 HDC hdcref;
1136 LPBYTE bytes;
1137 int i,j,ret;
1138 GifImageDesc *gid;
1139 SavedImage *si;
1140 ColorMapObject *cm;
1141 int transparent = -1;
1142 ExtensionBlock *eb;
1143 int padding;
1145 if(!libungif_handle) {
1146 if(!load_libungif()) {
1147 FIXME("Failed reading GIF because unable to find %s/%s\n", SONAME_LIBUNGIF, SONAME_LIBGIF);
1148 return E_FAIL;
1152 gd.data = xbuf;
1153 gd.curoff = 0;
1154 gd.len = xread;
1155 gif = pDGifOpen((void*)&gd, _gif_inputfunc);
1156 ret = pDGifSlurp(gif);
1157 if (ret == GIF_ERROR) {
1158 FIXME("Failed reading GIF using libgif.\n");
1159 return E_FAIL;
1161 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1162 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1163 TRACE("imgcnt %d\n", gif->ImageCount);
1164 if (gif->ImageCount<1) {
1165 FIXME("GIF stream does not have images inside?\n");
1166 return E_FAIL;
1168 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1169 gif->Image.Width, gif->Image.Height,
1170 gif->Image.Left, gif->Image.Top,
1171 gif->Image.Interlace
1173 /* */
1174 padding = (gif->SWidth+3) & ~3;
1175 si = gif->SavedImages+0;
1176 gid = &(si->ImageDesc);
1177 cm = gid->ColorMap;
1178 if (!cm) cm = gif->SColorMap;
1179 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1180 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1182 /* look for the transparent color extension */
1183 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1184 eb = si->ExtensionBlocks + i;
1185 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1186 if ((eb->Bytes[0] & 1) == 1) {
1187 transparent = (unsigned char)eb->Bytes[3];
1192 for (i = 0; i < cm->ColorCount; i++) {
1193 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1194 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1195 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1196 if (i == transparent) {
1197 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1198 bmi->bmiColors[i].rgbGreen,
1199 bmi->bmiColors[i].rgbBlue);
1203 /* Map to in picture coordinates */
1204 for (i = 0, j = 0; i < gid->Height; i++) {
1205 if (gif->Image.Interlace) {
1206 memcpy(
1207 bytes + (gid->Top + j) * padding + gid->Left,
1208 si->RasterBits + i * gid->Width,
1209 gid->Width);
1211 /* Lower bits of interlaced counter encode current interlace */
1212 if (j & 1) j += 2; /* Currently filling odd rows */
1213 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1214 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1216 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1217 /* End of current interlace, go to next interlace */
1218 if (j & 2) j = 1; /* Next iteration fills odd rows */
1219 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1220 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1222 } else {
1223 memcpy(
1224 bytes + (gid->Top + i) * padding + gid->Left,
1225 si->RasterBits + i * gid->Width,
1226 gid->Width);
1230 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1231 bmi->bmiHeader.biWidth = gif->SWidth;
1232 bmi->bmiHeader.biHeight = -gif->SHeight;
1233 bmi->bmiHeader.biPlanes = 1;
1234 bmi->bmiHeader.biBitCount = 8;
1235 bmi->bmiHeader.biCompression = BI_RGB;
1236 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1237 bmi->bmiHeader.biXPelsPerMeter = 0;
1238 bmi->bmiHeader.biYPelsPerMeter = 0;
1239 bmi->bmiHeader.biClrUsed = cm->ColorCount;
1240 bmi->bmiHeader.biClrImportant = 0;
1242 hdcref = GetDC(0);
1243 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1244 hdcref,
1245 &bmi->bmiHeader,
1246 CBM_INIT,
1247 bytes,
1248 bmi,
1249 DIB_RGB_COLORS
1252 if (transparent > -1) {
1253 /* Create the Mask */
1254 HDC hdc = CreateCompatibleDC(0);
1255 HDC hdcMask = CreateCompatibleDC(0);
1256 HBITMAP hOldbitmap;
1257 HBITMAP hOldbitmapmask;
1259 unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1260 HBITMAP hTempMask;
1262 This->hbmXor = CreateDIBitmap(
1263 hdcref,
1264 &bmi->bmiHeader,
1265 CBM_INIT,
1266 bytes,
1267 bmi,
1268 DIB_RGB_COLORS
1271 bmi->bmiColors[0].rgbRed = 0;
1272 bmi->bmiColors[0].rgbGreen = 0;
1273 bmi->bmiColors[0].rgbBlue = 0;
1274 bmi->bmiColors[1].rgbRed = 255;
1275 bmi->bmiColors[1].rgbGreen = 255;
1276 bmi->bmiColors[1].rgbBlue = 255;
1278 bmi->bmiHeader.biBitCount = 1;
1279 bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight;
1280 bmi->bmiHeader.biClrUsed = 2;
1282 for (i = 0; i < gif->SHeight; i++) {
1283 unsigned char * colorPointer = bytes + padding * i;
1284 unsigned char * monoPointer = bytes + monopadding * i;
1285 for (j = 0; j < gif->SWidth; j++) {
1286 unsigned char pixel = colorPointer[j];
1287 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1288 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1291 hdcref = GetDC(0);
1292 hTempMask = CreateDIBitmap(
1293 hdcref,
1294 &bmi->bmiHeader,
1295 CBM_INIT,
1296 bytes,
1297 bmi,
1298 DIB_RGB_COLORS
1300 DeleteDC(hdcref);
1302 bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1303 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1304 hOldbitmap = SelectObject(hdc, hTempMask);
1305 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1307 SetBkColor(hdc, RGB(255, 255, 255));
1308 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1310 /* We no longer need the original bitmap, so we apply the first
1311 transformation with the mask to speed up the rendering */
1312 SelectObject(hdc, This->hbmXor);
1313 SetBkColor(hdc, RGB(0,0,0));
1314 SetTextColor(hdc, RGB(255,255,255));
1315 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1316 hdcMask, 0, 0, SRCAND);
1318 SelectObject(hdc, hOldbitmap);
1319 SelectObject(hdcMask, hOldbitmapmask);
1320 DeleteDC(hdcMask);
1321 DeleteDC(hdc);
1322 DeleteObject(hTempMask);
1325 DeleteDC(hdcref);
1326 This->desc.picType = PICTYPE_BITMAP;
1327 OLEPictureImpl_SetBitmap(This);
1328 pDGifCloseFile(gif);
1329 HeapFree(GetProcessHeap(),0,bytes);
1330 return S_OK;
1331 #else
1332 FIXME("Trying to load GIF, but no support for libgif/libungif compiled in.\n");
1333 return E_FAIL;
1334 #endif
1336 case 0xd8ff: { /* JPEG */
1337 #ifdef HAVE_JPEGLIB_H
1338 struct jpeg_decompress_struct jd;
1339 struct jpeg_error_mgr jerr;
1340 int ret;
1341 JDIMENSION x;
1342 JSAMPROW samprow,oldsamprow;
1343 BITMAPINFOHEADER bmi;
1344 LPBYTE bits;
1345 HDC hdcref;
1346 struct jpeg_source_mgr xjsm;
1347 LPBYTE oldbits;
1348 unsigned int i;
1350 if(!libjpeg_handle) {
1351 if(!load_libjpeg()) {
1352 FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1353 return E_FAIL;
1357 /* This is basically so we can use in-memory data for jpeg decompression.
1358 * We need to have all the functions.
1360 xjsm.next_input_byte = xbuf;
1361 xjsm.bytes_in_buffer = xread;
1362 xjsm.init_source = _jpeg_init_source;
1363 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1364 xjsm.skip_input_data = _jpeg_skip_input_data;
1365 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1366 xjsm.term_source = _jpeg_term_source;
1368 jd.err = pjpeg_std_error(&jerr);
1369 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1370 * jpeg_create_decompress(&jd); */
1371 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct));
1372 jd.src = &xjsm;
1373 ret=pjpeg_read_header(&jd,TRUE);
1374 jd.out_color_space = JCS_RGB;
1375 pjpeg_start_decompress(&jd);
1376 if (ret != JPEG_HEADER_OK) {
1377 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1378 HeapFree(GetProcessHeap(),0,xbuf);
1379 return E_FAIL;
1382 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1383 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1384 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1386 oldbits = bits;
1387 oldsamprow = samprow;
1388 while ( jd.output_scanline<jd.output_height ) {
1389 x = pjpeg_read_scanlines(&jd,&samprow,1);
1390 if (x != 1) {
1391 FIXME("failed to read current scanline?\n");
1392 break;
1394 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1395 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1396 *(bits++) = *(samprow+2);
1397 *(bits++) = *(samprow+1);
1398 *(bits++) = *(samprow);
1400 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1401 samprow = oldsamprow;
1403 bits = oldbits;
1405 bmi.biSize = sizeof(bmi);
1406 bmi.biWidth = jd.output_width;
1407 bmi.biHeight = -jd.output_height;
1408 bmi.biPlanes = 1;
1409 bmi.biBitCount = jd.output_components<<3;
1410 bmi.biCompression = BI_RGB;
1411 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1412 bmi.biXPelsPerMeter = 0;
1413 bmi.biYPelsPerMeter = 0;
1414 bmi.biClrUsed = 0;
1415 bmi.biClrImportant = 0;
1417 HeapFree(GetProcessHeap(),0,samprow);
1418 pjpeg_finish_decompress(&jd);
1419 pjpeg_destroy_decompress(&jd);
1420 hdcref = GetDC(0);
1421 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1422 hdcref,
1423 &bmi,
1424 CBM_INIT,
1425 bits,
1426 (BITMAPINFO*)&bmi,
1427 DIB_RGB_COLORS
1429 DeleteDC(hdcref);
1430 This->desc.picType = PICTYPE_BITMAP;
1431 OLEPictureImpl_SetBitmap(This);
1432 hr = S_OK;
1433 HeapFree(GetProcessHeap(),0,bits);
1434 #else
1435 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1436 hr = E_FAIL;
1437 #endif
1438 break;
1440 case 0x4d42: { /* Bitmap */
1441 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1442 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1443 HDC hdcref;
1445 /* Does not matter whether this is a coreheader or not, we only use
1446 * components which are in both
1448 hdcref = GetDC(0);
1449 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1450 hdcref,
1451 &(bi->bmiHeader),
1452 CBM_INIT,
1453 xbuf+bfh->bfOffBits,
1455 DIB_RGB_COLORS
1457 DeleteDC(hdcref);
1458 This->desc.picType = PICTYPE_BITMAP;
1459 OLEPictureImpl_SetBitmap(This);
1460 hr = S_OK;
1461 break;
1463 case 0x0000: { /* ICON , first word is dwReserved */
1464 HICON hicon;
1465 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1466 HDC hdcRef;
1467 int i;
1470 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1471 FIXME("icon.idType=%d\n",cifd->idType);
1472 FIXME("icon.idCount=%d\n",cifd->idCount);
1474 for (i=0;i<cifd->idCount;i++) {
1475 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1476 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1477 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1478 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1479 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1480 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1481 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1482 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1485 i=0;
1486 /* If we have more than one icon, try to find the best.
1487 * this currently means '32 pixel wide'.
1489 if (cifd->idCount!=1) {
1490 for (i=0;i<cifd->idCount;i++) {
1491 if (cifd->idEntries[i].bWidth == 32)
1492 break;
1494 if (i==cifd->idCount) i=0;
1497 hicon = CreateIconFromResourceEx(
1498 xbuf+cifd->idEntries[i].dwDIBOffset,
1499 cifd->idEntries[i].dwDIBSize,
1500 TRUE, /* is icon */
1501 0x00030000,
1502 cifd->idEntries[i].bWidth,
1503 cifd->idEntries[i].bHeight,
1506 if (!hicon) {
1507 FIXME("CreateIcon failed.\n");
1508 hr = E_FAIL;
1509 } else {
1510 This->desc.picType = PICTYPE_ICON;
1511 This->desc.u.icon.hicon = hicon;
1512 This->origWidth = cifd->idEntries[i].bWidth;
1513 This->origHeight = cifd->idEntries[i].bHeight;
1514 hdcRef = CreateCompatibleDC(0);
1515 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1516 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1517 DeleteDC(hdcRef);
1518 hr = S_OK;
1520 break;
1522 default:
1524 unsigned int i;
1525 FIXME("Unknown magic %04x, %ld read bytes:\n",magic,xread);
1526 hr=E_FAIL;
1527 for (i=0;i<xread+8;i++) {
1528 if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
1529 else MESSAGE("%02x ",xbuf[i-8]);
1530 if (i % 10 == 9) MESSAGE("\n");
1532 MESSAGE("\n");
1533 break;
1536 This->bIsDirty = FALSE;
1538 /* FIXME: this notify is not really documented */
1539 if (hr==S_OK)
1540 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1541 return hr;
1544 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength);
1545 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength);
1546 static HRESULT WINAPI OLEPictureImpl_Save(
1547 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1549 HRESULT hResult = E_NOTIMPL;
1550 void * pIconData;
1551 unsigned int iDataSize;
1552 ULONG dummy;
1553 int iSerializeResult = 0;
1555 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1557 switch (This->desc.picType) {
1558 case PICTYPE_ICON:
1559 if (This->bIsDirty) {
1560 if (serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1561 if (This->loadtime_magic != 0xdeadbeef) {
1562 DWORD header[2];
1564 header[0] = This->loadtime_magic;
1565 header[1] = iDataSize;
1566 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1568 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1570 HeapFree(GetProcessHeap(), 0, This->data);
1571 This->data = pIconData;
1572 This->datalen = iDataSize;
1573 hResult = S_OK;
1574 } else {
1575 FIXME("(%p,%p,%d), unable to serializeIcon()!\n",This,pStm,fClearDirty);
1576 hResult = E_FAIL;
1578 } else {
1579 if (This->loadtime_magic != 0xdeadbeef) {
1580 DWORD header[2];
1582 header[0] = This->loadtime_magic;
1583 header[1] = This->datalen;
1584 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1586 IStream_Write(pStm, This->data, This->datalen, &dummy);
1587 hResult = S_OK;
1589 break;
1590 case PICTYPE_BITMAP:
1591 if (This->bIsDirty) {
1592 switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) {
1593 case 0x4d42:
1594 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1595 break;
1596 case 0xd8ff:
1597 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1598 break;
1599 case 0x4947:
1600 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1601 break;
1602 default:
1603 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1604 break;
1606 if (iSerializeResult) {
1608 if (This->loadtime_magic != 0xdeadbeef) {
1610 if (1) {
1611 DWORD header[2];
1613 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1614 header[1] = iDataSize;
1615 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1617 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1619 HeapFree(GetProcessHeap(), 0, This->data);
1620 This->data = pIconData;
1621 This->datalen = iDataSize;
1622 hResult = S_OK;
1624 } else {
1626 if (This->loadtime_magic != 0xdeadbeef) {
1628 if (1) {
1629 DWORD header[2];
1631 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1632 header[1] = This->datalen;
1633 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1635 IStream_Write(pStm, This->data, This->datalen, &dummy);
1636 hResult = S_OK;
1638 break;
1639 case PICTYPE_METAFILE:
1640 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1641 break;
1642 case PICTYPE_ENHMETAFILE:
1643 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1644 break;
1645 default:
1646 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1647 break;
1649 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1650 return hResult;
1653 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1655 int iSuccess = 0;
1656 HDC hDC;
1657 BITMAPINFO * pInfoBitmap;
1658 int iNumPaletteEntries;
1659 unsigned char * pPixelData;
1660 BITMAPFILEHEADER * pFileHeader;
1661 BITMAPINFO * pInfoHeader;
1663 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1664 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1666 /* Find out bitmap size and padded length */
1667 hDC = GetDC(0);
1668 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1669 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1671 /* Fetch bitmap palette & pixel data */
1673 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1674 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1676 /* Calculate the total length required for the BMP data */
1677 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1678 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1679 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1680 } else {
1681 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1682 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1683 else
1684 iNumPaletteEntries = 0;
1686 *pLength =
1687 sizeof(BITMAPFILEHEADER) +
1688 sizeof(BITMAPINFOHEADER) +
1689 iNumPaletteEntries * sizeof(RGBQUAD) +
1690 pInfoBitmap->bmiHeader.biSizeImage;
1691 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1693 /* Fill the BITMAPFILEHEADER */
1694 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1695 pFileHeader->bfType = 0x4d42;
1696 pFileHeader->bfSize = *pLength;
1697 pFileHeader->bfOffBits =
1698 sizeof(BITMAPFILEHEADER) +
1699 sizeof(BITMAPINFOHEADER) +
1700 iNumPaletteEntries * sizeof(RGBQUAD);
1702 /* Fill the BITMAPINFOHEADER and the palette data */
1703 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1704 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1705 memcpy(
1706 (unsigned char *)(*ppBuffer) +
1707 sizeof(BITMAPFILEHEADER) +
1708 sizeof(BITMAPINFOHEADER) +
1709 iNumPaletteEntries * sizeof(RGBQUAD),
1710 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1711 iSuccess = 1;
1713 HeapFree(GetProcessHeap(), 0, pPixelData);
1714 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1715 return iSuccess;
1718 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1720 ICONINFO infoIcon;
1721 int iSuccess = 0;
1723 *ppBuffer = NULL; *pLength = 0;
1724 if (GetIconInfo(hIcon, &infoIcon)) {
1725 HDC hDC;
1726 BITMAPINFO * pInfoBitmap;
1727 unsigned char * pIconData = NULL;
1728 unsigned int iDataSize = 0;
1730 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1732 /* Find out icon size */
1733 hDC = GetDC(0);
1734 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1735 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1736 if (1) {
1737 /* Auxiliary pointers */
1738 CURSORICONFILEDIR * pIconDir;
1739 CURSORICONFILEDIRENTRY * pIconEntry;
1740 BITMAPINFOHEADER * pIconBitmapHeader;
1741 unsigned int iOffsetPalette;
1742 unsigned int iOffsetColorData;
1743 unsigned int iOffsetMaskData;
1745 unsigned int iLengthScanLineColor;
1746 unsigned int iLengthScanLineMask;
1747 unsigned int iNumEntriesPalette;
1749 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1750 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
1752 FIXME("DEBUG: bitmap size is %d x %d\n",
1753 pInfoBitmap->bmiHeader.biWidth,
1754 pInfoBitmap->bmiHeader.biHeight);
1755 FIXME("DEBUG: bitmap bpp is %d\n",
1756 pInfoBitmap->bmiHeader.biBitCount);
1757 FIXME("DEBUG: bitmap nplanes is %d\n",
1758 pInfoBitmap->bmiHeader.biPlanes);
1759 FIXME("DEBUG: bitmap biSizeImage is %lu\n",
1760 pInfoBitmap->bmiHeader.biSizeImage);
1762 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1763 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1764 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1766 /* Fill out the CURSORICONFILEDIR */
1767 pIconDir = (CURSORICONFILEDIR *)pIconData;
1768 pIconDir->idType = 1;
1769 pIconDir->idCount = 1;
1771 /* Fill out the CURSORICONFILEDIRENTRY */
1772 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1773 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1774 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1775 pIconEntry->bColorCount =
1776 (pInfoBitmap->bmiHeader.biBitCount < 8)
1777 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1778 : 0;
1779 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1780 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1781 pIconEntry->dwDIBSize = 0;
1782 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1784 /* Fill out the BITMAPINFOHEADER */
1785 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1786 memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
1788 /* Find out whether a palette exists for the bitmap */
1789 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1790 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1791 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1792 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1793 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1794 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1795 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1796 iNumEntriesPalette = 3;
1797 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1798 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1799 } else {
1800 iNumEntriesPalette = 0;
1803 /* Add bitmap size and header size to icon data size. */
1804 iOffsetPalette = iDataSize;
1805 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1806 iOffsetColorData = iDataSize;
1807 iDataSize += pIconBitmapHeader->biSizeImage;
1808 iOffsetMaskData = iDataSize;
1809 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1810 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1811 pIconBitmapHeader->biHeight *= 2;
1812 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1813 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1814 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1815 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1817 /* Get the actual bitmap data from the icon bitmap */
1818 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1819 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1820 if (iNumEntriesPalette > 0) {
1821 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1822 iNumEntriesPalette * sizeof(RGBQUAD));
1825 /* Reset all values so that GetDIBits call succeeds */
1826 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1827 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1828 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1830 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1831 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1832 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1834 printf("ERROR: unable to get bitmap mask (error %lu)\n",
1835 GetLastError());
1839 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1840 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1842 /* Write out everything produced so far to the stream */
1843 *ppBuffer = pIconData; *pLength = iDataSize;
1844 iSuccess = 1;
1845 } else {
1847 printf("ERROR: unable to get bitmap information via GetDIBits() (error %lu)\n",
1848 GetLastError());
1852 Remarks (from MSDN entry on GetIconInfo):
1854 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1855 members of ICONINFO. The calling application must manage
1856 these bitmaps and delete them when they are no longer
1857 necessary.
1859 if (hDC) ReleaseDC(0, hDC);
1860 DeleteObject(infoIcon.hbmMask);
1861 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1862 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1863 } else {
1864 printf("ERROR: Unable to get icon information (error %lu)\n",
1865 GetLastError());
1867 return iSuccess;
1870 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1871 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1873 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1874 FIXME("(%p,%p),stub!\n",This,pcbSize);
1875 return E_NOTIMPL;
1878 /************************************************************************
1879 * 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 FIXME("():Stub\n");
1933 return E_NOTIMPL;
1936 /************************************************************************
1937 * OLEPictureImpl_GetTypeInfo (IDispatch)
1939 * See Windows documentation for more details on IDispatch methods.
1941 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1942 IDispatch* iface,
1943 UINT iTInfo,
1944 LCID lcid,
1945 ITypeInfo** ppTInfo)
1947 FIXME("():Stub\n");
1949 return E_NOTIMPL;
1952 /************************************************************************
1953 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1955 * See Windows documentation for more details on IDispatch methods.
1957 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1958 IDispatch* iface,
1959 REFIID riid,
1960 LPOLESTR* rgszNames,
1961 UINT cNames,
1962 LCID lcid,
1963 DISPID* rgDispId)
1965 FIXME("():Stub\n");
1967 return E_NOTIMPL;
1970 /************************************************************************
1971 * OLEPictureImpl_Invoke (IDispatch)
1973 * See Windows documentation for more details on IDispatch methods.
1975 static HRESULT WINAPI OLEPictureImpl_Invoke(
1976 IDispatch* iface,
1977 DISPID dispIdMember,
1978 REFIID riid,
1979 LCID lcid,
1980 WORD wFlags,
1981 DISPPARAMS* pDispParams,
1982 VARIANT* pVarResult,
1983 EXCEPINFO* pExepInfo,
1984 UINT* puArgErr)
1986 FIXME("(dispid: %ld):Stub\n",dispIdMember);
1988 VariantInit(pVarResult);
1989 V_VT(pVarResult) = VT_BOOL;
1990 V_BOOL(pVarResult) = FALSE;
1991 return S_OK;
1995 static const IPictureVtbl OLEPictureImpl_VTable =
1997 OLEPictureImpl_QueryInterface,
1998 OLEPictureImpl_AddRef,
1999 OLEPictureImpl_Release,
2000 OLEPictureImpl_get_Handle,
2001 OLEPictureImpl_get_hPal,
2002 OLEPictureImpl_get_Type,
2003 OLEPictureImpl_get_Width,
2004 OLEPictureImpl_get_Height,
2005 OLEPictureImpl_Render,
2006 OLEPictureImpl_set_hPal,
2007 OLEPictureImpl_get_CurDC,
2008 OLEPictureImpl_SelectPicture,
2009 OLEPictureImpl_get_KeepOriginalFormat,
2010 OLEPictureImpl_put_KeepOriginalFormat,
2011 OLEPictureImpl_PictureChanged,
2012 OLEPictureImpl_SaveAsFile,
2013 OLEPictureImpl_get_Attributes
2016 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2018 OLEPictureImpl_IDispatch_QueryInterface,
2019 OLEPictureImpl_IDispatch_AddRef,
2020 OLEPictureImpl_IDispatch_Release,
2021 OLEPictureImpl_GetTypeInfoCount,
2022 OLEPictureImpl_GetTypeInfo,
2023 OLEPictureImpl_GetIDsOfNames,
2024 OLEPictureImpl_Invoke
2027 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2029 OLEPictureImpl_IPersistStream_QueryInterface,
2030 OLEPictureImpl_IPersistStream_AddRef,
2031 OLEPictureImpl_IPersistStream_Release,
2032 OLEPictureImpl_GetClassID,
2033 OLEPictureImpl_IsDirty,
2034 OLEPictureImpl_Load,
2035 OLEPictureImpl_Save,
2036 OLEPictureImpl_GetSizeMax
2039 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2041 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2042 OLEPictureImpl_IConnectionPointContainer_AddRef,
2043 OLEPictureImpl_IConnectionPointContainer_Release,
2044 OLEPictureImpl_EnumConnectionPoints,
2045 OLEPictureImpl_FindConnectionPoint
2048 /***********************************************************************
2049 * OleCreatePictureIndirect (OLEAUT32.419)
2051 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2052 BOOL fOwn, LPVOID *ppvObj )
2054 OLEPictureImpl* newPict = NULL;
2055 HRESULT hr = S_OK;
2057 TRACE("(%p,%p,%d,%p)\n", lpPictDesc, riid, fOwn, ppvObj);
2060 * Sanity check
2062 if (ppvObj==0)
2063 return E_POINTER;
2065 *ppvObj = NULL;
2068 * Try to construct a new instance of the class.
2070 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2072 if (newPict == NULL)
2073 return E_OUTOFMEMORY;
2076 * Make sure it supports the interface required by the caller.
2078 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2081 * Release the reference obtained in the constructor. If
2082 * the QueryInterface was unsuccessful, it will free the class.
2084 IPicture_Release((IPicture*)newPict);
2086 return hr;
2090 /***********************************************************************
2091 * OleLoadPicture (OLEAUT32.418)
2093 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2094 REFIID riid, LPVOID *ppvObj )
2096 LPPERSISTSTREAM ps;
2097 IPicture *newpic;
2098 HRESULT hr;
2100 TRACE("(%p,%ld,%d,%s,%p), partially implemented.\n",
2101 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2103 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2104 if (hr)
2105 return hr;
2106 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2107 if (hr) {
2108 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2109 IPicture_Release(newpic);
2110 *ppvObj = NULL;
2111 return hr;
2113 IPersistStream_Load(ps,lpstream);
2114 IPersistStream_Release(ps);
2115 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2116 if (hr)
2117 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2118 IPicture_Release(newpic);
2119 return hr;
2122 /***********************************************************************
2123 * OleLoadPictureEx (OLEAUT32.401)
2125 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2126 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2128 LPPERSISTSTREAM ps;
2129 IPicture *newpic;
2130 HRESULT hr;
2132 FIXME("(%p,%ld,%d,%s,x=%ld,y=%ld,f=%lx,%p), partially implemented.\n",
2133 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2135 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2136 if (hr)
2137 return hr;
2138 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2139 if (hr) {
2140 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
2141 IPicture_Release(newpic);
2142 *ppvObj = NULL;
2143 return hr;
2145 IPersistStream_Load(ps,lpstream);
2146 IPersistStream_Release(ps);
2147 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2148 if (hr)
2149 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2150 IPicture_Release(newpic);
2151 return hr;
2154 /***********************************************************************
2155 * OleLoadPicturePath (OLEAUT32.424)
2157 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2158 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2159 LPVOID *ppvRet )
2161 static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2162 IPicture *ipicture;
2163 HANDLE hFile;
2164 DWORD dwFileSize;
2165 HGLOBAL hGlobal = NULL;
2166 DWORD dwBytesRead = 0;
2167 IStream *stream;
2168 BOOL bRead;
2169 IPersistStream *pStream;
2170 HRESULT hRes;
2172 TRACE("(%s,%p,%ld,%08lx,%s,%p): stub\n",
2173 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2174 debugstr_guid(riid), ppvRet);
2176 if (!ppvRet) return E_POINTER;
2178 if (strncmpW(szURLorPath, file, 7) == 0) {
2179 szURLorPath += 7;
2181 hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2182 0, NULL);
2183 if (hFile == INVALID_HANDLE_VALUE)
2184 return E_UNEXPECTED;
2186 dwFileSize = GetFileSize(hFile, NULL);
2187 if (dwFileSize != INVALID_FILE_SIZE )
2189 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2190 if ( hGlobal)
2192 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2193 if (!bRead)
2195 GlobalFree(hGlobal);
2196 hGlobal = 0;
2200 CloseHandle(hFile);
2202 if (!hGlobal)
2203 return E_UNEXPECTED;
2205 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2206 if (FAILED(hRes))
2208 GlobalFree(hGlobal);
2209 return hRes;
2211 } else {
2212 IMoniker *pmnk;
2213 IBindCtx *pbc;
2215 hRes = CreateBindCtx(0, &pbc);
2216 if (SUCCEEDED(hRes))
2218 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2219 if (SUCCEEDED(hRes))
2221 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2222 IMoniker_Release(pmnk);
2224 IBindCtx_Release(pbc);
2226 if (FAILED(hRes))
2227 return hRes;
2230 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2231 &IID_IPicture, (LPVOID*)&ipicture);
2232 if (hRes != S_OK) {
2233 IStream_Release(stream);
2234 return hRes;
2237 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2238 if (hRes) {
2239 IStream_Release(stream);
2240 IPicture_Release(ipicture);
2241 return hRes;
2244 hRes = IPersistStream_Load(pStream, stream);
2245 IPersistStream_Release(pStream);
2246 IStream_Release(stream);
2248 if (hRes) {
2249 IPicture_Release(ipicture);
2250 return hRes;
2253 hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2254 if (hRes)
2255 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2257 IPicture_Release(ipicture);
2258 return hRes;
2261 /*******************************************************************************
2262 * StdPic ClassFactory
2264 typedef struct
2266 /* IUnknown fields */
2267 const IClassFactoryVtbl *lpVtbl;
2268 LONG ref;
2269 } IClassFactoryImpl;
2271 static HRESULT WINAPI
2272 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2273 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2275 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2276 return E_NOINTERFACE;
2279 static ULONG WINAPI
2280 SPCF_AddRef(LPCLASSFACTORY iface) {
2281 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2282 return InterlockedIncrement(&This->ref);
2285 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2286 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2287 /* static class, won't be freed */
2288 return InterlockedDecrement(&This->ref);
2291 static HRESULT WINAPI SPCF_CreateInstance(
2292 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2294 /* Creates an uninitialized picture */
2295 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2299 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2300 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2301 FIXME("(%p)->(%d),stub!\n",This,dolock);
2302 return S_OK;
2305 static const IClassFactoryVtbl SPCF_Vtbl = {
2306 SPCF_QueryInterface,
2307 SPCF_AddRef,
2308 SPCF_Release,
2309 SPCF_CreateInstance,
2310 SPCF_LockServer
2312 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2314 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }