comctl32: Add NULL checks to SetWindowSubclass (Valgrind).
[wine.git] / dlls / oleaut32 / olepicture.c
blob03fd6cf521be62089fc02cd8514802e2cd5ee6c0
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 #define COBJMACROS
50 #define NONAMELESSUNION
52 #include "winerror.h"
53 #include "windef.h"
54 #include "winbase.h"
55 #include "wingdi.h"
56 #include "winuser.h"
57 #include "ole2.h"
58 #include "olectl.h"
59 #include "oleauto.h"
60 #include "connpt.h"
61 #include "urlmon.h"
62 #include "initguid.h"
63 #include "wincodec.h"
64 #include "wine/debug.h"
65 #include "wine/unicode.h"
66 #include "wine/library.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(olepicture);
70 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
71 #define BITMAP_FORMAT_JPEG 0xd8ff
72 #define BITMAP_FORMAT_GIF 0x4947
73 #define BITMAP_FORMAT_PNG 0x5089
74 #define BITMAP_FORMAT_APM 0xcdd7
76 #include "pshpack1.h"
78 /* Header for Aldus Placable Metafiles - a standard metafile follows */
79 typedef struct _APM_HEADER
81 DWORD key;
82 WORD handle;
83 SHORT left;
84 SHORT top;
85 SHORT right;
86 SHORT bottom;
87 WORD inch;
88 DWORD reserved;
89 WORD checksum;
90 } APM_HEADER;
92 typedef struct {
93 BYTE bWidth;
94 BYTE bHeight;
95 BYTE bColorCount;
96 BYTE bReserved;
97 WORD xHotspot;
98 WORD yHotspot;
99 DWORD dwDIBSize;
100 DWORD dwDIBOffset;
101 } CURSORICONFILEDIRENTRY;
103 typedef struct
105 WORD idReserved;
106 WORD idType;
107 WORD idCount;
108 CURSORICONFILEDIRENTRY idEntries[1];
109 } CURSORICONFILEDIR;
111 #include "poppack.h"
113 /*************************************************************************
114 * Declaration of implementation class
117 typedef struct OLEPictureImpl {
120 * IPicture handles IUnknown
123 IPicture IPicture_iface;
124 IDispatch IDispatch_iface;
125 IPersistStream IPersistStream_iface;
126 IConnectionPointContainer IConnectionPointContainer_iface;
128 /* Object reference count */
129 LONG ref;
131 /* We own the object and must destroy it ourselves */
132 BOOL fOwn;
134 /* Picture description */
135 PICTDESC desc;
137 /* These are the pixel size of a bitmap */
138 DWORD origWidth;
139 DWORD origHeight;
141 /* And these are the size of the picture converted into HIMETRIC units */
142 OLE_XSIZE_HIMETRIC himetricWidth;
143 OLE_YSIZE_HIMETRIC himetricHeight;
145 IConnectionPoint *pCP;
147 BOOL keepOrigFormat;
148 HDC hDCCur;
149 HBITMAP stock_bitmap;
151 /* Bitmap transparency mask */
152 HBITMAP hbmMask;
153 HBITMAP hbmXor;
154 COLORREF rgbTrans;
156 /* data */
157 void* data;
158 int datalen;
159 BOOL bIsDirty; /* Set to TRUE if picture has changed */
160 unsigned int loadtime_magic; /* If a length header was found, saves value */
161 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
162 } OLEPictureImpl;
164 static inline OLEPictureImpl *impl_from_IPicture(IPicture *iface)
166 return CONTAINING_RECORD(iface, OLEPictureImpl, IPicture_iface);
169 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
171 return CONTAINING_RECORD(iface, OLEPictureImpl, IDispatch_iface);
174 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
176 return CONTAINING_RECORD(iface, OLEPictureImpl, IPersistStream_iface);
179 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
181 return CONTAINING_RECORD(iface, OLEPictureImpl, IConnectionPointContainer_iface);
185 * Predeclare VTables. They get initialized at the end.
187 static const IPictureVtbl OLEPictureImpl_VTable;
188 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
189 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
190 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
192 /* pixels to HIMETRIC units conversion */
193 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
195 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
198 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
200 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
203 /***********************************************************************
204 * Implementation of the OLEPictureImpl class.
207 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
209 BITMAP bm;
210 HDC hdcRef;
212 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
213 if(GetObjectW(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
214 ERR("GetObject fails\n");
215 return;
217 This->origWidth = bm.bmWidth;
218 This->origHeight = bm.bmHeight;
220 TRACE("width %d, height %d, bpp %d\n", bm.bmWidth, bm.bmHeight, bm.bmBitsPixel);
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);
228 This->himetricWidth = xpixels_to_himetric(bm.bmWidth, hdcRef);
229 This->himetricHeight = ypixels_to_himetric(bm.bmHeight, hdcRef);
230 This->stock_bitmap = GetCurrentObject( hdcRef, OBJ_BITMAP );
232 This->loadtime_format = BITMAP_FORMAT_BMP;
234 DeleteDC(hdcRef);
237 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
239 ICONINFO infoIcon;
241 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
242 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
243 HDC hdcRef;
244 BITMAP bm;
246 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
247 if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
248 ERR("GetObject fails on icon bitmap\n");
249 return;
252 This->origWidth = bm.bmWidth;
253 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
254 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
255 hdcRef = GetDC(0);
257 This->himetricWidth = xpixels_to_himetric(This->origWidth, hdcRef);
258 This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
260 ReleaseDC(0, hdcRef);
262 DeleteObject(infoIcon.hbmMask);
263 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
264 } else {
265 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
269 /************************************************************************
270 * OLEPictureImpl_Construct
272 * This method will construct a new instance of the OLEPictureImpl
273 * class.
275 * The caller of this method must release the object when it's
276 * done with it.
278 static HRESULT OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn, OLEPictureImpl **pict)
280 OLEPictureImpl *newObject;
281 HRESULT hr;
283 if (pictDesc)
284 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
287 * Allocate space for the object.
289 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
290 if (!newObject)
291 return E_OUTOFMEMORY;
294 * Initialize the virtual function table.
296 newObject->IPicture_iface.lpVtbl = &OLEPictureImpl_VTable;
297 newObject->IDispatch_iface.lpVtbl = &OLEPictureImpl_IDispatch_VTable;
298 newObject->IPersistStream_iface.lpVtbl = &OLEPictureImpl_IPersistStream_VTable;
299 newObject->IConnectionPointContainer_iface.lpVtbl = &OLEPictureImpl_IConnectionPointContainer_VTable;
301 newObject->pCP = NULL;
302 hr = CreateConnectionPoint((IUnknown*)&newObject->IPicture_iface, &IID_IPropertyNotifySink,
303 &newObject->pCP);
304 if (hr != S_OK)
306 HeapFree(GetProcessHeap(), 0, newObject);
307 return hr;
311 * Start with one reference count. The caller of this function
312 * must release the interface pointer when it is done.
314 newObject->ref = 1;
315 newObject->hDCCur = 0;
317 newObject->fOwn = fOwn;
319 /* dunno about original value */
320 newObject->keepOrigFormat = TRUE;
322 newObject->hbmMask = NULL;
323 newObject->hbmXor = NULL;
324 newObject->loadtime_magic = 0xdeadbeef;
325 newObject->loadtime_format = 0;
326 newObject->bIsDirty = FALSE;
328 if (pictDesc) {
329 newObject->desc = *pictDesc;
331 switch(pictDesc->picType) {
332 case PICTYPE_BITMAP:
333 OLEPictureImpl_SetBitmap(newObject);
334 break;
336 case PICTYPE_METAFILE:
337 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
338 newObject->himetricWidth = pictDesc->u.wmf.xExt;
339 newObject->himetricHeight = pictDesc->u.wmf.yExt;
340 break;
342 case PICTYPE_NONE:
343 /* not sure what to do here */
344 newObject->himetricWidth = newObject->himetricHeight = 0;
345 break;
347 case PICTYPE_ICON:
348 OLEPictureImpl_SetIcon(newObject);
349 break;
351 case PICTYPE_ENHMETAFILE:
352 FIXME("EMF is not supported\n");
353 newObject->himetricWidth = newObject->himetricHeight = 0;
354 break;
356 default:
357 WARN("Unsupported type %d\n", pictDesc->picType);
358 IPicture_Release(&newObject->IPicture_iface);
359 return E_UNEXPECTED;
361 } else {
362 newObject->desc.picType = PICTYPE_UNINITIALIZED;
365 TRACE("returning %p\n", newObject);
366 *pict = newObject;
367 return S_OK;
370 /************************************************************************
371 * OLEPictureImpl_Destroy
373 * This method is called by the Release method when the reference
374 * count goes down to 0. It will free all resources used by
375 * this object. */
376 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
378 TRACE("(%p)\n", Obj);
380 if (Obj->pCP)
381 IConnectionPoint_Release(Obj->pCP);
383 if(Obj->fOwn) { /* We need to destroy the picture */
384 switch(Obj->desc.picType) {
385 case PICTYPE_BITMAP:
386 DeleteObject(Obj->desc.u.bmp.hbitmap);
387 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
388 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
389 break;
390 case PICTYPE_METAFILE:
391 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
392 break;
393 case PICTYPE_ICON:
394 DestroyIcon(Obj->desc.u.icon.hicon);
395 break;
396 case PICTYPE_ENHMETAFILE:
397 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
398 break;
399 case PICTYPE_NONE:
400 case PICTYPE_UNINITIALIZED:
401 /* Nothing to do */
402 break;
403 default:
404 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
405 break;
408 HeapFree(GetProcessHeap(), 0, Obj->data);
409 HeapFree(GetProcessHeap(), 0, Obj);
413 /************************************************************************
414 * OLEPictureImpl_AddRef (IUnknown)
416 * See Windows documentation for more details on IUnknown methods.
418 static ULONG WINAPI OLEPictureImpl_AddRef(
419 IPicture* iface)
421 OLEPictureImpl *This = impl_from_IPicture(iface);
422 ULONG refCount = InterlockedIncrement(&This->ref);
424 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
426 return refCount;
429 /************************************************************************
430 * OLEPictureImpl_Release (IUnknown)
432 * See Windows documentation for more details on IUnknown methods.
434 static ULONG WINAPI OLEPictureImpl_Release(
435 IPicture* iface)
437 OLEPictureImpl *This = impl_from_IPicture(iface);
438 ULONG refCount = InterlockedDecrement(&This->ref);
440 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
443 * If the reference count goes down to 0, perform suicide.
445 if (!refCount) OLEPictureImpl_Destroy(This);
447 return refCount;
450 /************************************************************************
451 * OLEPictureImpl_QueryInterface (IUnknown)
453 * See Windows documentation for more details on IUnknown methods.
455 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
456 IPicture* iface,
457 REFIID riid,
458 void** ppvObject)
460 OLEPictureImpl *This = impl_from_IPicture(iface);
462 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
464 if (!ppvObject)
465 return E_INVALIDARG;
467 *ppvObject = 0;
469 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
470 *ppvObject = &This->IPicture_iface;
471 else if (IsEqualIID(&IID_IDispatch, riid))
472 *ppvObject = &This->IDispatch_iface;
473 else if (IsEqualIID(&IID_IPictureDisp, riid))
474 *ppvObject = &This->IDispatch_iface;
475 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
476 *ppvObject = &This->IPersistStream_iface;
477 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
478 *ppvObject = &This->IConnectionPointContainer_iface;
480 if (!*ppvObject)
482 FIXME("() : asking for unsupported interface %s\n",debugstr_guid(riid));
483 return E_NOINTERFACE;
486 IPicture_AddRef(iface);
488 return S_OK;
491 /***********************************************************************
492 * OLEPicture_SendNotify (internal)
494 * Sends notification messages of changed properties to any interested
495 * connections.
497 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
499 IEnumConnections *pEnum;
500 CONNECTDATA CD;
502 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
503 return;
504 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
505 IPropertyNotifySink *sink;
507 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
508 IPropertyNotifySink_OnChanged(sink, dispID);
509 IPropertyNotifySink_Release(sink);
510 IUnknown_Release(CD.pUnk);
512 IEnumConnections_Release(pEnum);
515 /************************************************************************
516 * OLEPictureImpl_get_Handle
518 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
519 OLE_HANDLE *phandle)
521 OLEPictureImpl *This = impl_from_IPicture(iface);
522 TRACE("(%p)->(%p)\n", This, phandle);
524 if(!phandle)
525 return E_POINTER;
527 switch(This->desc.picType) {
528 case PICTYPE_NONE:
529 case PICTYPE_UNINITIALIZED:
530 *phandle = 0;
531 break;
532 case PICTYPE_BITMAP:
533 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
534 break;
535 case PICTYPE_METAFILE:
536 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
537 break;
538 case PICTYPE_ICON:
539 *phandle = HandleToUlong(This->desc.u.icon.hicon);
540 break;
541 case PICTYPE_ENHMETAFILE:
542 *phandle = HandleToUlong(This->desc.u.emf.hemf);
543 break;
544 default:
545 FIXME("Unimplemented type %d\n", This->desc.picType);
546 return E_NOTIMPL;
548 TRACE("returning handle %08x\n", *phandle);
549 return S_OK;
552 /************************************************************************
553 * OLEPictureImpl_get_hPal
555 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
556 OLE_HANDLE *phandle)
558 OLEPictureImpl *This = impl_from_IPicture(iface);
560 TRACE("(%p)->(%p)\n", This, phandle);
562 if (!phandle) return E_POINTER;
564 if (This->desc.picType == PICTYPE_BITMAP)
566 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
567 return S_OK;
570 return E_FAIL;
573 /************************************************************************
574 * OLEPictureImpl_get_Type
576 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
577 short *ptype)
579 OLEPictureImpl *This = impl_from_IPicture(iface);
580 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
582 if(!ptype)
583 return E_POINTER;
585 *ptype = This->desc.picType;
586 return S_OK;
589 /************************************************************************
590 * OLEPictureImpl_get_Width
592 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
593 OLE_XSIZE_HIMETRIC *pwidth)
595 OLEPictureImpl *This = impl_from_IPicture(iface);
596 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
597 *pwidth = This->himetricWidth;
598 return S_OK;
601 /************************************************************************
602 * OLEPictureImpl_get_Height
604 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
605 OLE_YSIZE_HIMETRIC *pheight)
607 OLEPictureImpl *This = impl_from_IPicture(iface);
608 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
609 *pheight = This->himetricHeight;
610 return S_OK;
613 static void render_masked_bitmap(OLEPictureImpl *This, HDC hdc,
614 LONG x, LONG y, LONG cx, LONG cy, OLE_XPOS_HIMETRIC xSrc, OLE_YPOS_HIMETRIC ySrc,
615 OLE_XSIZE_HIMETRIC cxSrc, OLE_YSIZE_HIMETRIC cySrc, HBITMAP hbmMask, HBITMAP hbmXor)
617 HBITMAP hbmpOld;
618 HDC hdcBmp;
620 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
621 * NB y-axis gets flipped
624 hdcBmp = CreateCompatibleDC(0);
625 SetMapMode(hdcBmp, MM_ANISOTROPIC);
626 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
627 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
628 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
629 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
631 if (hbmMask)
633 HDC hdcMask = CreateCompatibleDC(0);
634 HBITMAP hOldbm = SelectObject(hdcMask, hbmMask);
636 hbmpOld = SelectObject(hdcBmp, hbmXor);
638 SetMapMode(hdcMask, MM_ANISOTROPIC);
639 SetWindowOrgEx(hdcMask, 0, 0, NULL);
640 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
641 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
642 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
644 SetBkColor(hdc, RGB(255, 255, 255));
645 SetTextColor(hdc, RGB(0, 0, 0));
646 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
647 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
649 SelectObject(hdcMask, hOldbm);
650 DeleteDC(hdcMask);
652 else
654 hbmpOld = SelectObject(hdcBmp, hbmXor);
655 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
658 SelectObject(hdcBmp, hbmpOld);
659 DeleteDC(hdcBmp);
662 /************************************************************************
663 * OLEPictureImpl_Render
665 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
666 LONG x, LONG y, LONG cx, LONG cy,
667 OLE_XPOS_HIMETRIC xSrc,
668 OLE_YPOS_HIMETRIC ySrc,
669 OLE_XSIZE_HIMETRIC cxSrc,
670 OLE_YSIZE_HIMETRIC cySrc,
671 LPCRECT prcWBounds)
673 OLEPictureImpl *This = impl_from_IPicture(iface);
674 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
675 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
676 if(prcWBounds)
677 TRACE("prcWBounds %s\n", wine_dbgstr_rect(prcWBounds));
679 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
680 return CTL_E_INVALIDPROPERTYVALUE;
684 * While the documentation suggests this to be here (or after rendering?)
685 * it does cause an endless recursion in my sample app. -MM 20010804
686 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
689 switch(This->desc.picType) {
690 case PICTYPE_UNINITIALIZED:
691 case PICTYPE_NONE:
692 /* nothing to do */
693 return S_OK;
694 case PICTYPE_BITMAP:
696 HBITMAP hbmMask, hbmXor;
698 if (This->hbmMask)
700 hbmMask = This->hbmMask;
701 hbmXor = This->hbmXor;
703 else
705 hbmMask = 0;
706 hbmXor = This->desc.u.bmp.hbitmap;
709 render_masked_bitmap(This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, hbmMask, hbmXor);
710 break;
713 case PICTYPE_ICON:
715 ICONINFO info;
717 if (!GetIconInfo(This->desc.u.icon.hicon, &info))
718 return E_FAIL;
720 render_masked_bitmap(This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, info.hbmMask, info.hbmColor);
722 DeleteObject(info.hbmMask);
723 if (info.hbmColor) DeleteObject(info.hbmColor);
724 break;
727 case PICTYPE_METAFILE:
729 POINT prevOrg, prevWndOrg;
730 SIZE prevExt, prevWndExt;
731 int oldmode;
733 /* Render the WMF to the appropriate location by setting the
734 appropriate ratio between "device units" and "logical units" */
735 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
736 /* For the "source rectangle" the y-axis must be inverted */
737 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
738 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
739 /* For the "destination rectangle" no inversion is necessary */
740 SetViewportOrgEx(hdc, x, y, &prevOrg);
741 SetViewportExtEx(hdc, cx, cy, &prevExt);
743 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
744 ERR("PlayMetaFile failed!\n");
746 /* We're done, restore the DC to the previous settings for converting
747 logical units to device units */
748 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
749 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
750 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
751 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
752 SetMapMode(hdc, oldmode);
753 break;
756 case PICTYPE_ENHMETAFILE:
758 RECT rc = { x, y, x + cx, y + cy };
759 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
760 break;
763 default:
764 FIXME("type %d not implemented\n", This->desc.picType);
765 return E_NOTIMPL;
767 return S_OK;
770 /************************************************************************
771 * OLEPictureImpl_set_hPal
773 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
774 OLE_HANDLE hpal)
776 OLEPictureImpl *This = impl_from_IPicture(iface);
778 TRACE("(%p)->(%08x)\n", This, hpal);
780 if (This->desc.picType == PICTYPE_BITMAP)
782 This->desc.u.bmp.hpal = ULongToHandle(hpal);
783 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
784 return S_OK;
787 return E_FAIL;
790 /************************************************************************
791 * OLEPictureImpl_get_CurDC
793 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
794 HDC *phdc)
796 OLEPictureImpl *This = impl_from_IPicture(iface);
797 TRACE("(%p), returning %p\n", This, This->hDCCur);
798 if (phdc) *phdc = This->hDCCur;
799 return S_OK;
802 /************************************************************************
803 * OLEPictureImpl_SelectPicture
805 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
806 HDC hdcIn,
807 HDC *phdcOut,
808 OLE_HANDLE *phbmpOut)
810 OLEPictureImpl *This = impl_from_IPicture(iface);
811 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
812 if (This->desc.picType == PICTYPE_BITMAP) {
813 if (phdcOut)
814 *phdcOut = This->hDCCur;
815 if (This->hDCCur) SelectObject(This->hDCCur,This->stock_bitmap);
816 if (hdcIn) SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
817 This->hDCCur = hdcIn;
818 if (phbmpOut)
819 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
820 return S_OK;
821 } else {
822 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
823 return E_FAIL;
827 /************************************************************************
828 * OLEPictureImpl_get_KeepOriginalFormat
830 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
831 BOOL *pfKeep)
833 OLEPictureImpl *This = impl_from_IPicture(iface);
834 TRACE("(%p)->(%p)\n", This, pfKeep);
835 if (!pfKeep)
836 return E_POINTER;
837 *pfKeep = This->keepOrigFormat;
838 return S_OK;
841 /************************************************************************
842 * OLEPictureImpl_put_KeepOriginalFormat
844 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
845 BOOL keep)
847 OLEPictureImpl *This = impl_from_IPicture(iface);
848 TRACE("(%p)->(%d)\n", This, keep);
849 This->keepOrigFormat = keep;
850 /* FIXME: what DISPID notification here? */
851 return S_OK;
854 /************************************************************************
855 * OLEPictureImpl_PictureChanged
857 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
859 OLEPictureImpl *This = impl_from_IPicture(iface);
860 TRACE("(%p)->()\n", This);
861 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
862 This->bIsDirty = TRUE;
863 return S_OK;
866 /************************************************************************
867 * OLEPictureImpl_SaveAsFile
869 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
870 IStream *pstream,
871 BOOL SaveMemCopy,
872 LONG *pcbSize)
874 OLEPictureImpl *This = impl_from_IPicture(iface);
875 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
876 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
879 /************************************************************************
880 * OLEPictureImpl_get_Attributes
882 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
883 DWORD *pdwAttr)
885 OLEPictureImpl *This = impl_from_IPicture(iface);
886 TRACE("(%p)->(%p).\n", This, pdwAttr);
888 if(!pdwAttr)
889 return E_POINTER;
891 *pdwAttr = 0;
892 switch (This->desc.picType) {
893 case PICTYPE_UNINITIALIZED:
894 case PICTYPE_NONE: break;
895 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
896 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
897 case PICTYPE_ENHMETAFILE: /* fall through */
898 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
899 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
901 return S_OK;
905 /************************************************************************
906 * IConnectionPointContainer
908 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
909 IConnectionPointContainer* iface,
910 REFIID riid,
911 VOID** ppvoid)
913 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
915 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
918 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
919 IConnectionPointContainer* iface)
921 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
923 return IPicture_AddRef(&This->IPicture_iface);
926 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
927 IConnectionPointContainer* iface)
929 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
931 return IPicture_Release(&This->IPicture_iface);
934 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
935 IConnectionPointContainer* iface,
936 IEnumConnectionPoints** ppEnum)
938 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
940 FIXME("(%p,%p), stub!\n",This,ppEnum);
941 return E_NOTIMPL;
944 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
945 IConnectionPointContainer* iface,
946 REFIID riid,
947 IConnectionPoint **ppCP)
949 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
950 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
951 if (!ppCP)
952 return E_POINTER;
953 *ppCP = NULL;
954 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
955 return IConnectionPoint_QueryInterface(This->pCP, &IID_IConnectionPoint, (void**)ppCP);
956 FIXME("no connection point for %s\n",debugstr_guid(riid));
957 return CONNECT_E_NOCONNECTION;
961 /************************************************************************
962 * IPersistStream
965 /************************************************************************
966 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
968 * See Windows documentation for more details on IUnknown methods.
970 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
971 IPersistStream* iface,
972 REFIID riid,
973 VOID** ppvoid)
975 OLEPictureImpl *This = impl_from_IPersistStream(iface);
977 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
980 /************************************************************************
981 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
983 * See Windows documentation for more details on IUnknown methods.
985 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
986 IPersistStream* iface)
988 OLEPictureImpl *This = impl_from_IPersistStream(iface);
990 return IPicture_AddRef(&This->IPicture_iface);
993 /************************************************************************
994 * OLEPictureImpl_IPersistStream_Release (IUnknown)
996 * See Windows documentation for more details on IUnknown methods.
998 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
999 IPersistStream* iface)
1001 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1003 return IPicture_Release(&This->IPicture_iface);
1006 /************************************************************************
1007 * OLEPictureImpl_IPersistStream_GetClassID
1009 static HRESULT WINAPI OLEPictureImpl_GetClassID(
1010 IPersistStream* iface,CLSID* pClassID)
1012 TRACE("(%p)\n", pClassID);
1013 *pClassID = CLSID_StdPicture;
1014 return S_OK;
1017 /************************************************************************
1018 * OLEPictureImpl_IPersistStream_IsDirty
1020 static HRESULT WINAPI OLEPictureImpl_IsDirty(
1021 IPersistStream* iface)
1023 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1024 FIXME("(%p),stub!\n",This);
1025 return E_NOTIMPL;
1028 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1030 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1031 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1032 HDC hdcref;
1034 /* Does not matter whether this is a coreheader or not, we only use
1035 * components which are in both
1037 hdcref = GetDC(0);
1038 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1039 hdcref,
1040 &(bi->bmiHeader),
1041 CBM_INIT,
1042 xbuf+bfh->bfOffBits,
1044 DIB_RGB_COLORS
1046 ReleaseDC(0, hdcref);
1047 if (This->desc.u.bmp.hbitmap == 0)
1048 return E_FAIL;
1049 This->desc.picType = PICTYPE_BITMAP;
1050 OLEPictureImpl_SetBitmap(This);
1051 return S_OK;
1054 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1056 HRESULT hr;
1057 BITMAPINFOHEADER bih;
1058 HDC hdcref;
1059 UINT width, height;
1060 UINT stride, buffersize;
1061 LPBYTE bits=NULL;
1062 WICRect rc;
1063 IWICBitmapSource *real_source;
1064 UINT x, y;
1065 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1066 BOOL has_alpha=FALSE;
1068 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1069 if (FAILED(hr)) return hr;
1071 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1072 if (FAILED(hr)) goto end;
1074 bih.biSize = sizeof(bih);
1075 bih.biWidth = width;
1076 bih.biHeight = -height;
1077 bih.biPlanes = 1;
1078 bih.biBitCount = 32;
1079 bih.biCompression = BI_RGB;
1080 bih.biSizeImage = 0;
1081 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1082 bih.biYPelsPerMeter = 4085;
1083 bih.biClrUsed = 0;
1084 bih.biClrImportant = 0;
1086 stride = 4 * width;
1087 buffersize = stride * height;
1089 bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1090 if (!bits)
1092 hr = E_OUTOFMEMORY;
1093 goto end;
1096 rc.X = 0;
1097 rc.Y = 0;
1098 rc.Width = width;
1099 rc.Height = height;
1100 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1101 if (FAILED(hr))
1102 goto end;
1104 hdcref = GetDC(0);
1105 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1106 hdcref,
1107 &bih,
1108 CBM_INIT,
1109 bits,
1110 (BITMAPINFO*)&bih,
1111 DIB_RGB_COLORS);
1113 if (This->desc.u.bmp.hbitmap == 0)
1115 hr = E_FAIL;
1116 ReleaseDC(0, hdcref);
1117 goto end;
1120 This->desc.picType = PICTYPE_BITMAP;
1121 OLEPictureImpl_SetBitmap(This);
1123 /* set transparent pixels to black, all others to white */
1124 for(y = 0; y < height; y++){
1125 for(x = 0; x < width; x++){
1126 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1127 if((*pixel & 0x80000000) == 0)
1129 has_alpha = TRUE;
1130 *pixel = black;
1132 else
1133 *pixel = white;
1137 if (has_alpha)
1139 HDC hdcBmp, hdcXor, hdcMask;
1140 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1142 This->hbmXor = CreateDIBitmap(
1143 hdcref,
1144 &bih,
1145 CBM_INIT,
1146 bits,
1147 (BITMAPINFO*)&bih,
1148 DIB_RGB_COLORS
1151 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1152 hdcBmp = CreateCompatibleDC(NULL);
1153 hdcXor = CreateCompatibleDC(NULL);
1154 hdcMask = CreateCompatibleDC(NULL);
1156 hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1157 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1158 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1160 SetBkColor(hdcXor,black);
1161 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1162 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1164 SelectObject(hdcBmp,hbmoldBmp);
1165 SelectObject(hdcXor,hbmoldXor);
1166 SelectObject(hdcMask,hbmoldMask);
1168 DeleteDC(hdcBmp);
1169 DeleteDC(hdcXor);
1170 DeleteDC(hdcMask);
1173 ReleaseDC(0, hdcref);
1175 end:
1176 HeapFree(GetProcessHeap(), 0, bits);
1177 IWICBitmapSource_Release(real_source);
1178 return hr;
1181 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1183 HRESULT hr;
1184 IWICImagingFactory *factory;
1185 IWICBitmapDecoder *decoder;
1186 IWICBitmapFrameDecode *framedecode;
1187 HRESULT initresult;
1188 IWICStream *stream;
1190 initresult = CoInitialize(NULL);
1192 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1193 &IID_IWICImagingFactory, (void**)&factory);
1194 if (SUCCEEDED(hr)) /* created factory */
1196 hr = IWICImagingFactory_CreateStream(factory, &stream);
1197 IWICImagingFactory_Release(factory);
1200 if (SUCCEEDED(hr)) /* created stream */
1202 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1204 if (SUCCEEDED(hr)) /* initialized stream */
1206 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1207 &IID_IWICBitmapDecoder, (void**)&decoder);
1208 if (SUCCEEDED(hr)) /* created decoder */
1210 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1212 if (SUCCEEDED(hr)) /* initialized decoder */
1213 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1215 IWICBitmapDecoder_Release(decoder);
1219 IWICStream_Release(stream);
1222 if (SUCCEEDED(hr)) /* got framedecode */
1224 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1225 IWICBitmapFrameDecode_Release(framedecode);
1228 if (SUCCEEDED(initresult)) CoUninitialize();
1229 return hr;
1232 /*****************************************************
1233 * start of Icon-specific code
1236 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1238 HICON hicon;
1239 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1240 HDC hdcRef;
1241 int i;
1243 TRACE("(this %p, xbuf %p, xread %u)\n", This, xbuf, xread);
1246 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1247 FIXME("icon.idType=%d\n",cifd->idType);
1248 FIXME("icon.idCount=%d\n",cifd->idCount);
1250 for (i=0;i<cifd->idCount;i++) {
1251 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1252 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1253 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1254 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1255 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1256 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1257 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1258 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1262 /* Need at least one icon to do something. */
1263 if (!cifd->idCount)
1265 ERR("Invalid icon count of zero.\n");
1266 return E_FAIL;
1268 i=0;
1269 /* If we have more than one icon, try to find the best.
1270 * this currently means '32 pixel wide'.
1272 if (cifd->idCount!=1) {
1273 for (i=0;i<cifd->idCount;i++) {
1274 if (cifd->idEntries[i].bWidth == 32)
1275 break;
1277 if (i==cifd->idCount) i=0;
1279 if (xread < cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize)
1281 ERR("Icon data address %u is over %u bytes available.\n",
1282 cifd->idEntries[i].dwDIBOffset + cifd->idEntries[i].dwDIBSize, xread);
1283 return E_FAIL;
1285 if (cifd->idType == 2)
1287 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, cifd->idEntries[i].dwDIBSize + 4);
1288 memcpy(buf, &cifd->idEntries[i].xHotspot, 4);
1289 memcpy(buf + 4, xbuf+cifd->idEntries[i].dwDIBOffset, cifd->idEntries[i].dwDIBSize);
1290 hicon = CreateIconFromResourceEx(
1291 buf,
1292 cifd->idEntries[i].dwDIBSize + 4,
1293 FALSE, /* is cursor */
1294 0x00030000,
1295 cifd->idEntries[i].bWidth,
1296 cifd->idEntries[i].bHeight,
1299 HeapFree(GetProcessHeap(), 0, buf);
1301 else
1303 hicon = CreateIconFromResourceEx(
1304 xbuf+cifd->idEntries[i].dwDIBOffset,
1305 cifd->idEntries[i].dwDIBSize,
1306 TRUE, /* is icon */
1307 0x00030000,
1308 cifd->idEntries[i].bWidth,
1309 cifd->idEntries[i].bHeight,
1313 if (!hicon) {
1314 ERR("CreateIcon failed.\n");
1315 return E_FAIL;
1316 } else {
1317 This->desc.picType = PICTYPE_ICON;
1318 This->desc.u.icon.hicon = hicon;
1319 This->origWidth = cifd->idEntries[i].bWidth;
1320 This->origHeight = cifd->idEntries[i].bHeight;
1321 hdcRef = CreateCompatibleDC(0);
1322 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1323 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1324 DeleteDC(hdcRef);
1325 return S_OK;
1329 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1330 const BYTE *data, ULONG size)
1332 HENHMETAFILE hemf;
1333 ENHMETAHEADER hdr;
1335 hemf = SetEnhMetaFileBits(size, data);
1336 if (!hemf) return E_FAIL;
1338 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1340 This->desc.picType = PICTYPE_ENHMETAFILE;
1341 This->desc.u.emf.hemf = hemf;
1343 This->origWidth = 0;
1344 This->origHeight = 0;
1345 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1346 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1348 return S_OK;
1351 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1352 const BYTE *data, ULONG size)
1354 const APM_HEADER *header = (const APM_HEADER *)data;
1355 HMETAFILE hmf;
1357 if (size < sizeof(APM_HEADER))
1358 return E_FAIL;
1359 if (header->key != 0x9ac6cdd7)
1360 return E_FAIL;
1362 /* SetMetaFileBitsEx performs data check on its own */
1363 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1364 if (!hmf) return E_FAIL;
1366 This->desc.picType = PICTYPE_METAFILE;
1367 This->desc.u.wmf.hmeta = hmf;
1368 This->desc.u.wmf.xExt = 0;
1369 This->desc.u.wmf.yExt = 0;
1371 This->origWidth = 0;
1372 This->origHeight = 0;
1373 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1374 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1375 return S_OK;
1378 /************************************************************************
1379 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1381 * Loads the binary data from the IStream. Starts at current position.
1382 * There appears to be an 2 DWORD header:
1383 * DWORD magic;
1384 * DWORD len;
1386 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1388 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1389 HRESULT hr;
1390 BOOL headerisdata;
1391 BOOL statfailed = FALSE;
1392 ULONG xread, toread;
1393 ULONG headerread;
1394 BYTE *xbuf;
1395 DWORD header[2];
1396 WORD magic;
1397 STATSTG statstg;
1398 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1400 TRACE("(%p,%p)\n",This,pStm);
1402 /****************************************************************************************
1403 * Part 1: Load the data
1405 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1406 * out whether we do.
1408 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1409 * compound file. This may explain most, if not all, of the cases of "no
1410 * header", and the header validation should take this into account.
1411 * At least in Visual Basic 6, resource streams, valid headers are
1412 * header[0] == "lt\0\0",
1413 * header[1] == length_of_stream.
1415 * Also handle streams where we do not have a working "Stat" method by
1416 * reading all data until the end of the stream.
1418 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1419 if (hr != S_OK) {
1420 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1421 statfailed = TRUE;
1422 /* we will read at least 8 byte ... just right below */
1423 statstg.cbSize.QuadPart = 8;
1426 toread = 0;
1427 headerread = 0;
1428 headerisdata = FALSE;
1429 do {
1430 hr = IStream_Read(pStm, header, 8, &xread);
1431 if (hr != S_OK || xread!=8) {
1432 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1433 return (hr?hr:E_FAIL);
1435 headerread += xread;
1436 xread = 0;
1438 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1439 if (toread != 0 && toread != header[1])
1440 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1441 toread, header[1]);
1442 toread = header[1];
1443 if (statfailed)
1445 statstg.cbSize.QuadPart = header[1] + 8;
1446 statfailed = FALSE;
1448 if (toread == 0) break;
1449 } else {
1450 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1451 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1452 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1453 (header[0] == EMR_HEADER) || /* EMF header */
1454 (header[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1455 (header[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1456 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1457 (header[1]==0)
1458 ) {/* Found start of bitmap data */
1459 headerisdata = TRUE;
1460 if (toread == 0)
1461 toread = statstg.cbSize.QuadPart-8;
1462 else toread -= 8;
1463 xread = 8;
1464 } else {
1465 FIXME("Unknown stream header magic: %08x\n", header[0]);
1466 toread = header[1];
1469 } while (!headerisdata);
1471 if (statfailed) { /* we don't know the size ... read all we get */
1472 unsigned int sizeinc = 4096;
1473 unsigned int origsize = sizeinc;
1474 ULONG nread = 42;
1476 TRACE("Reading all data from stream.\n");
1477 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1478 if (headerisdata)
1479 memcpy (xbuf, header, 8);
1480 while (1) {
1481 while (xread < origsize) {
1482 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1483 xread += nread;
1484 if (hr != S_OK || !nread)
1485 break;
1487 if (!nread || hr != S_OK) /* done, or error */
1488 break;
1489 if (xread == origsize) {
1490 origsize += sizeinc;
1491 sizeinc = 2*sizeinc; /* exponential increase */
1492 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1495 if (hr != S_OK)
1496 TRACE("hr in no-stat loader case is %08x\n", hr);
1497 TRACE("loaded %d bytes.\n", xread);
1498 This->datalen = xread;
1499 This->data = xbuf;
1500 } else {
1501 This->datalen = toread+(headerisdata?8:0);
1502 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1503 if (!xbuf)
1504 return E_OUTOFMEMORY;
1506 if (headerisdata)
1507 memcpy (xbuf, header, 8);
1509 while (xread < This->datalen) {
1510 ULONG nread;
1511 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1512 xread += nread;
1513 if (hr != S_OK || !nread)
1514 break;
1516 if (xread != This->datalen)
1517 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1519 if (This->datalen == 0) { /* Marks the "NONE" picture */
1520 This->desc.picType = PICTYPE_NONE;
1521 return S_OK;
1525 /****************************************************************************************
1526 * Part 2: Process the loaded data
1529 magic = xbuf[0] + (xbuf[1]<<8);
1530 This->loadtime_format = magic;
1532 switch (magic) {
1533 case BITMAP_FORMAT_GIF: /* GIF */
1534 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1535 break;
1536 case BITMAP_FORMAT_JPEG: /* JPEG */
1537 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1538 break;
1539 case BITMAP_FORMAT_BMP: /* Bitmap */
1540 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1541 break;
1542 case BITMAP_FORMAT_PNG: /* PNG */
1543 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1544 break;
1545 case BITMAP_FORMAT_APM: /* APM */
1546 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1547 break;
1548 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1549 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1550 break;
1552 default:
1554 unsigned int i;
1556 /* let's see if it's a EMF */
1557 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1558 if (hr == S_OK) break;
1560 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1561 hr=E_FAIL;
1562 for (i=0;i<xread+8;i++) {
1563 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1564 else MESSAGE("%02x ",xbuf[i-8]);
1565 if (i % 10 == 9) MESSAGE("\n");
1567 MESSAGE("\n");
1568 break;
1571 This->bIsDirty = FALSE;
1573 /* FIXME: this notify is not really documented */
1574 if (hr==S_OK)
1575 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1576 return hr;
1579 static BOOL serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1581 BOOL success = FALSE;
1582 HDC hDC;
1583 BITMAPINFO * pInfoBitmap;
1584 int iNumPaletteEntries;
1585 unsigned char * pPixelData;
1586 BITMAPFILEHEADER * pFileHeader;
1587 BITMAPINFO * pInfoHeader;
1589 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1590 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1592 /* Find out bitmap size and padded length */
1593 hDC = GetDC(0);
1594 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1595 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1597 /* Fetch bitmap palette & pixel data */
1599 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1600 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1602 /* Calculate the total length required for the BMP data */
1603 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1604 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1605 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1606 } else {
1607 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1608 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1609 else
1610 iNumPaletteEntries = 0;
1612 *pLength =
1613 sizeof(BITMAPFILEHEADER) +
1614 sizeof(BITMAPINFOHEADER) +
1615 iNumPaletteEntries * sizeof(RGBQUAD) +
1616 pInfoBitmap->bmiHeader.biSizeImage;
1617 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1619 /* Fill the BITMAPFILEHEADER */
1620 pFileHeader = *ppBuffer;
1621 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1622 pFileHeader->bfSize = *pLength;
1623 pFileHeader->bfOffBits =
1624 sizeof(BITMAPFILEHEADER) +
1625 sizeof(BITMAPINFOHEADER) +
1626 iNumPaletteEntries * sizeof(RGBQUAD);
1628 /* Fill the BITMAPINFOHEADER and the palette data */
1629 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1630 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1631 memcpy(
1632 (unsigned char *)(*ppBuffer) +
1633 sizeof(BITMAPFILEHEADER) +
1634 sizeof(BITMAPINFOHEADER) +
1635 iNumPaletteEntries * sizeof(RGBQUAD),
1636 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1637 success = TRUE;
1639 HeapFree(GetProcessHeap(), 0, pPixelData);
1640 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1641 return success;
1644 static BOOL serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1646 ICONINFO infoIcon;
1647 BOOL success = FALSE;
1649 *ppBuffer = NULL; *pLength = 0;
1650 if (GetIconInfo(hIcon, &infoIcon)) {
1651 HDC hDC;
1652 BITMAPINFO * pInfoBitmap;
1653 unsigned char * pIconData = NULL;
1654 unsigned int iDataSize = 0;
1656 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1658 /* Find out icon size */
1659 hDC = GetDC(0);
1660 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1661 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1662 if (1) {
1663 /* Auxiliary pointers */
1664 CURSORICONFILEDIR * pIconDir;
1665 CURSORICONFILEDIRENTRY * pIconEntry;
1666 BITMAPINFOHEADER * pIconBitmapHeader;
1667 unsigned int iOffsetPalette;
1668 unsigned int iOffsetColorData;
1669 unsigned int iOffsetMaskData;
1671 unsigned int iLengthScanLineMask;
1672 unsigned int iNumEntriesPalette;
1674 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1676 FIXME("DEBUG: bitmap size is %d x %d\n",
1677 pInfoBitmap->bmiHeader.biWidth,
1678 pInfoBitmap->bmiHeader.biHeight);
1679 FIXME("DEBUG: bitmap bpp is %d\n",
1680 pInfoBitmap->bmiHeader.biBitCount);
1681 FIXME("DEBUG: bitmap nplanes is %d\n",
1682 pInfoBitmap->bmiHeader.biPlanes);
1683 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1684 pInfoBitmap->bmiHeader.biSizeImage);
1686 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1687 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1688 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1690 /* Fill out the CURSORICONFILEDIR */
1691 pIconDir = (CURSORICONFILEDIR *)pIconData;
1692 pIconDir->idType = 1;
1693 pIconDir->idCount = 1;
1694 pIconDir->idReserved = 0;
1696 /* Fill out the CURSORICONFILEDIRENTRY */
1697 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1698 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1699 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1700 pIconEntry->bColorCount =
1701 (pInfoBitmap->bmiHeader.biBitCount < 8)
1702 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1703 : 0;
1704 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1705 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1706 pIconEntry->dwDIBSize = 0;
1707 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1709 /* Fill out the BITMAPINFOHEADER */
1710 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1711 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1713 /* Find out whether a palette exists for the bitmap */
1714 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1715 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1716 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1717 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1718 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1719 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1720 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1721 iNumEntriesPalette = 3;
1722 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1723 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1724 } else {
1725 iNumEntriesPalette = 0;
1728 /* Add bitmap size and header size to icon data size. */
1729 iOffsetPalette = iDataSize;
1730 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1731 iOffsetColorData = iDataSize;
1732 iDataSize += pIconBitmapHeader->biSizeImage;
1733 iOffsetMaskData = iDataSize;
1734 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1735 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1736 pIconBitmapHeader->biHeight *= 2;
1737 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1738 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1739 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1740 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1742 /* Get the actual bitmap data from the icon bitmap */
1743 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1744 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1745 if (iNumEntriesPalette > 0) {
1746 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1747 iNumEntriesPalette * sizeof(RGBQUAD));
1750 /* Reset all values so that GetDIBits call succeeds */
1751 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1752 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1753 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1755 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1756 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1757 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1759 printf("ERROR: unable to get bitmap mask (error %u)\n",
1760 GetLastError());
1764 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1765 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1767 /* Write out everything produced so far to the stream */
1768 *ppBuffer = pIconData; *pLength = iDataSize;
1769 success = TRUE;
1770 } else {
1772 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1773 GetLastError());
1777 Remarks (from MSDN entry on GetIconInfo):
1779 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1780 members of ICONINFO. The calling application must manage
1781 these bitmaps and delete them when they are no longer
1782 necessary.
1784 if (hDC) ReleaseDC(0, hDC);
1785 DeleteObject(infoIcon.hbmMask);
1786 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1787 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1788 } else {
1789 printf("ERROR: Unable to get icon information (error %u)\n",
1790 GetLastError());
1792 return success;
1795 static HRESULT WINAPI OLEPictureImpl_Save(
1796 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1798 HRESULT hResult = E_NOTIMPL;
1799 void * pIconData;
1800 unsigned int iDataSize;
1801 DWORD header[2];
1802 ULONG dummy;
1803 BOOL serializeResult = FALSE;
1804 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1806 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1808 switch (This->desc.picType) {
1809 case PICTYPE_NONE:
1810 header[0] = 0x0000746c;
1811 header[1] = 0;
1812 hResult = IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1813 break;
1815 case PICTYPE_ICON:
1816 if (This->bIsDirty || !This->data) {
1817 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1818 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1819 hResult = E_FAIL;
1820 break;
1822 HeapFree(GetProcessHeap(), 0, This->data);
1823 This->data = pIconData;
1824 This->datalen = iDataSize;
1827 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1828 header[1] = This->datalen;
1829 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1830 IStream_Write(pStm, This->data, This->datalen, &dummy);
1831 hResult = S_OK;
1832 break;
1833 case PICTYPE_BITMAP:
1834 if (This->bIsDirty || !This->data) {
1835 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1836 case BITMAP_FORMAT_BMP:
1837 serializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1838 break;
1839 case BITMAP_FORMAT_JPEG:
1840 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1841 break;
1842 case BITMAP_FORMAT_GIF:
1843 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1844 break;
1845 case BITMAP_FORMAT_PNG:
1846 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1847 break;
1848 default:
1849 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1850 break;
1853 if (!serializeResult)
1855 hResult = E_FAIL;
1856 break;
1859 HeapFree(GetProcessHeap(), 0, This->data);
1860 This->data = pIconData;
1861 This->datalen = iDataSize;
1864 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1865 header[1] = This->datalen;
1866 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1867 IStream_Write(pStm, This->data, This->datalen, &dummy);
1868 hResult = S_OK;
1869 break;
1870 case PICTYPE_METAFILE:
1871 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1872 break;
1873 case PICTYPE_ENHMETAFILE:
1874 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1875 break;
1876 default:
1877 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1878 break;
1880 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1881 return hResult;
1884 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1885 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1887 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1888 FIXME("(%p,%p),stub!\n",This,pcbSize);
1889 return E_NOTIMPL;
1893 /************************************************************************
1894 * IDispatch
1897 /************************************************************************
1898 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1900 * See Windows documentation for more details on IUnknown methods.
1902 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1903 IDispatch* iface,
1904 REFIID riid,
1905 VOID** ppvoid)
1907 OLEPictureImpl *This = impl_from_IDispatch(iface);
1909 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1912 /************************************************************************
1913 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1915 * See Windows documentation for more details on IUnknown methods.
1917 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1918 IDispatch* iface)
1920 OLEPictureImpl *This = impl_from_IDispatch(iface);
1922 return IPicture_AddRef(&This->IPicture_iface);
1925 /************************************************************************
1926 * OLEPictureImpl_IDispatch_Release (IUnknown)
1928 * See Windows documentation for more details on IUnknown methods.
1930 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1931 IDispatch* iface)
1933 OLEPictureImpl *This = impl_from_IDispatch(iface);
1935 return IPicture_Release(&This->IPicture_iface);
1938 /************************************************************************
1939 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1941 * See Windows documentation for more details on IDispatch methods.
1943 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1944 IDispatch* iface,
1945 unsigned int* pctinfo)
1947 TRACE("(%p)\n", pctinfo);
1949 *pctinfo = 1;
1951 return S_OK;
1954 /************************************************************************
1955 * OLEPictureImpl_GetTypeInfo (IDispatch)
1957 * See Windows documentation for more details on IDispatch methods.
1959 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1960 IDispatch* iface,
1961 UINT iTInfo,
1962 LCID lcid,
1963 ITypeInfo** ppTInfo)
1965 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1966 ITypeLib *tl;
1967 HRESULT hres;
1969 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1971 if (iTInfo != 0)
1972 return E_FAIL;
1974 hres = LoadTypeLib(stdole2tlb, &tl);
1975 if (FAILED(hres))
1977 ERR("Could not load stdole2.tlb\n");
1978 return hres;
1981 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1982 if (FAILED(hres))
1983 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1985 return hres;
1988 /************************************************************************
1989 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1991 * See Windows documentation for more details on IDispatch methods.
1993 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1994 IDispatch* iface,
1995 REFIID riid,
1996 LPOLESTR* rgszNames,
1997 UINT cNames,
1998 LCID lcid,
1999 DISPID* rgDispId)
2001 ITypeInfo * pTInfo;
2002 HRESULT hres;
2004 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2005 rgszNames, cNames, (int)lcid, rgDispId);
2007 if (cNames == 0)
2009 return E_INVALIDARG;
2011 else
2013 /* retrieve type information */
2014 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2016 if (FAILED(hres))
2018 ERR("GetTypeInfo failed.\n");
2019 return hres;
2022 /* convert names to DISPIDs */
2023 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2024 ITypeInfo_Release(pTInfo);
2026 return hres;
2030 /************************************************************************
2031 * OLEPictureImpl_Invoke (IDispatch)
2033 * See Windows documentation for more details on IDispatch methods.
2035 static HRESULT WINAPI OLEPictureImpl_Invoke(
2036 IDispatch* iface,
2037 DISPID dispIdMember,
2038 REFIID riid,
2039 LCID lcid,
2040 WORD wFlags,
2041 DISPPARAMS* pDispParams,
2042 VARIANT* pVarResult,
2043 EXCEPINFO* pExepInfo,
2044 UINT* puArgErr)
2046 OLEPictureImpl *This = impl_from_IDispatch(iface);
2047 HRESULT hr;
2049 /* validate parameters */
2051 if (!IsEqualIID(riid, &IID_NULL))
2053 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2054 return DISP_E_UNKNOWNNAME;
2057 if (!pDispParams)
2059 ERR("null pDispParams not allowed\n");
2060 return DISP_E_PARAMNOTOPTIONAL;
2063 if (wFlags & DISPATCH_PROPERTYGET)
2065 if (pDispParams->cArgs != 0)
2067 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2068 return DISP_E_BADPARAMCOUNT;
2070 if (!pVarResult)
2072 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2073 return DISP_E_PARAMNOTOPTIONAL;
2076 else if (wFlags & DISPATCH_PROPERTYPUT)
2078 if (pDispParams->cArgs != 1)
2080 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2081 return DISP_E_BADPARAMCOUNT;
2085 switch (dispIdMember)
2087 case DISPID_PICT_HANDLE:
2088 if (wFlags & DISPATCH_PROPERTYGET)
2090 TRACE("DISPID_PICT_HANDLE\n");
2091 V_VT(pVarResult) = VT_I4;
2092 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2094 break;
2095 case DISPID_PICT_HPAL:
2096 if (wFlags & DISPATCH_PROPERTYGET)
2098 TRACE("DISPID_PICT_HPAL\n");
2099 V_VT(pVarResult) = VT_I4;
2100 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2102 else if (wFlags & DISPATCH_PROPERTYPUT)
2104 VARIANTARG vararg;
2106 TRACE("DISPID_PICT_HPAL\n");
2108 VariantInit(&vararg);
2109 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2110 if (FAILED(hr))
2111 return hr;
2113 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2115 VariantClear(&vararg);
2116 return hr;
2118 break;
2119 case DISPID_PICT_TYPE:
2120 if (wFlags & DISPATCH_PROPERTYGET)
2122 TRACE("DISPID_PICT_TYPE\n");
2123 V_VT(pVarResult) = VT_I2;
2124 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2126 break;
2127 case DISPID_PICT_WIDTH:
2128 if (wFlags & DISPATCH_PROPERTYGET)
2130 TRACE("DISPID_PICT_WIDTH\n");
2131 V_VT(pVarResult) = VT_I4;
2132 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2134 break;
2135 case DISPID_PICT_HEIGHT:
2136 if (wFlags & DISPATCH_PROPERTYGET)
2138 TRACE("DISPID_PICT_HEIGHT\n");
2139 V_VT(pVarResult) = VT_I4;
2140 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2142 break;
2143 case DISPID_PICT_RENDER:
2144 if (wFlags & DISPATCH_METHOD)
2146 VARIANTARG *args = pDispParams->rgvarg;
2147 int i;
2149 TRACE("DISPID_PICT_RENDER\n");
2151 if (pDispParams->cArgs != 10)
2152 return DISP_E_BADPARAMCOUNT;
2154 /* All parameters are supposed to be VT_I4 (on 64 bits too). */
2155 for (i = 0; i < pDispParams->cArgs; i++)
2156 if (V_VT(&args[i]) != VT_I4)
2158 ERR("DISPID_PICT_RENDER: wrong argument type %d:%d\n", i, V_VT(&args[i]));
2159 return DISP_E_TYPEMISMATCH;
2162 /* FIXME: rectangle pointer argument handling seems broken on 64 bits,
2163 currently Render() doesn't use it at all so for now NULL is passed. */
2164 return IPicture_Render(&This->IPicture_iface,
2165 LongToHandle(V_I4(&args[9])),
2166 V_I4(&args[8]),
2167 V_I4(&args[7]),
2168 V_I4(&args[6]),
2169 V_I4(&args[5]),
2170 V_I4(&args[4]),
2171 V_I4(&args[3]),
2172 V_I4(&args[2]),
2173 V_I4(&args[1]),
2174 NULL);
2176 break;
2179 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2180 return DISP_E_MEMBERNOTFOUND;
2184 static const IPictureVtbl OLEPictureImpl_VTable =
2186 OLEPictureImpl_QueryInterface,
2187 OLEPictureImpl_AddRef,
2188 OLEPictureImpl_Release,
2189 OLEPictureImpl_get_Handle,
2190 OLEPictureImpl_get_hPal,
2191 OLEPictureImpl_get_Type,
2192 OLEPictureImpl_get_Width,
2193 OLEPictureImpl_get_Height,
2194 OLEPictureImpl_Render,
2195 OLEPictureImpl_set_hPal,
2196 OLEPictureImpl_get_CurDC,
2197 OLEPictureImpl_SelectPicture,
2198 OLEPictureImpl_get_KeepOriginalFormat,
2199 OLEPictureImpl_put_KeepOriginalFormat,
2200 OLEPictureImpl_PictureChanged,
2201 OLEPictureImpl_SaveAsFile,
2202 OLEPictureImpl_get_Attributes
2205 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2207 OLEPictureImpl_IDispatch_QueryInterface,
2208 OLEPictureImpl_IDispatch_AddRef,
2209 OLEPictureImpl_IDispatch_Release,
2210 OLEPictureImpl_GetTypeInfoCount,
2211 OLEPictureImpl_GetTypeInfo,
2212 OLEPictureImpl_GetIDsOfNames,
2213 OLEPictureImpl_Invoke
2216 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2218 OLEPictureImpl_IPersistStream_QueryInterface,
2219 OLEPictureImpl_IPersistStream_AddRef,
2220 OLEPictureImpl_IPersistStream_Release,
2221 OLEPictureImpl_GetClassID,
2222 OLEPictureImpl_IsDirty,
2223 OLEPictureImpl_Load,
2224 OLEPictureImpl_Save,
2225 OLEPictureImpl_GetSizeMax
2228 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2230 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2231 OLEPictureImpl_IConnectionPointContainer_AddRef,
2232 OLEPictureImpl_IConnectionPointContainer_Release,
2233 OLEPictureImpl_EnumConnectionPoints,
2234 OLEPictureImpl_FindConnectionPoint
2237 /***********************************************************************
2238 * OleCreatePictureIndirect (OLEAUT32.419)
2240 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2241 BOOL Own, void **ppvObj )
2243 OLEPictureImpl* newPict;
2244 HRESULT hr;
2246 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2248 *ppvObj = NULL;
2250 hr = OLEPictureImpl_Construct(lpPictDesc, Own, &newPict);
2251 if (hr != S_OK) return hr;
2254 * Make sure it supports the interface required by the caller.
2256 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2259 * Release the reference obtained in the constructor. If
2260 * the QueryInterface was unsuccessful, it will free the class.
2262 IPicture_Release(&newPict->IPicture_iface);
2264 return hr;
2268 /***********************************************************************
2269 * OleLoadPicture (OLEAUT32.418)
2271 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2272 REFIID riid, LPVOID *ppvObj )
2274 LPPERSISTSTREAM ps;
2275 IPicture *newpic;
2276 HRESULT hr;
2278 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2279 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2281 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2282 if (hr != S_OK)
2283 return hr;
2284 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2285 if (hr != S_OK) {
2286 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2287 IPicture_Release(newpic);
2288 *ppvObj = NULL;
2289 return hr;
2291 hr = IPersistStream_Load(ps,lpstream);
2292 IPersistStream_Release(ps);
2293 if (FAILED(hr))
2295 ERR("IPersistStream_Load failed\n");
2296 IPicture_Release(newpic);
2297 *ppvObj = NULL;
2298 return hr;
2300 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2301 if (hr != S_OK)
2302 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2303 IPicture_Release(newpic);
2304 return hr;
2307 /***********************************************************************
2308 * OleLoadPictureEx (OLEAUT32.401)
2310 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2311 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2313 LPPERSISTSTREAM ps;
2314 IPicture *newpic;
2315 HRESULT hr;
2317 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2318 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2320 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2321 if (hr != S_OK)
2322 return hr;
2323 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2324 if (hr != S_OK) {
2325 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2326 IPicture_Release(newpic);
2327 *ppvObj = NULL;
2328 return hr;
2330 hr = IPersistStream_Load(ps,lpstream);
2331 IPersistStream_Release(ps);
2332 if (FAILED(hr))
2334 ERR("IPersistStream_Load failed\n");
2335 IPicture_Release(newpic);
2336 *ppvObj = NULL;
2337 return hr;
2339 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2340 if (hr != S_OK)
2341 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2342 IPicture_Release(newpic);
2343 return hr;
2346 /***********************************************************************
2347 * OleLoadPictureFile (OLEAUT32.422)
2349 HRESULT WINAPI OleLoadPictureFile(VARIANT file, LPDISPATCH *picture)
2351 FIXME("(%s %p): stub\n", wine_dbgstr_variant(&file), picture);
2352 return E_NOTIMPL;
2355 /***********************************************************************
2356 * OleSavePictureFile (OLEAUT32.423)
2358 HRESULT WINAPI OleSavePictureFile(IDispatch *picture, BSTR filename)
2360 FIXME("(%p %s): stub\n", picture, debugstr_w(filename));
2361 return CTL_E_FILENOTFOUND;
2364 /***********************************************************************
2365 * OleLoadPicturePath (OLEAUT32.424)
2367 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2368 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2369 LPVOID *ppvRet )
2371 static const WCHAR file[] = { 'f','i','l','e',':',0 };
2372 IPicture *ipicture;
2373 HANDLE hFile;
2374 DWORD dwFileSize;
2375 HGLOBAL hGlobal = NULL;
2376 DWORD dwBytesRead;
2377 IStream *stream;
2378 BOOL bRead;
2379 IPersistStream *pStream;
2380 HRESULT hRes;
2381 HRESULT init_res;
2382 WCHAR *file_candidate;
2383 WCHAR path_buf[MAX_PATH];
2385 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2386 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2387 debugstr_guid(riid), ppvRet);
2389 if (!szURLorPath || !ppvRet)
2390 return E_INVALIDARG;
2392 *ppvRet = NULL;
2394 /* Convert file URLs to DOS paths. */
2395 if (strncmpW(szURLorPath, file, 5) == 0) {
2396 DWORD size;
2397 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2398 ARRAY_SIZE(path_buf), &size, 0);
2399 if (FAILED(hRes))
2400 return hRes;
2402 file_candidate = path_buf;
2404 else
2405 file_candidate = szURLorPath;
2407 /* Handle candidate DOS paths separately. */
2408 if (file_candidate[1] == ':') {
2409 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2410 0, NULL);
2411 if (hFile == INVALID_HANDLE_VALUE)
2412 return INET_E_RESOURCE_NOT_FOUND;
2414 dwFileSize = GetFileSize(hFile, NULL);
2415 if (dwFileSize != INVALID_FILE_SIZE )
2417 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2418 if ( hGlobal)
2420 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL) && dwBytesRead == dwFileSize;
2421 if (!bRead)
2423 GlobalFree(hGlobal);
2424 hGlobal = 0;
2428 CloseHandle(hFile);
2430 if (!hGlobal)
2431 return INET_E_RESOURCE_NOT_FOUND;
2433 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2434 if (FAILED(hRes))
2436 GlobalFree(hGlobal);
2437 return hRes;
2439 } else {
2440 IMoniker *pmnk;
2441 IBindCtx *pbc;
2443 hRes = CreateBindCtx(0, &pbc);
2444 if (SUCCEEDED(hRes))
2446 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2447 if (SUCCEEDED(hRes))
2449 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2450 IMoniker_Release(pmnk);
2452 IBindCtx_Release(pbc);
2454 if (FAILED(hRes))
2455 return hRes;
2458 init_res = CoInitialize(NULL);
2460 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2461 &IID_IPicture, (LPVOID*)&ipicture);
2462 if (SUCCEEDED(hRes)) {
2463 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2465 if (SUCCEEDED(hRes)) {
2466 hRes = IPersistStream_Load(pStream, stream);
2468 if (SUCCEEDED(hRes)) {
2469 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2471 if (FAILED(hRes))
2472 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2474 IPersistStream_Release(pStream);
2476 IPicture_Release(ipicture);
2479 IStream_Release(stream);
2481 if (SUCCEEDED(init_res))
2482 CoUninitialize();
2484 return hRes;
2487 /*******************************************************************************
2488 * StdPic ClassFactory
2490 typedef struct
2492 /* IUnknown fields */
2493 IClassFactory IClassFactory_iface;
2494 LONG ref;
2495 } IClassFactoryImpl;
2497 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2499 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2502 static HRESULT WINAPI
2503 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2504 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2506 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2507 return E_NOINTERFACE;
2510 static ULONG WINAPI
2511 SPCF_AddRef(LPCLASSFACTORY iface) {
2512 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2513 return InterlockedIncrement(&This->ref);
2516 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2517 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2518 /* static class, won't be freed */
2519 return InterlockedDecrement(&This->ref);
2522 static HRESULT WINAPI SPCF_CreateInstance(
2523 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2525 /* Creates an uninitialized picture */
2526 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2530 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2531 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2532 FIXME("(%p)->(%d),stub!\n",This,dolock);
2533 return S_OK;
2536 static const IClassFactoryVtbl SPCF_Vtbl = {
2537 SPCF_QueryInterface,
2538 SPCF_AddRef,
2539 SPCF_Release,
2540 SPCF_CreateInstance,
2541 SPCF_LockServer
2543 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2545 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }