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