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