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