Remove two ancient FAQ entries that did more harm than good.
[wine.git] / dlls / oleaut32 / olepicture.c
blobde74c36a7426b489a61a75a6c9e1b85bcf58cd3f
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 "wine/debug.h"
76 #include "wine/wingdi16.h"
77 #include "cursoricon.h"
79 #ifdef HAVE_JPEGLIB_H
80 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
81 #define XMD_H
82 #define UINT8 JPEG_UINT8
83 #define UINT16 JPEG_UINT16
84 #undef FAR
85 # include <jpeglib.h>
86 #undef UINT16
87 #ifndef SONAME_LIBJPEG
88 #define SONAME_LIBJPEG "libjpeg.so"
89 #endif
90 #endif
92 WINE_DEFAULT_DEBUG_CHANNEL(ole);
94 /*************************************************************************
95 * Declaration of implementation class
98 typedef struct OLEPictureImpl {
101 * IPicture handles IUnknown
104 IPictureVtbl *lpvtbl1;
105 IDispatchVtbl *lpvtbl2;
106 IPersistStreamVtbl *lpvtbl3;
107 IConnectionPointContainerVtbl *lpvtbl4;
109 /* Object referenece count */
110 DWORD ref;
112 /* We own the object and must destroy it ourselves */
113 BOOL fOwn;
115 /* Picture description */
116 PICTDESC desc;
118 /* These are the pixel size of a bitmap */
119 DWORD origWidth;
120 DWORD origHeight;
122 /* And these are the size of the picture converted into HIMETRIC units */
123 OLE_XSIZE_HIMETRIC himetricWidth;
124 OLE_YSIZE_HIMETRIC himetricHeight;
126 IConnectionPoint *pCP;
128 BOOL keepOrigFormat;
129 HDC hDCCur;
131 /* Bitmap transparency mask */
132 HBITMAP hbmMask;
133 COLORREF rgbTrans;
135 /* data */
136 void* data;
137 int datalen;
138 BOOL bIsDirty; /* Set to TRUE if picture has changed */
139 unsigned int loadtime_magic; /* If a length header was found, saves value */
140 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
141 } OLEPictureImpl;
144 * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
146 #define ICOM_THIS_From_IDispatch(impl, name) \
147 impl *This = (impl*)(((char*)name)-sizeof(void*));
148 #define ICOM_THIS_From_IPersistStream(impl, name) \
149 impl *This = (impl*)(((char*)name)-2*sizeof(void*));
150 #define ICOM_THIS_From_IConnectionPointContainer(impl, name) \
151 impl *This = (impl*)(((char*)name)-3*sizeof(void*));
154 * Predeclare VTables. They get initialized at the end.
156 static IPictureVtbl OLEPictureImpl_VTable;
157 static IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
158 static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
159 static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
161 /***********************************************************************
162 * Implementation of the OLEPictureImpl class.
165 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
166 BITMAP bm;
167 HDC hdcRef;
169 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
170 if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
171 ERR("GetObject fails\n");
172 return;
174 This->origWidth = bm.bmWidth;
175 This->origHeight = bm.bmHeight;
176 /* The width and height are stored in HIMETRIC units (0.01 mm),
177 so we take our pixel width divide by pixels per inch and
178 multiply by 25.4 * 100 */
179 /* Should we use GetBitmapDimension if available? */
180 hdcRef = CreateCompatibleDC(0);
181 This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
182 This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
183 DeleteDC(hdcRef);
186 /************************************************************************
187 * OLEPictureImpl_Construct
189 * This method will construct a new instance of the OLEPictureImpl
190 * class.
192 * The caller of this method must release the object when it's
193 * done with it.
195 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
197 OLEPictureImpl* newObject = 0;
199 if (pictDesc)
200 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
203 * Allocate space for the object.
205 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
207 if (newObject==0)
208 return newObject;
211 * Initialize the virtual function table.
213 newObject->lpvtbl1 = &OLEPictureImpl_VTable;
214 newObject->lpvtbl2 = &OLEPictureImpl_IDispatch_VTable;
215 newObject->lpvtbl3 = &OLEPictureImpl_IPersistStream_VTable;
216 newObject->lpvtbl4 = &OLEPictureImpl_IConnectionPointContainer_VTable;
218 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
221 * Start with one reference count. The caller of this function
222 * must release the interface pointer when it is done.
224 newObject->ref = 1;
225 newObject->hDCCur = 0;
227 newObject->fOwn = fOwn;
229 /* dunno about original value */
230 newObject->keepOrigFormat = TRUE;
232 newObject->hbmMask = NULL;
233 newObject->loadtime_magic = 0xdeadbeef;
234 newObject->loadtime_format = 0;
235 newObject->bIsDirty = FALSE;
237 if (pictDesc) {
238 if(pictDesc->cbSizeofstruct != sizeof(PICTDESC)) {
239 FIXME("struct size = %d\n", pictDesc->cbSizeofstruct);
241 memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC));
244 switch(pictDesc->picType) {
245 case PICTYPE_BITMAP:
246 OLEPictureImpl_SetBitmap(newObject);
247 break;
249 case PICTYPE_METAFILE:
250 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
251 newObject->himetricWidth = pictDesc->u.wmf.xExt;
252 newObject->himetricHeight = pictDesc->u.wmf.yExt;
253 break;
255 case PICTYPE_NONE:
256 /* not sure what to do here */
257 newObject->himetricWidth = newObject->himetricHeight = 0;
258 break;
260 case PICTYPE_ICON:
261 case PICTYPE_ENHMETAFILE:
262 default:
263 FIXME("Unsupported type %d\n", pictDesc->picType);
264 newObject->himetricWidth = newObject->himetricHeight = 0;
265 break;
267 } else {
268 newObject->desc.picType = PICTYPE_UNINITIALIZED;
271 TRACE("returning %p\n", newObject);
272 return newObject;
275 /************************************************************************
276 * OLEPictureImpl_Destroy
278 * This method is called by the Release method when the reference
279 * count goes down to 0. It will free all resources used by
280 * this object. */
281 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
283 TRACE("(%p)\n", Obj);
285 if(Obj->fOwn) { /* We need to destroy the picture */
286 switch(Obj->desc.picType) {
287 case PICTYPE_BITMAP:
288 DeleteObject(Obj->desc.u.bmp.hbitmap);
289 break;
290 case PICTYPE_METAFILE:
291 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
292 break;
293 case PICTYPE_ICON:
294 DestroyIcon(Obj->desc.u.icon.hicon);
295 break;
296 case PICTYPE_ENHMETAFILE:
297 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
298 break;
299 default:
300 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
301 break;
304 HeapFree(GetProcessHeap(), 0, Obj->data);
305 HeapFree(GetProcessHeap(), 0, Obj);
308 static ULONG WINAPI OLEPictureImpl_AddRef(IPicture* iface);
310 /************************************************************************
311 * OLEPictureImpl_QueryInterface (IUnknown)
313 * See Windows documentation for more details on IUnknown methods.
315 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
316 IPicture* iface,
317 REFIID riid,
318 void** ppvObject)
320 OLEPictureImpl *This = (OLEPictureImpl *)iface;
321 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
324 * Perform a sanity check on the parameters.
326 if ( (This==0) || (ppvObject==0) )
327 return E_INVALIDARG;
330 * Initialize the return parameter.
332 *ppvObject = 0;
335 * Compare the riid with the interface IDs implemented by this object.
337 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
339 *ppvObject = (IPicture*)This;
341 else if (memcmp(&IID_IPicture, riid, sizeof(IID_IPicture)) == 0)
343 *ppvObject = (IPicture*)This;
345 else if (memcmp(&IID_IDispatch, riid, sizeof(IID_IDispatch)) == 0)
347 *ppvObject = (IDispatch*)&(This->lpvtbl2);
349 else if (memcmp(&IID_IPictureDisp, riid, sizeof(IID_IPictureDisp)) == 0)
351 *ppvObject = (IDispatch*)&(This->lpvtbl2);
353 else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0)
355 *ppvObject = (IPersistStream*)&(This->lpvtbl3);
357 else if (memcmp(&IID_IConnectionPointContainer, riid, sizeof(IID_IConnectionPointContainer)) == 0)
359 *ppvObject = (IConnectionPointContainer*)&(This->lpvtbl4);
362 * Check that we obtained an interface.
364 if ((*ppvObject)==0)
366 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
367 return E_NOINTERFACE;
371 * Query Interface always increases the reference count by one when it is
372 * successful
374 OLEPictureImpl_AddRef((IPicture*)This);
376 return S_OK;
378 /***********************************************************************
379 * OLEPicture_SendNotify (internal)
381 * Sends notification messages of changed properties to any interested
382 * connections.
384 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
386 IEnumConnections *pEnum;
387 CONNECTDATA CD;
389 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
390 return;
391 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
392 IPropertyNotifySink *sink;
394 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
395 IPropertyNotifySink_OnChanged(sink, dispID);
396 IPropertyNotifySink_Release(sink);
397 IUnknown_Release(CD.pUnk);
399 IEnumConnections_Release(pEnum);
400 return;
403 /************************************************************************
404 * OLEPictureImpl_AddRef (IUnknown)
406 * See Windows documentation for more details on IUnknown methods.
408 static ULONG WINAPI OLEPictureImpl_AddRef(
409 IPicture* iface)
411 OLEPictureImpl *This = (OLEPictureImpl *)iface;
412 ULONG refCount = InterlockedIncrement(&This->ref);
414 TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1);
416 return refCount;
419 /************************************************************************
420 * OLEPictureImpl_Release (IUnknown)
422 * See Windows documentation for more details on IUnknown methods.
424 static ULONG WINAPI OLEPictureImpl_Release(
425 IPicture* iface)
427 OLEPictureImpl *This = (OLEPictureImpl *)iface;
428 ULONG refCount = InterlockedDecrement(&This->ref);
430 TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1);
433 * If the reference count goes down to 0, perform suicide.
435 if (!refCount) OLEPictureImpl_Destroy(This);
437 return refCount;
441 /************************************************************************
442 * OLEPictureImpl_get_Handle
444 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
445 OLE_HANDLE *phandle)
447 OLEPictureImpl *This = (OLEPictureImpl *)iface;
448 TRACE("(%p)->(%p)\n", This, phandle);
449 switch(This->desc.picType) {
450 case PICTYPE_BITMAP:
451 *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
452 break;
453 case PICTYPE_METAFILE:
454 *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
455 break;
456 case PICTYPE_ICON:
457 *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
458 break;
459 case PICTYPE_ENHMETAFILE:
460 *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
461 break;
462 default:
463 FIXME("Unimplemented type %d\n", This->desc.picType);
464 return E_NOTIMPL;
466 TRACE("returning handle %08x\n", *phandle);
467 return S_OK;
470 /************************************************************************
471 * OLEPictureImpl_get_hPal
473 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
474 OLE_HANDLE *phandle)
476 OLEPictureImpl *This = (OLEPictureImpl *)iface;
477 FIXME("(%p)->(%p): stub\n", This, phandle);
478 return E_NOTIMPL;
481 /************************************************************************
482 * OLEPictureImpl_get_Type
484 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
485 short *ptype)
487 OLEPictureImpl *This = (OLEPictureImpl *)iface;
488 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
489 *ptype = This->desc.picType;
490 return S_OK;
493 /************************************************************************
494 * OLEPictureImpl_get_Width
496 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
497 OLE_XSIZE_HIMETRIC *pwidth)
499 OLEPictureImpl *This = (OLEPictureImpl *)iface;
500 TRACE("(%p)->(%p): width is %ld\n", This, pwidth, This->himetricWidth);
501 *pwidth = This->himetricWidth;
502 return S_OK;
505 /************************************************************************
506 * OLEPictureImpl_get_Height
508 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
509 OLE_YSIZE_HIMETRIC *pheight)
511 OLEPictureImpl *This = (OLEPictureImpl *)iface;
512 TRACE("(%p)->(%p): height is %ld\n", This, pheight, This->himetricHeight);
513 *pheight = This->himetricHeight;
514 return S_OK;
517 /************************************************************************
518 * OLEPictureImpl_Render
520 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
521 LONG x, LONG y, LONG cx, LONG cy,
522 OLE_XPOS_HIMETRIC xSrc,
523 OLE_YPOS_HIMETRIC ySrc,
524 OLE_XSIZE_HIMETRIC cxSrc,
525 OLE_YSIZE_HIMETRIC cySrc,
526 LPCRECT prcWBounds)
528 OLEPictureImpl *This = (OLEPictureImpl *)iface;
529 TRACE("(%p)->(%p, (%ld,%ld), (%ld,%ld) <- (%ld,%ld), (%ld,%ld), %p)\n",
530 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
531 if(prcWBounds)
532 TRACE("prcWBounds (%ld,%ld) - (%ld,%ld)\n", prcWBounds->left, prcWBounds->top,
533 prcWBounds->right, prcWBounds->bottom);
536 * While the documentation suggests this to be here (or after rendering?)
537 * it does cause an endless recursion in my sample app. -MM 20010804
538 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
541 switch(This->desc.picType) {
542 case PICTYPE_BITMAP:
544 HBITMAP hbmpOld;
545 HDC hdcBmp;
547 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
548 NB y-axis gets flipped */
550 hdcBmp = CreateCompatibleDC(0);
551 SetMapMode(hdcBmp, MM_ANISOTROPIC);
552 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
553 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
554 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
555 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
557 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
559 if (This->hbmMask) {
560 HDC hdcMask = CreateCompatibleDC(0);
561 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
563 SetMapMode(hdcMask, MM_ANISOTROPIC);
564 SetWindowOrgEx(hdcMask, 0, 0, NULL);
565 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
566 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
567 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
569 SetBkColor(hdc, RGB(255, 255, 255));
570 SetTextColor(hdc, RGB(0, 0, 0));
571 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
572 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
574 SelectObject(hdcMask, hOldbm);
575 DeleteDC(hdcMask);
576 } else
577 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
579 SelectObject(hdcBmp, hbmpOld);
580 DeleteDC(hdcBmp);
582 break;
583 case PICTYPE_ICON:
584 FIXME("Not quite correct implementation of rendering icons...\n");
585 DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
586 break;
588 case PICTYPE_METAFILE:
589 case PICTYPE_ENHMETAFILE:
590 default:
591 FIXME("type %d not implemented\n", This->desc.picType);
592 return E_NOTIMPL;
594 return S_OK;
597 /************************************************************************
598 * OLEPictureImpl_set_hPal
600 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
601 OLE_HANDLE hpal)
603 OLEPictureImpl *This = (OLEPictureImpl *)iface;
604 FIXME("(%p)->(%08x): stub\n", This, hpal);
605 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
606 return E_NOTIMPL;
609 /************************************************************************
610 * OLEPictureImpl_get_CurDC
612 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
613 HDC *phdc)
615 OLEPictureImpl *This = (OLEPictureImpl *)iface;
616 TRACE("(%p), returning %p\n", This, This->hDCCur);
617 if (phdc) *phdc = This->hDCCur;
618 return S_OK;
621 /************************************************************************
622 * OLEPictureImpl_SelectPicture
624 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
625 HDC hdcIn,
626 HDC *phdcOut,
627 OLE_HANDLE *phbmpOut)
629 OLEPictureImpl *This = (OLEPictureImpl *)iface;
630 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
631 if (This->desc.picType == PICTYPE_BITMAP) {
632 SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
634 if (phdcOut)
635 *phdcOut = This->hDCCur;
636 This->hDCCur = hdcIn;
637 if (phbmpOut)
638 *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
639 return S_OK;
640 } else {
641 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
642 return E_FAIL;
646 /************************************************************************
647 * OLEPictureImpl_get_KeepOriginalFormat
649 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
650 BOOL *pfKeep)
652 OLEPictureImpl *This = (OLEPictureImpl *)iface;
653 TRACE("(%p)->(%p)\n", This, pfKeep);
654 if (!pfKeep)
655 return E_POINTER;
656 *pfKeep = This->keepOrigFormat;
657 return S_OK;
660 /************************************************************************
661 * OLEPictureImpl_put_KeepOriginalFormat
663 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
664 BOOL keep)
666 OLEPictureImpl *This = (OLEPictureImpl *)iface;
667 TRACE("(%p)->(%d)\n", This, keep);
668 This->keepOrigFormat = keep;
669 /* FIXME: what DISPID notification here? */
670 return S_OK;
673 /************************************************************************
674 * OLEPictureImpl_PictureChanged
676 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
678 OLEPictureImpl *This = (OLEPictureImpl *)iface;
679 TRACE("(%p)->()\n", This);
680 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
681 This->bIsDirty = TRUE;
682 return S_OK;
685 /************************************************************************
686 * OLEPictureImpl_SaveAsFile
688 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
689 IStream *pstream,
690 BOOL SaveMemCopy,
691 LONG *pcbSize)
693 OLEPictureImpl *This = (OLEPictureImpl *)iface;
694 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
695 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
698 /************************************************************************
699 * OLEPictureImpl_get_Attributes
701 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
702 DWORD *pdwAttr)
704 OLEPictureImpl *This = (OLEPictureImpl *)iface;
705 TRACE("(%p)->(%p).\n", This, pdwAttr);
706 *pdwAttr = 0;
707 switch (This->desc.picType) {
708 case PICTYPE_BITMAP: break; /* not 'truely' scalable, see MSDN. */
709 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
710 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
711 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
713 return S_OK;
717 /************************************************************************
718 * IConnectionPointContainer
721 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
722 IConnectionPointContainer* iface,
723 REFIID riid,
724 VOID** ppvoid
726 ICOM_THIS_From_IConnectionPointContainer(IPicture,iface);
728 return IPicture_QueryInterface(This,riid,ppvoid);
731 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
732 IConnectionPointContainer* iface)
734 ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
736 return IPicture_AddRef(This);
739 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
740 IConnectionPointContainer* iface)
742 ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
744 return IPicture_Release(This);
747 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
748 IConnectionPointContainer* iface,
749 IEnumConnectionPoints** ppEnum
751 ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
753 FIXME("(%p,%p), stub!\n",This,ppEnum);
754 return E_NOTIMPL;
757 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
758 IConnectionPointContainer* iface,
759 REFIID riid,
760 IConnectionPoint **ppCP
762 ICOM_THIS_From_IConnectionPointContainer(OLEPictureImpl, iface);
763 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
764 if (!ppCP)
765 return E_POINTER;
766 *ppCP = NULL;
767 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
768 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
769 FIXME("tried to find connection point on %s?\n",debugstr_guid(riid));
770 return 0x80040200;
772 /************************************************************************
773 * IPersistStream
775 /************************************************************************
776 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
778 * See Windows documentation for more details on IUnknown methods.
780 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
781 IPersistStream* iface,
782 REFIID riid,
783 VOID** ppvoid)
785 ICOM_THIS_From_IPersistStream(IPicture, iface);
787 return IPicture_QueryInterface(This, riid, ppvoid);
790 /************************************************************************
791 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
793 * See Windows documentation for more details on IUnknown methods.
795 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
796 IPersistStream* iface)
798 ICOM_THIS_From_IPersistStream(IPicture, iface);
800 return IPicture_AddRef(This);
803 /************************************************************************
804 * OLEPictureImpl_IPersistStream_Release (IUnknown)
806 * See Windows documentation for more details on IUnknown methods.
808 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
809 IPersistStream* iface)
811 ICOM_THIS_From_IPersistStream(IPicture, iface);
813 return IPicture_Release(This);
816 /************************************************************************
817 * OLEPictureImpl_IPersistStream_GetClassID
819 static HRESULT WINAPI OLEPictureImpl_GetClassID(
820 IPersistStream* iface,CLSID* pClassID)
822 ICOM_THIS_From_IPersistStream(IPicture, iface);
823 FIXME("(%p),stub!\n",This);
824 return E_FAIL;
827 /************************************************************************
828 * OLEPictureImpl_IPersistStream_IsDirty
830 static HRESULT WINAPI OLEPictureImpl_IsDirty(
831 IPersistStream* iface)
833 ICOM_THIS_From_IPersistStream(IPicture, iface);
834 FIXME("(%p),stub!\n",This);
835 return E_NOTIMPL;
838 #ifdef HAVE_JPEGLIB_H
840 static void *libjpeg_handle;
841 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
842 MAKE_FUNCPTR(jpeg_std_error);
843 MAKE_FUNCPTR(jpeg_CreateDecompress);
844 MAKE_FUNCPTR(jpeg_read_header);
845 MAKE_FUNCPTR(jpeg_start_decompress);
846 MAKE_FUNCPTR(jpeg_read_scanlines);
847 MAKE_FUNCPTR(jpeg_finish_decompress);
848 MAKE_FUNCPTR(jpeg_destroy_decompress);
849 #undef MAKE_FUNCPTR
851 static void *load_libjpeg(void)
853 if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
855 #define LOAD_FUNCPTR(f) \
856 if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
857 libjpeg_handle = NULL; \
858 return NULL; \
861 LOAD_FUNCPTR(jpeg_std_error);
862 LOAD_FUNCPTR(jpeg_CreateDecompress);
863 LOAD_FUNCPTR(jpeg_read_header);
864 LOAD_FUNCPTR(jpeg_start_decompress);
865 LOAD_FUNCPTR(jpeg_read_scanlines);
866 LOAD_FUNCPTR(jpeg_finish_decompress);
867 LOAD_FUNCPTR(jpeg_destroy_decompress);
868 #undef LOAD_FUNCPTR
870 return libjpeg_handle;
873 /* for the jpeg decompressor source manager. */
874 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
876 static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
877 ERR("(), should not get here.\n");
878 return FALSE;
881 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
882 TRACE("Skipping %ld bytes...\n", num_bytes);
883 cinfo->src->next_input_byte += num_bytes;
884 cinfo->src->bytes_in_buffer -= num_bytes;
887 static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
888 ERR("(desired=%d), should not get here.\n",desired);
889 return FALSE;
891 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
892 #endif /* HAVE_JPEGLIB_H */
894 #ifdef HAVE_GIF_LIB_H
896 static void *libungif_handle;
897 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
898 MAKE_FUNCPTR(DGifOpen);
899 MAKE_FUNCPTR(DGifSlurp);
900 MAKE_FUNCPTR(DGifCloseFile);
901 #undef MAKE_FUNCPTR
903 struct gifdata {
904 unsigned char *data;
905 unsigned int curoff;
906 unsigned int len;
909 static void *load_libungif(void)
911 if(((libungif_handle = wine_dlopen(SONAME_LIBUNGIF, RTLD_NOW, NULL, 0)) != NULL) ||
912 ((libungif_handle = wine_dlopen(SONAME_LIBGIF , RTLD_NOW, NULL, 0)) != NULL)
915 #define LOAD_FUNCPTR(f) \
916 if((p##f = wine_dlsym(libungif_handle, #f, NULL, 0)) == NULL) { \
917 libungif_handle = NULL; \
918 return NULL; \
921 LOAD_FUNCPTR(DGifOpen);
922 LOAD_FUNCPTR(DGifSlurp);
923 LOAD_FUNCPTR(DGifCloseFile);
924 #undef LOAD_FUNCPTR
926 return libungif_handle;
929 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
930 struct gifdata *gd = (struct gifdata*)gif->UserData;
932 if (len+gd->curoff > gd->len) {
933 FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
934 len = gd->len - gd->curoff;
936 memcpy(data, gd->data+gd->curoff, len);
937 gd->curoff += len;
938 return len;
941 #endif /* HAVE_GIF_LIB_H */
943 /************************************************************************
944 * OLEPictureImpl_IPersistStream_Load (IUnknown)
946 * Loads the binary data from the IStream. Starts at current position.
947 * There appears to be an 2 DWORD header:
948 * DWORD magic;
949 * DWORD len;
951 * Currently implemented: BITMAP, ICON, JPEG, GIF
953 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
954 HRESULT hr = E_FAIL;
955 ULONG xread;
956 BYTE *xbuf;
957 DWORD header[2];
958 WORD magic;
959 STATSTG statstg;
960 ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface);
962 TRACE("(%p,%p)\n",This,pStm);
964 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
965 * out whether we do.
967 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
968 * compound file. This may explain most, if not all, of the cases of "no header",
969 * and the header validation should take this into account. At least in Visual Basic 6,
970 * resource streams, valid headers are
971 * header[0] == "lt\0\0",
972 * header[1] == length_of_stream.
974 hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
975 if (hr)
976 FIXME("Stat failed with hres %lx\n",hr);
977 hr=IStream_Read(pStm,header,8,&xread);
978 if (hr || xread!=8) {
979 FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
980 return hr;
982 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
983 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
984 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
985 header[1] > statstg.cbSize.QuadPart || (header[1]==0)) {/* Incorrect header, assume none. */
986 xread = 8;
987 xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,statstg.cbSize.QuadPart);
988 memcpy(xbuf,&header,8);
989 This->datalen = statstg.cbSize.QuadPart;
990 while (xread < This->datalen) {
991 ULONG nread;
992 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
993 xread+=nread;
994 if (hr || !nread)
995 break;
997 if (xread != This->datalen)
998 FIXME("Could only read %ld of %d bytes in no-header case?\n",xread,This->datalen);
999 } else {
1000 xread = 0;
1001 xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]);
1002 This->datalen = header[1];
1003 while (xread < header[1]) {
1004 ULONG nread;
1005 hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread);
1006 xread+=nread;
1007 if (hr || !nread)
1008 break;
1010 if (xread != header[1])
1011 FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]);
1013 magic = xbuf[0] + (xbuf[1]<<8);
1014 switch (magic) {
1015 case 0x4947: { /* GIF */
1016 #ifdef HAVE_GIF_LIB_H
1017 struct gifdata gd;
1018 GifFileType *gif;
1019 BITMAPINFO *bmi;
1020 HDC hdcref;
1021 LPBYTE bytes;
1022 int i,j,ret;
1023 GifImageDesc *gid;
1024 SavedImage *si;
1025 ColorMapObject *cm;
1026 int transparent = -1;
1027 ExtensionBlock *eb;
1028 int padding;
1030 if(!libungif_handle) {
1031 if(!load_libungif()) {
1032 FIXME("Failed reading GIF because unable to find %s/%s\n", SONAME_LIBUNGIF, SONAME_LIBGIF);
1033 return E_FAIL;
1037 gd.data = xbuf;
1038 gd.curoff = 0;
1039 gd.len = xread;
1040 gif = pDGifOpen((void*)&gd, _gif_inputfunc);
1041 ret = pDGifSlurp(gif);
1042 if (ret == GIF_ERROR) {
1043 FIXME("Failed reading GIF using libgif.\n");
1044 return E_FAIL;
1046 TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1047 TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1048 TRACE("imgcnt %d\n", gif->ImageCount);
1049 if (gif->ImageCount<1) {
1050 FIXME("GIF stream does not have images inside?\n");
1051 return E_FAIL;
1053 TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1054 gif->Image.Width, gif->Image.Height,
1055 gif->Image.Left, gif->Image.Top,
1056 gif->Image.Interlace
1058 /* */
1059 padding = (gif->SWidth+3) & ~3;
1060 bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(1<<gif->SColorResolution)*sizeof(RGBQUAD));
1061 bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1062 si = gif->SavedImages+0;
1063 gid = &(si->ImageDesc);
1064 cm = gid->ColorMap;
1065 if (!cm) cm = gif->SColorMap;
1067 /* look for the transparent color extension */
1068 for (i = 0; i < si->ExtensionBlockCount; ++i) {
1069 eb = si->ExtensionBlocks + i;
1070 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1071 if ((eb->Bytes[0] & 1) == 1) {
1072 transparent = eb->Bytes[3];
1077 for (i=0;i<(1<<gif->SColorResolution);i++) {
1078 bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1079 bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1080 bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1081 if (i == transparent) {
1082 This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1083 bmi->bmiColors[i].rgbGreen,
1084 bmi->bmiColors[i].rgbBlue);
1088 /* Map to in picture coordinates */
1089 for (i = 0, j = 0; i < gid->Height; i++) {
1090 if (gif->Image.Interlace) {
1091 memcpy(
1092 bytes + (gid->Top + j) * padding + gid->Left,
1093 si->RasterBits + i * gid->Width,
1094 gid->Width);
1096 /* Lower bits of interlaced counter encode current interlace */
1097 if (j & 1) j += 2; /* Currently filling odd rows */
1098 else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1099 else j += 8; /* Currently filling every 8th row or 4th row in-between */
1101 if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1102 /* End of current interlace, go to next interlace */
1103 if (j & 2) j = 1; /* Next iteration fills odd rows */
1104 else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */
1105 else j = 4; /* Next iteration fills rows in-between rows mod 6 */
1107 } else {
1108 memcpy(
1109 bytes + (gid->Top + i) * padding + gid->Left,
1110 si->RasterBits + i * gid->Width,
1111 gid->Width);
1115 bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1116 bmi->bmiHeader.biWidth = gif->SWidth;
1117 bmi->bmiHeader.biHeight = -gif->SHeight;
1118 bmi->bmiHeader.biPlanes = 1;
1119 bmi->bmiHeader.biBitCount = 8;
1120 bmi->bmiHeader.biCompression = BI_RGB;
1121 bmi->bmiHeader.biSizeImage = padding*gif->SHeight;
1122 bmi->bmiHeader.biXPelsPerMeter = 0;
1123 bmi->bmiHeader.biYPelsPerMeter = 0;
1124 bmi->bmiHeader.biClrUsed = 1 << gif->SColorResolution;
1125 bmi->bmiHeader.biClrImportant = 0;
1127 hdcref = GetDC(0);
1128 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1129 hdcref,
1130 &bmi->bmiHeader,
1131 CBM_INIT,
1132 bytes,
1133 bmi,
1134 DIB_RGB_COLORS
1137 if (transparent > -1) {
1138 /* Create the Mask */
1139 HDC hdc = CreateCompatibleDC(0);
1140 HDC hdcMask = CreateCompatibleDC(0);
1141 HBITMAP hOldbitmap;
1142 HBITMAP hOldbitmapmask;
1144 This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1146 hOldbitmap = SelectObject(hdc,This->desc.u.bmp.hbitmap);
1147 hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1148 SetBkColor(hdc, This->rgbTrans);
1149 BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1151 /* We no longer need the original bitmap, so we apply the first
1152 transformation with the mask to speed up the rendering */
1153 SetBkColor(hdc, RGB(0,0,0));
1154 SetTextColor(hdc, RGB(255,255,255));
1155 BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight,
1156 hdcMask, 0, 0, SRCAND);
1158 SelectObject(hdc, hOldbitmap);
1159 SelectObject(hdcMask, hOldbitmapmask);
1160 DeleteDC(hdcMask);
1161 DeleteDC(hdc);
1164 DeleteDC(hdcref);
1165 This->desc.picType = PICTYPE_BITMAP;
1166 OLEPictureImpl_SetBitmap(This);
1167 pDGifCloseFile(gif);
1168 HeapFree(GetProcessHeap(),0,bytes);
1169 return S_OK;
1170 #else
1171 FIXME("Trying to load GIF, but no support for libgif/libungif compiled in.\n");
1172 return E_FAIL;
1173 #endif
1175 case 0xd8ff: { /* JPEG */
1176 #ifdef HAVE_JPEGLIB_H
1177 struct jpeg_decompress_struct jd;
1178 struct jpeg_error_mgr jerr;
1179 int ret;
1180 JDIMENSION x;
1181 JSAMPROW samprow,oldsamprow;
1182 BITMAPINFOHEADER bmi;
1183 LPBYTE bits;
1184 HDC hdcref;
1185 struct jpeg_source_mgr xjsm;
1186 LPBYTE oldbits;
1187 unsigned int i;
1189 if(!libjpeg_handle) {
1190 if(!load_libjpeg()) {
1191 FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1192 return E_FAIL;
1196 /* This is basically so we can use in-memory data for jpeg decompression.
1197 * We need to have all the functions.
1199 xjsm.next_input_byte = xbuf;
1200 xjsm.bytes_in_buffer = xread;
1201 xjsm.init_source = _jpeg_init_source;
1202 xjsm.fill_input_buffer = _jpeg_fill_input_buffer;
1203 xjsm.skip_input_data = _jpeg_skip_input_data;
1204 xjsm.resync_to_restart = _jpeg_resync_to_restart;
1205 xjsm.term_source = _jpeg_term_source;
1207 jd.err = pjpeg_std_error(&jerr);
1208 /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1209 * jpeg_create_decompress(&jd); */
1210 pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct));
1211 jd.src = &xjsm;
1212 ret=pjpeg_read_header(&jd,TRUE);
1213 jd.out_color_space = JCS_RGB;
1214 pjpeg_start_decompress(&jd);
1215 if (ret != JPEG_HEADER_OK) {
1216 ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1217 HeapFree(GetProcessHeap(),0,xbuf);
1218 return E_FAIL;
1221 bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1222 (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1223 samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1225 oldbits = bits;
1226 oldsamprow = samprow;
1227 while ( jd.output_scanline<jd.output_height ) {
1228 x = pjpeg_read_scanlines(&jd,&samprow,1);
1229 if (x != 1) {
1230 FIXME("failed to read current scanline?\n");
1231 break;
1233 /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1234 for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1235 *(bits++) = *(samprow+2);
1236 *(bits++) = *(samprow+1);
1237 *(bits++) = *(samprow);
1239 bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1240 samprow = oldsamprow;
1242 bits = oldbits;
1244 bmi.biSize = sizeof(bmi);
1245 bmi.biWidth = jd.output_width;
1246 bmi.biHeight = -jd.output_height;
1247 bmi.biPlanes = 1;
1248 bmi.biBitCount = jd.output_components<<3;
1249 bmi.biCompression = BI_RGB;
1250 bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components;
1251 bmi.biXPelsPerMeter = 0;
1252 bmi.biYPelsPerMeter = 0;
1253 bmi.biClrUsed = 0;
1254 bmi.biClrImportant = 0;
1256 HeapFree(GetProcessHeap(),0,samprow);
1257 pjpeg_finish_decompress(&jd);
1258 pjpeg_destroy_decompress(&jd);
1259 hdcref = GetDC(0);
1260 This->desc.u.bmp.hbitmap=CreateDIBitmap(
1261 hdcref,
1262 &bmi,
1263 CBM_INIT,
1264 bits,
1265 (BITMAPINFO*)&bmi,
1266 DIB_RGB_COLORS
1268 DeleteDC(hdcref);
1269 This->desc.picType = PICTYPE_BITMAP;
1270 OLEPictureImpl_SetBitmap(This);
1271 hr = S_OK;
1272 HeapFree(GetProcessHeap(),0,bits);
1273 #else
1274 ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1275 hr = E_FAIL;
1276 #endif
1277 break;
1279 case 0x4d42: { /* Bitmap */
1280 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1281 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1282 HDC hdcref;
1284 /* Does not matter whether this is a coreheader or not, we only use
1285 * components which are in both
1287 hdcref = GetDC(0);
1288 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1289 hdcref,
1290 &(bi->bmiHeader),
1291 CBM_INIT,
1292 xbuf+bfh->bfOffBits,
1294 DIB_RGB_COLORS
1296 DeleteDC(hdcref);
1297 This->desc.picType = PICTYPE_BITMAP;
1298 OLEPictureImpl_SetBitmap(This);
1299 hr = S_OK;
1300 break;
1302 case 0x0000: { /* ICON , first word is dwReserved */
1303 HICON hicon;
1304 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1305 HDC hdcRef;
1306 int i;
1309 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1310 FIXME("icon.idType=%d\n",cifd->idType);
1311 FIXME("icon.idCount=%d\n",cifd->idCount);
1313 for (i=0;i<cifd->idCount;i++) {
1314 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1315 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1316 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1317 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1318 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1319 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1320 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1321 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1324 i=0;
1325 /* If we have more than one icon, try to find the best.
1326 * this currently means '32 pixel wide'.
1328 if (cifd->idCount!=1) {
1329 for (i=0;i<cifd->idCount;i++) {
1330 if (cifd->idEntries[i].bWidth == 32)
1331 break;
1333 if (i==cifd->idCount) i=0;
1336 hicon = CreateIconFromResourceEx(
1337 xbuf+cifd->idEntries[i].dwDIBOffset,
1338 cifd->idEntries[i].dwDIBSize,
1339 TRUE, /* is icon */
1340 0x00030000,
1341 cifd->idEntries[i].bWidth,
1342 cifd->idEntries[i].bHeight,
1345 if (!hicon) {
1346 FIXME("CreateIcon failed.\n");
1347 hr = E_FAIL;
1348 } else {
1349 This->desc.picType = PICTYPE_ICON;
1350 This->desc.u.icon.hicon = hicon;
1351 This->origWidth = cifd->idEntries[i].bWidth;
1352 This->origHeight = cifd->idEntries[i].bHeight;
1353 hdcRef = CreateCompatibleDC(0);
1354 This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1355 This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1356 DeleteDC(hdcRef);
1357 hr = S_OK;
1359 break;
1361 default:
1363 unsigned int i;
1364 FIXME("Unknown magic %04x, %ld read bytes:\n",magic,xread);
1365 hr=E_FAIL;
1366 for (i=0;i<xread+8;i++) {
1367 if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]);
1368 else MESSAGE("%02x ",xbuf[i-8]);
1369 if (i % 10 == 9) MESSAGE("\n");
1371 MESSAGE("\n");
1372 break;
1375 This->bIsDirty = FALSE;
1377 /* FIXME: this notify is not really documented */
1378 if (hr==S_OK)
1379 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1380 return hr;
1383 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength);
1384 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength);
1385 static HRESULT WINAPI OLEPictureImpl_Save(
1386 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1388 HRESULT hResult = E_NOTIMPL;
1389 void * pIconData;
1390 unsigned int iDataSize;
1391 ULONG dummy;
1392 int iSerializeResult = 0;
1394 ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface);
1396 switch (This->desc.picType) {
1397 case PICTYPE_ICON:
1398 if (This->bIsDirty) {
1399 if (serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1400 if (This->loadtime_magic != 0xdeadbeef) {
1401 DWORD header[2];
1403 header[0] = This->loadtime_magic;
1404 header[1] = iDataSize;
1405 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1407 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1409 HeapFree(GetProcessHeap(), 0, This->data);
1410 This->data = pIconData;
1411 This->datalen = iDataSize;
1412 hResult = S_OK;
1413 } else {
1414 FIXME("(%p,%p,%d), unable to serializeIcon()!\n",This,pStm,fClearDirty);
1415 hResult = E_FAIL;
1417 } else {
1418 if (This->loadtime_magic != 0xdeadbeef) {
1419 DWORD header[2];
1421 header[0] = This->loadtime_magic;
1422 header[1] = This->datalen;
1423 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1425 IStream_Write(pStm, This->data, This->datalen, &dummy);
1426 hResult = S_OK;
1428 break;
1429 case PICTYPE_BITMAP:
1430 if (This->bIsDirty) {
1431 switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) {
1432 case 0x4d42:
1433 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1434 break;
1435 case 0xd8ff:
1436 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1437 break;
1438 case 0x4947:
1439 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1440 break;
1441 default:
1442 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1443 break;
1445 if (iSerializeResult) {
1447 if (This->loadtime_magic != 0xdeadbeef) {
1449 if (1) {
1450 DWORD header[2];
1452 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1453 header[1] = iDataSize;
1454 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1456 IStream_Write(pStm, pIconData, iDataSize, &dummy);
1458 HeapFree(GetProcessHeap(), 0, This->data);
1459 This->data = pIconData;
1460 This->datalen = iDataSize;
1461 hResult = S_OK;
1463 } else {
1465 if (This->loadtime_magic != 0xdeadbeef) {
1467 if (1) {
1468 DWORD header[2];
1470 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1471 header[1] = This->datalen;
1472 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1474 IStream_Write(pStm, This->data, This->datalen, &dummy);
1475 hResult = S_OK;
1477 break;
1478 case PICTYPE_METAFILE:
1479 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1480 break;
1481 case PICTYPE_ENHMETAFILE:
1482 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1483 break;
1484 default:
1485 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1486 break;
1488 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1489 return hResult;
1492 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1494 int iSuccess = 0;
1495 HDC hDC;
1496 BITMAPINFO * pInfoBitmap;
1497 int iNumPaletteEntries;
1498 unsigned char * pPixelData;
1499 BITMAPFILEHEADER * pFileHeader;
1500 BITMAPINFO * pInfoHeader;
1502 pInfoBitmap = (BITMAPINFO *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1503 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1505 /* Find out bitmap size and padded length */
1506 hDC = GetDC(0);
1507 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1508 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1510 /* Fetch bitmap palette & pixel data */
1512 pPixelData = (unsigned char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1513 pInfoBitmap->bmiHeader.biSizeImage);
1514 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1516 /* Calculate the total length required for the BMP data */
1517 if (pInfoBitmap->bmiHeader.biClrUsed != 0) iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1518 else if (pInfoBitmap->bmiHeader.biBitCount <= 8) iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1519 else iNumPaletteEntries = 0;
1520 *pLength =
1521 sizeof(BITMAPFILEHEADER) +
1522 sizeof(BITMAPINFOHEADER) +
1523 iNumPaletteEntries * sizeof(RGBQUAD) +
1524 pInfoBitmap->bmiHeader.biSizeImage;
1525 *ppBuffer = (void *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1527 /* Fill the BITMAPFILEHEADER */
1528 pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1529 pFileHeader->bfType = 0x4d42;
1530 pFileHeader->bfSize = *pLength;
1531 pFileHeader->bfOffBits =
1532 sizeof(BITMAPFILEHEADER) +
1533 sizeof(BITMAPINFOHEADER) +
1534 iNumPaletteEntries * sizeof(RGBQUAD);
1536 /* Fill the BITMAPINFOHEADER and the palette data */
1537 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1538 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1539 memcpy(
1540 (unsigned char *)(*ppBuffer) +
1541 sizeof(BITMAPFILEHEADER) +
1542 sizeof(BITMAPINFOHEADER) +
1543 iNumPaletteEntries * sizeof(RGBQUAD),
1544 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1545 iSuccess = 1;
1547 HeapFree(GetProcessHeap(), 0, pPixelData);
1548 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1549 return iSuccess;
1552 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1554 ICONINFO infoIcon;
1555 int iSuccess = 0;
1557 *ppBuffer = NULL; *pLength = 0;
1558 if (GetIconInfo(hIcon, &infoIcon)) {
1559 HDC hDC;
1560 BITMAPINFO * pInfoBitmap;
1561 unsigned char * pIconData = NULL;
1562 unsigned int iDataSize = 0;
1564 pInfoBitmap = (BITMAPINFO *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1566 /* Find out icon size */
1567 hDC = GetDC(0);
1568 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1569 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1570 if (1) {
1571 /* Auxiliary pointers */
1572 CURSORICONFILEDIR * pIconDir;
1573 CURSORICONFILEDIRENTRY * pIconEntry;
1574 BITMAPINFOHEADER * pIconBitmapHeader;
1575 unsigned int iOffsetPalette;
1576 unsigned int iOffsetColorData;
1577 unsigned int iOffsetMaskData;
1579 unsigned int iLengthScanLineColor;
1580 unsigned int iLengthScanLineMask;
1581 unsigned int iNumEntriesPalette;
1583 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1584 iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
1586 FIXME("DEBUG: bitmap size is %d x %d\n",
1587 pInfoBitmap->bmiHeader.biWidth,
1588 pInfoBitmap->bmiHeader.biHeight);
1589 FIXME("DEBUG: bitmap bpp is %d\n",
1590 pInfoBitmap->bmiHeader.biBitCount);
1591 FIXME("DEBUG: bitmap nplanes is %d\n",
1592 pInfoBitmap->bmiHeader.biPlanes);
1593 FIXME("DEBUG: bitmap biSizeImage is %lu\n",
1594 pInfoBitmap->bmiHeader.biSizeImage);
1596 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1597 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1598 pIconData = (unsigned char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1600 /* Fill out the CURSORICONFILEDIR */
1601 pIconDir = (CURSORICONFILEDIR *)pIconData;
1602 pIconDir->idType = 1;
1603 pIconDir->idCount = 1;
1605 /* Fill out the CURSORICONFILEDIRENTRY */
1606 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1607 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1608 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1609 pIconEntry->bColorCount =
1610 (pInfoBitmap->bmiHeader.biBitCount < 8)
1611 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1612 : 0;
1613 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1614 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1615 pIconEntry->dwDIBSize = 0;
1616 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1618 /* Fill out the BITMAPINFOHEADER */
1619 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1620 memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER));
1622 /* Find out whether a palette exists for the bitmap */
1623 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1624 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1625 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1626 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1627 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1628 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1629 iNumEntriesPalette = 3;
1630 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1631 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1632 } else {
1633 iNumEntriesPalette = 0;
1636 /* Add bitmap size and header size to icon data size. */
1637 iOffsetPalette = iDataSize;
1638 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1639 iOffsetColorData = iDataSize;
1640 iDataSize += pIconBitmapHeader->biSizeImage;
1641 iOffsetMaskData = iDataSize;
1642 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1643 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1644 pIconBitmapHeader->biHeight *= 2;
1645 pIconData = (unsigned char *)HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1646 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1647 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1648 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1650 /* Get the actual bitmap data from the icon bitmap */
1651 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1652 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1653 if (iNumEntriesPalette > 0) {
1654 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1655 iNumEntriesPalette * sizeof(RGBQUAD));
1658 /* Reset all values so that GetDIBits call succeeds */
1659 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1660 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1661 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1663 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1664 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1665 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1667 printf("ERROR: unable to get bitmap mask (error %lu)\n",
1668 GetLastError());
1672 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1673 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1675 /* Write out everything produced so far to the stream */
1676 *ppBuffer = pIconData; *pLength = iDataSize;
1677 iSuccess = 1;
1678 } else {
1680 printf("ERROR: unable to get bitmap information via GetDIBits() (error %lu)\n",
1681 GetLastError());
1685 Remarks (from MSDN entry on GetIconInfo):
1687 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1688 members of ICONINFO. The calling application must manage
1689 these bitmaps and delete them when they are no longer
1690 necessary.
1692 if (hDC) ReleaseDC(0, hDC);
1693 DeleteObject(infoIcon.hbmMask);
1694 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1695 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1696 } else {
1697 printf("ERROR: Unable to get icon information (error %lu)\n",
1698 GetLastError());
1700 return iSuccess;
1703 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1704 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1706 ICOM_THIS_From_IPersistStream(IPicture, iface);
1707 FIXME("(%p,%p),stub!\n",This,pcbSize);
1708 return E_NOTIMPL;
1711 /************************************************************************
1712 * IDispatch
1714 /************************************************************************
1715 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1717 * See Windows documentation for more details on IUnknown methods.
1719 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1720 IDispatch* iface,
1721 REFIID riid,
1722 VOID** ppvoid)
1724 ICOM_THIS_From_IDispatch(IPicture, iface);
1726 return IPicture_QueryInterface(This, riid, ppvoid);
1729 /************************************************************************
1730 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1732 * See Windows documentation for more details on IUnknown methods.
1734 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1735 IDispatch* iface)
1737 ICOM_THIS_From_IDispatch(IPicture, iface);
1739 return IPicture_AddRef(This);
1742 /************************************************************************
1743 * OLEPictureImpl_IDispatch_Release (IUnknown)
1745 * See Windows documentation for more details on IUnknown methods.
1747 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1748 IDispatch* iface)
1750 ICOM_THIS_From_IDispatch(IPicture, iface);
1752 return IPicture_Release(This);
1755 /************************************************************************
1756 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1758 * See Windows documentation for more details on IDispatch methods.
1760 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1761 IDispatch* iface,
1762 unsigned int* pctinfo)
1764 FIXME("():Stub\n");
1766 return E_NOTIMPL;
1769 /************************************************************************
1770 * OLEPictureImpl_GetTypeInfo (IDispatch)
1772 * See Windows documentation for more details on IDispatch methods.
1774 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1775 IDispatch* iface,
1776 UINT iTInfo,
1777 LCID lcid,
1778 ITypeInfo** ppTInfo)
1780 FIXME("():Stub\n");
1782 return E_NOTIMPL;
1785 /************************************************************************
1786 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1788 * See Windows documentation for more details on IDispatch methods.
1790 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1791 IDispatch* iface,
1792 REFIID riid,
1793 LPOLESTR* rgszNames,
1794 UINT cNames,
1795 LCID lcid,
1796 DISPID* rgDispId)
1798 FIXME("():Stub\n");
1800 return E_NOTIMPL;
1803 /************************************************************************
1804 * OLEPictureImpl_Invoke (IDispatch)
1806 * See Windows documentation for more details on IDispatch methods.
1808 static HRESULT WINAPI OLEPictureImpl_Invoke(
1809 IDispatch* iface,
1810 DISPID dispIdMember,
1811 REFIID riid,
1812 LCID lcid,
1813 WORD wFlags,
1814 DISPPARAMS* pDispParams,
1815 VARIANT* pVarResult,
1816 EXCEPINFO* pExepInfo,
1817 UINT* puArgErr)
1819 FIXME("(dispid: %ld):Stub\n",dispIdMember);
1821 VariantInit(pVarResult);
1822 V_VT(pVarResult) = VT_BOOL;
1823 V_UNION(pVarResult,boolVal) = FALSE;
1824 return S_OK;
1828 static IPictureVtbl OLEPictureImpl_VTable =
1830 OLEPictureImpl_QueryInterface,
1831 OLEPictureImpl_AddRef,
1832 OLEPictureImpl_Release,
1833 OLEPictureImpl_get_Handle,
1834 OLEPictureImpl_get_hPal,
1835 OLEPictureImpl_get_Type,
1836 OLEPictureImpl_get_Width,
1837 OLEPictureImpl_get_Height,
1838 OLEPictureImpl_Render,
1839 OLEPictureImpl_set_hPal,
1840 OLEPictureImpl_get_CurDC,
1841 OLEPictureImpl_SelectPicture,
1842 OLEPictureImpl_get_KeepOriginalFormat,
1843 OLEPictureImpl_put_KeepOriginalFormat,
1844 OLEPictureImpl_PictureChanged,
1845 OLEPictureImpl_SaveAsFile,
1846 OLEPictureImpl_get_Attributes
1849 static IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
1851 OLEPictureImpl_IDispatch_QueryInterface,
1852 OLEPictureImpl_IDispatch_AddRef,
1853 OLEPictureImpl_IDispatch_Release,
1854 OLEPictureImpl_GetTypeInfoCount,
1855 OLEPictureImpl_GetTypeInfo,
1856 OLEPictureImpl_GetIDsOfNames,
1857 OLEPictureImpl_Invoke
1860 static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
1862 OLEPictureImpl_IPersistStream_QueryInterface,
1863 OLEPictureImpl_IPersistStream_AddRef,
1864 OLEPictureImpl_IPersistStream_Release,
1865 OLEPictureImpl_GetClassID,
1866 OLEPictureImpl_IsDirty,
1867 OLEPictureImpl_Load,
1868 OLEPictureImpl_Save,
1869 OLEPictureImpl_GetSizeMax
1872 static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
1874 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
1875 OLEPictureImpl_IConnectionPointContainer_AddRef,
1876 OLEPictureImpl_IConnectionPointContainer_Release,
1877 OLEPictureImpl_EnumConnectionPoints,
1878 OLEPictureImpl_FindConnectionPoint
1881 /***********************************************************************
1882 * OleCreatePictureIndirect (OLEAUT32.419)
1884 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
1885 BOOL fOwn, LPVOID *ppvObj )
1887 OLEPictureImpl* newPict = NULL;
1888 HRESULT hr = S_OK;
1890 TRACE("(%p,%p,%d,%p)\n", lpPictDesc, riid, fOwn, ppvObj);
1893 * Sanity check
1895 if (ppvObj==0)
1896 return E_POINTER;
1898 *ppvObj = NULL;
1901 * Try to construct a new instance of the class.
1903 newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
1905 if (newPict == NULL)
1906 return E_OUTOFMEMORY;
1909 * Make sure it supports the interface required by the caller.
1911 hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
1914 * Release the reference obtained in the constructor. If
1915 * the QueryInterface was unsuccessful, it will free the class.
1917 IPicture_Release((IPicture*)newPict);
1919 return hr;
1923 /***********************************************************************
1924 * OleLoadPicture (OLEAUT32.418)
1926 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
1927 REFIID riid, LPVOID *ppvObj )
1929 LPPERSISTSTREAM ps;
1930 IPicture *newpic;
1931 HRESULT hr;
1933 TRACE("(%p,%ld,%d,%s,%p), partially implemented.\n",
1934 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
1936 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
1937 if (hr)
1938 return hr;
1939 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
1940 if (hr) {
1941 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
1942 IPicture_Release(newpic);
1943 *ppvObj = NULL;
1944 return hr;
1946 IPersistStream_Load(ps,lpstream);
1947 IPersistStream_Release(ps);
1948 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
1949 if (hr)
1950 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
1951 IPicture_Release(newpic);
1952 return hr;
1955 /***********************************************************************
1956 * OleLoadPictureEx (OLEAUT32.401)
1958 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
1959 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
1961 LPPERSISTSTREAM ps;
1962 IPicture *newpic;
1963 HRESULT hr;
1965 FIXME("(%p,%ld,%d,%s,x=%ld,y=%ld,f=%lx,%p), partially implemented.\n",
1966 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
1968 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
1969 if (hr)
1970 return hr;
1971 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
1972 if (hr) {
1973 FIXME("Could not get IPersistStream iface from Ole Picture?\n");
1974 IPicture_Release(newpic);
1975 *ppvObj = NULL;
1976 return hr;
1978 IPersistStream_Load(ps,lpstream);
1979 IPersistStream_Release(ps);
1980 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
1981 if (hr)
1982 FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
1983 IPicture_Release(newpic);
1984 return hr;
1987 /*******************************************************************************
1988 * StdPic ClassFactory
1990 typedef struct
1992 /* IUnknown fields */
1993 IClassFactoryVtbl *lpVtbl;
1994 DWORD ref;
1995 } IClassFactoryImpl;
1997 static HRESULT WINAPI
1998 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
1999 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2001 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2002 return E_NOINTERFACE;
2005 static ULONG WINAPI
2006 SPCF_AddRef(LPCLASSFACTORY iface) {
2007 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2008 return InterlockedIncrement(&This->ref);
2011 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2012 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2013 /* static class, won't be freed */
2014 return InterlockedDecrement(&This->ref);
2017 static HRESULT WINAPI SPCF_CreateInstance(
2018 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2020 PICTDESC pd;
2022 FIXME("(%p,%p,%s,%p), creating stdpic with PICTYPE_NONE.\n",iface,pOuter,debugstr_guid(riid),ppobj);
2023 pd.cbSizeofstruct = sizeof(pd);
2024 pd.picType = PICTYPE_NONE;
2025 return OleCreatePictureIndirect(&pd,riid,TRUE,ppobj);
2029 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2030 IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2031 FIXME("(%p)->(%d),stub!\n",This,dolock);
2032 return S_OK;
2035 static IClassFactoryVtbl SPCF_Vtbl = {
2036 SPCF_QueryInterface,
2037 SPCF_AddRef,
2038 SPCF_Release,
2039 SPCF_CreateInstance,
2040 SPCF_LockServer
2042 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2044 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }