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