PATCH: OleLoadPicture

Marcus Meissner marcus at jet.franken.de
Sat Aug 4 11:14:48 CDT 2001


Hi,

Well, that MS VB 5 app uses several features of IPicture, which were not
implemented.

The app loads JPEGs, BITMAPs and ICONs from the IStream -> verified.
It also uses some notifications -> verified.
I also cross checked everything against MSDN.

Please rerun autoconf and autoheader -l include.

I hope that I did not forget any include files, my tree is a bit in a mess
with lots of other unfinished stuff ;)

Note that this now requires libjpeg. I don't know a good way to convert
jpegs to bitmaps without forking wine, which is even worse.

Ciao, Marcus

Changelog
    Implemented OleLoadPicture.
    Added support for loading JPEG, Bitmap and Icons from persistant streams.
    Implemented JPEG support using libjpeg, added necessary configure.in 
    options. Added IConnectionPoint style notifications to the IPicture iface.
    Implemented several of the stubs already there, added some more.

Index: configure.in
===================================================================
RCS file: /home/wine/wine/configure.in,v
retrieving revision 1.218
diff -u -r1.218 configure.in
--- configure.in	2001/07/30 20:21:34	1.218
+++ configure.in	2001/08/04 15:49:32
@@ -122,6 +122,16 @@
  	LIBEXT="a"
     )
 
+JPEGLIB=""
+AC_SUBST(JPEGLIB)
+AC_CHECK_HEADERS(jpeglib.h,
+    AC_CHECK_LIB(jpeg,jpeg_start_decompress,
+    	AC_DEFINE(HAVE_LIBJPEG,1,[Define if you have libjpeg including devel headers])
+	JPEGLIB="-ljpeg"
+    )
+)
+
+
 AC_SUBST(XLIB)
 AC_SUBST(X_DLLS)
 X_DLLS=""
Index: include/olectl.h
===================================================================
RCS file: /home/wine/wine/include/olectl.h,v
retrieving revision 1.12
diff -u -r1.12 olectl.h
--- include/olectl.h	2000/10/19 20:32:18	1.12
+++ include/olectl.h	2001/08/04 15:49:37
@@ -227,6 +227,14 @@
 #define DISPID_FONT_STRIKE 6
 #define DISPID_FONT_WEIGHT 7
 #define DISPID_FONT_CHARSET 8
+
+/* IPicture */
+#define	DISPID_PICT_HANDLE	0
+#define	DISPID_PICT_HPAL	2
+#define	DISPID_PICT_TYPE	3
+#define	DISPID_PICT_WIDTH	4
+#define	DISPID_PICT_HEIGHT	5
+#define	DISPID_PICT_RENDER	6
  
 /* Reflected Window Message IDs */
 #define OCM__BASE           (WM_USER+0x1c00)
Index: include/wine/obj_picture.h
===================================================================
RCS file: /home/wine/wine/include/wine/obj_picture.h,v
retrieving revision 1.7
diff -u -r1.7 obj_picture.h
--- include/wine/obj_picture.h	2000/09/26 00:01:01	1.7
+++ include/wine/obj_picture.h	2001/08/04 15:50:01
@@ -20,7 +20,10 @@
 typedef LONG OLE_XSIZE_HIMETRIC;
 typedef LONG OLE_YSIZE_HIMETRIC;
 
-
+typedef enum tagPicture { /* bitmasks */
+    PICTURE_SCALABLE	= 0x1,
+    PICTURE_TRANSPARENT	= 0x2
+} PICTUREATTRIBUTES;
 
 /*****************************************************************************
  * Predeclare the interfaces
Index: dlls/oleaut32/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/Makefile.in,v
retrieving revision 1.23
diff -u -r1.23 Makefile.in
--- dlls/oleaut32/Makefile.in	2001/03/19 19:17:27	1.23
+++ dlls/oleaut32/Makefile.in	2001/08/04 15:50:01
@@ -4,7 +4,7 @@
 VPATH     = @srcdir@
 MODULE    = oleaut32
 ALTNAMES  = ole2disp typelib
-EXTRALIBS = $(LIBUUID)
+EXTRALIBS = $(LIBUUID) @JPEGLIB@
 
 LDDLLFLAGS = @LDDLLFLAGS@
 SYMBOLFILE = $(MODULE).tmp.o
Index: olepicture.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/olepicture.c,v
retrieving revision 1.7
diff -u -r1.7 olepicture.c
--- olepicture.c	2001/06/19 18:20:49	1.7
+++ olepicture.c	2001/08/04 16:04:46
@@ -4,13 +4,13 @@
  * Implementation of OLE IPicture and related interfaces
  *
  * Copyright 2000 Huw D M Davies for CodeWeavers.
+ * Copyright 2001 Marcus Meissner
  *
  *
  * BUGS
  *
- * Only implements PICTYPE_BITMAP.
- * Most methods are just stubs.
- * Doesn't even expose IPersistStream, IConnectionPointContainer.
+ * Support PICTYPE_BITMAP and PICTYPE_ICON, altough only bitmaps very well..
+ * Lots of methods are just stubs.
  *
  *
  * NOTES (or things that msdn doesn't tell you)
@@ -22,6 +22,8 @@
  *
  */
 
+#include <unistd.h>
+#include <stdio.h>
 #include <string.h>
 #include "winerror.h"
 #include "winbase.h"
@@ -29,9 +31,21 @@
 #include "winuser.h"
 #include "ole2.h"
 #include "olectl.h"
+#include "oleauto.h"
 #include "wine/obj_picture.h"
+#include "wine/obj_connection.h"
+#include "connpt.h"
 #include "debugtools.h"
 
+#include "wine/wingdi16.h"
+#include "cursoricon.h"
+
+#ifdef HAVE_LIBJPEG
+/* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
+#define XMD_H 
+#include <jpeglib.h>
+#endif
+
 DEFAULT_DEBUG_CHANNEL(ole);
 
 /*************************************************************************
@@ -47,6 +61,7 @@
     ICOM_VTABLE(IPicture)       *lpvtbl1;
     ICOM_VTABLE(IDispatch)      *lpvtbl2;
     ICOM_VTABLE(IPersistStream) *lpvtbl3;
+    ICOM_VTABLE(IConnectionPointContainer) *lpvtbl4;
 
   /* Object referenece count */
     DWORD ref;
@@ -65,6 +80,10 @@
     OLE_XSIZE_HIMETRIC himetricWidth;
     OLE_YSIZE_HIMETRIC himetricHeight;
 
+    IConnectionPoint *pCP;
+
+    BOOL keepOrigFormat;
+    HDC	hDCCur;
 } OLEPictureImpl;
 
 /*
@@ -72,9 +91,10 @@
  */
 #define ICOM_THIS_From_IDispatch(impl, name) \
     impl *This = (impl*)(((char*)name)-sizeof(void*));
-
 #define ICOM_THIS_From_IPersistStream(impl, name) \
     impl *This = (impl*)(((char*)name)-2*sizeof(void*));
+#define ICOM_THIS_From_IConnectionPointContainer(impl, name) \
+    impl *This = (impl*)(((char*)name)-3*sizeof(void*));
 
 /*
  * Predeclare VTables.  They get initialized at the end.
@@ -82,11 +102,33 @@
 static ICOM_VTABLE(IPicture) OLEPictureImpl_VTable;
 static ICOM_VTABLE(IDispatch) OLEPictureImpl_IDispatch_VTable;
 static ICOM_VTABLE(IPersistStream) OLEPictureImpl_IPersistStream_VTable;
+static ICOM_VTABLE(IConnectionPointContainer) OLEPictureImpl_IConnectionPointContainer_VTable;
 
 /***********************************************************************
  * Implementation of the OLEPictureImpl class.
  */
 
+static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
+  BITMAP bm;
+  HDC hdcRef;
+
+  TRACE("bitmap handle %08x\n", This->desc.u.bmp.hbitmap);
+  if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
+    ERR("GetObject fails\n");
+    return;
+  }
+  This->origWidth = bm.bmWidth;
+  This->origHeight = bm.bmHeight;
+  /* The width and height are stored in HIMETRIC units (0.01 mm),
+     so we take our pixel width divide by pixels per inch and
+     multiply by 25.4 * 100 */
+  /* Should we use GetBitmapDimension if available? */
+  hdcRef = CreateCompatibleDC(0);
+  This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
+  This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
+  DeleteDC(hdcRef);
+}
+
 /************************************************************************
  * OLEPictureImpl_Construct
  *
@@ -99,7 +141,9 @@
 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
 {
   OLEPictureImpl* newObject = 0;
-  TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
+
+  if (pictDesc)
+      TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
 
   /*
    * Allocate space for the object.
@@ -115,63 +159,49 @@
   newObject->lpvtbl1 = &OLEPictureImpl_VTable;
   newObject->lpvtbl2 = &OLEPictureImpl_IDispatch_VTable;
   newObject->lpvtbl3 = &OLEPictureImpl_IPersistStream_VTable;
-  
+  newObject->lpvtbl4 = &OLEPictureImpl_IConnectionPointContainer_VTable;
+
+  CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
+
   /*
    * Start with one reference count. The caller of this function 
    * must release the interface pointer when it is done.
    */
-  newObject->ref = 1;
+  newObject->ref	= 1;
+  newObject->hDCCur	= 0;
 
-  newObject->fOwn = fOwn;
+  newObject->fOwn	= fOwn;
 
-  if(pictDesc->cbSizeofstruct != sizeof(PICTDESC)) {
-      FIXME("struct size = %d\n", pictDesc->cbSizeofstruct);
-  }
-  memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC));
+  /* dunno about original value */
+  newObject->keepOrigFormat = TRUE;
 
-  switch(pictDesc->picType) {
-  case PICTYPE_BITMAP:
-    {
-      BITMAP bm;
-      HDC hdcRef;
-
-      TRACE("bitmap handle %08x\n", pictDesc->u.bmp.hbitmap);
-      if(GetObjectA(pictDesc->u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
-	ERR("GetObject fails\n");
-	break;
+  if (pictDesc) {
+      if(pictDesc->cbSizeofstruct != sizeof(PICTDESC)) {
+	  FIXME("struct size = %d\n", pictDesc->cbSizeofstruct);
       }
+      memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC));
 
-      newObject->origWidth = bm.bmWidth;
-      newObject->origHeight = bm.bmHeight;
 
-      /* The width and height are stored in HIMETRIC units (0.01 mm),
-	 so we take our pixel width divide by pixels per inch and
-	 multiply by 25.4 * 100 */
-
-      /* Should we use GetBitmapDimension if available? */
-
-      hdcRef = CreateCompatibleDC(0);
-
-      newObject->himetricWidth = (bm.bmWidth * 2540) /
-	GetDeviceCaps(hdcRef, LOGPIXELSX);
-      newObject->himetricHeight = (bm.bmHeight * 2540) / 
-	GetDeviceCaps(hdcRef, LOGPIXELSY);
-      DeleteDC(hdcRef);
-    }
-    break;
+      switch(pictDesc->picType) {
+      case PICTYPE_BITMAP:
+	OLEPictureImpl_SetBitmap(newObject);
+	break;
 
-  case PICTYPE_METAFILE:
-    TRACE("metafile handle %08x\n", pictDesc->u.wmf.hmeta);
-    newObject->himetricWidth = pictDesc->u.wmf.xExt;
-    newObject->himetricHeight = pictDesc->u.wmf.yExt;
-    break;
+      case PICTYPE_METAFILE:
+	TRACE("metafile handle %08x\n", pictDesc->u.wmf.hmeta);
+	newObject->himetricWidth = pictDesc->u.wmf.xExt;
+	newObject->himetricHeight = pictDesc->u.wmf.yExt;
+	break;
 
-  case PICTYPE_ICON:
-  case PICTYPE_ENHMETAFILE:
-  default:
-    FIXME("Unsupported type %d\n", pictDesc->picType);
-    newObject->himetricWidth = newObject->himetricHeight = 0;
-    break;
+      case PICTYPE_ICON:
+      case PICTYPE_ENHMETAFILE:
+      default:
+	FIXME("Unsupported type %d\n", pictDesc->picType);
+	newObject->himetricWidth = newObject->himetricHeight = 0;
+	break;
+      }
+  } else {
+      newObject->desc.picType = PICTYPE_UNINITIALIZED;
   }
     
   TRACE("returning %p\n", newObject);
@@ -255,11 +285,14 @@
   {
     *ppvObject = (IDispatch*)&(This->lpvtbl2);
   }
-  /*  else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0) 
+  else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0) 
   {
   *ppvObject = (IPersistStream*)&(This->lpvtbl3);
-  }*/
-  
+  }
+  else if (memcmp(&IID_IConnectionPointContainer, riid, sizeof(IID_IConnectionPointContainer)) == 0) 
+  {
+  *ppvObject = (IConnectionPointContainer*)&(This->lpvtbl4);
+  }
   /*
    * Check that we obtained an interface.
    */
@@ -277,7 +310,31 @@
 
   return S_OK;;
 }
-        
+/***********************************************************************
+ *    OLEPicture_SendNotify (internal)
+ *
+ * Sends notification messages of changed properties to any interested
+ * connections.
+ */
+static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
+{
+  IEnumConnections *pEnum;
+  CONNECTDATA CD;
+
+  if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
+      return;
+  while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
+    IPropertyNotifySink *sink;
+
+    IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
+    IPropertyNotifySink_OnChanged(sink, dispID);
+    IPropertyNotifySink_Release(sink);
+    IUnknown_Release(CD.pUnk);
+  }
+  IEnumConnections_Release(pEnum);
+  return;
+}
+
 /************************************************************************
  * OLEPictureImpl_AddRef (IUnknown)
  *
@@ -417,6 +474,12 @@
     TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
 	  prcWBounds->right, prcWBounds->bottom);
 
+  /*
+   * While the documentation suggests this to be here (or after rendering?)
+   * it does cause an endless recursion in my sample app. -MM 20010804
+  OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
+   */
+
   switch(This->desc.picType) {
   case PICTYPE_BITMAP:
     {
@@ -441,15 +504,17 @@
       DeleteDC(hdcBmp);
     }
     break;
+  case PICTYPE_ICON:
+    FIXME("Not quite correct implementation of rendering icons...\n");
+    DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
+    break;
 
   case PICTYPE_METAFILE:
-  case PICTYPE_ICON:
   case PICTYPE_ENHMETAFILE:
   default:
     FIXME("type %d not implemented\n", This->desc.picType);
     return E_NOTIMPL;
   }
-
   return S_OK;
 }
 
@@ -461,6 +526,7 @@
 {
   ICOM_THIS(OLEPictureImpl, iface);
   FIXME("(%p)->(%08x): stub\n", This, hpal);
+  OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
   return E_NOTIMPL;
 }
 
@@ -471,8 +537,9 @@
 					       HDC *phdc)
 {
   ICOM_THIS(OLEPictureImpl, iface);
-  FIXME("(%p)->(%p): stub\n", This, phdc);
-  return E_NOTIMPL;
+  TRACE("(%p), returning %x\n", This, This->hDCCur);
+  if (phdc) *phdc = This->hDCCur;
+  return S_OK;
 }
 
 /************************************************************************
@@ -484,8 +551,20 @@
 						   OLE_HANDLE *phbmpOut)
 {
   ICOM_THIS(OLEPictureImpl, iface);
-  FIXME("(%p)->(%08x, %p, %p): stub\n", This, hdcIn, phdcOut, phbmpOut);
-  return E_NOTIMPL;
+  TRACE("(%p)->(%08x, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
+  if (This->desc.picType == PICTYPE_BITMAP) {
+      SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
+
+      if (phdcOut)
+	  *phdcOut = This->hDCCur;
+      This->hDCCur = hdcIn;
+      if (phbmpOut)
+	  *phbmpOut = This->desc.u.bmp.hbitmap;
+      return S_OK;
+  } else {
+      FIXME("Don't know how to select picture type %d\n",This->desc.picType);
+      return E_FAIL;
+  }
 }
 
 /************************************************************************
@@ -495,8 +574,11 @@
 							    BOOL *pfKeep)
 {
   ICOM_THIS(OLEPictureImpl, iface);
-  FIXME("(%p)->(%p): stub\n", This, pfKeep);
-  return E_NOTIMPL;
+  TRACE("(%p)->(%p)\n", This, pfKeep);
+  if (!pfKeep)
+      return E_POINTER;
+  *pfKeep = This->keepOrigFormat;
+  return S_OK;
 }
 
 /************************************************************************
@@ -506,8 +588,10 @@
 							    BOOL keep)
 {
   ICOM_THIS(OLEPictureImpl, iface);
-  FIXME("(%p)->(%d): stub\n", This, keep);
-  return E_NOTIMPL;
+  TRACE("(%p)->(%d)\n", This, keep);
+  This->keepOrigFormat = keep;
+  /* FIXME: what DISPID notification here? */
+  return S_OK;
 }
 
 /************************************************************************
@@ -516,8 +600,9 @@
 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
 {
   ICOM_THIS(OLEPictureImpl, iface);
-  FIXME("(%p)->(): stub\n", This);
-  return E_NOTIMPL;
+  TRACE("(%p)->()\n", This);
+  OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
+  return S_OK;
 }
 
 /************************************************************************
@@ -540,11 +625,382 @@
 						    DWORD *pdwAttr)
 {
   ICOM_THIS(OLEPictureImpl, iface);
-  FIXME("(%p)->(%p): stub\n", This, pdwAttr);
+  TRACE("(%p)->(%p).\n", This, pdwAttr);
+  *pdwAttr = 0;
+  switch (This->desc.picType) {
+  case PICTYPE_BITMAP: 	break;	/* not 'truely' scalable, see MSDN. */
+  case PICTYPE_ICON: *pdwAttr     = PICTURE_TRANSPARENT;break;
+  case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
+  default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
+  }
+  return S_OK;
+}
+
+
+/************************************************************************
+ *    IConnectionPointContainer
+ */
+
+static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
+  IConnectionPointContainer* iface,
+  REFIID riid,
+  VOID** ppvoid
+) {
+  ICOM_THIS_From_IConnectionPointContainer(IPicture,iface);
+
+  return IPicture_QueryInterface(This,riid,ppvoid);
+}
+
+static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
+  IConnectionPointContainer* iface)
+{
+  ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
+
+  return IPicture_AddRef(This);
+}
+
+static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
+  IConnectionPointContainer* iface)
+{
+  ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
+
+  return IPicture_Release(This);
+}
+
+static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
+  IConnectionPointContainer* iface,
+  IEnumConnectionPoints** ppEnum
+) {
+  ICOM_THIS_From_IConnectionPointContainer(IPicture, iface);
+
+  FIXME("(%p,%p), stub!\n",This,ppEnum);
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
+  IConnectionPointContainer* iface,
+  REFIID riid,
+  IConnectionPoint **ppCP
+) {
+  ICOM_THIS_From_IConnectionPointContainer(OLEPictureImpl, iface);
+  TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
+  if (!ppCP) 
+      return E_POINTER;
+  *ppCP = NULL;
+  if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
+      return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
+  FIXME("tried to find connection point on %s?\n",debugstr_guid(riid));
+  return 0x80040200;
+}
+/************************************************************************
+ *    IPersistStream
+ */
+/************************************************************************
+ * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
+  IPersistStream* iface,
+  REFIID     riid,
+  VOID**     ppvoid)
+{
+  ICOM_THIS_From_IPersistStream(IPicture, iface);
+
+  return IPicture_QueryInterface(This, riid, ppvoid);
+}
+
+/************************************************************************
+ * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
+  IPersistStream* iface)
+{
+  ICOM_THIS_From_IPersistStream(IPicture, iface);
+
+  return IPicture_AddRef(This);
+}
+
+/************************************************************************
+ * OLEPictureImpl_IPersistStream_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
+  IPersistStream* iface)
+{
+  ICOM_THIS_From_IPersistStream(IPicture, iface);
+
+  return IPicture_Release(This);
+}
+
+/************************************************************************
+ * OLEPictureImpl_IPersistStream_GetClassID
+ */
+static HRESULT WINAPI OLEPictureImpl_GetClassID(
+  IPersistStream* iface,CLSID* pClassID)
+{
+  ICOM_THIS_From_IPersistStream(IPicture, iface);
+  FIXME("(%p),stub!\n",This);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEPictureImpl_IPersistStream_IsDirty
+ */
+static HRESULT WINAPI OLEPictureImpl_IsDirty(
+  IPersistStream* iface)
+{
+  ICOM_THIS_From_IPersistStream(IPicture, iface);
+  FIXME("(%p),stub!\n",This);
   return E_NOTIMPL;
 }
 
+#ifdef HAVE_LIBJPEG
+/* for the jpeg decompressor source manager. */
+static void _jpeg_init_source(j_decompress_ptr cinfo) { }
+
+static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
+    ERR("(), should not get here.\n");
+    return FALSE;
+}
+
+static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
+    ERR("(%ld), should not get here.\n",num_bytes);
+}
+
+static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
+    ERR("(desired=%d), should not get here.\n",desired);
+    return FALSE;
+}
+static void _jpeg_term_source(j_decompress_ptr cinfo) { }
+#endif /* HAVE_LIBJPEG */
+
+/************************************************************************
+ * OLEPictureImpl_IPersistStream_Load (IUnknown)
+ *
+ * Loads the binary data from the IStream. Starts at current position.
+ * There appears to be an 2 DWORD header:
+ * 	DWORD magic;
+ * 	DWORD len;
+ *
+ * Currently implemented: BITMAP, ICON, JPEG.
+ */
+static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
+  HRESULT	hr = E_FAIL;
+  ULONG		xread;
+  BYTE 		*xbuf;
+  DWORD		header[2];
+  WORD		magic;
+  ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface);
+
+  TRACE("(%p,%p)\n",This,pStm);
+
+  hr=IStream_Read(pStm,header,8,&xread);
+  if (hr || xread!=8) {
+      FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
+      return hr;
+  }
+  xread = 0;
+  xbuf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]);
+  while (xread < header[1]) {
+    ULONG nread; 
+    hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread);
+    xread+=nread;
+    if (hr || !nread)
+      break;
+  }
+  if (xread != header[1])
+    FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]);
+
+  magic = xbuf[0] + (xbuf[1]<<8);
+  switch (magic) {
+  case 0xd8ff: { /* JPEG */
+#ifdef HAVE_LIBJPEG
+    struct jpeg_decompress_struct	jd;
+    struct jpeg_error_mgr		jerr;
+    int					ret;
+    JDIMENSION				x;
+    JSAMPROW				samprow;
+    BITMAPINFOHEADER			bmi;
+    LPBYTE				bits;
+    HDC					hdcref;
+    struct jpeg_source_mgr		xjsm;
+
+    /* This is basically so we can use in-memory data for jpeg decompression.
+     * We need to have all the functions.
+     */
+    xjsm.next_input_byte	= xbuf;
+    xjsm.bytes_in_buffer	= xread;
+    xjsm.init_source		= _jpeg_init_source;
+    xjsm.fill_input_buffer	= _jpeg_fill_input_buffer;
+    xjsm.skip_input_data	= _jpeg_skip_input_data;
+    xjsm.resync_to_restart	= _jpeg_resync_to_restart;
+    xjsm.term_source		= _jpeg_term_source;
+
+    jd.err = jpeg_std_error(&jerr);
+    jpeg_create_decompress(&jd);
+    jd.src = &xjsm;
+    ret=jpeg_read_header(&jd,TRUE);
+    jpeg_start_decompress(&jd);
+    if (ret != JPEG_HEADER_OK) {
+	ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
+	HeapFree(GetProcessHeap(),0,xbuf);
+	return E_FAIL;
+    }
+    bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(jd.output_height+1)*jd.output_width*jd.output_components);
+    samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
+    while ( jd.output_scanline<jd.output_height ) {
+      x = jpeg_read_scanlines(&jd,&samprow,1);
+      if (x != 1) {
+	FIXME("failed to read current scanline?\n");
+	break;
+      }
+      memcpy( bits+jd.output_scanline*jd.output_width*jd.output_components,
+	      samprow,
+      	      jd.output_width*jd.output_components
+      );
+    }
+    bmi.biSize		= sizeof(bmi);
+    bmi.biWidth		=  jd.output_width;
+    bmi.biHeight	= -jd.output_height;
+    bmi.biPlanes	= 1;
+    bmi.biBitCount	= jd.output_components<<3;
+    bmi.biCompression	= BI_RGB;
+    bmi.biSizeImage	= jd.output_height*jd.output_width*jd.output_components;
+    bmi.biXPelsPerMeter	= 0;
+    bmi.biYPelsPerMeter	= 0;
+    bmi.biClrUsed	= 0;
+    bmi.biClrImportant	= 0;
+
+    HeapFree(GetProcessHeap(),0,samprow);
+    jpeg_finish_decompress(&jd);
+    jpeg_destroy_decompress(&jd);
+    hdcref = CreateCompatibleDC(0);
+    This->desc.u.bmp.hbitmap=CreateDIBitmap(
+	    hdcref,
+	    &bmi,
+	    CBM_INIT,
+	    bits,
+	    (BITMAPINFO*)&bmi,
+	    DIB_RGB_COLORS
+    );
+    DeleteDC(hdcref);
+    This->desc.picType = PICTYPE_BITMAP;
+    OLEPictureImpl_SetBitmap(This);
+    hr = S_OK;
+    HeapFree(GetProcessHeap(),0,bits);
+#else
+    ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
+    hr = E_FAIL;
+#endif
+    break;
+  }
+  case 0x4d42: { /* Bitmap */
+    BITMAPFILEHEADER	*bfh = (BITMAPFILEHEADER*)xbuf;
+    BITMAPINFO		*bi = (BITMAPINFO*)(bfh+1);
+    HDC			hdcref;
+
+    /* Does not matter whether this is a coreheader or not, we only use
+     * components which are in both
+     */
+    hdcref = CreateCompatibleDC(0);
+    This->desc.u.bmp.hbitmap = CreateDIBitmap(
+	hdcref,
+	&(bi->bmiHeader),
+	CBM_INIT,
+	xbuf+bfh->bfOffBits,
+	bi,
+	(bi->bmiHeader.biBitCount<=8)?DIB_PAL_COLORS:DIB_RGB_COLORS
+    );
+    DeleteDC(hdcref);
+    This->desc.picType = PICTYPE_BITMAP;
+    OLEPictureImpl_SetBitmap(This);
+    hr = S_OK;
+    break;
+  }
+  case 0x0000: { /* ICON , first word is dwReserved */
+    HICON hicon;
+    CURSORICONFILEDIR	*cifd = (CURSORICONFILEDIR*)xbuf;
+    int	i;
+
+    /*
+    FIXME("icon.idReserved=%d\n",cifd->idReserved);
+    FIXME("icon.idType=%d\n",cifd->idType);
+    FIXME("icon.idCount=%d\n",cifd->idCount);
+
+    for (i=0;i<cifd->idCount;i++) {
+	FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
+	FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
+	FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
+	FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
+	FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
+	FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
+	FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
+	FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
+    }
+    */
+    i=0;
+    /* If we have more than one icon, try to find the best.
+     * this currently means '32 pixel wide'.
+     */
+    if (cifd->idCount!=1) {
+	for (i=0;i<cifd->idCount;i++) {
+	    if (cifd->idEntries[i].bWidth == 32)
+		break;
+	}
+	if (i==cifd->idCount) i=0;
+    }
+
+    hicon = CreateIconFromResourceEx(
+		xbuf+cifd->idEntries[i].dwDIBOffset,
+		cifd->idEntries[i].dwDIBSize,
+		TRUE, /* is icon */
+		0x00030000,
+		cifd->idEntries[i].bWidth,
+		cifd->idEntries[i].bHeight,
+		0
+    );
+    if (!hicon) {
+	FIXME("CreateIcon failed.\n");
+	hr = E_FAIL;
+    } else {
+	This->desc.picType = PICTYPE_ICON;
+	This->desc.u.icon.hicon = hicon;
+	hr = S_OK;
+    }
+    break;
+  }
+  default:
+    FIXME("Unknown magic %04x\n",magic);
+    hr=E_FAIL;
+    break;
+  }
+  HeapFree(GetProcessHeap(),0,xbuf);
+
+  /* FIXME: this notify is not really documented */
+  if (hr==S_OK)
+      OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
+  return hr;
+}
+
+static HRESULT WINAPI OLEPictureImpl_Save(
+  IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
+{
+  ICOM_THIS_From_IPersistStream(IPicture, iface);
+  FIXME("(%p,%p,%d),stub!\n",This,pStm,fClearDirty);
+  return E_NOTIMPL;
+}
 
+static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
+  IPersistStream* iface,ULARGE_INTEGER*pcbSize)
+{
+  ICOM_THIS_From_IPersistStream(IPicture, iface);
+  FIXME("(%p,%p),stub!\n",This,pcbSize);
+  return E_NOTIMPL;
+}
 
 /************************************************************************
  *    IDispatch
@@ -654,9 +1110,12 @@
   EXCEPINFO*  pExepInfo,
   UINT*     puArgErr)
 {
-  FIXME("():Stub\n");
+  FIXME("(dispid: %ld):Stub\n",dispIdMember);
 
-  return E_NOTIMPL;
+  VariantInit(pVarResult);
+  pVarResult->vt = VT_BOOL;
+  pVarResult->u.boolVal = FALSE;
+  return S_OK;
 }
 
 
@@ -694,6 +1153,29 @@
   OLEPictureImpl_Invoke
 };
 
+static ICOM_VTABLE(IPersistStream) OLEPictureImpl_IPersistStream_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  OLEPictureImpl_IPersistStream_QueryInterface,
+  OLEPictureImpl_IPersistStream_AddRef,
+  OLEPictureImpl_IPersistStream_Release,
+  OLEPictureImpl_GetClassID,
+  OLEPictureImpl_IsDirty,
+  OLEPictureImpl_Load,
+  OLEPictureImpl_Save,
+  OLEPictureImpl_GetSizeMax
+};
+
+static ICOM_VTABLE(IConnectionPointContainer) OLEPictureImpl_IConnectionPointContainer_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  OLEPictureImpl_IConnectionPointContainer_QueryInterface,
+  OLEPictureImpl_IConnectionPointContainer_AddRef,
+  OLEPictureImpl_IConnectionPointContainer_Release,
+  OLEPictureImpl_EnumConnectionPoints,
+  OLEPictureImpl_FindConnectionPoint
+};
+
 /***********************************************************************
  * OleCreatePictureIndirect (OLEAUT32.419)
  */
@@ -740,11 +1222,32 @@
  * OleLoadPicture (OLEAUT32.418)
  */
 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
-		            REFIID reed, LPVOID *ppvObj )
+		            REFIID riid, LPVOID *ppvObj )
 {
-  FIXME("(%p,%ld,%d,%p,%p), not implemented\n",
-	lpstream, lSize, fRunmode, reed, ppvObj);
-  return S_OK;
+  LPPERSISTSTREAM ps;
+  IPicture	*newpic;
+  HRESULT hr;
+
+  TRACE("(%p,%ld,%d,%s,%p), partially implemented.\n",
+	lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
+
+  hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
+  if (hr)
+    return hr;
+  hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
+  if (hr) {
+      FIXME("Could not get IPersistStream iface from Ole Picture?\n");
+      IPicture_Release(newpic);
+      *ppvObj = NULL;
+      return hr;
+  }
+  IPersistStream_Load(ps,lpstream);
+  IPersistStream_Release(ps);
+  hr = IPicture_QueryInterface(newpic,riid,ppvObj);
+  if (hr)
+      FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
+  IPicture_Release(newpic);
+  return hr;
 }
 
 /***********************************************************************




More information about the wine-patches mailing list