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