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