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