Synchronize with trunk r58606.
[reactos.git] / dll / win32 / oleaut32 / olepicture.c
1 /*
2 * OLE Picture object
3 *
4 * Implementation of OLE IPicture and related interfaces
5 *
6 * Copyright 2000 Huw D M Davies for CodeWeavers.
7 * Copyright 2001 Marcus Meissner
8 * Copyright 2008 Kirill K. Smirnov
9 *
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.
14 *
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.
19 *
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
23 *
24 * BUGS
25 *
26 * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
27 * Lots of methods are just stubs.
28 *
29 *
30 * NOTES (or things that msdn doesn't tell you)
31 *
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).
36 *
37 */
38
39 #define WIN32_NO_STATUS
40 #define _INC_WINDOWS
41
42 #include <config.h>
43 //#include "wine/port.h"
44
45 #ifdef HAVE_UNISTD_H
46 # include <unistd.h>
47 #endif
48 //#include <stdarg.h>
49 #include <stdio.h>
50 //#include <string.h>
51
52 #define COBJMACROS
53 #define NONAMELESSUNION
54 #define NONAMELESSSTRUCT
55
56 //#include "winerror.h"
57 #include <windef.h>
58 #include <winbase.h>
59 #include <wingdi.h>
60 //#include "winuser.h"
61 #include <ole2.h>
62 #include <olectl.h>
63 //#include "oleauto.h"
64 #include "connpt.h"
65 //#include "urlmon.h"
66 #include <initguid.h>
67 #include <wincodec.h>
68 #include <wine/debug.h>
69 #include <wine/unicode.h>
70 //#include "wine/library.h"
71
72 WINE_DEFAULT_DEBUG_CHANNEL(olepicture);
73
74 #define BITMAP_FORMAT_BMP 0x4d42 /* "BM" */
75 #define BITMAP_FORMAT_JPEG 0xd8ff
76 #define BITMAP_FORMAT_GIF 0x4947
77 #define BITMAP_FORMAT_PNG 0x5089
78 #define BITMAP_FORMAT_APM 0xcdd7
79
80 #include "pshpack1.h"
81
82 /* Header for Aldus Placable Metafiles - a standard metafile follows */
83 typedef struct _APM_HEADER
84 {
85 DWORD key;
86 WORD handle;
87 SHORT left;
88 SHORT top;
89 SHORT right;
90 SHORT bottom;
91 WORD inch;
92 DWORD reserved;
93 WORD checksum;
94 } APM_HEADER;
95
96 typedef struct {
97 BYTE bWidth;
98 BYTE bHeight;
99 BYTE bColorCount;
100 BYTE bReserved;
101 WORD xHotspot;
102 WORD yHotspot;
103 DWORD dwDIBSize;
104 DWORD dwDIBOffset;
105 } CURSORICONFILEDIRENTRY;
106
107 typedef struct
108 {
109 WORD idReserved;
110 WORD idType;
111 WORD idCount;
112 CURSORICONFILEDIRENTRY idEntries[1];
113 } CURSORICONFILEDIR;
114
115 #include "poppack.h"
116
117 /*************************************************************************
118 * Declaration of implementation class
119 */
120
121 typedef struct OLEPictureImpl {
122
123 /*
124 * IPicture handles IUnknown
125 */
126
127 IPicture IPicture_iface;
128 IDispatch IDispatch_iface;
129 IPersistStream IPersistStream_iface;
130 IConnectionPointContainer IConnectionPointContainer_iface;
131
132 /* Object reference count */
133 LONG ref;
134
135 /* We own the object and must destroy it ourselves */
136 BOOL fOwn;
137
138 /* Picture description */
139 PICTDESC desc;
140
141 /* These are the pixel size of a bitmap */
142 DWORD origWidth;
143 DWORD origHeight;
144
145 /* And these are the size of the picture converted into HIMETRIC units */
146 OLE_XSIZE_HIMETRIC himetricWidth;
147 OLE_YSIZE_HIMETRIC himetricHeight;
148
149 IConnectionPoint *pCP;
150
151 BOOL keepOrigFormat;
152 HDC hDCCur;
153 HBITMAP stock_bitmap;
154
155 /* Bitmap transparency mask */
156 HBITMAP hbmMask;
157 HBITMAP hbmXor;
158 COLORREF rgbTrans;
159
160 /* data */
161 void* data;
162 int datalen;
163 BOOL bIsDirty; /* Set to TRUE if picture has changed */
164 unsigned int loadtime_magic; /* If a length header was found, saves value */
165 unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
166 } OLEPictureImpl;
167
168 static inline OLEPictureImpl *impl_from_IPicture(IPicture *iface)
169 {
170 return CONTAINING_RECORD(iface, OLEPictureImpl, IPicture_iface);
171 }
172
173 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
174 {
175 return CONTAINING_RECORD(iface, OLEPictureImpl, IDispatch_iface);
176 }
177
178 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
179 {
180 return CONTAINING_RECORD(iface, OLEPictureImpl, IPersistStream_iface);
181 }
182
183 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
184 {
185 return CONTAINING_RECORD(iface, OLEPictureImpl, IConnectionPointContainer_iface);
186 }
187
188 /*
189 * Predeclare VTables. They get initialized at the end.
190 */
191 static const IPictureVtbl OLEPictureImpl_VTable;
192 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
193 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
194 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
195
196 /* pixels to HIMETRIC units conversion */
197 static inline OLE_XSIZE_HIMETRIC xpixels_to_himetric(INT pixels, HDC hdc)
198 {
199 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
200 }
201
202 static inline OLE_YSIZE_HIMETRIC ypixels_to_himetric(INT pixels, HDC hdc)
203 {
204 return MulDiv(pixels, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
205 }
206
207 /***********************************************************************
208 * Implementation of the OLEPictureImpl class.
209 */
210
211 static void OLEPictureImpl_SetBitmap(OLEPictureImpl *This)
212 {
213 BITMAP bm;
214 HDC hdcRef;
215
216 TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
217 if(GetObjectW(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
218 ERR("GetObject fails\n");
219 return;
220 }
221 This->origWidth = bm.bmWidth;
222 This->origHeight = bm.bmHeight;
223
224 TRACE("width %d, height %d, bpp %d\n", bm.bmWidth, bm.bmHeight, bm.bmBitsPixel);
225
226 /* The width and height are stored in HIMETRIC units (0.01 mm),
227 so we take our pixel width divide by pixels per inch and
228 multiply by 25.4 * 100 */
229 /* Should we use GetBitmapDimension if available? */
230 hdcRef = CreateCompatibleDC(0);
231
232 This->himetricWidth = xpixels_to_himetric(bm.bmWidth, hdcRef);
233 This->himetricHeight = ypixels_to_himetric(bm.bmHeight, hdcRef);
234 This->stock_bitmap = GetCurrentObject( hdcRef, OBJ_BITMAP );
235
236 This->loadtime_format = BITMAP_FORMAT_BMP;
237
238 DeleteDC(hdcRef);
239 }
240
241 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
242 {
243 ICONINFO infoIcon;
244
245 TRACE("icon handle %p\n", This->desc.u.icon.hicon);
246 if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
247 HDC hdcRef;
248 BITMAP bm;
249
250 TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
251 if(GetObjectW(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
252 ERR("GetObject fails on icon bitmap\n");
253 return;
254 }
255
256 This->origWidth = bm.bmWidth;
257 This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
258 /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
259 hdcRef = GetDC(0);
260
261 This->himetricWidth = xpixels_to_himetric(This->origWidth, hdcRef);
262 This->himetricHeight = ypixels_to_himetric(This->origHeight, hdcRef);
263
264 ReleaseDC(0, hdcRef);
265
266 DeleteObject(infoIcon.hbmMask);
267 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
268 } else {
269 ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
270 }
271 }
272
273 /************************************************************************
274 * OLEPictureImpl_Construct
275 *
276 * This method will construct a new instance of the OLEPictureImpl
277 * class.
278 *
279 * The caller of this method must release the object when it's
280 * done with it.
281 */
282 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
283 {
284 OLEPictureImpl* newObject = 0;
285
286 if (pictDesc)
287 TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
288
289 /*
290 * Allocate space for the object.
291 */
292 newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
293
294 if (newObject==0)
295 return newObject;
296
297 /*
298 * Initialize the virtual function table.
299 */
300 newObject->IPicture_iface.lpVtbl = &OLEPictureImpl_VTable;
301 newObject->IDispatch_iface.lpVtbl = &OLEPictureImpl_IDispatch_VTable;
302 newObject->IPersistStream_iface.lpVtbl = &OLEPictureImpl_IPersistStream_VTable;
303 newObject->IConnectionPointContainer_iface.lpVtbl = &OLEPictureImpl_IConnectionPointContainer_VTable;
304
305 newObject->pCP = NULL;
306 CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
307 if (!newObject->pCP)
308 {
309 HeapFree(GetProcessHeap(), 0, newObject);
310 return NULL;
311 }
312
313 /*
314 * Start with one reference count. The caller of this function
315 * must release the interface pointer when it is done.
316 */
317 newObject->ref = 1;
318 newObject->hDCCur = 0;
319
320 newObject->fOwn = fOwn;
321
322 /* dunno about original value */
323 newObject->keepOrigFormat = TRUE;
324
325 newObject->hbmMask = NULL;
326 newObject->hbmXor = NULL;
327 newObject->loadtime_magic = 0xdeadbeef;
328 newObject->loadtime_format = 0;
329 newObject->bIsDirty = FALSE;
330
331 if (pictDesc) {
332 newObject->desc = *pictDesc;
333
334 switch(pictDesc->picType) {
335 case PICTYPE_BITMAP:
336 OLEPictureImpl_SetBitmap(newObject);
337 break;
338
339 case PICTYPE_METAFILE:
340 TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
341 newObject->himetricWidth = pictDesc->u.wmf.xExt;
342 newObject->himetricHeight = pictDesc->u.wmf.yExt;
343 break;
344
345 case PICTYPE_NONE:
346 /* not sure what to do here */
347 newObject->himetricWidth = newObject->himetricHeight = 0;
348 break;
349
350 case PICTYPE_ICON:
351 OLEPictureImpl_SetIcon(newObject);
352 break;
353 case PICTYPE_ENHMETAFILE:
354 default:
355 FIXME("Unsupported type %d\n", pictDesc->picType);
356 newObject->himetricWidth = newObject->himetricHeight = 0;
357 break;
358 }
359 } else {
360 newObject->desc.picType = PICTYPE_UNINITIALIZED;
361 }
362
363 TRACE("returning %p\n", newObject);
364 return newObject;
365 }
366
367 /************************************************************************
368 * OLEPictureImpl_Destroy
369 *
370 * This method is called by the Release method when the reference
371 * count goes down to 0. It will free all resources used by
372 * this object. */
373 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
374 {
375 TRACE("(%p)\n", Obj);
376
377 if (Obj->pCP)
378 IConnectionPoint_Release(Obj->pCP);
379
380 if(Obj->fOwn) { /* We need to destroy the picture */
381 switch(Obj->desc.picType) {
382 case PICTYPE_BITMAP:
383 DeleteObject(Obj->desc.u.bmp.hbitmap);
384 if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
385 if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
386 break;
387 case PICTYPE_METAFILE:
388 DeleteMetaFile(Obj->desc.u.wmf.hmeta);
389 break;
390 case PICTYPE_ICON:
391 DestroyIcon(Obj->desc.u.icon.hicon);
392 break;
393 case PICTYPE_ENHMETAFILE:
394 DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
395 break;
396 case PICTYPE_NONE:
397 case PICTYPE_UNINITIALIZED:
398 /* Nothing to do */
399 break;
400 default:
401 FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
402 break;
403 }
404 }
405 HeapFree(GetProcessHeap(), 0, Obj->data);
406 HeapFree(GetProcessHeap(), 0, Obj);
407 }
408
409
410 /************************************************************************
411 * OLEPictureImpl_AddRef (IUnknown)
412 *
413 * See Windows documentation for more details on IUnknown methods.
414 */
415 static ULONG WINAPI OLEPictureImpl_AddRef(
416 IPicture* iface)
417 {
418 OLEPictureImpl *This = impl_from_IPicture(iface);
419 ULONG refCount = InterlockedIncrement(&This->ref);
420
421 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
422
423 return refCount;
424 }
425
426 /************************************************************************
427 * OLEPictureImpl_Release (IUnknown)
428 *
429 * See Windows documentation for more details on IUnknown methods.
430 */
431 static ULONG WINAPI OLEPictureImpl_Release(
432 IPicture* iface)
433 {
434 OLEPictureImpl *This = impl_from_IPicture(iface);
435 ULONG refCount = InterlockedDecrement(&This->ref);
436
437 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
438
439 /*
440 * If the reference count goes down to 0, perform suicide.
441 */
442 if (!refCount) OLEPictureImpl_Destroy(This);
443
444 return refCount;
445 }
446
447 /************************************************************************
448 * OLEPictureImpl_QueryInterface (IUnknown)
449 *
450 * See Windows documentation for more details on IUnknown methods.
451 */
452 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
453 IPicture* iface,
454 REFIID riid,
455 void** ppvObject)
456 {
457 OLEPictureImpl *This = impl_from_IPicture(iface);
458
459 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
460
461 if (!ppvObject)
462 return E_INVALIDARG;
463
464 *ppvObject = 0;
465
466 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
467 *ppvObject = This;
468 else if (IsEqualIID(&IID_IDispatch, riid))
469 *ppvObject = &This->IDispatch_iface;
470 else if (IsEqualIID(&IID_IPictureDisp, riid))
471 *ppvObject = &This->IDispatch_iface;
472 else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
473 *ppvObject = &This->IPersistStream_iface;
474 else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
475 *ppvObject = &This->IConnectionPointContainer_iface;
476
477 if (!*ppvObject)
478 {
479 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
480 return E_NOINTERFACE;
481 }
482
483 IPicture_AddRef(iface);
484
485 return S_OK;
486 }
487
488 /***********************************************************************
489 * OLEPicture_SendNotify (internal)
490 *
491 * Sends notification messages of changed properties to any interested
492 * connections.
493 */
494 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
495 {
496 IEnumConnections *pEnum;
497 CONNECTDATA CD;
498
499 if (IConnectionPoint_EnumConnections(this->pCP, &pEnum) != S_OK)
500 return;
501 while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
502 IPropertyNotifySink *sink;
503
504 IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
505 IPropertyNotifySink_OnChanged(sink, dispID);
506 IPropertyNotifySink_Release(sink);
507 IUnknown_Release(CD.pUnk);
508 }
509 IEnumConnections_Release(pEnum);
510 }
511
512 /************************************************************************
513 * OLEPictureImpl_get_Handle
514 */
515 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
516 OLE_HANDLE *phandle)
517 {
518 OLEPictureImpl *This = impl_from_IPicture(iface);
519 TRACE("(%p)->(%p)\n", This, phandle);
520
521 if(!phandle)
522 return E_POINTER;
523
524 switch(This->desc.picType) {
525 case PICTYPE_NONE:
526 case PICTYPE_UNINITIALIZED:
527 *phandle = 0;
528 break;
529 case PICTYPE_BITMAP:
530 *phandle = HandleToUlong(This->desc.u.bmp.hbitmap);
531 break;
532 case PICTYPE_METAFILE:
533 *phandle = HandleToUlong(This->desc.u.wmf.hmeta);
534 break;
535 case PICTYPE_ICON:
536 *phandle = HandleToUlong(This->desc.u.icon.hicon);
537 break;
538 case PICTYPE_ENHMETAFILE:
539 *phandle = HandleToUlong(This->desc.u.emf.hemf);
540 break;
541 default:
542 FIXME("Unimplemented type %d\n", This->desc.picType);
543 return E_NOTIMPL;
544 }
545 TRACE("returning handle %08x\n", *phandle);
546 return S_OK;
547 }
548
549 /************************************************************************
550 * OLEPictureImpl_get_hPal
551 */
552 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
553 OLE_HANDLE *phandle)
554 {
555 OLEPictureImpl *This = impl_from_IPicture(iface);
556 HRESULT hres;
557 TRACE("(%p)->(%p)\n", This, phandle);
558
559 if (!phandle)
560 return E_POINTER;
561
562 switch (This->desc.picType) {
563 case (UINT)PICTYPE_UNINITIALIZED:
564 case PICTYPE_NONE:
565 *phandle = 0;
566 hres = S_FALSE;
567 break;
568 case PICTYPE_BITMAP:
569 *phandle = HandleToUlong(This->desc.u.bmp.hpal);
570 hres = S_OK;
571 break;
572 case PICTYPE_METAFILE:
573 hres = E_FAIL;
574 break;
575 case PICTYPE_ICON:
576 case PICTYPE_ENHMETAFILE:
577 default:
578 FIXME("unimplemented for type %d. Returning 0 palette.\n",
579 This->desc.picType);
580 *phandle = 0;
581 hres = S_OK;
582 }
583
584 TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
585 return hres;
586 }
587
588 /************************************************************************
589 * OLEPictureImpl_get_Type
590 */
591 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
592 short *ptype)
593 {
594 OLEPictureImpl *This = impl_from_IPicture(iface);
595 TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
596
597 if(!ptype)
598 return E_POINTER;
599
600 *ptype = This->desc.picType;
601 return S_OK;
602 }
603
604 /************************************************************************
605 * OLEPictureImpl_get_Width
606 */
607 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
608 OLE_XSIZE_HIMETRIC *pwidth)
609 {
610 OLEPictureImpl *This = impl_from_IPicture(iface);
611 TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
612 *pwidth = This->himetricWidth;
613 return S_OK;
614 }
615
616 /************************************************************************
617 * OLEPictureImpl_get_Height
618 */
619 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
620 OLE_YSIZE_HIMETRIC *pheight)
621 {
622 OLEPictureImpl *This = impl_from_IPicture(iface);
623 TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
624 *pheight = This->himetricHeight;
625 return S_OK;
626 }
627
628 /************************************************************************
629 * OLEPictureImpl_Render
630 */
631 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
632 LONG x, LONG y, LONG cx, LONG cy,
633 OLE_XPOS_HIMETRIC xSrc,
634 OLE_YPOS_HIMETRIC ySrc,
635 OLE_XSIZE_HIMETRIC cxSrc,
636 OLE_YSIZE_HIMETRIC cySrc,
637 LPCRECT prcWBounds)
638 {
639 OLEPictureImpl *This = impl_from_IPicture(iface);
640 TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
641 This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
642 if(prcWBounds)
643 TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
644 prcWBounds->right, prcWBounds->bottom);
645
646 if(cx == 0 || cy == 0 || cxSrc == 0 || cySrc == 0){
647 return CTL_E_INVALIDPROPERTYVALUE;
648 }
649
650 /*
651 * While the documentation suggests this to be here (or after rendering?)
652 * it does cause an endless recursion in my sample app. -MM 20010804
653 OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
654 */
655
656 switch(This->desc.picType) {
657 case PICTYPE_UNINITIALIZED:
658 case PICTYPE_NONE:
659 /* nothing to do */
660 return S_OK;
661 case PICTYPE_BITMAP:
662 {
663 HBITMAP hbmpOld;
664 HDC hdcBmp;
665
666 /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
667 NB y-axis gets flipped */
668
669 hdcBmp = CreateCompatibleDC(0);
670 SetMapMode(hdcBmp, MM_ANISOTROPIC);
671 SetWindowOrgEx(hdcBmp, 0, 0, NULL);
672 SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
673 SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
674 SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
675
676 if (This->hbmMask) {
677 HDC hdcMask = CreateCompatibleDC(0);
678 HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
679
680 hbmpOld = SelectObject(hdcBmp, This->hbmXor);
681
682 SetMapMode(hdcMask, MM_ANISOTROPIC);
683 SetWindowOrgEx(hdcMask, 0, 0, NULL);
684 SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
685 SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
686 SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
687
688 SetBkColor(hdc, RGB(255, 255, 255));
689 SetTextColor(hdc, RGB(0, 0, 0));
690 StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND);
691 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
692
693 SelectObject(hdcMask, hOldbm);
694 DeleteDC(hdcMask);
695 } else {
696 hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
697 StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
698 }
699
700 SelectObject(hdcBmp, hbmpOld);
701 DeleteDC(hdcBmp);
702 }
703 break;
704 case PICTYPE_ICON:
705 FIXME("Not quite correct implementation of rendering icons...\n");
706 DrawIconEx(hdc, x, y, This->desc.u.icon.hicon, cx, cy, 0, NULL, DI_NORMAL);
707 break;
708
709 case PICTYPE_METAFILE:
710 {
711 POINT prevOrg, prevWndOrg;
712 SIZE prevExt, prevWndExt;
713 int oldmode;
714
715 /* Render the WMF to the appropriate location by setting the
716 appropriate ratio between "device units" and "logical units" */
717 oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
718 /* For the "source rectangle" the y-axis must be inverted */
719 SetWindowOrgEx(hdc, xSrc, This->himetricHeight-ySrc, &prevWndOrg);
720 SetWindowExtEx(hdc, cxSrc, -cySrc, &prevWndExt);
721 /* For the "destination rectangle" no inversion is necessary */
722 SetViewportOrgEx(hdc, x, y, &prevOrg);
723 SetViewportExtEx(hdc, cx, cy, &prevExt);
724
725 if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
726 ERR("PlayMetaFile failed!\n");
727
728 /* We're done, restore the DC to the previous settings for converting
729 logical units to device units */
730 SetWindowExtEx(hdc, prevWndExt.cx, prevWndExt.cy, NULL);
731 SetWindowOrgEx(hdc, prevWndOrg.x, prevWndOrg.y, NULL);
732 SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
733 SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
734 SetMapMode(hdc, oldmode);
735 break;
736 }
737
738 case PICTYPE_ENHMETAFILE:
739 {
740 RECT rc = { x, y, x + cx, y + cy };
741 PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
742 break;
743 }
744
745 default:
746 FIXME("type %d not implemented\n", This->desc.picType);
747 return E_NOTIMPL;
748 }
749 return S_OK;
750 }
751
752 /************************************************************************
753 * OLEPictureImpl_set_hPal
754 */
755 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
756 OLE_HANDLE hpal)
757 {
758 OLEPictureImpl *This = impl_from_IPicture(iface);
759 FIXME("(%p)->(%08x): stub\n", This, hpal);
760 OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
761 return E_NOTIMPL;
762 }
763
764 /************************************************************************
765 * OLEPictureImpl_get_CurDC
766 */
767 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
768 HDC *phdc)
769 {
770 OLEPictureImpl *This = impl_from_IPicture(iface);
771 TRACE("(%p), returning %p\n", This, This->hDCCur);
772 if (phdc) *phdc = This->hDCCur;
773 return S_OK;
774 }
775
776 /************************************************************************
777 * OLEPictureImpl_SelectPicture
778 */
779 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
780 HDC hdcIn,
781 HDC *phdcOut,
782 OLE_HANDLE *phbmpOut)
783 {
784 OLEPictureImpl *This = impl_from_IPicture(iface);
785 TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
786 if (This->desc.picType == PICTYPE_BITMAP) {
787 if (phdcOut)
788 *phdcOut = This->hDCCur;
789 if (This->hDCCur) SelectObject(This->hDCCur,This->stock_bitmap);
790 if (hdcIn) SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
791 This->hDCCur = hdcIn;
792 if (phbmpOut)
793 *phbmpOut = HandleToUlong(This->desc.u.bmp.hbitmap);
794 return S_OK;
795 } else {
796 FIXME("Don't know how to select picture type %d\n",This->desc.picType);
797 return E_FAIL;
798 }
799 }
800
801 /************************************************************************
802 * OLEPictureImpl_get_KeepOriginalFormat
803 */
804 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
805 BOOL *pfKeep)
806 {
807 OLEPictureImpl *This = impl_from_IPicture(iface);
808 TRACE("(%p)->(%p)\n", This, pfKeep);
809 if (!pfKeep)
810 return E_POINTER;
811 *pfKeep = This->keepOrigFormat;
812 return S_OK;
813 }
814
815 /************************************************************************
816 * OLEPictureImpl_put_KeepOriginalFormat
817 */
818 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
819 BOOL keep)
820 {
821 OLEPictureImpl *This = impl_from_IPicture(iface);
822 TRACE("(%p)->(%d)\n", This, keep);
823 This->keepOrigFormat = keep;
824 /* FIXME: what DISPID notification here? */
825 return S_OK;
826 }
827
828 /************************************************************************
829 * OLEPictureImpl_PictureChanged
830 */
831 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
832 {
833 OLEPictureImpl *This = impl_from_IPicture(iface);
834 TRACE("(%p)->()\n", This);
835 OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
836 This->bIsDirty = TRUE;
837 return S_OK;
838 }
839
840 /************************************************************************
841 * OLEPictureImpl_SaveAsFile
842 */
843 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
844 IStream *pstream,
845 BOOL SaveMemCopy,
846 LONG *pcbSize)
847 {
848 OLEPictureImpl *This = impl_from_IPicture(iface);
849 FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
850 return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
851 }
852
853 /************************************************************************
854 * OLEPictureImpl_get_Attributes
855 */
856 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
857 DWORD *pdwAttr)
858 {
859 OLEPictureImpl *This = impl_from_IPicture(iface);
860 TRACE("(%p)->(%p).\n", This, pdwAttr);
861
862 if(!pdwAttr)
863 return E_POINTER;
864
865 *pdwAttr = 0;
866 switch (This->desc.picType) {
867 case PICTYPE_UNINITIALIZED:
868 case PICTYPE_NONE: break;
869 case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */
870 case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break;
871 case PICTYPE_ENHMETAFILE: /* fall through */
872 case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
873 default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
874 }
875 return S_OK;
876 }
877
878
879 /************************************************************************
880 * IConnectionPointContainer
881 */
882 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
883 IConnectionPointContainer* iface,
884 REFIID riid,
885 VOID** ppvoid)
886 {
887 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
888
889 return IPicture_QueryInterface(&This->IPicture_iface,riid,ppvoid);
890 }
891
892 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
893 IConnectionPointContainer* iface)
894 {
895 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
896
897 return IPicture_AddRef(&This->IPicture_iface);
898 }
899
900 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
901 IConnectionPointContainer* iface)
902 {
903 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
904
905 return IPicture_Release(&This->IPicture_iface);
906 }
907
908 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
909 IConnectionPointContainer* iface,
910 IEnumConnectionPoints** ppEnum)
911 {
912 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
913
914 FIXME("(%p,%p), stub!\n",This,ppEnum);
915 return E_NOTIMPL;
916 }
917
918 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
919 IConnectionPointContainer* iface,
920 REFIID riid,
921 IConnectionPoint **ppCP)
922 {
923 OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
924 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
925 if (!ppCP)
926 return E_POINTER;
927 *ppCP = NULL;
928 if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
929 return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
930 FIXME("no connection point for %s\n",debugstr_guid(riid));
931 return CONNECT_E_NOCONNECTION;
932 }
933
934
935 /************************************************************************
936 * IPersistStream
937 */
938
939 /************************************************************************
940 * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
941 *
942 * See Windows documentation for more details on IUnknown methods.
943 */
944 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
945 IPersistStream* iface,
946 REFIID riid,
947 VOID** ppvoid)
948 {
949 OLEPictureImpl *This = impl_from_IPersistStream(iface);
950
951 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
952 }
953
954 /************************************************************************
955 * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
956 *
957 * See Windows documentation for more details on IUnknown methods.
958 */
959 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
960 IPersistStream* iface)
961 {
962 OLEPictureImpl *This = impl_from_IPersistStream(iface);
963
964 return IPicture_AddRef(&This->IPicture_iface);
965 }
966
967 /************************************************************************
968 * OLEPictureImpl_IPersistStream_Release (IUnknown)
969 *
970 * See Windows documentation for more details on IUnknown methods.
971 */
972 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
973 IPersistStream* iface)
974 {
975 OLEPictureImpl *This = impl_from_IPersistStream(iface);
976
977 return IPicture_Release(&This->IPicture_iface);
978 }
979
980 /************************************************************************
981 * OLEPictureImpl_IPersistStream_GetClassID
982 */
983 static HRESULT WINAPI OLEPictureImpl_GetClassID(
984 IPersistStream* iface,CLSID* pClassID)
985 {
986 TRACE("(%p)\n", pClassID);
987 *pClassID = CLSID_StdPicture;
988 return S_OK;
989 }
990
991 /************************************************************************
992 * OLEPictureImpl_IPersistStream_IsDirty
993 */
994 static HRESULT WINAPI OLEPictureImpl_IsDirty(
995 IPersistStream* iface)
996 {
997 OLEPictureImpl *This = impl_from_IPersistStream(iface);
998 FIXME("(%p),stub!\n",This);
999 return E_NOTIMPL;
1000 }
1001
1002 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1003 {
1004 BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf;
1005 BITMAPINFO *bi = (BITMAPINFO*)(bfh+1);
1006 HDC hdcref;
1007
1008 /* Does not matter whether this is a coreheader or not, we only use
1009 * components which are in both
1010 */
1011 hdcref = GetDC(0);
1012 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1013 hdcref,
1014 &(bi->bmiHeader),
1015 CBM_INIT,
1016 xbuf+bfh->bfOffBits,
1017 bi,
1018 DIB_RGB_COLORS
1019 );
1020 ReleaseDC(0, hdcref);
1021 if (This->desc.u.bmp.hbitmap == 0)
1022 return E_FAIL;
1023 This->desc.picType = PICTYPE_BITMAP;
1024 OLEPictureImpl_SetBitmap(This);
1025 return S_OK;
1026 }
1027
1028 static HRESULT OLEPictureImpl_LoadWICSource(OLEPictureImpl *This, IWICBitmapSource *src)
1029 {
1030 HRESULT hr;
1031 BITMAPINFOHEADER bih;
1032 HDC hdcref;
1033 UINT width, height;
1034 UINT stride, buffersize;
1035 LPBYTE bits=NULL;
1036 WICRect rc;
1037 IWICBitmapSource *real_source;
1038 UINT x, y;
1039 COLORREF white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1040 BOOL has_alpha=FALSE;
1041
1042 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, src, &real_source);
1043 if (FAILED(hr)) return hr;
1044
1045 hr = IWICBitmapSource_GetSize(real_source, &width, &height);
1046 if (FAILED(hr)) goto end;
1047
1048 bih.biSize = sizeof(bih);
1049 bih.biWidth = width;
1050 bih.biHeight = -height;
1051 bih.biPlanes = 1;
1052 bih.biBitCount = 32;
1053 bih.biCompression = BI_RGB;
1054 bih.biSizeImage = 0;
1055 bih.biXPelsPerMeter = 4085; /* olepicture ignores the stored resolution */
1056 bih.biYPelsPerMeter = 4085;
1057 bih.biClrUsed = 0;
1058 bih.biClrImportant = 0;
1059
1060 stride = 4 * width;
1061 buffersize = stride * height;
1062
1063 bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
1064 if (!bits)
1065 {
1066 hr = E_OUTOFMEMORY;
1067 goto end;
1068 }
1069
1070 rc.X = 0;
1071 rc.Y = 0;
1072 rc.Width = width;
1073 rc.Height = height;
1074 hr = IWICBitmapSource_CopyPixels(real_source, &rc, stride, buffersize, bits);
1075 if (FAILED(hr))
1076 goto end;
1077
1078 hdcref = GetDC(0);
1079 This->desc.u.bmp.hbitmap = CreateDIBitmap(
1080 hdcref,
1081 &bih,
1082 CBM_INIT,
1083 bits,
1084 (BITMAPINFO*)&bih,
1085 DIB_RGB_COLORS);
1086
1087 if (This->desc.u.bmp.hbitmap == 0)
1088 {
1089 hr = E_FAIL;
1090 ReleaseDC(0, hdcref);
1091 goto end;
1092 }
1093
1094 This->desc.picType = PICTYPE_BITMAP;
1095 OLEPictureImpl_SetBitmap(This);
1096
1097 /* set transparent pixels to black, all others to white */
1098 for(y = 0; y < height; y++){
1099 for(x = 0; x < width; x++){
1100 DWORD *pixel = (DWORD*)(bits + stride*y + 4*x);
1101 if((*pixel & 0x80000000) == 0)
1102 {
1103 has_alpha = TRUE;
1104 *pixel = black;
1105 }
1106 else
1107 *pixel = white;
1108 }
1109 }
1110
1111 if (has_alpha)
1112 {
1113 HDC hdcBmp, hdcXor, hdcMask;
1114 HBITMAP hbmoldBmp, hbmoldXor, hbmoldMask;
1115
1116 This->hbmXor = CreateDIBitmap(
1117 hdcref,
1118 &bih,
1119 CBM_INIT,
1120 bits,
1121 (BITMAPINFO*)&bih,
1122 DIB_RGB_COLORS
1123 );
1124
1125 This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1126 hdcBmp = CreateCompatibleDC(NULL);
1127 hdcXor = CreateCompatibleDC(NULL);
1128 hdcMask = CreateCompatibleDC(NULL);
1129
1130 hbmoldBmp = SelectObject(hdcBmp,This->desc.u.bmp.hbitmap);
1131 hbmoldXor = SelectObject(hdcXor,This->hbmXor);
1132 hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1133
1134 SetBkColor(hdcXor,black);
1135 BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1136 BitBlt(hdcXor,0,0,width,height,hdcBmp,0,0,SRCAND);
1137
1138 SelectObject(hdcBmp,hbmoldBmp);
1139 SelectObject(hdcXor,hbmoldXor);
1140 SelectObject(hdcMask,hbmoldMask);
1141
1142 DeleteDC(hdcBmp);
1143 DeleteDC(hdcXor);
1144 DeleteDC(hdcMask);
1145 }
1146
1147 ReleaseDC(0, hdcref);
1148
1149 end:
1150 HeapFree(GetProcessHeap(), 0, bits);
1151 IWICBitmapSource_Release(real_source);
1152 return hr;
1153 }
1154
1155 static HRESULT OLEPictureImpl_LoadWICDecoder(OLEPictureImpl *This, REFCLSID decoder_clsid, BYTE *xbuf, ULONG xread)
1156 {
1157 HRESULT hr;
1158 IWICImagingFactory *factory;
1159 IWICBitmapDecoder *decoder;
1160 IWICBitmapFrameDecode *framedecode;
1161 HRESULT initresult;
1162 IWICStream *stream;
1163
1164 initresult = CoInitialize(NULL);
1165
1166 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1167 &IID_IWICImagingFactory, (void**)&factory);
1168 if (SUCCEEDED(hr)) /* created factory */
1169 {
1170 hr = IWICImagingFactory_CreateStream(factory, &stream);
1171 IWICImagingFactory_Release(factory);
1172 }
1173
1174 if (SUCCEEDED(hr)) /* created stream */
1175 {
1176 hr = IWICStream_InitializeFromMemory(stream, xbuf, xread);
1177
1178 if (SUCCEEDED(hr)) /* initialized stream */
1179 {
1180 hr = CoCreateInstance(decoder_clsid, NULL, CLSCTX_INPROC_SERVER,
1181 &IID_IWICBitmapDecoder, (void**)&decoder);
1182 if (SUCCEEDED(hr)) /* created decoder */
1183 {
1184 hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)stream, WICDecodeMetadataCacheOnLoad);
1185
1186 if (SUCCEEDED(hr)) /* initialized decoder */
1187 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
1188
1189 IWICBitmapDecoder_Release(decoder);
1190 }
1191 }
1192
1193 IWICStream_Release(stream);
1194 }
1195
1196 if (SUCCEEDED(hr)) /* got framedecode */
1197 {
1198 hr = OLEPictureImpl_LoadWICSource(This, (IWICBitmapSource*)framedecode);
1199 IWICBitmapFrameDecode_Release(framedecode);
1200 }
1201
1202 if (SUCCEEDED(initresult)) CoUninitialize();
1203 return hr;
1204 }
1205
1206 /*****************************************************
1207 * start of Icon-specific code
1208 */
1209
1210 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1211 {
1212 HICON hicon;
1213 CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf;
1214 HDC hdcRef;
1215 int i;
1216
1217 /*
1218 FIXME("icon.idReserved=%d\n",cifd->idReserved);
1219 FIXME("icon.idType=%d\n",cifd->idType);
1220 FIXME("icon.idCount=%d\n",cifd->idCount);
1221
1222 for (i=0;i<cifd->idCount;i++) {
1223 FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1224 FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1225 FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1226 FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1227 FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1228 FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1229 FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1230 FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1231 }
1232 */
1233 i=0;
1234 /* If we have more than one icon, try to find the best.
1235 * this currently means '32 pixel wide'.
1236 */
1237 if (cifd->idCount!=1) {
1238 for (i=0;i<cifd->idCount;i++) {
1239 if (cifd->idEntries[i].bWidth == 32)
1240 break;
1241 }
1242 if (i==cifd->idCount) i=0;
1243 }
1244 if (cifd->idType == 2)
1245 {
1246 LPBYTE buf = HeapAlloc(GetProcessHeap(), 0, cifd->idEntries[i].dwDIBSize + 4);
1247 memcpy(buf, &cifd->idEntries[i].xHotspot, 4);
1248 memcpy(buf + 4, xbuf+cifd->idEntries[i].dwDIBOffset, cifd->idEntries[i].dwDIBSize);
1249 hicon = CreateIconFromResourceEx(
1250 buf,
1251 cifd->idEntries[i].dwDIBSize + 4,
1252 FALSE, /* is cursor */
1253 0x00030000,
1254 cifd->idEntries[i].bWidth,
1255 cifd->idEntries[i].bHeight,
1256 0
1257 );
1258 HeapFree(GetProcessHeap(), 0, buf);
1259 }
1260 else
1261 {
1262 hicon = CreateIconFromResourceEx(
1263 xbuf+cifd->idEntries[i].dwDIBOffset,
1264 cifd->idEntries[i].dwDIBSize,
1265 TRUE, /* is icon */
1266 0x00030000,
1267 cifd->idEntries[i].bWidth,
1268 cifd->idEntries[i].bHeight,
1269 0
1270 );
1271 }
1272 if (!hicon) {
1273 ERR("CreateIcon failed.\n");
1274 return E_FAIL;
1275 } else {
1276 This->desc.picType = PICTYPE_ICON;
1277 This->desc.u.icon.hicon = hicon;
1278 This->origWidth = cifd->idEntries[i].bWidth;
1279 This->origHeight = cifd->idEntries[i].bHeight;
1280 hdcRef = CreateCompatibleDC(0);
1281 This->himetricWidth = xpixels_to_himetric(cifd->idEntries[i].bWidth, hdcRef);
1282 This->himetricHeight= ypixels_to_himetric(cifd->idEntries[i].bHeight, hdcRef);
1283 DeleteDC(hdcRef);
1284 return S_OK;
1285 }
1286 }
1287
1288 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1289 const BYTE *data, ULONG size)
1290 {
1291 HENHMETAFILE hemf;
1292 ENHMETAHEADER hdr;
1293
1294 hemf = SetEnhMetaFileBits(size, data);
1295 if (!hemf) return E_FAIL;
1296
1297 GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1298
1299 This->desc.picType = PICTYPE_ENHMETAFILE;
1300 This->desc.u.emf.hemf = hemf;
1301
1302 This->origWidth = 0;
1303 This->origHeight = 0;
1304 This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1305 This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1306
1307 return S_OK;
1308 }
1309
1310 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1311 const BYTE *data, ULONG size)
1312 {
1313 const APM_HEADER *header = (const APM_HEADER *)data;
1314 HMETAFILE hmf;
1315
1316 if (size < sizeof(APM_HEADER))
1317 return E_FAIL;
1318 if (header->key != 0x9ac6cdd7)
1319 return E_FAIL;
1320
1321 /* SetMetaFileBitsEx performs data check on its own */
1322 hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1323 if (!hmf) return E_FAIL;
1324
1325 This->desc.picType = PICTYPE_METAFILE;
1326 This->desc.u.wmf.hmeta = hmf;
1327 This->desc.u.wmf.xExt = 0;
1328 This->desc.u.wmf.yExt = 0;
1329
1330 This->origWidth = 0;
1331 This->origHeight = 0;
1332 This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1333 This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1334 return S_OK;
1335 }
1336
1337 /************************************************************************
1338 * OLEPictureImpl_IPersistStream_Load (IUnknown)
1339 *
1340 * Loads the binary data from the IStream. Starts at current position.
1341 * There appears to be an 2 DWORD header:
1342 * DWORD magic;
1343 * DWORD len;
1344 *
1345 * Currently implemented: BITMAP, ICON, CURSOR, JPEG, GIF, WMF, EMF
1346 */
1347 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface, IStream *pStm) {
1348 HRESULT hr;
1349 BOOL headerisdata;
1350 BOOL statfailed = FALSE;
1351 ULONG xread, toread;
1352 ULONG headerread;
1353 BYTE *xbuf;
1354 DWORD header[2];
1355 WORD magic;
1356 STATSTG statstg;
1357 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1358
1359 TRACE("(%p,%p)\n",This,pStm);
1360
1361 /****************************************************************************************
1362 * Part 1: Load the data
1363 */
1364 /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1365 * out whether we do.
1366 *
1367 * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1368 * compound file. This may explain most, if not all, of the cases of "no
1369 * header", and the header validation should take this into account.
1370 * At least in Visual Basic 6, resource streams, valid headers are
1371 * header[0] == "lt\0\0",
1372 * header[1] == length_of_stream.
1373 *
1374 * Also handle streams where we do not have a working "Stat" method by
1375 * reading all data until the end of the stream.
1376 */
1377 hr = IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1378 if (hr != S_OK) {
1379 TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1380 statfailed = TRUE;
1381 /* we will read at least 8 byte ... just right below */
1382 statstg.cbSize.QuadPart = 8;
1383 }
1384
1385 toread = 0;
1386 headerread = 0;
1387 headerisdata = FALSE;
1388 do {
1389 hr = IStream_Read(pStm, header, 8, &xread);
1390 if (hr != S_OK || xread!=8) {
1391 ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1392 return (hr?hr:E_FAIL);
1393 }
1394 headerread += xread;
1395 xread = 0;
1396
1397 if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1398 if (toread != 0 && toread != header[1])
1399 FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1400 toread, header[1]);
1401 toread = header[1];
1402 if (toread == 0) break;
1403 } else {
1404 if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */
1405 !memcmp(&(header[0]), "BM", 2) || /* BMP header */
1406 !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */
1407 (header[0] == EMR_HEADER) || /* EMF header */
1408 (header[0] == 0x10000) || /* icon: idReserved 0, idType 1 */
1409 (header[0] == 0x20000) || /* cursor: idReserved 0, idType 2 */
1410 (header[1] > statstg.cbSize.QuadPart)|| /* invalid size */
1411 (header[1]==0)
1412 ) {/* Found start of bitmap data */
1413 headerisdata = TRUE;
1414 if (toread == 0)
1415 toread = statstg.cbSize.QuadPart-8;
1416 else toread -= 8;
1417 xread = 8;
1418 } else {
1419 FIXME("Unknown stream header magic: %08x\n", header[0]);
1420 toread = header[1];
1421 }
1422 }
1423 } while (!headerisdata);
1424
1425 if (statfailed) { /* we don't know the size ... read all we get */
1426 unsigned int sizeinc = 4096;
1427 unsigned int origsize = sizeinc;
1428 ULONG nread = 42;
1429
1430 TRACE("Reading all data from stream.\n");
1431 xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1432 if (headerisdata)
1433 memcpy (xbuf, header, 8);
1434 while (1) {
1435 while (xread < origsize) {
1436 hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1437 xread += nread;
1438 if (hr != S_OK || !nread)
1439 break;
1440 }
1441 if (!nread || hr != S_OK) /* done, or error */
1442 break;
1443 if (xread == origsize) {
1444 origsize += sizeinc;
1445 sizeinc = 2*sizeinc; /* exponential increase */
1446 xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1447 }
1448 }
1449 if (hr != S_OK)
1450 TRACE("hr in no-stat loader case is %08x\n", hr);
1451 TRACE("loaded %d bytes.\n", xread);
1452 This->datalen = xread;
1453 This->data = xbuf;
1454 } else {
1455 This->datalen = toread+(headerisdata?8:0);
1456 xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1457 if (!xbuf)
1458 return E_OUTOFMEMORY;
1459
1460 if (headerisdata)
1461 memcpy (xbuf, header, 8);
1462
1463 while (xread < This->datalen) {
1464 ULONG nread;
1465 hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1466 xread += nread;
1467 if (hr != S_OK || !nread)
1468 break;
1469 }
1470 if (xread != This->datalen)
1471 ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1472 }
1473 if (This->datalen == 0) { /* Marks the "NONE" picture */
1474 This->desc.picType = PICTYPE_NONE;
1475 return S_OK;
1476 }
1477
1478
1479 /****************************************************************************************
1480 * Part 2: Process the loaded data
1481 */
1482
1483 magic = xbuf[0] + (xbuf[1]<<8);
1484 This->loadtime_format = magic;
1485
1486 switch (magic) {
1487 case BITMAP_FORMAT_GIF: /* GIF */
1488 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICGifDecoder, xbuf, xread);
1489 break;
1490 case BITMAP_FORMAT_JPEG: /* JPEG */
1491 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICJpegDecoder, xbuf, xread);
1492 break;
1493 case BITMAP_FORMAT_BMP: /* Bitmap */
1494 hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1495 break;
1496 case BITMAP_FORMAT_PNG: /* PNG */
1497 hr = OLEPictureImpl_LoadWICDecoder(This, &CLSID_WICPngDecoder, xbuf, xread);
1498 break;
1499 case BITMAP_FORMAT_APM: /* APM */
1500 hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1501 break;
1502 case 0x0000: { /* ICON or CURSOR, first word is dwReserved */
1503 hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1504 break;
1505 }
1506 default:
1507 {
1508 unsigned int i;
1509
1510 /* let's see if it's a EMF */
1511 hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1512 if (hr == S_OK) break;
1513
1514 FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1515 hr=E_FAIL;
1516 for (i=0;i<xread+8;i++) {
1517 if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1518 else MESSAGE("%02x ",xbuf[i-8]);
1519 if (i % 10 == 9) MESSAGE("\n");
1520 }
1521 MESSAGE("\n");
1522 break;
1523 }
1524 }
1525 This->bIsDirty = FALSE;
1526
1527 /* FIXME: this notify is not really documented */
1528 if (hr==S_OK)
1529 OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1530 return hr;
1531 }
1532
1533 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1534 {
1535 int iSuccess = 0;
1536 HDC hDC;
1537 BITMAPINFO * pInfoBitmap;
1538 int iNumPaletteEntries;
1539 unsigned char * pPixelData;
1540 BITMAPFILEHEADER * pFileHeader;
1541 BITMAPINFO * pInfoHeader;
1542
1543 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1544 sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1545
1546 /* Find out bitmap size and padded length */
1547 hDC = GetDC(0);
1548 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1549 GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1550
1551 /* Fetch bitmap palette & pixel data */
1552
1553 pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1554 GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1555
1556 /* Calculate the total length required for the BMP data */
1557 if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1558 iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1559 if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1560 } else {
1561 if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1562 iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1563 else
1564 iNumPaletteEntries = 0;
1565 }
1566 *pLength =
1567 sizeof(BITMAPFILEHEADER) +
1568 sizeof(BITMAPINFOHEADER) +
1569 iNumPaletteEntries * sizeof(RGBQUAD) +
1570 pInfoBitmap->bmiHeader.biSizeImage;
1571 *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1572
1573 /* Fill the BITMAPFILEHEADER */
1574 pFileHeader = *ppBuffer;
1575 pFileHeader->bfType = BITMAP_FORMAT_BMP;
1576 pFileHeader->bfSize = *pLength;
1577 pFileHeader->bfOffBits =
1578 sizeof(BITMAPFILEHEADER) +
1579 sizeof(BITMAPINFOHEADER) +
1580 iNumPaletteEntries * sizeof(RGBQUAD);
1581
1582 /* Fill the BITMAPINFOHEADER and the palette data */
1583 pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1584 memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1585 memcpy(
1586 (unsigned char *)(*ppBuffer) +
1587 sizeof(BITMAPFILEHEADER) +
1588 sizeof(BITMAPINFOHEADER) +
1589 iNumPaletteEntries * sizeof(RGBQUAD),
1590 pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
1591 iSuccess = 1;
1592
1593 HeapFree(GetProcessHeap(), 0, pPixelData);
1594 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1595 return iSuccess;
1596 }
1597
1598 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
1599 {
1600 ICONINFO infoIcon;
1601 int iSuccess = 0;
1602
1603 *ppBuffer = NULL; *pLength = 0;
1604 if (GetIconInfo(hIcon, &infoIcon)) {
1605 HDC hDC;
1606 BITMAPINFO * pInfoBitmap;
1607 unsigned char * pIconData = NULL;
1608 unsigned int iDataSize = 0;
1609
1610 pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1611
1612 /* Find out icon size */
1613 hDC = GetDC(0);
1614 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1615 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1616 if (1) {
1617 /* Auxiliary pointers */
1618 CURSORICONFILEDIR * pIconDir;
1619 CURSORICONFILEDIRENTRY * pIconEntry;
1620 BITMAPINFOHEADER * pIconBitmapHeader;
1621 unsigned int iOffsetPalette;
1622 unsigned int iOffsetColorData;
1623 unsigned int iOffsetMaskData;
1624
1625 unsigned int iLengthScanLineMask;
1626 unsigned int iNumEntriesPalette;
1627
1628 iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
1629 /*
1630 FIXME("DEBUG: bitmap size is %d x %d\n",
1631 pInfoBitmap->bmiHeader.biWidth,
1632 pInfoBitmap->bmiHeader.biHeight);
1633 FIXME("DEBUG: bitmap bpp is %d\n",
1634 pInfoBitmap->bmiHeader.biBitCount);
1635 FIXME("DEBUG: bitmap nplanes is %d\n",
1636 pInfoBitmap->bmiHeader.biPlanes);
1637 FIXME("DEBUG: bitmap biSizeImage is %u\n",
1638 pInfoBitmap->bmiHeader.biSizeImage);
1639 */
1640 /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
1641 iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
1642 pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
1643
1644 /* Fill out the CURSORICONFILEDIR */
1645 pIconDir = (CURSORICONFILEDIR *)pIconData;
1646 pIconDir->idType = 1;
1647 pIconDir->idCount = 1;
1648 pIconDir->idReserved = 0;
1649
1650 /* Fill out the CURSORICONFILEDIRENTRY */
1651 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1652 pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
1653 pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
1654 pIconEntry->bColorCount =
1655 (pInfoBitmap->bmiHeader.biBitCount < 8)
1656 ? 1 << pInfoBitmap->bmiHeader.biBitCount
1657 : 0;
1658 pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
1659 pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
1660 pIconEntry->dwDIBSize = 0;
1661 pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
1662
1663 /* Fill out the BITMAPINFOHEADER */
1664 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1665 *pIconBitmapHeader = pInfoBitmap->bmiHeader;
1666
1667 /* Find out whether a palette exists for the bitmap */
1668 if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
1669 || (pInfoBitmap->bmiHeader.biBitCount == 24)
1670 || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
1671 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
1672 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256;
1673 } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
1674 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
1675 iNumEntriesPalette = 3;
1676 } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
1677 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
1678 } else {
1679 iNumEntriesPalette = 0;
1680 }
1681
1682 /* Add bitmap size and header size to icon data size. */
1683 iOffsetPalette = iDataSize;
1684 iDataSize += iNumEntriesPalette * sizeof(DWORD);
1685 iOffsetColorData = iDataSize;
1686 iDataSize += pIconBitmapHeader->biSizeImage;
1687 iOffsetMaskData = iDataSize;
1688 iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1689 pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
1690 pIconBitmapHeader->biHeight *= 2;
1691 pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
1692 pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
1693 pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1694 pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
1695
1696 /* Get the actual bitmap data from the icon bitmap */
1697 GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
1698 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
1699 if (iNumEntriesPalette > 0) {
1700 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
1701 iNumEntriesPalette * sizeof(RGBQUAD));
1702 }
1703
1704 /* Reset all values so that GetDIBits call succeeds */
1705 memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
1706 memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1707 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1708 /*
1709 if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
1710 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
1711 pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
1712
1713 printf("ERROR: unable to get bitmap mask (error %u)\n",
1714 GetLastError());
1715
1716 }
1717 */
1718 GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1719 GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
1720
1721 /* Write out everything produced so far to the stream */
1722 *ppBuffer = pIconData; *pLength = iDataSize;
1723 iSuccess = 1;
1724 } else {
1725 /*
1726 printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
1727 GetLastError());
1728 */
1729 }
1730 /*
1731 Remarks (from MSDN entry on GetIconInfo):
1732
1733 GetIconInfo creates bitmaps for the hbmMask and hbmColor
1734 members of ICONINFO. The calling application must manage
1735 these bitmaps and delete them when they are no longer
1736 necessary.
1737 */
1738 if (hDC) ReleaseDC(0, hDC);
1739 DeleteObject(infoIcon.hbmMask);
1740 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
1741 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
1742 } else {
1743 printf("ERROR: Unable to get icon information (error %u)\n",
1744 GetLastError());
1745 }
1746 return iSuccess;
1747 }
1748
1749 static HRESULT WINAPI OLEPictureImpl_Save(
1750 IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
1751 {
1752 HRESULT hResult = E_NOTIMPL;
1753 void * pIconData;
1754 unsigned int iDataSize;
1755 DWORD header[2];
1756 ULONG dummy;
1757 int iSerializeResult = 0;
1758 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1759
1760 TRACE("%p %p %d\n", This, pStm, fClearDirty);
1761
1762 switch (This->desc.picType) {
1763 case PICTYPE_NONE:
1764 header[0] = 0x0000746c;
1765 header[1] = 0;
1766 hResult = IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1767 break;
1768
1769 case PICTYPE_ICON:
1770 if (This->bIsDirty || !This->data) {
1771 if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
1772 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
1773 hResult = E_FAIL;
1774 break;
1775 }
1776 HeapFree(GetProcessHeap(), 0, This->data);
1777 This->data = pIconData;
1778 This->datalen = iDataSize;
1779 }
1780
1781 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1782 header[1] = This->datalen;
1783 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1784 IStream_Write(pStm, This->data, This->datalen, &dummy);
1785 hResult = S_OK;
1786 break;
1787 case PICTYPE_BITMAP:
1788 if (This->bIsDirty || !This->data) {
1789 switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
1790 case BITMAP_FORMAT_BMP:
1791 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
1792 break;
1793 case BITMAP_FORMAT_JPEG:
1794 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
1795 break;
1796 case BITMAP_FORMAT_GIF:
1797 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
1798 break;
1799 case BITMAP_FORMAT_PNG:
1800 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
1801 break;
1802 default:
1803 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
1804 break;
1805 }
1806
1807 if (!iSerializeResult)
1808 {
1809 hResult = E_FAIL;
1810 break;
1811 }
1812
1813 HeapFree(GetProcessHeap(), 0, This->data);
1814 This->data = pIconData;
1815 This->datalen = iDataSize;
1816 }
1817
1818 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
1819 header[1] = This->datalen;
1820 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
1821 IStream_Write(pStm, This->data, This->datalen, &dummy);
1822 hResult = S_OK;
1823 break;
1824 case PICTYPE_METAFILE:
1825 FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
1826 break;
1827 case PICTYPE_ENHMETAFILE:
1828 FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
1829 break;
1830 default:
1831 FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
1832 break;
1833 }
1834 if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
1835 return hResult;
1836 }
1837
1838 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
1839 IPersistStream* iface,ULARGE_INTEGER*pcbSize)
1840 {
1841 OLEPictureImpl *This = impl_from_IPersistStream(iface);
1842 FIXME("(%p,%p),stub!\n",This,pcbSize);
1843 return E_NOTIMPL;
1844 }
1845
1846
1847 /************************************************************************
1848 * IDispatch
1849 */
1850
1851 /************************************************************************
1852 * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
1853 *
1854 * See Windows documentation for more details on IUnknown methods.
1855 */
1856 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
1857 IDispatch* iface,
1858 REFIID riid,
1859 VOID** ppvoid)
1860 {
1861 OLEPictureImpl *This = impl_from_IDispatch(iface);
1862
1863 return IPicture_QueryInterface(&This->IPicture_iface, riid, ppvoid);
1864 }
1865
1866 /************************************************************************
1867 * OLEPictureImpl_IDispatch_AddRef (IUnknown)
1868 *
1869 * See Windows documentation for more details on IUnknown methods.
1870 */
1871 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
1872 IDispatch* iface)
1873 {
1874 OLEPictureImpl *This = impl_from_IDispatch(iface);
1875
1876 return IPicture_AddRef(&This->IPicture_iface);
1877 }
1878
1879 /************************************************************************
1880 * OLEPictureImpl_IDispatch_Release (IUnknown)
1881 *
1882 * See Windows documentation for more details on IUnknown methods.
1883 */
1884 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
1885 IDispatch* iface)
1886 {
1887 OLEPictureImpl *This = impl_from_IDispatch(iface);
1888
1889 return IPicture_Release(&This->IPicture_iface);
1890 }
1891
1892 /************************************************************************
1893 * OLEPictureImpl_GetTypeInfoCount (IDispatch)
1894 *
1895 * See Windows documentation for more details on IDispatch methods.
1896 */
1897 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
1898 IDispatch* iface,
1899 unsigned int* pctinfo)
1900 {
1901 TRACE("(%p)\n", pctinfo);
1902
1903 *pctinfo = 1;
1904
1905 return S_OK;
1906 }
1907
1908 /************************************************************************
1909 * OLEPictureImpl_GetTypeInfo (IDispatch)
1910 *
1911 * See Windows documentation for more details on IDispatch methods.
1912 */
1913 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
1914 IDispatch* iface,
1915 UINT iTInfo,
1916 LCID lcid,
1917 ITypeInfo** ppTInfo)
1918 {
1919 static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1920 ITypeLib *tl;
1921 HRESULT hres;
1922
1923 TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
1924
1925 if (iTInfo != 0)
1926 return E_FAIL;
1927
1928 hres = LoadTypeLib(stdole2tlb, &tl);
1929 if (FAILED(hres))
1930 {
1931 ERR("Could not load stdole2.tlb\n");
1932 return hres;
1933 }
1934
1935 hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
1936 if (FAILED(hres))
1937 ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
1938
1939 return hres;
1940 }
1941
1942 /************************************************************************
1943 * OLEPictureImpl_GetIDsOfNames (IDispatch)
1944 *
1945 * See Windows documentation for more details on IDispatch methods.
1946 */
1947 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
1948 IDispatch* iface,
1949 REFIID riid,
1950 LPOLESTR* rgszNames,
1951 UINT cNames,
1952 LCID lcid,
1953 DISPID* rgDispId)
1954 {
1955 ITypeInfo * pTInfo;
1956 HRESULT hres;
1957
1958 TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
1959 rgszNames, cNames, (int)lcid, rgDispId);
1960
1961 if (cNames == 0)
1962 {
1963 return E_INVALIDARG;
1964 }
1965 else
1966 {
1967 /* retrieve type information */
1968 hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
1969
1970 if (FAILED(hres))
1971 {
1972 ERR("GetTypeInfo failed.\n");
1973 return hres;
1974 }
1975
1976 /* convert names to DISPIDs */
1977 hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1978 ITypeInfo_Release(pTInfo);
1979
1980 return hres;
1981 }
1982 }
1983
1984 /************************************************************************
1985 * OLEPictureImpl_Invoke (IDispatch)
1986 *
1987 * See Windows documentation for more details on IDispatch methods.
1988 */
1989 static HRESULT WINAPI OLEPictureImpl_Invoke(
1990 IDispatch* iface,
1991 DISPID dispIdMember,
1992 REFIID riid,
1993 LCID lcid,
1994 WORD wFlags,
1995 DISPPARAMS* pDispParams,
1996 VARIANT* pVarResult,
1997 EXCEPINFO* pExepInfo,
1998 UINT* puArgErr)
1999 {
2000 OLEPictureImpl *This = impl_from_IDispatch(iface);
2001
2002 /* validate parameters */
2003
2004 if (!IsEqualIID(riid, &IID_NULL))
2005 {
2006 ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2007 return DISP_E_UNKNOWNNAME;
2008 }
2009
2010 if (!pDispParams)
2011 {
2012 ERR("null pDispParams not allowed\n");
2013 return DISP_E_PARAMNOTOPTIONAL;
2014 }
2015
2016 if (wFlags & DISPATCH_PROPERTYGET)
2017 {
2018 if (pDispParams->cArgs != 0)
2019 {
2020 ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2021 return DISP_E_BADPARAMCOUNT;
2022 }
2023 if (!pVarResult)
2024 {
2025 ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2026 return DISP_E_PARAMNOTOPTIONAL;
2027 }
2028 }
2029 else if (wFlags & DISPATCH_PROPERTYPUT)
2030 {
2031 if (pDispParams->cArgs != 1)
2032 {
2033 ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2034 return DISP_E_BADPARAMCOUNT;
2035 }
2036 }
2037
2038 switch (dispIdMember)
2039 {
2040 case DISPID_PICT_HANDLE:
2041 if (wFlags & DISPATCH_PROPERTYGET)
2042 {
2043 TRACE("DISPID_PICT_HANDLE\n");
2044 V_VT(pVarResult) = VT_I4;
2045 return IPicture_get_Handle(&This->IPicture_iface, &V_UINT(pVarResult));
2046 }
2047 break;
2048 case DISPID_PICT_HPAL:
2049 if (wFlags & DISPATCH_PROPERTYGET)
2050 {
2051 TRACE("DISPID_PICT_HPAL\n");
2052 V_VT(pVarResult) = VT_I4;
2053 return IPicture_get_hPal(&This->IPicture_iface, &V_UINT(pVarResult));
2054 }
2055 else if (wFlags & DISPATCH_PROPERTYPUT)
2056 {
2057 VARIANTARG vararg;
2058 HRESULT hr;
2059 TRACE("DISPID_PICT_HPAL\n");
2060
2061 VariantInit(&vararg);
2062 hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2063 if (FAILED(hr))
2064 return hr;
2065
2066 hr = IPicture_set_hPal(&This->IPicture_iface, V_I4(&vararg));
2067
2068 VariantClear(&vararg);
2069 return hr;
2070 }
2071 break;
2072 case DISPID_PICT_TYPE:
2073 if (wFlags & DISPATCH_PROPERTYGET)
2074 {
2075 TRACE("DISPID_PICT_TYPE\n");
2076 V_VT(pVarResult) = VT_I2;
2077 return OLEPictureImpl_get_Type(&This->IPicture_iface, &V_I2(pVarResult));
2078 }
2079 break;
2080 case DISPID_PICT_WIDTH:
2081 if (wFlags & DISPATCH_PROPERTYGET)
2082 {
2083 TRACE("DISPID_PICT_WIDTH\n");
2084 V_VT(pVarResult) = VT_I4;
2085 return IPicture_get_Width(&This->IPicture_iface, &V_I4(pVarResult));
2086 }
2087 break;
2088 case DISPID_PICT_HEIGHT:
2089 if (wFlags & DISPATCH_PROPERTYGET)
2090 {
2091 TRACE("DISPID_PICT_HEIGHT\n");
2092 V_VT(pVarResult) = VT_I4;
2093 return IPicture_get_Height(&This->IPicture_iface, &V_I4(pVarResult));
2094 }
2095 break;
2096 }
2097
2098 ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2099 return DISP_E_MEMBERNOTFOUND;
2100 }
2101
2102
2103 static const IPictureVtbl OLEPictureImpl_VTable =
2104 {
2105 OLEPictureImpl_QueryInterface,
2106 OLEPictureImpl_AddRef,
2107 OLEPictureImpl_Release,
2108 OLEPictureImpl_get_Handle,
2109 OLEPictureImpl_get_hPal,
2110 OLEPictureImpl_get_Type,
2111 OLEPictureImpl_get_Width,
2112 OLEPictureImpl_get_Height,
2113 OLEPictureImpl_Render,
2114 OLEPictureImpl_set_hPal,
2115 OLEPictureImpl_get_CurDC,
2116 OLEPictureImpl_SelectPicture,
2117 OLEPictureImpl_get_KeepOriginalFormat,
2118 OLEPictureImpl_put_KeepOriginalFormat,
2119 OLEPictureImpl_PictureChanged,
2120 OLEPictureImpl_SaveAsFile,
2121 OLEPictureImpl_get_Attributes
2122 };
2123
2124 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2125 {
2126 OLEPictureImpl_IDispatch_QueryInterface,
2127 OLEPictureImpl_IDispatch_AddRef,
2128 OLEPictureImpl_IDispatch_Release,
2129 OLEPictureImpl_GetTypeInfoCount,
2130 OLEPictureImpl_GetTypeInfo,
2131 OLEPictureImpl_GetIDsOfNames,
2132 OLEPictureImpl_Invoke
2133 };
2134
2135 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2136 {
2137 OLEPictureImpl_IPersistStream_QueryInterface,
2138 OLEPictureImpl_IPersistStream_AddRef,
2139 OLEPictureImpl_IPersistStream_Release,
2140 OLEPictureImpl_GetClassID,
2141 OLEPictureImpl_IsDirty,
2142 OLEPictureImpl_Load,
2143 OLEPictureImpl_Save,
2144 OLEPictureImpl_GetSizeMax
2145 };
2146
2147 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2148 {
2149 OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2150 OLEPictureImpl_IConnectionPointContainer_AddRef,
2151 OLEPictureImpl_IConnectionPointContainer_Release,
2152 OLEPictureImpl_EnumConnectionPoints,
2153 OLEPictureImpl_FindConnectionPoint
2154 };
2155
2156 /***********************************************************************
2157 * OleCreatePictureIndirect (OLEAUT32.419)
2158 */
2159 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2160 BOOL Own, void **ppvObj )
2161 {
2162 OLEPictureImpl* newPict;
2163 HRESULT hr;
2164
2165 TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), Own, ppvObj);
2166
2167 *ppvObj = NULL;
2168
2169 newPict = OLEPictureImpl_Construct(lpPictDesc, Own);
2170
2171 if (newPict == NULL)
2172 return E_OUTOFMEMORY;
2173
2174 /*
2175 * Make sure it supports the interface required by the caller.
2176 */
2177 hr = IPicture_QueryInterface(&newPict->IPicture_iface, riid, ppvObj);
2178
2179 /*
2180 * Release the reference obtained in the constructor. If
2181 * the QueryInterface was unsuccessful, it will free the class.
2182 */
2183 IPicture_Release(&newPict->IPicture_iface);
2184
2185 return hr;
2186 }
2187
2188
2189 /***********************************************************************
2190 * OleLoadPicture (OLEAUT32.418)
2191 */
2192 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2193 REFIID riid, LPVOID *ppvObj )
2194 {
2195 LPPERSISTSTREAM ps;
2196 IPicture *newpic;
2197 HRESULT hr;
2198
2199 TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2200 lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2201
2202 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2203 if (hr != S_OK)
2204 return hr;
2205 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2206 if (hr != S_OK) {
2207 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2208 IPicture_Release(newpic);
2209 *ppvObj = NULL;
2210 return hr;
2211 }
2212 hr = IPersistStream_Load(ps,lpstream);
2213 IPersistStream_Release(ps);
2214 if (FAILED(hr))
2215 {
2216 ERR("IPersistStream_Load failed\n");
2217 IPicture_Release(newpic);
2218 *ppvObj = NULL;
2219 return hr;
2220 }
2221 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2222 if (hr != S_OK)
2223 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2224 IPicture_Release(newpic);
2225 return hr;
2226 }
2227
2228 /***********************************************************************
2229 * OleLoadPictureEx (OLEAUT32.401)
2230 */
2231 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2232 REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2233 {
2234 LPPERSISTSTREAM ps;
2235 IPicture *newpic;
2236 HRESULT hr;
2237
2238 FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2239 lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2240
2241 hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2242 if (hr != S_OK)
2243 return hr;
2244 hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2245 if (hr != S_OK) {
2246 ERR("Could not get IPersistStream iface from Ole Picture?\n");
2247 IPicture_Release(newpic);
2248 *ppvObj = NULL;
2249 return hr;
2250 }
2251 hr = IPersistStream_Load(ps,lpstream);
2252 IPersistStream_Release(ps);
2253 if (FAILED(hr))
2254 {
2255 ERR("IPersistStream_Load failed\n");
2256 IPicture_Release(newpic);
2257 *ppvObj = NULL;
2258 return hr;
2259 }
2260 hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2261 if (hr != S_OK)
2262 ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2263 IPicture_Release(newpic);
2264 return hr;
2265 }
2266
2267 /***********************************************************************
2268 * OleLoadPicturePath (OLEAUT32.424)
2269 */
2270 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2271 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2272 LPVOID *ppvRet )
2273 {
2274 static const WCHAR file[] = { 'f','i','l','e',':',0 };
2275 IPicture *ipicture;
2276 HANDLE hFile;
2277 DWORD dwFileSize;
2278 HGLOBAL hGlobal = NULL;
2279 DWORD dwBytesRead = 0;
2280 IStream *stream;
2281 BOOL bRead;
2282 IPersistStream *pStream;
2283 HRESULT hRes;
2284 HRESULT init_res;
2285 WCHAR *file_candidate;
2286 WCHAR path_buf[MAX_PATH];
2287
2288 TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2289 debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2290 debugstr_guid(riid), ppvRet);
2291
2292 if (!szURLorPath || !ppvRet)
2293 return E_INVALIDARG;
2294
2295 *ppvRet = NULL;
2296
2297 /* Convert file URLs to DOS paths. */
2298 if (strncmpW(szURLorPath, file, 5) == 0) {
2299 DWORD size;
2300 hRes = CoInternetParseUrl(szURLorPath, PARSE_PATH_FROM_URL, 0, path_buf,
2301 sizeof(path_buf)/sizeof(WCHAR), &size, 0);
2302 if (FAILED(hRes))
2303 return hRes;
2304
2305 file_candidate = path_buf;
2306 }
2307 else
2308 file_candidate = szURLorPath;
2309
2310 /* Handle candidate DOS paths separately. */
2311 if (file_candidate[1] == ':') {
2312 hFile = CreateFileW(file_candidate, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2313 0, NULL);
2314 if (hFile == INVALID_HANDLE_VALUE)
2315 return INET_E_RESOURCE_NOT_FOUND;
2316
2317 dwFileSize = GetFileSize(hFile, NULL);
2318 if (dwFileSize != INVALID_FILE_SIZE )
2319 {
2320 hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2321 if ( hGlobal)
2322 {
2323 bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2324 if (!bRead)
2325 {
2326 GlobalFree(hGlobal);
2327 hGlobal = 0;
2328 }
2329 }
2330 }
2331 CloseHandle(hFile);
2332
2333 if (!hGlobal)
2334 return INET_E_RESOURCE_NOT_FOUND;
2335
2336 hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2337 if (FAILED(hRes))
2338 {
2339 GlobalFree(hGlobal);
2340 return hRes;
2341 }
2342 } else {
2343 IMoniker *pmnk;
2344 IBindCtx *pbc;
2345
2346 hRes = CreateBindCtx(0, &pbc);
2347 if (SUCCEEDED(hRes))
2348 {
2349 hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2350 if (SUCCEEDED(hRes))
2351 {
2352 hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2353 IMoniker_Release(pmnk);
2354 }
2355 IBindCtx_Release(pbc);
2356 }
2357 if (FAILED(hRes))
2358 return hRes;
2359 }
2360
2361 init_res = CoInitialize(NULL);
2362
2363 hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER,
2364 &IID_IPicture, (LPVOID*)&ipicture);
2365 if (SUCCEEDED(hRes)) {
2366 hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2367
2368 if (SUCCEEDED(hRes)) {
2369 hRes = IPersistStream_Load(pStream, stream);
2370
2371 if (SUCCEEDED(hRes)) {
2372 hRes = IPicture_QueryInterface(ipicture, riid, ppvRet);
2373
2374 if (FAILED(hRes))
2375 ERR("Failed to get interface %s from IPicture.\n", debugstr_guid(riid));
2376 }
2377 IPersistStream_Release(pStream);
2378 }
2379 IPicture_Release(ipicture);
2380 }
2381
2382 IStream_Release(stream);
2383
2384 if (SUCCEEDED(init_res))
2385 CoUninitialize();
2386
2387 return hRes;
2388 }
2389
2390 /*******************************************************************************
2391 * StdPic ClassFactory
2392 */
2393 typedef struct
2394 {
2395 /* IUnknown fields */
2396 IClassFactory IClassFactory_iface;
2397 LONG ref;
2398 } IClassFactoryImpl;
2399
2400 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2401 {
2402 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2403 }
2404
2405 static HRESULT WINAPI
2406 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2407 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2408
2409 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2410 return E_NOINTERFACE;
2411 }
2412
2413 static ULONG WINAPI
2414 SPCF_AddRef(LPCLASSFACTORY iface) {
2415 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2416 return InterlockedIncrement(&This->ref);
2417 }
2418
2419 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2420 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2421 /* static class, won't be freed */
2422 return InterlockedDecrement(&This->ref);
2423 }
2424
2425 static HRESULT WINAPI SPCF_CreateInstance(
2426 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2427 ) {
2428 /* Creates an uninitialized picture */
2429 return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2430
2431 }
2432
2433 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2434 IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2435 FIXME("(%p)->(%d),stub!\n",This,dolock);
2436 return S_OK;
2437 }
2438
2439 static const IClassFactoryVtbl SPCF_Vtbl = {
2440 SPCF_QueryInterface,
2441 SPCF_AddRef,
2442 SPCF_Release,
2443 SPCF_CreateInstance,
2444 SPCF_LockServer
2445 };
2446 static IClassFactoryImpl STDPIC_CF = {{&SPCF_Vtbl}, 1 };
2447
2448 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = &STDPIC_CF; }