Index: trunk/src/ole32/new/antimoniker.cpp
===================================================================
--- trunk/src/ole32/new/antimoniker.cpp	(revision 3456)
+++ trunk/src/ole32/new/antimoniker.cpp	(revision 3456)
@@ -0,0 +1,647 @@
+/* $Id: antimoniker.cpp,v 1.1 2000-04-27 22:18:14 davidr Exp $ */
+/* 
+ * AntiMonikers functions.
+ * 
+ * 20/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *   Copyright 1999  Noomen Hamza
+ */
+
+#include "ole32.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+/* AntiMoniker data structure */
+typedef struct AntiMonikerImpl
+{
+
+    ICOM_VTABLE(IMoniker)*  lpvtbl1;  /* VTable relative to the IMoniker interface.*/
+
+    /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether 
+     * two monikers are equal. That's whay IROTData interface is implemented by monikers.
+     */
+    ICOM_VTABLE(IROTData)*  lpvtbl2;  /* VTable relative to the IROTData interface.*/
+
+    ULONG ref; /* reference counter for this object */
+
+} AntiMonikerImpl;
+
+/********************************************************************************/
+/* AntiMoniker prototype functions :                                            */
+
+/* IUnknown prototype functions */
+static HRESULT WINAPI AntiMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject);
+static ULONG   WINAPI AntiMonikerImpl_AddRef(IMoniker* iface);
+static ULONG   WINAPI AntiMonikerImpl_Release(IMoniker* iface);
+
+/* IPersist prototype functions */
+static HRESULT WINAPI AntiMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID);
+
+/* IPersistStream prototype functions */
+static HRESULT WINAPI AntiMonikerImpl_IsDirty(IMoniker* iface);
+static HRESULT WINAPI AntiMonikerImpl_Load(IMoniker* iface, IStream* pStm);
+static HRESULT WINAPI AntiMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty);
+static HRESULT WINAPI AntiMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize);
+
+/* IMoniker prototype functions */
+static HRESULT WINAPI AntiMonikerImpl_BindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult);
+static HRESULT WINAPI AntiMonikerImpl_BindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult);
+static HRESULT WINAPI AntiMonikerImpl_Reduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced);
+static HRESULT WINAPI AntiMonikerImpl_ComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite);
+static HRESULT WINAPI AntiMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker);
+static HRESULT WINAPI AntiMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker);
+static HRESULT WINAPI AntiMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash);
+static HRESULT WINAPI AntiMonikerImpl_IsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning);
+static HRESULT WINAPI AntiMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pAntiTime);
+static HRESULT WINAPI AntiMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk);
+static HRESULT WINAPI AntiMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix);
+static HRESULT WINAPI AntiMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath);
+static HRESULT WINAPI AntiMonikerImpl_GetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName);
+static HRESULT WINAPI AntiMonikerImpl_ParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut);
+static HRESULT WINAPI AntiMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys);
+
+/********************************************************************************/
+/* IROTData prototype functions                                                 */
+
+/* IUnknown prototype functions */
+static HRESULT WINAPI AntiMonikerROTDataImpl_QueryInterface(IROTData* iface,REFIID riid,VOID** ppvObject);
+static ULONG   WINAPI AntiMonikerROTDataImpl_AddRef(IROTData* iface);
+static ULONG   WINAPI AntiMonikerROTDataImpl_Release(IROTData* iface);
+
+/* IROTData prototype function */
+static HRESULT WINAPI AntiMonikerROTDataImpl_GetComparaisonData(IROTData* iface,BYTE* pbData,ULONG cbMax,ULONG* pcbData);
+
+/* Local function used by AntiMoniker implementation */
+HRESULT WINAPI AntiMonikerImpl_Construct(AntiMonikerImpl* iface);
+HRESULT WINAPI AntiMonikerImpl_Destroy(AntiMonikerImpl* iface);
+
+/********************************************************************************/
+/* Virtual function table for the AntiMonikerImpl class witch  include Ipersist,*/
+/* IPersistStream and IMoniker functions.                                       */
+static ICOM_VTABLE(IMoniker) VT_AntiMonikerImpl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    AntiMonikerImpl_QueryInterface,
+    AntiMonikerImpl_AddRef,
+    AntiMonikerImpl_Release,
+    AntiMonikerImpl_GetClassID,
+    AntiMonikerImpl_IsDirty,
+    AntiMonikerImpl_Load,
+    AntiMonikerImpl_Save,
+    AntiMonikerImpl_GetSizeMax,
+    AntiMonikerImpl_BindToObject,
+    AntiMonikerImpl_BindToStorage,
+    AntiMonikerImpl_Reduce,
+    AntiMonikerImpl_ComposeWith,
+    AntiMonikerImpl_Enum,
+    AntiMonikerImpl_IsEqual,
+    AntiMonikerImpl_Hash,
+    AntiMonikerImpl_IsRunning,
+    AntiMonikerImpl_GetTimeOfLastChange,
+    AntiMonikerImpl_Inverse,
+    AntiMonikerImpl_CommonPrefixWith,
+    AntiMonikerImpl_RelativePathTo,
+    AntiMonikerImpl_GetDisplayName,
+    AntiMonikerImpl_ParseDisplayName,
+    AntiMonikerImpl_IsSystemMoniker
+};
+
+/********************************************************************************/
+/* Virtual function table for the IROTData class.                               */
+static ICOM_VTABLE(IROTData) VT_ROTDataImpl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    AntiMonikerROTDataImpl_QueryInterface,
+    AntiMonikerROTDataImpl_AddRef,
+    AntiMonikerROTDataImpl_Release,
+    AntiMonikerROTDataImpl_GetComparaisonData
+};
+
+/*******************************************************************************
+ *        AntiMoniker_QueryInterface
+ *******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
+{
+    ICOM_THIS(AntiMonikerImpl,iface);
+  
+  TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
+
+  /* Perform a sanity check on the parameters.*/
+    if ( (This==0) || (ppvObject==0) )
+	return E_INVALIDARG;
+  
+  /* Initialize the return parameter */
+  *ppvObject = 0;
+
+  /* Compare the riid with the interface IDs implemented by this object.*/
+  if (IsEqualIID(&IID_IUnknown, riid) ||
+      IsEqualIID(&IID_IPersist, riid) ||
+      IsEqualIID(&IID_IPersistStream, riid) ||
+      IsEqualIID(&IID_IMoniker, riid)
+     )
+      *ppvObject = iface;
+    else if (IsEqualIID(&IID_IROTData, riid))
+        *ppvObject = (IROTData*)&(This->lpvtbl2);
+
+  /* Check that we obtained an interface.*/
+    if ((*ppvObject)==0)
+        return E_NOINTERFACE;
+  
+   /* Query Interface always increases the reference count by one when it is successful */
+  AntiMonikerImpl_AddRef(iface);
+
+  return S_OK;
+}
+
+/******************************************************************************
+ *        AntiMoniker_AddRef
+ ******************************************************************************/
+ULONG WINAPI AntiMonikerImpl_AddRef(IMoniker* iface)
+{
+    ICOM_THIS(AntiMonikerImpl,iface);
+
+    TRACE("(%p)\n",This);
+
+    return ++(This->ref);
+}
+
+/******************************************************************************
+ *        AntiMoniker_Release
+ ******************************************************************************/
+ULONG WINAPI AntiMonikerImpl_Release(IMoniker* iface)
+{
+    ICOM_THIS(AntiMonikerImpl,iface);
+
+    TRACE("(%p)\n",This);
+
+    This->ref--;
+
+    /* destroy the object if there's no more reference on it */
+    if (This->ref==0){
+
+        AntiMonikerImpl_Destroy(This);
+
+        return 0;
+    }
+    return This->ref;;
+}
+
+/******************************************************************************
+ *        AntiMoniker_GetClassID
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
+{
+    TRACE("(%p,%p),stub!\n",iface,pClassID);
+
+    if (pClassID==NULL)
+        return E_POINTER;
+            
+    *pClassID = CLSID_AntiMoniker;
+        
+    return S_OK;
+}
+
+/******************************************************************************
+ *        AntiMoniker_IsDirty
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_IsDirty(IMoniker* iface)
+{
+    /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
+       method in the OLE-provided moniker interfaces always return S_FALSE because
+       their internal state never changes. */
+
+    TRACE("(%p)\n",iface);
+
+    return S_FALSE;
+}
+
+/******************************************************************************
+ *        AntiMoniker_Load
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_Load(IMoniker* iface,IStream* pStm)
+{
+    DWORD constant=1,dwbuffer;
+    HRESULT res;
+
+    /* data read by this function is only a DWORD constant (must be 1) ! */
+    res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),NULL);
+
+    if (SUCCEEDED(res)&& dwbuffer!=constant)
+        return E_FAIL;
+
+    return res;
+}
+
+/******************************************************************************
+ *        AntiMoniker_Save
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
+{
+    DWORD constant=1;
+    HRESULT res;
+    
+    /* data writen by this function is only a DWORD constant seted to 1 ! */
+    res=IStream_Write(pStm,&constant,sizeof(constant),NULL);
+
+    return res;
+}
+
+/******************************************************************************
+ *        AntiMoniker_GetSizeMax
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_GetSizeMax(IMoniker* iface,
+                                          ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */
+{
+    TRACE("(%p,%p)\n",iface,pcbSize);
+
+    if (pcbSize!=NULL)
+        return E_POINTER;
+
+    /* for more details see AntiMonikerImpl_Save coments */
+    
+    /* Normaly the sizemax must be the  size of DWORD ! but I tested this function it ususlly return 16 bytes */
+    /* more than the number of bytes used by AntiMoniker::Save function */
+    pcbSize->LowPart =  sizeof(DWORD)+16;
+
+    pcbSize->HighPart=0;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *         AntiMoniker_Construct (local function)
+ *******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_Construct(AntiMonikerImpl* This)
+{
+
+    TRACE("(%p)\n",This);
+
+    /* Initialize the virtual fgunction table. */
+    This->lpvtbl1      = &VT_AntiMonikerImpl;
+    This->lpvtbl2      = &VT_ROTDataImpl;
+    This->ref          = 0;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        AntiMoniker_Destroy (local function)
+ *******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_Destroy(AntiMonikerImpl* This)
+{
+    TRACE("(%p)\n",This);
+
+    return HeapFree(GetProcessHeap(),0,This);
+}
+
+/******************************************************************************
+ *                  AntiMoniker_BindToObject
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_BindToObject(IMoniker* iface,
+                                            IBindCtx* pbc,
+                                            IMoniker* pmkToLeft,
+                                            REFIID riid,
+                                            VOID** ppvResult)
+{
+    TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        AntiMoniker_BindToStorage
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_BindToStorage(IMoniker* iface,
+                                             IBindCtx* pbc,
+                                             IMoniker* pmkToLeft,
+                                             REFIID riid,
+                                             VOID** ppvResult)
+{
+    TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        AntiMoniker_Reduce
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_Reduce(IMoniker* iface,
+                                      IBindCtx* pbc,
+                                      DWORD dwReduceHowFar,
+                                      IMoniker** ppmkToLeft,
+                                      IMoniker** ppmkReduced)
+{
+    TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
+
+    if (ppmkReduced==NULL)
+        return E_POINTER;
+
+    AntiMonikerImpl_AddRef(iface);
+
+    *ppmkReduced=iface;
+    
+    return MK_S_REDUCED_TO_SELF;
+}
+/******************************************************************************
+ *        AntiMoniker_ComposeWith
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_ComposeWith(IMoniker* iface,
+                                           IMoniker* pmkRight,
+                                           BOOL fOnlyIfNotGeneric,
+                                           IMoniker** ppmkComposite)
+{
+
+    TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
+
+    if ((ppmkComposite==NULL)||(pmkRight==NULL))
+	return E_POINTER;
+
+    *ppmkComposite=0;
+    
+    if (fOnlyIfNotGeneric)
+        return MK_E_NEEDGENERIC;
+    else
+        return CreateGenericComposite(iface,pmkRight,ppmkComposite);
+}
+
+/******************************************************************************
+ *        AntiMoniker_Enum
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
+{
+    TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
+
+    if (ppenumMoniker == NULL)
+        return E_POINTER;
+    
+    *ppenumMoniker = NULL;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        AntiMoniker_IsEqual
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
+{
+    DWORD mkSys;
+    
+    TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
+
+    if (pmkOtherMoniker==NULL)
+        return S_FALSE;
+    
+    IMoniker_IsSystemMoniker(pmkOtherMoniker,&mkSys);
+
+    if (mkSys==MKSYS_ANTIMONIKER)
+        return S_OK;
+    else
+        return S_FALSE;
+}
+
+/******************************************************************************
+ *        AntiMoniker_Hash
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
+{
+    if (pdwHash==NULL)
+        return E_POINTER;
+
+    *pdwHash=0;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        AntiMoniker_IsRunning
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_IsRunning(IMoniker* iface,
+                                         IBindCtx* pbc,
+                                         IMoniker* pmkToLeft,
+                                         IMoniker* pmkNewlyRunning)
+{
+    IRunningObjectTable* rot;
+    HRESULT res;
+
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
+
+    if (pbc==NULL)
+        return E_INVALIDARG;
+
+    res=IBindCtx_GetRunningObjectTable(pbc,&rot);
+
+    if (FAILED(res))
+    return res;
+
+    res = IRunningObjectTable_IsRunning(rot,iface);
+
+    IRunningObjectTable_Release(rot);
+
+    return res;
+}
+
+/******************************************************************************
+ *        AntiMoniker_GetTimeOfLastChange
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_GetTimeOfLastChange(IMoniker* iface,
+                                                   IBindCtx* pbc,
+                                                   IMoniker* pmkToLeft,
+                                                   FILETIME* pAntiTime)
+{
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pAntiTime);
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        AntiMoniker_Inverse
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
+{
+    TRACE("(%p,%p)\n",iface,ppmk);
+
+    if (ppmk==NULL)
+        return E_POINTER;
+
+    *ppmk=0;
+
+    return MK_E_NOINVERSE;
+}
+
+/******************************************************************************
+ *        AntiMoniker_CommonPrefixWith
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
+{
+    DWORD mkSys;
+    
+    IMoniker_IsSystemMoniker(pmkOther,&mkSys);
+
+    if(mkSys==MKSYS_ITEMMONIKER){
+
+        IMoniker_AddRef(iface);
+
+        *ppmkPrefix=iface;
+
+        IMoniker_AddRef(iface);
+        
+        return MK_S_US;
+    }
+    else
+        return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix);
+}
+
+/******************************************************************************
+ *        AntiMoniker_RelativePathTo
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
+{
+    TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
+
+    if (ppmkRelPath==NULL)
+        return E_POINTER;
+
+    IMoniker_AddRef(pmOther);
+
+    *ppmkRelPath=pmOther;
+
+    return MK_S_HIM;
+}
+
+/******************************************************************************
+ *        AntiMoniker_GetDisplayName
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_GetDisplayName(IMoniker* iface,
+                                              IBindCtx* pbc,
+                                              IMoniker* pmkToLeft,
+                                              LPOLESTR *ppszDisplayName)
+{
+    WCHAR back[]={'\\','.','.',0};
+    
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
+
+    if (ppszDisplayName==NULL)
+        return E_POINTER;
+
+    if (pmkToLeft!=NULL){
+        FIXME("() pmkToLeft!=NULL not implemented \n");
+        return E_NOTIMPL;
+    }
+
+    *ppszDisplayName=(LPOLESTR)CoTaskMemAlloc(sizeof(back));
+
+    if (*ppszDisplayName==NULL)
+        return E_OUTOFMEMORY;
+
+    lstrcpyW(*ppszDisplayName,back);
+    
+    return S_OK;
+}
+
+/******************************************************************************
+ *        AntiMoniker_ParseDisplayName
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_ParseDisplayName(IMoniker* iface,
+                                                IBindCtx* pbc,
+                                                IMoniker* pmkToLeft,
+                                                LPOLESTR pszDisplayName,
+                                                ULONG* pchEaten,
+                                                IMoniker** ppmkOut)
+{
+    TRACE("(%p,%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        AntiMoniker_IsSystemMonker
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
+{
+    TRACE("(%p,%p)\n",iface,pwdMksys);
+
+    if (!pwdMksys)
+        return E_POINTER;
+    
+    (*pwdMksys)=MKSYS_ANTIMONIKER;
+
+    return S_OK;
+}
+
+/*******************************************************************************
+ *        AntiMonikerIROTData_QueryInterface
+ *******************************************************************************/
+HRESULT WINAPI AntiMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
+{
+
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+
+    TRACE("(%p,%p,%p)\n",iface,riid,ppvObject);
+
+    return AntiMonikerImpl_QueryInterface(This, riid, ppvObject);
+}
+
+/***********************************************************************
+ *        AntiMonikerIROTData_AddRef
+ */
+ULONG   WINAPI AntiMonikerROTDataImpl_AddRef(IROTData *iface)
+{
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+
+    TRACE("(%p)\n",iface);
+
+    return AntiMonikerImpl_AddRef(This);
+}
+
+/***********************************************************************
+ *        AntiMonikerIROTData_Release
+ */
+ULONG   WINAPI AntiMonikerROTDataImpl_Release(IROTData* iface)
+{
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+    
+    TRACE("(%p)\n",iface);
+
+    return AntiMonikerImpl_Release(This);
+}
+
+/******************************************************************************
+ *        AntiMonikerIROTData_GetComparaisonData
+ ******************************************************************************/
+HRESULT WINAPI AntiMonikerROTDataImpl_GetComparaisonData(IROTData* iface,
+                                                         BYTE* pbData,
+                                                         ULONG cbMax,
+                                                         ULONG* pcbData)
+{
+    FIXME("(),stub!\n");
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        CreateAntiMoniker	[OLE.55]
+ ******************************************************************************/
+HRESULT WINAPI CreateAntiMoniker(LPMONIKER * ppmk)
+{
+    AntiMonikerImpl* newAntiMoniker = 0;
+    HRESULT        hr = S_OK;
+    IID riid=IID_IMoniker;
+    
+    TRACE("(%p)\n",ppmk);
+
+    newAntiMoniker = (AntiMonikerImpl*)HeapAlloc(GetProcessHeap(), 0, sizeof(AntiMonikerImpl));
+
+    if (newAntiMoniker == 0)
+        return STG_E_INSUFFICIENTMEMORY;
+
+    hr = AntiMonikerImpl_Construct(newAntiMoniker);
+
+    if (FAILED(hr)){
+
+        HeapFree(GetProcessHeap(),0,newAntiMoniker);
+        return hr;
+    }
+
+    hr = AntiMonikerImpl_QueryInterface((IMoniker*)newAntiMoniker,&riid,(void**)ppmk);
+
+    return hr;
+}
Index: trunk/src/ole32/new/apartment.cpp
===================================================================
--- trunk/src/ole32/new/apartment.cpp	(revision 3456)
+++ trunk/src/ole32/new/apartment.cpp	(revision 3456)
@@ -0,0 +1,134 @@
+/* $Id: apartment.cpp,v 1.1 2000-04-27 22:18:14 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * COM Apartment handling
+ * 
+ * 22/04/2000
+ * 
+ * Copyright 2000 David J. Raison
+ * 
+ */
+
+#include "ole32.h"
+#include "oString.h"
+#include "oTls.h"
+#include "apartment.h"
+#include "rpcdce.h"
+
+CHAR ComMessagePumpWndClass[] = "OleMainThreadWndClass";
+CHAR ComMessagePumpWndName[] = "OleMainThreadWndName";
+
+// ======================================================================
+// OleMainThreadWndProc
+// ======================================================================
+LRESULT CALLBACK ComMessagePumpWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch (msg)
+    {
+	case WM_USER:
+
+	    // Dispatch method call...
+
+	    break;
+
+	default:
+	    return DefWindowProcA(hWnd, msg, wParam, lParam);
+    }
+
+    return 0;
+}
+
+// ======================================================================
+// Apartment
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// Apartment::Apartment
+// ----------------------------------------------------------------------
+Apartment::Apartment(enAptType aptType)
+{
+    WNDCLASSEXA		wcex;
+
+    m_AptType = aptType;
+
+    UuidCreate(&m_Guid);
+
+    m_pDefaultContext = new ObjectContext;
+    m_pDefaultContext->SetApt(this);
+
+    if (IsMessageBased())
+    {
+	// First STA shall always be MAIN...
+	if (m_AptType == APT_MAIN)
+	{
+	    // Register our window class...
+	    ZeroMemory( &wcex, sizeof(WNDCLASSEXA));
+	    wcex.cbSize         = sizeof(WNDCLASSEXA);
+	    wcex.style          = CS_GLOBALCLASS;
+	    wcex.lpfnWndProc    = (WNDPROC)ComMessagePumpWndProc;
+	    wcex.hInstance      = 0;
+	    wcex.lpszClassName  = ComMessagePumpWndClass;
+
+	    RegisterClassExA(&wcex);
+	}
+
+	// Initialise message pump window...
+	m_hwndPump = CreateWindowA(ComMessagePumpWndClass,
+				   ComMessagePumpWndName,
+				   WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
+				   CW_USEDEFAULT, CW_USEDEFAULT,
+				   CW_USEDEFAULT, CW_USEDEFAULT,
+				   0,
+				   0,
+				   0,
+				   0);
+    }
+}
+
+// ----------------------------------------------------------------------
+// Apartment::~Apartment
+// ----------------------------------------------------------------------
+Apartment::~Apartment()
+{
+    if (IsMessageBased())
+	DestroyWindow(m_hwndPump);
+
+    delete m_pDefaultContext;
+}
+
+// ----------------------------------------------------------------------
+// Apartment::IsCompatible
+// ----------------------------------------------------------------------
+BOOL		Apartment::IsCompatible(Attributes * const pTarget) const
+{
+    switch (pTarget->GetThreadingModel())
+    {
+	case  THM_BOTH:
+	    return TRUE;
+
+	case  THM_FREE:
+	    return m_AptType == APT_MT;
+
+	case  THM_NEUTRAL:
+	    return m_AptType == APT_TN;
+
+	case  THM_UNDEFINED:
+	    return m_AptType == APT_MAIN;
+
+	case  THM_APARTMENT:
+	    return IsMessageBased();
+
+	default:
+	    // drop thru to warning msg.
+	    break;
+    }
+
+    dprintf(("Apartment::IsCompatible() - Invalid Threading model (%d)",
+							pTarget->GetThreadingModel()));
+
+    return FALSE;
+}
Index: trunk/src/ole32/new/apartment.h
===================================================================
--- trunk/src/ole32/new/apartment.h	(revision 3456)
+++ trunk/src/ole32/new/apartment.h	(revision 3456)
@@ -0,0 +1,163 @@
+/* $Id: apartment.h,v 1.1 2000-04-27 22:21:35 davidr Exp $ */
+/*
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+#ifndef APARTMENT_INCLUDED
+#define APARTMENT_INCLUDED 1
+
+class	Apartment;
+
+class	ObjectContext;
+
+// ----------------------------------------------------------------------
+// 
+// ----------------------------------------------------------------------
+enum enAptType
+{
+    APT_TN = 0,
+    APT_MT = 1,
+    APT_ST = 2,
+    APT_MAIN = 3,
+    APT_HOST = 4
+};
+
+enum enThreadingModel
+{
+    THM_UNDEFINED = 0,
+    THM_APARTMENT,
+    THM_FREE,
+    THM_BOTH,
+    THM_NEUTRAL
+};
+
+// ----------------------------------------------------------------------
+// Attributes associated with an object...
+// ----------------------------------------------------------------------
+class Attributes
+{
+public:
+    enThreadingModel	GetThreadingModel(void ) const
+	{ return m_ThreadingModel; }
+
+    BOOL		GetConfiguredComponent(void ) const
+	{ return m_fConfiguredComponent; }
+
+protected:
+
+private:
+    enThreadingModel	m_ThreadingModel;
+    BOOL		m_fConfiguredComponent;
+
+    // Loads more stuff to do with COM+ object context to go here :-)
+
+};
+
+// ----------------------------------------------------------------------
+// COntext in which an object runs...
+// ----------------------------------------------------------------------
+class	ObjectContext
+{
+private:
+    GUID		m_Guid;
+    Apartment *		m_pApt;
+
+    // Loads more stuff to do with COM+ object context to go here :-)
+
+protected:
+
+public:
+
+    ObjectContext();
+
+    const GUID &	GetGUID(void ) const		// Object context GUID...
+    	{ return m_Guid; }
+
+    const Apartment *	GetApt(void ) const	// Associated apartment...
+    	{ return m_pApt; }
+
+    void		SetApt(Apartment * const pApt)
+    	{ m_pApt = pApt; }
+
+    // Longhand methods...
+    BOOL		IsCompatible(Attributes * const pTarget) const;
+};
+
+// ----------------------------------------------------------------------
+// Class to represent an apartment.
+// Apartments have varing thread affinity dependant on their type.
+// ----------------------------------------------------------------------
+class Apartment
+{
+private:
+    GUID		m_Guid;
+    ObjectContext *	m_pDefaultContext;
+    HWND		m_hwndPump;
+    enAptType		m_AptType;
+
+protected:
+
+public:
+
+    Apartment(enAptType aptType);
+    virtual ~Apartment();
+
+    enAptType		GetAptType(void ) const
+    	{ return m_AptType; }
+
+    const GUID &	GetGUID(void ) const
+    	{ return m_Guid; }
+
+    ObjectContext * const GetDefaultContext(void ) const
+	{ return m_pDefaultContext; }
+
+    BOOL		IsMessageBased(void ) const
+	{ return !((m_AptType == APT_MT) || (m_AptType == APT_TN)); }
+
+    // Longhand methods...
+    BOOL		IsCompatible(Attributes * const pTarget) const;
+};
+
+// ----------------------------------------------------------------------
+// Info stored against each thread by COM
+// ----------------------------------------------------------------------
+class ThreadInfo
+{
+private:
+    LONG		m_RefCount;
+
+    Apartment *		m_pAptHome;
+    ObjectContext *	m_pCurContext;
+
+protected:
+public:
+    ThreadInfo() : m_RefCount(1), m_pAptHome(0), m_pCurContext(0)
+	{};
+
+    virtual ~ThreadInfo()
+	{ delete m_pAptHome; }
+
+    LONG		AddRef(void )
+    	{ return ++m_RefCount; }
+
+    LONG		Release(void )
+    	{ return --m_RefCount; }
+
+    Apartment *		GetHomeApt(void )
+	{ return m_pAptHome; }
+
+    void		SetHomeApt(Apartment * pApt)
+	{ m_pAptHome = pApt; }
+
+    ObjectContext *	GetCurContext(void )
+	{ return m_pCurContext; }
+
+    void		SetCurContext(ObjectContext * curContext)
+	{ m_pCurContext = curContext; }
+
+};
+
+
+#endif /* APARTMENT_INCLUDED */
Index: trunk/src/ole32/new/apartmentbase.cpp
===================================================================
--- trunk/src/ole32/new/apartmentbase.cpp	(revision 3456)
+++ trunk/src/ole32/new/apartmentbase.cpp	(revision 3456)
@@ -0,0 +1,19 @@
+/* $Id: apartmentbase.cpp,v 1.1 2000-04-27 22:18:14 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * COM Apartment handling
+ * 
+ * 22/04/2000
+ * 
+ * Copyright 2000 David J. Raison
+ * 
+ */
+
+#include "ole32.h"
+#include "oString.h"
+#include "apartment.h"
+
Index: trunk/src/ole32/new/bindctx.cpp
===================================================================
--- trunk/src/ole32/new/bindctx.cpp	(revision 3456)
+++ trunk/src/ole32/new/bindctx.cpp	(revision 3456)
@@ -0,0 +1,540 @@
+/* $Id: bindctx.cpp,v 1.1 2000-04-27 22:18:15 davidr Exp $ */
+/* 
+ * BindCtx implementation
+ * 
+ * 20/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *   Copyright 1999  Noomen Hamza
+ */
+
+#include "ole32.h"
+#include "heapstring.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+/* represent the first size table and it's increment block size */
+#define  BLOCK_TAB_SIZE 10 
+#define  MAX_TAB_SIZE   0xFFFFFFFF
+
+/* data structure of the BindCtx table elements */
+typedef struct BindCtxObject{
+
+    IUnknown*   pObj; /* point on a bound object */
+
+    LPOLESTR  pkeyObj; /* key associated to this bound object */
+
+    BYTE regType; /* registration type: 1 if RegisterObjectParam and 0 if RegisterObjectBound */
+
+} BindCtxObject;
+
+/* BindCtx data strucrture */
+typedef struct BindCtxImpl{
+
+    ICOM_VFIELD(IBindCtx); /* VTable relative to the IBindCtx interface.*/
+                                     
+    ULONG ref; /* reference counter for this object */
+
+    BindCtxObject* bindCtxTable; /* this is a table in witch all bounded objects are stored*/
+    DWORD          bindCtxTableLastIndex;  /* first free index in the table */
+    DWORD          bindCtxTableSize;   /* size table */
+
+    BIND_OPTS2 bindOption2; /* a structure witch contains the bind options*/
+
+} BindCtxImpl;
+
+/* IBindCtx prototype functions : */
+
+/* IUnknown functions*/
+static HRESULT WINAPI BindCtxImpl_QueryInterface(IBindCtx* iface,REFIID riid,void** ppvObject);
+static ULONG   WINAPI BindCtxImpl_AddRef(IBindCtx* iface);
+static ULONG   WINAPI BindCtxImpl_Release(IBindCtx* iface);
+/* IBindCtx functions */
+static HRESULT WINAPI BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk);
+static HRESULT WINAPI BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk);
+static HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface);
+static HRESULT WINAPI BindCtxImpl_SetBindOptions(IBindCtx* iface,LPBIND_OPTS2 pbindopts);
+static HRESULT WINAPI BindCtxImpl_GetBindOptions(IBindCtx* iface,LPBIND_OPTS2 pbindopts);
+static HRESULT WINAPI BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot);
+static HRESULT WINAPI BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk);
+static HRESULT WINAPI BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk);
+static HRESULT WINAPI BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** ppenum);
+static HRESULT WINAPI BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR pszkey);
+/* Local functions*/
+HRESULT WINAPI BindCtxImpl_Construct(BindCtxImpl* This);
+HRESULT WINAPI BindCtxImpl_Destroy(BindCtxImpl* This);
+HRESULT WINAPI BindCtxImpl_GetObjectIndex(BindCtxImpl* This,IUnknown* punk,LPOLESTR pszkey,DWORD *index);
+
+/* Virtual function table for the BindCtx class. */
+static ICOM_VTABLE(IBindCtx) VT_BindCtxImpl =
+    {
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    BindCtxImpl_QueryInterface,
+    BindCtxImpl_AddRef,
+    BindCtxImpl_Release,
+    BindCtxImpl_RegisterObjectBound,
+    BindCtxImpl_RevokeObjectBound,
+    BindCtxImpl_ReleaseBoundObjects,
+    BindCtxImpl_SetBindOptions,
+    BindCtxImpl_GetBindOptions,
+    BindCtxImpl_GetRunningObjectTable,
+    BindCtxImpl_RegisterObjectParam,
+    BindCtxImpl_GetObjectParam,
+    BindCtxImpl_EnumObjectParam,
+    BindCtxImpl_RevokeObjectParam
+};
+
+/*******************************************************************************
+ *        BindCtx_QueryInterface
+ *******************************************************************************/
+HRESULT WINAPI BindCtxImpl_QueryInterface(IBindCtx* iface,REFIID riid,void** ppvObject)
+{
+  ICOM_THIS(BindCtxImpl,iface);
+
+  TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
+
+  /* Perform a sanity check on the parameters.*/
+  if ( (This==0) || (ppvObject==0) )
+      return E_INVALIDARG;
+  
+  /* Initialize the return parameter.*/
+  *ppvObject = 0;
+
+  /* Compare the riid with the interface IDs implemented by this object.*/
+  if (IsEqualIID(&IID_IUnknown, riid))
+      *ppvObject = (IBindCtx*)This;
+  else
+      if (IsEqualIID(&IID_IBindCtx, riid))
+          *ppvObject = (IBindCtx*)This;
+
+  /* Check that we obtained an interface.*/
+  if ((*ppvObject)==0)
+      return E_NOINTERFACE;
+  
+   /* Query Interface always increases the reference count by one when it is successful */
+  BindCtxImpl_AddRef(iface);
+
+  return S_OK;
+}
+
+/******************************************************************************
+ *       BindCtx_AddRef
+ ******************************************************************************/
+ULONG WINAPI BindCtxImpl_AddRef(IBindCtx* iface)
+{
+    ICOM_THIS(BindCtxImpl,iface);
+
+    TRACE("(%p)\n",This);
+
+    return ++(This->ref);
+}
+
+/******************************************************************************
+ *        BindCtx_Release
+ ******************************************************************************/
+ULONG WINAPI BindCtxImpl_Release(IBindCtx* iface)
+{
+    ICOM_THIS(BindCtxImpl,iface);
+
+    TRACE("(%p)\n",This);
+
+    This->ref--;
+
+    if (This->ref==0){
+
+        /* release all registred objects */
+        BindCtxImpl_ReleaseBoundObjects((IBindCtx*)This);
+
+        BindCtxImpl_Destroy(This);
+
+        return 0;
+    }
+    return This->ref;;
+}
+
+
+/******************************************************************************
+ *         BindCtx_Construct (local function)
+ *******************************************************************************/
+HRESULT WINAPI BindCtxImpl_Construct(BindCtxImpl* This)
+{
+    TRACE("(%p)\n",This);
+
+    /* Initialize the virtual function table.*/
+    ICOM_VTBL(This)    = &VT_BindCtxImpl;
+    This->ref          = 0;
+
+    /* Initialize the BIND_OPTS2 structure */
+    This->bindOption2.cbStruct  = sizeof(BIND_OPTS2);
+    This->bindOption2.grfFlags = 0;
+    This->bindOption2.grfMode = STGM_READWRITE;
+    This->bindOption2.dwTickCountDeadline = 0;
+
+    This->bindOption2.dwTrackFlags = 0;
+    This->bindOption2.dwClassContext = CLSCTX_SERVER;
+    This->bindOption2.locale = 1033;
+    This->bindOption2.pServerInfo = 0;
+
+    /* Initialize the bindctx table */
+    This->bindCtxTableSize=BLOCK_TAB_SIZE;
+    This->bindCtxTableLastIndex=0;
+    This->bindCtxTable= (BindCtxObject *)HeapAlloc(GetProcessHeap(), 0,This->bindCtxTableSize*sizeof(BindCtxObject));
+
+    if (This->bindCtxTable==NULL)
+        return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        BindCtx_Destroy    (local function)
+ *******************************************************************************/
+HRESULT WINAPI BindCtxImpl_Destroy(BindCtxImpl* This)
+{
+    TRACE("(%p)\n",This);
+
+    /* free the table space memory */
+    HeapFree(GetProcessHeap(),0,This->bindCtxTable);
+
+    /* free the bindctx structure */
+    HeapFree(GetProcessHeap(),0,This);
+
+    return S_OK;
+}
+
+
+/******************************************************************************
+ *        BindCtx_RegisterObjectBound
+ ******************************************************************************/
+HRESULT WINAPI BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk)
+{
+
+    ICOM_THIS(BindCtxImpl,iface);
+    DWORD lastIndex=This->bindCtxTableLastIndex;
+    BindCtxObject cell;
+
+    TRACE("(%p,%p)\n",This,punk);
+
+    if (punk==NULL)
+        return E_POINTER;
+    
+    IUnknown_AddRef(punk);
+    
+    /* put the object in the first free element in the table */
+    This->bindCtxTable[lastIndex].pObj = punk;
+    This->bindCtxTable[lastIndex].pkeyObj = NULL;
+    This->bindCtxTable[lastIndex].regType = 0;
+    cell=This->bindCtxTable[lastIndex];
+    lastIndex= ++This->bindCtxTableLastIndex;
+
+    if (lastIndex == This->bindCtxTableSize){ /* the table is full so it must be resized */
+
+        if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)){
+            FIXME("This->bindCtxTableSize: %ld is out of data limite \n",This->bindCtxTableSize);
+            return E_FAIL;
+}
+
+        This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */
+
+        This->bindCtxTable =
+            (BindCtxObject *)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
+                                         This->bindCtxTableSize * sizeof(BindCtxObject));
+        if (!This->bindCtxTable)
+            return E_OUTOFMEMORY;
+    }
+    return S_OK;
+}
+
+/******************************************************************************
+ *        BindCtx_RevokeObjectBound
+ ******************************************************************************/
+HRESULT WINAPI BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk)
+{
+    DWORD index,j;
+
+    ICOM_THIS(BindCtxImpl,iface);
+
+    TRACE("(%p,%p)\n",This,punk);
+
+    /* check if the object was registred or not */
+    if (BindCtxImpl_GetObjectIndex(This,punk,NULL,&index)==S_FALSE)
+        
+        return MK_E_NOTBOUND;
+
+    IUnknown_Release(This->bindCtxTable[index].pObj);
+    
+    /* left-shift all elements in the rigth side of the curent revoked object */
+    for(j=index; j<This->bindCtxTableLastIndex-1; j++)
+        This->bindCtxTable[j]= This->bindCtxTable[j+1];
+    
+    This->bindCtxTableLastIndex--;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        BindCtx_ReleaseBoundObjects
+ ******************************************************************************/
+HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface)
+{
+    DWORD i;
+
+    ICOM_THIS(BindCtxImpl,iface);
+
+    TRACE("(%p)\n",This);
+
+    for(i=0;i<This->bindCtxTableLastIndex;i++)
+       IUnknown_Release(This->bindCtxTable[i].pObj);
+
+    This->bindCtxTableLastIndex = 0;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        BindCtx_SetBindOptions
+ ******************************************************************************/
+HRESULT WINAPI BindCtxImpl_SetBindOptions(IBindCtx* iface,LPBIND_OPTS2 pbindopts)
+{
+    ICOM_THIS(BindCtxImpl,iface);
+
+    TRACE("(%p,%p)\n",This,pbindopts);
+
+    if (pbindopts==NULL)
+        return E_POINTER;
+    
+    This->bindOption2=*pbindopts;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        BindCtx_GetBindOptions
+ ******************************************************************************/
+HRESULT WINAPI BindCtxImpl_GetBindOptions(IBindCtx* iface,LPBIND_OPTS2 pbindopts)
+{
+    ICOM_THIS(BindCtxImpl,iface);
+
+    TRACE("(%p,%p)\n",This,pbindopts);
+
+    if (pbindopts==NULL)
+        return E_POINTER;
+
+    *pbindopts=This->bindOption2;
+    
+    return S_OK;
+}
+
+/******************************************************************************
+ *        BindCtx_GetRunningObjectTable
+ ******************************************************************************/
+HRESULT WINAPI BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot)
+{
+    HRESULT res;
+
+    ICOM_THIS(BindCtxImpl,iface);
+
+    TRACE("(%p,%p)\n",This,pprot);
+
+    if (pprot==NULL)
+        return E_POINTER;
+    
+    res=GetRunningObjectTable(0, pprot);
+
+    return res;
+}
+
+/******************************************************************************
+ *        BindCtx_RegisterObjectParam
+ ******************************************************************************/
+HRESULT WINAPI BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk)
+{
+    ICOM_THIS(BindCtxImpl,iface);
+
+    TRACE("(%p,%p,%p)\n",This,pszkey,punk);
+
+    if (punk==NULL)
+        return E_INVALIDARG;
+    
+    IUnknown_AddRef(punk);
+
+    This->bindCtxTable[This->bindCtxTableLastIndex].pObj = punk;
+    This->bindCtxTable[This->bindCtxTableLastIndex].regType = 1;
+
+    if (pszkey==NULL)
+
+        This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=NULL;
+
+    else{
+
+        This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=
+            (WCHAR *)HeapAlloc(GetProcessHeap(),0,(sizeof(WCHAR)*(1+lstrlenW(pszkey))));
+
+        if (This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj==NULL)
+            return E_OUTOFMEMORY;
+        lstrcpyW(This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj,pszkey);
+}
+
+    This->bindCtxTableLastIndex++;
+    
+    if (This->bindCtxTableLastIndex == This->bindCtxTableSize){ /* table is full ! must be resized */
+
+        This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */
+
+        if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)){
+            FIXME("This->bindCtxTableSize: %ld is out of data limite \n",This->bindCtxTableSize);
+            return E_FAIL;
+        }
+        This->bindCtxTable =
+            (BindCtxObject *)HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable,
+                                         This->bindCtxTableSize * sizeof(BindCtxObject));
+        if (!This->bindCtxTable)
+            return E_OUTOFMEMORY;
+    }
+    return S_OK;
+}
+/******************************************************************************
+ *        BindCtx_GetObjectParam
+ ******************************************************************************/
+HRESULT WINAPI BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk)
+{
+    DWORD index;
+    ICOM_THIS(BindCtxImpl,iface);
+
+    TRACE("(%p,%p,%p)\n",This,pszkey,punk);
+
+    if (punk==NULL)
+        return E_POINTER;
+
+    *punk=0;
+    
+    if (BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_FALSE)
+        return E_FAIL;
+
+    IUnknown_AddRef(This->bindCtxTable[index].pObj);
+    
+    *punk = This->bindCtxTable[index].pObj;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        BindCtx_RevokeObjectParam
+ ******************************************************************************/
+HRESULT WINAPI BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum)
+{
+    DWORD index,j;
+
+    ICOM_THIS(BindCtxImpl,iface);
+
+    TRACE("(%p,%p)\n",This,ppenum);
+
+    if (BindCtxImpl_GetObjectIndex(This,NULL,ppenum,&index)==S_FALSE)
+        return E_FAIL;
+
+    /* release the object if it's found */
+    IUnknown_Release(This->bindCtxTable[index].pObj);
+    
+    /* remove the object from the table with a left-shifting of all objects in the right side */
+    for(j=index; j<This->bindCtxTableLastIndex-1; j++)
+        This->bindCtxTable[j]= This->bindCtxTable[j+1];
+    
+    This->bindCtxTableLastIndex--;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        BindCtx_EnumObjectParam
+ ******************************************************************************/
+HRESULT WINAPI BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey)
+{
+    FIXME("(%p,%p),stub!\n",iface,pszkey);
+    return E_NOTIMPL;
+}
+
+/********************************************************************************
+ *        GetObjectIndex (local function)
+ ********************************************************************************/
+HRESULT WINAPI BindCtxImpl_GetObjectIndex(BindCtxImpl* This,
+                                          IUnknown* punk,
+                                          LPOLESTR pszkey,
+                                          DWORD *index)
+{
+
+    DWORD i;
+    BYTE found=0;
+    
+    TRACE("(%p,%p,%p,%p)\n",This,punk,pszkey,index);
+
+    if (punk==NULL)
+        /* search object identified by a register key */
+        for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++){
+
+            if(This->bindCtxTable[i].regType==1){
+
+                if ( ( (This->bindCtxTable[i].pkeyObj==NULL) && (pszkey==NULL) ) ||
+                     ( (This->bindCtxTable[i].pkeyObj!=NULL) &&
+                       (pszkey!=NULL) &&
+                       (lstrcmpW(This->bindCtxTable[i].pkeyObj,pszkey)==0)
+                     )
+                   )
+
+                    found=1;
+            }
+        }
+    else
+        /* search object identified by a moniker*/
+        for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++)
+            if(This->bindCtxTable[i].pObj==punk)
+                found=1;
+
+    if (index != NULL)
+        *index=i-1;
+
+    if (found)
+        return S_OK;
+    else
+        return S_FALSE;
+}
+
+/******************************************************************************
+ *        CreateBindCtx16
+ ******************************************************************************/
+HRESULT WINAPI CreateBindCtx16(DWORD reserved, LPBC * ppbc)
+{
+    FIXME("(%ld,%p),stub!\n",reserved,ppbc);
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        CreateBindCtx
+ ******************************************************************************/
+HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc)
+{
+    BindCtxImpl* newBindCtx = 0;
+    HRESULT hr;
+    IID riid=IID_IBindCtx;
+
+    TRACE("(%ld,%p)\n",reserved,ppbc);
+
+    newBindCtx = (BindCtxImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(BindCtxImpl));
+
+    if (newBindCtx == 0)
+        return E_OUTOFMEMORY;
+
+    hr = BindCtxImpl_Construct(newBindCtx);
+
+    if (FAILED(hr)){
+
+        HeapFree(GetProcessHeap(),0,newBindCtx);
+        return hr;
+    }
+
+    hr = BindCtxImpl_QueryInterface((IBindCtx*)newBindCtx,&riid,(void**)ppbc);
+
+    return hr;
+}
Index: trunk/src/ole32/new/clsid.cpp
===================================================================
--- trunk/src/ole32/new/clsid.cpp	(revision 3456)
+++ trunk/src/ole32/new/clsid.cpp	(revision 3456)
@@ -0,0 +1,418 @@
+/* $Id: clsid.cpp,v 1.1 2000-04-27 22:18:15 davidr Exp $ */
+/*
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+/*
+ * ClassID Manipulation.
+ *
+ * 1/7/99
+ *
+ * Copyright 2000 David J. Raison 
+ *
+ * Some portions from Wine Implementation
+ *
+ *   Copyright 1995  Martin von Loewis
+ *             1998  Justin Bradford
+ *             1999  Francis Beaudet
+ *             1999  Sylvain St-Germain
+ */
+
+#include "ole32.h"
+#include "rpcdce.h"
+
+#include "oString.h"
+
+
+// ----------------------------------------------------------------------
+// CoCreateGuid						[OLE32.6]
+//
+// Creates a 128bit GUID.
+// ----------------------------------------------------------------------
+HRESULT WINAPI CoCreateGuid(
+    GUID *	pguid)		/* [out] points to the GUID to initialize */
+{
+    HRESULT		hr;
+
+    dprintf(("OLE32: CoCreateGuid"));
+    hr = UuidCreate(pguid);
+
+    return hr;
+}
+
+// ----------------------------------------------------------------------
+// CLSIDFromProgID16()
+// ----------------------------------------------------------------------
+HRESULT WIN32API CLSIDFromProgID16(
+    LPCOLESTR16		lpszProgID,	// [in] - UNICODE program id as found in registry
+    LPCLSID		pclsid)		// [out] - CLSID
+{
+//    dprintf(("OLE32: CLSIDFromProgID16"));
+
+    LONG		lDataLen = 80;
+    oStringA		szKey(lpszProgID);
+    oStringA		szCLSID(lDataLen, 1);
+    HKEY		hKey;
+    HRESULT		rc;
+
+    // Create the registry lookup string...
+    szKey += "\\CLSID";
+
+    // Try to open the key in the registry...
+    rc = RegOpenKeyA(HKEY_CLASSES_ROOT, szKey, &hKey);
+    if (rc != 0)
+    	return OLE_ERROR_GENERIC;
+
+    // Now get the data from the _default_ entry on this key...
+    rc = RegQueryValueA(hKey, NULL, szCLSID, &lDataLen);
+    RegCloseKey(hKey);
+    if (rc != 0)
+    	return OLE_ERROR_GENERIC;
+
+    // Now convert from a string to a UUID
+    return CLSIDFromString16(szCLSID, pclsid);
+}
+
+// ----------------------------------------------------------------------
+// CLSIDFromProgID()
+// ----------------------------------------------------------------------
+HRESULT WIN32API CLSIDFromProgID(
+    LPCOLESTR		lpszProgID,	// [in] - UNICODE program id as found in registry
+    LPCLSID		pclsid)		// [out] - CLSID
+{
+//    dprintf(("OLE32: CLSIDFromProgID"));
+
+    LONG		lDataLen = 80;
+    oStringW		szKey(lpszProgID);
+    oStringW		szCLSID(lDataLen, 1);
+    HKEY		hKey;
+    HRESULT		rc;
+
+    // Create the registry lookup string...
+    szKey += L"\\CLSID";
+
+    // Try to open the key in the registry...
+    rc = RegOpenKeyW(HKEY_CLASSES_ROOT, szKey, &hKey);
+    if (rc != 0)
+    	return OLE_ERROR_GENERIC;
+
+    // Now get the data from the _default_ entry on this key...
+    rc = RegQueryValueW(hKey, NULL, szCLSID, &lDataLen);
+    RegCloseKey(hKey);
+    if (rc != 0)
+    	return OLE_ERROR_GENERIC;
+
+    // Now convert from a string to a UUID
+    return CLSIDFromString(szCLSID, pclsid);
+}
+
+// ----------------------------------------------------------------------
+// IIDFromString
+// ----------------------------------------------------------------------
+HRESULT WIN32API IIDFromString(LPSTR lpsz, LPIID lpiid)
+{
+//    dprintf(("OLE32: IIDFromString"));
+    return CLSIDFromString((LPCOLESTR)lpsz, (LPCLSID)lpiid);
+}
+
+
+// ----------------------------------------------------------------------
+// CLSIDFromStringA()
+// @@@PH: this is not a WINE API, but a replacement for CLSIDFromString16
+//        which used to accept ASCII strings instead of OLE strings
+// ----------------------------------------------------------------------
+
+HRESULT WIN32API CLSIDFromStringA(
+    LPCSTR		lpsz,		// [in] - ASCII string CLSID
+    LPCLSID		pclsid)		// [out] - Binary CLSID
+{
+    return CLSIDFromString16(lpsz, pclsid);
+}
+
+
+// ----------------------------------------------------------------------
+// CLSIDFromString16()
+// ----------------------------------------------------------------------
+HRESULT WIN32API CLSIDFromString16(
+    LPCOLESTR16		lpsz,		// [in] - Unicode string CLSID
+    LPCLSID		pclsid)		// [out] - Binary CLSID
+{
+//    dprintf(("OLE32: CLSIDFromString16"));
+
+    // Convert to binary CLSID
+    char *s = (char *) lpsz;
+    char *p;
+    int   i;
+    char table[256];
+
+    /* quick lookup table */
+    memset(table, 0, 256);
+
+    for (i = 0; i < 10; i++)
+    {
+	table['0' + i] = i;
+    }
+    for (i = 0; i < 6; i++)
+    {
+	table['A' + i] = i+10;
+	table['a' + i] = i+10;
+    }
+
+    /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
+
+    if (lstrlenA(lpsz) != 38)
+	return OLE_ERROR_OBJECT;
+
+    p = (char *) pclsid;
+
+    s++;  /* skip leading brace  */
+    for (i = 0; i < 4; i++)
+    {
+	p[3 - i] = table[*s]<<4 | table[*(s+1)];
+	s += 2;
+    }
+    p += 4;
+    s++;  /* skip - */
+
+    for (i = 0; i < 2; i++)
+    {
+	p[1-i] = table[*s]<<4 | table[*(s+1)];
+	s += 2;
+    }
+    p += 2;
+    s++;  /* skip - */
+
+    for (i = 0; i < 2; i++)
+    {
+	p[1-i] = table[*s]<<4 | table[*(s+1)];
+	s += 2;
+    }
+    p += 2;
+    s++;  /* skip - */
+
+    /* these are just sequential bytes */
+    for (i = 0; i < 2; i++)
+    {
+	*p++ = table[*s]<<4 | table[*(s+1)];
+	s += 2;
+    }
+    s++;  /* skip - */
+
+    for (i = 0; i < 6; i++)
+    {
+	*p++ = table[*s]<<4 | table[*(s+1)];
+	s += 2;
+    }
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// CLSIDFromString()
+// ----------------------------------------------------------------------
+HRESULT WIN32API CLSIDFromString(
+    LPCOLESTR		lpsz,		// [in] - Unicode string CLSID
+    LPCLSID		pclsid)		// [out] - Binary CLSID
+{
+//    dprintf(("OLE32: CLSIDFromString"));
+
+    oStringA		tClsId(lpsz);
+
+    return CLSIDFromString16(tClsId, pclsid);
+}
+
+// ----------------------------------------------------------------------
+// WINE_StringFromCLSID
+// ----------------------------------------------------------------------
+HRESULT WIN32API WINE_StringFromCLSID(const CLSID *rclsid, LPSTR idstr)
+{
+//    dprintf(("OLE32: WINE_StringFromCLSID"));
+
+    if (rclsid == NULL)
+    {
+	dprintf(("       clsid: (NULL)"));
+	*idstr = 0;
+	return E_FAIL;
+    }
+
+    // Setup new string...
+    sprintf(idstr, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+	    rclsid->Data1,
+	    rclsid->Data2,
+	    rclsid->Data3,
+	    rclsid->Data4[0],
+	    rclsid->Data4[1],
+	    rclsid->Data4[2],
+	    rclsid->Data4[3],
+	    rclsid->Data4[4],
+	    rclsid->Data4[5],
+	    rclsid->Data4[6],
+	    rclsid->Data4[7]);
+
+//    dprintf(("       clsid: %s", idstr));
+
+    return OLE_OK;
+}
+
+// ----------------------------------------------------------------------
+// StringFromCLSID
+// Memory allocated here on behalf of application should be freed using CoTaskMemFree()
+// ----------------------------------------------------------------------
+HRESULT WIN32API StringFromCLSID(REFCLSID rclsid, LPOLESTR *ppsz)
+{
+    char	tmp[50];
+    LPWSTR	szclsid;
+    size_t	strLen;
+
+//    dprintf(("OLE32: StringFromCLSID"));
+
+    // Setup new string...
+    WINE_StringFromCLSID(rclsid, tmp);
+
+    strLen = strlen(tmp);
+
+    // Grab buffer for string...
+    szclsid = (LPWSTR)CoTaskMemAlloc((strLen + 1) * sizeof(WCHAR));
+
+    AsciiToUnicode(tmp, szclsid);
+
+    *ppsz = (LPOLESTR)szclsid;
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// StringFromIID
+// Memory allocated here on behalf of application should be freed using CoTaskMemFree()
+// ----------------------------------------------------------------------
+HRESULT WIN32API StringFromIID(REFIID riid, LPOLESTR *ppsz)
+{
+    char	tmp[50];
+    LPWSTR	sziid;
+    size_t	strLen;
+
+//    dprintf(("OLE32: StringFromIID"));
+
+    // Setup new string...
+    WINE_StringFromCLSID(riid, tmp);
+
+    strLen = strlen(tmp);
+
+    // Grab buffer for string...
+    sziid = (LPWSTR)CoTaskMemAlloc((strLen + 1) * sizeof(WCHAR));
+
+    AsciiToUnicode(tmp, sziid);
+
+    *ppsz = (LPOLESTR)sziid;
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// StringFromGUID2
+// ----------------------------------------------------------------------
+int WIN32API StringFromGUID2(REFGUID rguid, LPOLESTR lpsz, int cbMax)
+{
+// NB cbMax is a CHARACTER count not a BYTE count... :-)
+    char 	tmp[50];
+    size_t	strLen;
+
+    // Setup new string...
+    WINE_StringFromCLSID(rguid, tmp);
+
+    strLen = (strlen(tmp) + 1);
+    if (strLen > cbMax)
+	strLen = cbMax;
+
+    AsciiToUnicodeN(tmp, lpsz, strLen);
+
+    return strLen;  // Num CHARACTERS including 0 terminator
+}
+
+// ----------------------------------------------------------------------
+// CONCRETE_IsEqualGUID
+// ----------------------------------------------------------------------
+int WIN32API CONCRETE_IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
+{
+    return IsEqualGUID(rguid1, rguid2);
+}
+
+// ----------------------------------------------------------------------
+// ReadClassStm
+// ----------------------------------------------------------------------
+HRESULT WIN32API ReadClassStm(IStream *pStm, CLSID *rclsid)
+{
+    ULONG nbByte;
+    HRESULT res;
+
+    dprintf(("OLE32: ReadClassStm"));
+
+    if (rclsid == NULL)
+        return E_INVALIDARG;
+
+    res = IStream_Read(pStm,(void*)rclsid,sizeof(CLSID),&nbByte);
+
+    if (FAILED(res))
+        return res;
+
+    if (nbByte != sizeof(CLSID))
+        return S_FALSE;
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// WriteClassStm
+// ----------------------------------------------------------------------
+HRESULT WIN32API WriteClassStm(IStream *pStm, REFCLSID rclsid)
+{
+    dprintf(("OLE32: WriteClassStm"));
+
+    if (rclsid == NULL)
+        return E_INVALIDARG;
+
+    return IStream_Write(pStm, rclsid, sizeof(CLSID), NULL);
+}
+
+// ----------------------------------------------------------------------
+// ProgIDFromCLSID
+// ----------------------------------------------------------------------
+HRESULT WIN32API ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID)
+{
+    oStringA		tClsId(clsid);
+    oStringA		szKey("CLSID\\");
+    LONG		lDataLen = 255;
+    oStringA		szProgID(lDataLen, 1);
+    HKEY		hKey;
+    HRESULT		rc;
+    LPOLESTR		tmp;
+    LPMALLOC		pMllc;
+
+//    dprintf(("OLE32: ProgIDFromCLSID"));
+//    dprintf(("       clsid = %s", (char *)tClsId));
+
+    szKey += tClsId + "\\ProgID";
+
+    // Open key...
+    if (RegOpenKeyA(HKEY_CLASSES_ROOT, szKey, &hKey))
+    	return REGDB_E_CLASSNOTREG;
+
+    // Get default string from the key...
+    rc = RegQueryValueA(hKey, NULL, szProgID, &lDataLen);
+    RegCloseKey(hKey);
+    if (rc != 0)
+	return REGDB_E_CLASSNOTREG;
+
+    if (CoGetMalloc(0, &pMllc))		// Singleton instance, no need to release
+	return E_OUTOFMEMORY;
+
+    tmp = (LPOLESTR)IMalloc_Alloc(pMllc, (strlen(szProgID) + 1) * 2); 
+    if (tmp == NULL)
+	return E_OUTOFMEMORY;
+
+    AsciiToUnicode(szProgID, tmp);
+    *lplpszProgID = tmp;
+
+    return S_OK;
+}
Index: trunk/src/ole32/new/compositemoniker.cpp
===================================================================
--- trunk/src/ole32/new/compositemoniker.cpp	(revision 3456)
+++ trunk/src/ole32/new/compositemoniker.cpp	(revision 3456)
@@ -0,0 +1,1699 @@
+/* $Id: compositemoniker.cpp,v 1.1 2000-04-27 22:18:15 davidr Exp $ */
+/* 
+ * CompositeMonikers functions.
+ * 
+ * 20/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *   Copyright 1999  Noomen Hamza
+ */
+
+#include "ole32.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+#define  BLOCK_TAB_SIZE 5 /* represent the first size table and it's increment block size */
+
+/* CompositeMoniker data structure */
+typedef struct CompositeMonikerImpl{
+
+    ICOM_VTABLE(IMoniker)*  lpvtbl1;  /* VTable relative to the IMoniker interface.*/
+
+    /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether 
+     * two monikers are equal. That's whay IROTData interface is implemented by monikers.
+     */
+    ICOM_VTABLE(IROTData)*  lpvtbl2;  /* VTable relative to the IROTData interface.*/
+
+    ULONG ref; /* reference counter for this object */
+
+    IMoniker** tabMoniker; /* dynamaic table containing all components (monikers) of this composite moniker */
+
+    ULONG    tabSize;      /* size of tabMoniker */
+
+    ULONG    tabLastIndex;  /* first free index in tabMoniker */
+
+} CompositeMonikerImpl;
+
+
+/* EnumMoniker data structure */
+typedef struct EnumMonikerImpl{
+
+    ICOM_VTABLE(IEnumMoniker)*  lpvtbl;  /* VTable relative to the IEnumMoniker interface.*/
+
+    ULONG ref; /* reference counter for this object */
+
+    IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
+
+    ULONG      tabSize; /* size of tabMoniker */
+
+    ULONG      currentPos;  /* index pointer on the current moniker */
+
+} EnumMonikerImpl;
+
+
+/********************************************************************************/
+/* CompositeMoniker prototype functions :                                       */
+
+/* IUnknown prototype functions */
+static HRESULT WINAPI CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject);
+static ULONG   WINAPI CompositeMonikerImpl_AddRef(IMoniker* iface);
+static ULONG   WINAPI CompositeMonikerImpl_Release(IMoniker* iface);
+
+/* IPersist prototype functions */
+static HRESULT WINAPI CompositeMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID);
+
+/* IPersistStream prototype functions */
+static HRESULT WINAPI CompositeMonikerImpl_IsDirty(IMoniker* iface);
+static HRESULT WINAPI CompositeMonikerImpl_Load(IMoniker* iface, IStream* pStm);
+static HRESULT WINAPI CompositeMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty);
+static HRESULT WINAPI CompositeMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize);
+
+/* IMoniker prototype functions */
+static HRESULT WINAPI CompositeMonikerImpl_BindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult);
+static HRESULT WINAPI CompositeMonikerImpl_BindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult);
+static HRESULT WINAPI CompositeMonikerImpl_Reduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced);
+static HRESULT WINAPI CompositeMonikerImpl_ComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite);
+static HRESULT WINAPI CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker);
+static HRESULT WINAPI CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker);
+static HRESULT WINAPI CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash);
+static HRESULT WINAPI CompositeMonikerImpl_IsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning);
+static HRESULT WINAPI CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pCompositeTime);
+static HRESULT WINAPI CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk);
+static HRESULT WINAPI CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix);
+static HRESULT WINAPI CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath);
+static HRESULT WINAPI CompositeMonikerImpl_GetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName);
+static HRESULT WINAPI CompositeMonikerImpl_ParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut);
+static HRESULT WINAPI CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys);
+
+/********************************************************************************/
+/* IROTData prototype functions                                                 */
+
+/* IUnknown prototype functions */
+static HRESULT WINAPI CompositeMonikerROTDataImpl_QueryInterface(IROTData* iface,REFIID riid,VOID** ppvObject);
+static ULONG   WINAPI CompositeMonikerROTDataImpl_AddRef(IROTData* iface);
+static ULONG   WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface);
+
+/* IROTData prototype function */
+static HRESULT WINAPI CompositeMonikerROTDataImpl_GetComparaisonData(IROTData* iface,BYTE* pbData,ULONG cbMax,ULONG* pcbData);
+
+/* Local function used by CompositeMoniker implementation */
+HRESULT WINAPI CompositeMonikerImpl_Construct(CompositeMonikerImpl* This,LPMONIKER pmkFirst, LPMONIKER pmkRest);
+HRESULT WINAPI CompositeMonikerImpl_Destroy(CompositeMonikerImpl* iface);
+
+/********************************************************************************/
+/* IEnumMoniker prototype functions                                             */
+
+/* IUnknown prototype functions */
+static HRESULT WINAPI EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject);
+static ULONG   WINAPI EnumMonikerImpl_AddRef(IEnumMoniker* iface);
+static ULONG   WINAPI EnumMonikerImpl_Release(IEnumMoniker* iface);
+
+/* IEnumMonker prototype functions */
+static HRESULT WINAPI EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt,IMoniker** rgelt,ULONG* pceltFetched);
+static HRESULT WINAPI EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt);
+static HRESULT WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface);
+static HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum);
+
+HRESULT WINAPI EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk);
+
+/********************************************************************************/
+/* Virtual function table for the CompositeMonikerImpl class witch  include     */
+/* Ipersist, IPersistStream and IMoniker functions.                             */
+
+static ICOM_VTABLE(IMoniker) VT_CompositeMonikerImpl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    CompositeMonikerImpl_QueryInterface,
+    CompositeMonikerImpl_AddRef,
+    CompositeMonikerImpl_Release,
+    CompositeMonikerImpl_GetClassID,
+    CompositeMonikerImpl_IsDirty,
+    CompositeMonikerImpl_Load,
+    CompositeMonikerImpl_Save,
+    CompositeMonikerImpl_GetSizeMax,
+    CompositeMonikerImpl_BindToObject,
+    CompositeMonikerImpl_BindToStorage,
+    CompositeMonikerImpl_Reduce,
+    CompositeMonikerImpl_ComposeWith,
+    CompositeMonikerImpl_Enum,
+    CompositeMonikerImpl_IsEqual,
+    CompositeMonikerImpl_Hash,
+    CompositeMonikerImpl_IsRunning,
+    CompositeMonikerImpl_GetTimeOfLastChange,
+    CompositeMonikerImpl_Inverse,
+    CompositeMonikerImpl_CommonPrefixWith,
+    CompositeMonikerImpl_RelativePathTo,
+    CompositeMonikerImpl_GetDisplayName,
+    CompositeMonikerImpl_ParseDisplayName,
+    CompositeMonikerImpl_IsSystemMoniker
+};
+
+/********************************************************************************/
+/* Virtual function table for the IROTData class.                               */
+static ICOM_VTABLE(IROTData) VT_ROTDataImpl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    CompositeMonikerROTDataImpl_QueryInterface,
+    CompositeMonikerROTDataImpl_AddRef,
+    CompositeMonikerROTDataImpl_Release,
+    CompositeMonikerROTDataImpl_GetComparaisonData
+};
+
+/********************************************************************************/
+/* Virtual function table for the IROTData class                                */
+static ICOM_VTABLE(IEnumMoniker) VT_EnumMonikerImpl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    EnumMonikerImpl_QueryInterface,
+    EnumMonikerImpl_AddRef,
+    EnumMonikerImpl_Release,
+    EnumMonikerImpl_Next,
+    EnumMonikerImpl_Skip,
+    EnumMonikerImpl_Reset,
+    EnumMonikerImpl_Clone
+};
+
+/*******************************************************************************
+ *        CompositeMoniker_QueryInterface
+ *******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
+{
+    ICOM_THIS(CompositeMonikerImpl,iface);
+  
+    TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
+
+    /* Perform a sanity check on the parameters.*/
+    if ( (This==0) || (ppvObject==0) )
+	return E_INVALIDARG;
+  
+    /* Initialize the return parameter */
+    *ppvObject = 0;
+
+    /* Compare the riid with the interface IDs implemented by this object.*/
+    if (IsEqualIID(&IID_IUnknown, riid) ||
+        IsEqualIID(&IID_IPersist, riid) ||
+        IsEqualIID(&IID_IPersistStream, riid) ||
+        IsEqualIID(&IID_IMoniker, riid)
+       )
+        *ppvObject = iface;
+    else if (IsEqualIID(&IID_IROTData, riid))
+        *ppvObject = (IROTData*)&(This->lpvtbl2);
+
+    /* Check that we obtained an interface.*/
+    if ((*ppvObject)==0)
+        return E_NOINTERFACE;
+
+    /* Query Interface always increases the reference count by one when it is successful */
+    CompositeMonikerImpl_AddRef(iface);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_AddRef
+ ******************************************************************************/
+ULONG WINAPI CompositeMonikerImpl_AddRef(IMoniker* iface)
+{
+    ICOM_THIS(CompositeMonikerImpl,iface);
+
+    TRACE("(%p)\n",This);
+
+    return ++(This->ref);
+}
+
+/******************************************************************************
+ *        CompositeMoniker_Release
+ ******************************************************************************/
+ULONG WINAPI CompositeMonikerImpl_Release(IMoniker* iface)
+{
+    ICOM_THIS(CompositeMonikerImpl,iface);
+    ULONG i;
+    
+    TRACE("(%p)\n",This);
+
+    This->ref--;
+
+    /* destroy the object if there's no more reference on it */
+    if (This->ref==0){
+
+        /* release all the components before destroying this object */
+        for (i=0;i<This->tabLastIndex;i++)
+            IMoniker_Release(This->tabMoniker[i]);
+        
+        CompositeMonikerImpl_Destroy(This);
+
+        return 0;
+    }
+    return This->ref;;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_GetClassID
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
+{
+    TRACE("(%p,%p),stub!\n",iface,pClassID);
+
+    if (pClassID==NULL)
+        return E_POINTER;
+            
+    *pClassID = CLSID_CompositeMoniker;
+        
+    return S_OK;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_IsDirty
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_IsDirty(IMoniker* iface)
+{
+    /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
+       method in the OLE-provided moniker interfaces always return S_FALSE because
+       their internal state never changes. */
+
+    TRACE("(%p)\n",iface);
+
+    return S_FALSE;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_Load
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
+{
+    HRESULT res;
+    DWORD constant;
+    CLSID clsid;
+    WCHAR string[1]={0};
+    
+    ICOM_THIS(CompositeMonikerImpl,iface);    
+
+    TRACE("(%p,%p)\n",iface,pStm);
+
+    /* this function call OleLoadFromStream function for each moniker within this object */
+
+    /* read the a constant writen by CompositeMonikerImpl_Save (see CompositeMonikerImpl_Save for more details)*/
+    res=IStream_Read(pStm,&constant,sizeof(DWORD),NULL);
+
+    if (SUCCEEDED(res)&& constant!=3)
+        return E_FAIL;
+
+    while(1){
+#if 0
+        res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
+#endif
+        res=ReadClassStm(pStm,&clsid);
+        printf("res=%ld",res);
+        if (FAILED(res))
+            break;
+
+        if (IsEqualIID(&clsid,&CLSID_FileMoniker)){
+            res=CreateFileMoniker(string,&This->tabMoniker[This->tabLastIndex]);
+            if (FAILED(res))
+                break;
+            res=IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);
+            if (FAILED(res))
+                break;
+        }
+        else if (IsEqualIID(&clsid,&CLSID_ItemMoniker)){
+            CreateItemMoniker(string,string,&This->tabMoniker[This->tabLastIndex]);
+            if (res!=S_OK)
+                break;
+            IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);
+            if (FAILED(res))
+                break;
+        }
+        else if (IsEqualIID(&clsid,&CLSID_AntiMoniker)){
+            CreateAntiMoniker(&This->tabMoniker[This->tabLastIndex]);
+            if (FAILED(res))
+                break;
+            IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);
+            if (FAILED(res))
+                break;
+        }
+        else if (IsEqualIID(&clsid,&CLSID_CompositeMoniker))
+            return E_FAIL;
+
+        else{
+            FIXME("()");
+            break;
+            return E_NOTIMPL;
+        }
+
+        /* resize the table if needed */
+        if (++This->tabLastIndex==This->tabSize){
+                
+            This->tabSize+=BLOCK_TAB_SIZE;
+            This->tabMoniker=(IMoniker**)HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
+
+            if (This->tabMoniker==NULL)
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    return res;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_Save
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
+{
+    HRESULT res;
+    IEnumMoniker *enumMk;
+    IMoniker *pmk;
+    DWORD constant=3;
+    
+    TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
+
+    /* this function call OleSaveToStream function for each moniker within this object */
+
+    /* when I tested this function in windows system ! I usually found this constant in the begining of */
+    /* the stream  I dont known why (there's no indication in specification) ! */
+    res=IStream_Write(pStm,&constant,sizeof(constant),NULL);
+
+    IMoniker_Enum(iface,TRUE,&enumMk);
+
+    while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
+
+        res=OleSaveToStream((IPersistStream*)pmk,pStm);
+
+        IMoniker_Release(pmk);
+
+        if (FAILED(res)){
+
+            IEnumMoniker_Release(pmk);
+            return res;
+        }
+    }
+
+    IEnumMoniker_Release(enumMk);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_GetSizeMax
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
+{
+    IEnumMoniker *enumMk;
+    IMoniker *pmk;
+    ULARGE_INTEGER ptmpSize;
+
+    /* the sizeMax of this object is calculated by calling  GetSizeMax on each moniker within this object then */
+    /* suming all returned sizemax */
+
+    TRACE("(%p,%p)\n",iface,pcbSize);
+
+    if (pcbSize!=NULL)
+        return E_POINTER;
+
+    pcbSize->LowPart =0;
+    pcbSize->HighPart=0;
+
+    IMoniker_Enum(iface,TRUE,&enumMk);
+
+    while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==TRUE){
+
+        IMoniker_GetSizeMax(pmk,&ptmpSize);
+
+        IMoniker_Release(pmk);
+
+        pcbSize->LowPart +=ptmpSize.LowPart;
+        pcbSize->HighPart+=ptmpSize.HighPart;
+    }
+
+    IEnumMoniker_Release(enumMk);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *         Composite-Moniker_Construct (local function)
+ *******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_Construct(CompositeMonikerImpl* This,LPMONIKER pmkFirst, LPMONIKER pmkRest)
+{
+    DWORD mkSys;
+    IEnumMoniker *enumMoniker;
+    IMoniker *tempMk;
+    HRESULT res;
+    
+    TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);
+
+    /* Initialize the virtual fgunction table. */
+    This->lpvtbl1      = &VT_CompositeMonikerImpl;
+    This->lpvtbl2      = &VT_ROTDataImpl;
+    This->ref          = 0;
+
+    This->tabSize=BLOCK_TAB_SIZE;
+    This->tabLastIndex=0;
+
+    This->tabMoniker=(IMoniker**)HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(IMoniker));
+    if (This->tabMoniker==NULL)
+        return E_OUTOFMEMORY;
+
+    IMoniker_IsSystemMoniker(pmkFirst,&mkSys);
+
+    /* put the first moniker contents in the begining of the table */
+    if (mkSys!=MKSYS_GENERICCOMPOSITE){
+
+        This->tabMoniker[(This->tabLastIndex)++]=pmkFirst;
+        IMoniker_AddRef(pmkFirst);
+    }
+    else{
+
+        IMoniker_Enum(pmkFirst,TRUE,&enumMoniker);
+        
+        while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
+
+
+            if (++This->tabLastIndex==This->tabSize){
+                
+                This->tabSize+=BLOCK_TAB_SIZE;
+                This->tabMoniker=(IMoniker**)HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
+
+                if (This->tabMoniker==NULL)
+                    return E_OUTOFMEMORY;
+            }
+        }
+
+        IEnumMoniker_Release(enumMoniker);
+    }
+
+    /* put the rest moniker contents after the first one and make simplification if needed */
+
+    IMoniker_IsSystemMoniker(pmkRest,&mkSys);
+    
+    if (mkSys!=MKSYS_GENERICCOMPOSITE){
+
+        /* add a simple moniker to the moniker table */
+
+        res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk);
+
+        if (res==MK_E_NEEDGENERIC){ 
+
+            /* there's no simplification in this case */
+            This->tabMoniker[This->tabLastIndex]=pmkRest;
+
+            This->tabLastIndex++;
+
+            IMoniker_AddRef(pmkRest);
+        }
+        else if (tempMk==NULL){ 
+
+            /* we have an antimoniker after a simple moniker so we can make a simplification in this case */
+            IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
+
+            This->tabLastIndex--;
+        }
+        else if (SUCCEEDED(res)){
+
+            /* the non-generic composition was successful so we can make a simplification in this case */
+            IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
+
+            This->tabMoniker[This->tabLastIndex-1]=tempMk;
+        } else
+            return res;
+
+        /* resize tabMoniker if needed */
+        if (This->tabLastIndex==This->tabSize){
+                
+            This->tabSize+=BLOCK_TAB_SIZE;
+
+            This->tabMoniker=(IMoniker**)HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
+
+            if (This->tabMoniker==NULL)
+            return E_OUTOFMEMORY;
+        }
+    }
+    else{
+
+        /* add a composite moniker to the moniker table (do the same thing for each moniker within the */
+        /* composite moniker as a simple moniker (see above how to add a simple moniker case) ) */
+        IMoniker_Enum(pmkRest,TRUE,&enumMoniker);
+
+        while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
+
+            res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk);
+
+            if (res==MK_E_NEEDGENERIC){
+
+                This->tabLastIndex++;
+            }
+            else if (tempMk==NULL){
+
+                IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
+                IMoniker_Release(This->tabMoniker[This->tabLastIndex]);
+                This->tabLastIndex--;
+            }
+            else{
+
+                IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
+
+                This->tabMoniker[This->tabLastIndex-1]=tempMk;
+            }
+
+            if (This->tabLastIndex==This->tabSize){
+                
+                This->tabSize+=BLOCK_TAB_SIZE;
+
+                This->tabMoniker=(IMoniker**)HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
+
+                if (This->tabMoniker==NULL)
+                    return E_OUTOFMEMORY;
+            }
+        }
+
+        IEnumMoniker_Release(enumMoniker);
+    }
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_Destroy (local function)
+ *******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_Destroy(CompositeMonikerImpl* This)
+{
+    TRACE("(%p)\n",This);
+
+    HeapFree(GetProcessHeap(),0,This->tabMoniker);
+
+    HeapFree(GetProcessHeap(),0,This);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *                  CompositeMoniker_BindToObject
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_BindToObject(IMoniker* iface,
+                                                 IBindCtx* pbc,
+                                                 IMoniker* pmkToLeft,
+                                                 REFIID riid,
+                                                 VOID** ppvResult)
+{
+    HRESULT   res;
+    IRunningObjectTable *prot;
+    IMoniker *tempMk,*antiMk,*mostRigthMk;
+    IEnumMoniker *enumMoniker;
+    
+    TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
+
+    if (ppvResult==NULL)
+        return E_POINTER;
+    
+    *ppvResult=0;
+    /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
+    /* object for the requested interface pointer. */
+    if(pmkToLeft==NULL){
+
+        res=IBindCtx_GetRunningObjectTable(pbc,&prot);
+
+        if (SUCCEEDED(res)){
+
+            /* if the requested class was loaded befor ! we dont need to reload it */
+            res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
+
+            if (res==S_OK)
+                return res;
+        }
+    }
+    else{
+        /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
+        /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
+
+        IMoniker_Enum(iface,FALSE,&enumMoniker);
+        IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
+        IEnumMoniker_Release(enumMoniker);
+        
+        res=CreateAntiMoniker(&antiMk);
+        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
+        IMoniker_Release(antiMk);
+        
+        res=CompositeMonikerImpl_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult);
+
+        IMoniker_Release(tempMk);
+        IMoniker_Release(mostRigthMk);
+    }
+
+    return res;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_BindToStorage
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_BindToStorage(IMoniker* iface,
+                                                  IBindCtx* pbc,
+                                                  IMoniker* pmkToLeft,
+                                                  REFIID riid,
+                                                  VOID** ppvResult)
+{
+    HRESULT   res;
+    IMoniker *tempMk,*antiMk,*mostRigthMk;
+    IEnumMoniker *enumMoniker;
+
+    TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
+
+    *ppvResult=0;
+
+    /* This method recursively calls BindToStorage on the rightmost component of the composite, */
+    /* passing the rest of the composite as the pmkToLeft parameter for that call. */
+
+    if (pmkToLeft!=NULL){
+        
+        IMoniker_Enum(iface,FALSE,&enumMoniker);
+        IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
+        IEnumMoniker_Release(enumMoniker);
+        
+        res=CreateAntiMoniker(&antiMk);
+        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
+        IMoniker_Release(antiMk);
+        
+        res=CompositeMonikerImpl_BindToStorage(mostRigthMk,pbc,tempMk,riid,ppvResult);
+
+        IMoniker_Release(tempMk);
+
+        IMoniker_Release(mostRigthMk);
+
+        return res;
+    }
+    else
+        return IMoniker_BindToStorage(iface,pbc,NULL,riid,ppvResult);
+}
+
+/******************************************************************************
+ *        CompositeMoniker_Reduce
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_Reduce(IMoniker* iface,
+                                           IBindCtx* pbc,
+                                           DWORD dwReduceHowFar,
+                                           IMoniker** ppmkToLeft,
+                                           IMoniker** ppmkReduced)
+{
+    HRESULT   res;
+    IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk;
+    IEnumMoniker *enumMoniker;
+
+    TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
+
+    if (ppmkReduced==NULL)
+        return E_POINTER;
+
+    /* This method recursively calls Reduce for each of its component monikers. */
+
+    if (ppmkToLeft==NULL){
+
+        IMoniker_Enum(iface,FALSE,&enumMoniker);
+        IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
+        IEnumMoniker_Release(enumMoniker);
+        
+        res=CreateAntiMoniker(&antiMk);
+        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
+        IMoniker_Release(antiMk);
+
+        return CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
+    }
+    else if (*ppmkToLeft==NULL)
+
+        return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);
+
+    else{
+
+        /* separate the copmosite moniker in to left and wrigth moniker */
+        IMoniker_Enum(iface,FALSE,&enumMoniker);
+        IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
+        IEnumMoniker_Release(enumMoniker);
+        
+        res=CreateAntiMoniker(&antiMk);
+        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
+        IMoniker_Release(antiMk);
+
+        /* If any of the components  reduces itself, the method returns S_OK and passes back a composite */
+        /* of the reduced components */
+        if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) &&
+            CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk)
+           )
+
+            return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced);
+
+        else{
+            /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
+
+            IMoniker_AddRef(iface);
+
+            *ppmkReduced=iface;
+
+            return MK_S_REDUCED_TO_SELF;
+        }
+    }
+}
+
+/******************************************************************************
+ *        CompositeMoniker_ComposeWith
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_ComposeWith(IMoniker* iface,
+                                                IMoniker* pmkRight,
+                                                BOOL fOnlyIfNotGeneric,
+                                                IMoniker** ppmkComposite)
+{
+    TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
+
+    if ((ppmkComposite==NULL)||(pmkRight==NULL))
+	return E_POINTER;
+
+    *ppmkComposite=0;
+
+    /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */
+    /* otherwise, the method returns the result of combining the two monikers by calling the */
+    /* CreateGenericComposite function */
+    
+    if (fOnlyIfNotGeneric)
+        return MK_E_NEEDGENERIC;
+    
+    return CreateGenericComposite(iface,pmkRight,ppmkComposite);
+}
+
+/******************************************************************************
+ *        CompositeMoniker_Enum
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
+{
+    ICOM_THIS(CompositeMonikerImpl,iface);
+
+    TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
+
+    if (ppenumMoniker == NULL)
+        return E_POINTER;
+    
+    return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);
+}
+
+/******************************************************************************
+ *        CompositeMoniker_IsEqual
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
+{
+    IEnumMoniker *enumMoniker1,*enumMoniker2;
+    IMoniker *tempMk1,*tempMk2;
+    HRESULT res1,res2,res;
+    
+    TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
+
+    if (pmkOtherMoniker==NULL)
+        return S_FALSE;
+
+    /* This method returns S_OK if the components of both monikers are equal when compared in the */
+    /* left-to-right order.*/
+    IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);
+
+    if (enumMoniker1==NULL)
+        return S_FALSE;
+    
+    IMoniker_Enum(iface,TRUE,&enumMoniker2);
+
+    while(1){
+
+        res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
+        res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
+        
+        if((res1==S_OK)&&(res2==S_OK)){
+
+            if(IMoniker_IsEqual(tempMk1,tempMk2)==S_FALSE){
+                res= S_FALSE;
+                break;
+            }
+            else
+                continue;
+        }
+        else if ( (res1==S_FALSE) && (res2==S_FALSE) ){
+                res = S_OK;
+                break;
+        }
+        else{
+            res = S_FALSE;
+            break;
+        }
+
+        if (res1==S_OK)
+            IMoniker_Release(tempMk1);
+
+        if (res2==S_OK)
+            IMoniker_Release(tempMk2);
+    }
+
+    IEnumMoniker_Release(enumMoniker1);
+    IEnumMoniker_Release(enumMoniker2);
+
+    return res;
+}
+/******************************************************************************
+ *        CompositeMoniker_Hash
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
+{
+    FIXME("(),stub!\n");
+
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_IsRunning
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_IsRunning(IMoniker* iface,
+                                              IBindCtx* pbc,
+                                              IMoniker* pmkToLeft,
+                                              IMoniker* pmkNewlyRunning)
+{
+    IRunningObjectTable* rot;
+    HRESULT res;
+    IMoniker *tempMk,*antiMk,*mostRigthMk;
+    IEnumMoniker *enumMoniker;
+
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
+
+    /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/
+    if (pmkToLeft!=NULL){
+
+        CreateGenericComposite(pmkToLeft,iface,&tempMk);
+
+        res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);
+
+        IMoniker_Release(tempMk);
+
+        return res;
+    }
+    else
+        /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */
+        /* to this moniker */
+        
+        if (pmkNewlyRunning!=NULL)
+
+            if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)
+                return S_OK;
+
+            else
+                return S_FALSE;
+
+        else{
+
+            if (pbc==NULL)
+                return E_POINTER;
+
+            /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */
+            /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls   */
+            /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */
+            /* the composite as the pmkToLeft parameter for that call.                                   */
+            
+             res=IBindCtx_GetRunningObjectTable(pbc,&rot);
+
+            if (FAILED(res))
+                return res;
+
+            res = IRunningObjectTable_IsRunning(rot,iface);
+            IRunningObjectTable_Release(rot);
+
+            if(res==S_OK)
+                return S_OK;
+
+            else{
+
+                IMoniker_Enum(iface,FALSE,&enumMoniker);
+                IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
+                IEnumMoniker_Release(enumMoniker);
+
+                res=CreateAntiMoniker(&antiMk);
+                res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
+                IMoniker_Release(antiMk);
+
+                res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning);
+
+                IMoniker_Release(tempMk);
+                IMoniker_Release(mostRigthMk);
+
+                return res;
+            }
+        }
+}
+
+/******************************************************************************
+ *        CompositeMoniker_GetTimeOfLastChange
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface,
+                                                        IBindCtx* pbc,
+                                                        IMoniker* pmkToLeft,
+                                                        FILETIME* pCompositeTime)
+{
+    IRunningObjectTable* rot;
+    HRESULT res;
+    IMoniker *tempMk,*antiMk,*mostRigthMk;
+    IEnumMoniker *enumMoniker;
+    
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);
+
+    if (pCompositeTime==NULL)
+        return E_INVALIDARG;
+
+    /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to  */
+    /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls  */
+    /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */
+    /* of the composite as the pmkToLeft parameter for that call.                                       */
+    if (pmkToLeft!=NULL){
+
+        res=CreateGenericComposite(pmkToLeft,iface,&tempMk);
+
+        res=IBindCtx_GetRunningObjectTable(pbc,&rot);
+
+        if (FAILED(res))
+            return res;
+
+        if (IRunningObjectTable_GetTimeOfLastChange(rot,tempMk,pCompositeTime)==S_OK)
+            return res;
+        else
+
+            IMoniker_Enum(iface,FALSE,&enumMoniker);
+            IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
+            IEnumMoniker_Release(enumMoniker);
+
+            res=CreateAntiMoniker(&antiMk);
+            res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
+            IMoniker_Release(antiMk);
+
+            res=CompositeMonikerImpl_GetTimeOfLastChange(mostRigthMk,pbc,tempMk,pCompositeTime);
+
+            IMoniker_Release(tempMk);
+            IMoniker_Release(mostRigthMk);
+
+            return res;
+    }
+    else
+        return IMoniker_GetTimeOfLastChange(iface,pbc,NULL,pCompositeTime);
+}
+
+/******************************************************************************
+ *        CompositeMoniker_Inverse
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
+{
+    HRESULT res;
+    IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk;
+    IEnumMoniker *enumMoniker;
+
+    TRACE("(%p,%p)\n",iface,ppmk);
+
+    if (ppmk==NULL)
+        return E_POINTER;
+
+    /* This method returns a composite moniker that consists of the inverses of each of the components */
+    /* of the original composite, stored in reverse order */
+
+    res=CreateAntiMoniker(&antiMk);
+    res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
+    IMoniker_Release(antiMk);
+
+    if (tempMk==NULL)
+
+        return IMoniker_Inverse(iface,ppmk);
+
+    else{
+
+        IMoniker_Enum(iface,FALSE,&enumMoniker);
+        IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
+        IEnumMoniker_Release(enumMoniker);
+
+        IMoniker_Inverse(mostRigthMk,&mostRigthInvMk);
+        CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);
+
+        res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk);
+
+        IMoniker_Release(tempMk);
+        IMoniker_Release(mostRigthMk);
+        IMoniker_Release(tempInvMk);
+        IMoniker_Release(mostRigthInvMk);
+
+        return res;
+    }
+}
+
+/******************************************************************************
+ *        CompositeMoniker_CommonPrefixWith
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
+{
+    DWORD mkSys;
+    HRESULT res1,res2;
+    IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
+    IEnumMoniker *enumMoniker1,*enumMoniker2;
+    ULONG i,nbCommonMk=0;
+    
+    /* If the other moniker is a composite, this method compares the components of each composite from left  */
+    /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
+    /* of the leftmost components were common to both monikers.                                              */
+
+    if (ppmkPrefix==NULL)
+        return E_POINTER;
+    
+    *ppmkPrefix=0;
+
+    if (pmkOther==NULL)
+        return MK_E_NOPREFIX;
+    
+    IMoniker_IsSystemMoniker(pmkOther,&mkSys);
+
+    if((mkSys==MKSYS_GENERICCOMPOSITE)){
+
+        IMoniker_Enum(iface,TRUE,&enumMoniker1);
+        IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
+
+        while(1){
+
+            res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
+            res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
+
+            if ((res1==S_FALSE) && (res2==S_FALSE)){
+
+                /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
+                *ppmkPrefix=iface;
+                IMoniker_AddRef(iface);
+                return  MK_S_US;
+            }
+            else if ((res1==S_OK) && (res2==S_OK)){
+
+                if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
+
+                    nbCommonMk++;
+
+                else
+                    break;
+
+            }
+            else if (res1==S_OK){
+
+                /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
+                /* ppmkPrefix to the other moniker.                                                       */
+                *ppmkPrefix=pmkOther;
+                return MK_S_HIM;
+            }
+            else{
+                /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
+                /* to this moniker.                                                                          */
+                *ppmkPrefix=iface;
+                return MK_S_ME;
+            }
+        }
+
+        IEnumMoniker_Release(enumMoniker1);
+        IEnumMoniker_Release(enumMoniker2);
+
+        /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
+        if (nbCommonMk==0)
+            return MK_E_NOPREFIX;
+
+        IEnumMoniker_Reset(enumMoniker1);
+
+        IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
+
+        /* if we have more than one commun moniker the result will be a composite moniker */
+        if (nbCommonMk>1){
+
+            /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
+            IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
+            CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
+            IMoniker_Release(tempMk1);
+            IMoniker_Release(tempMk2);
+            
+            /* compose all common monikers in a composite moniker */
+            for(i=0;i<nbCommonMk;i++){
+
+                IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
+
+                CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
+
+                IMoniker_Release(*ppmkPrefix);
+
+                IMoniker_Release(tempMk1);
+                
+                *ppmkPrefix=tempMk2;
+            }
+            return S_OK;
+        }
+        else{
+            /* if we have only one commun moniker the result will be a simple moniker which is the most-left one*/
+            *ppmkPrefix=tempMk1;
+
+            return S_OK;
+        }
+    }
+    else{
+        /* If the other moniker is not a composite, the method simply compares it to the leftmost component
+         of this moniker.*/
+
+        IMoniker_Enum(iface,TRUE,&enumMoniker1);
+
+        IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
+
+        if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){
+
+            *ppmkPrefix=pmkOther;
+
+            return MK_S_HIM;
+        }
+        else
+            return MK_E_NOPREFIX;
+    }
+}
+/***************************************************************************************************
+ *        GetAfterCommonPrefix (local function)
+ *  This function returns a moniker that consist of the remainder when the common prefix is removed
+ ***************************************************************************************************/
+VOID WINAPI GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk)
+{
+    IMoniker *tempMk,*tempMk1,*tempMk2;
+    IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3;
+    ULONG nbRestMk=0;
+    DWORD mkSys;
+    HRESULT res1,res2;
+    
+    *restMk=0;
+
+    /* to create an enumerator for pGenMk with current position pointed on the first element after common  */
+    /* prefix: enum the two monikers (left-wrigth) then compare these enumerations (left-wrigth) and stop  */
+    /* on the first difference. */
+    IMoniker_Enum(pGenMk,TRUE,&enumMoniker1);
+
+    IMoniker_IsSystemMoniker(commonMk,&mkSys);
+
+    if (mkSys==MKSYS_GENERICCOMPOSITE){
+
+        IMoniker_Enum(commonMk,TRUE,&enumMoniker2);
+        while(1){
+
+            res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
+            res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
+
+            if ((res1==S_FALSE)||(res2==S_FALSE)){
+
+                if (res1==S_OK)
+
+                    nbRestMk++;
+
+                IMoniker_Release(tempMk1);
+                IMoniker_Release(tempMk1);
+
+                break;
+            }
+            IMoniker_Release(tempMk1);
+            IMoniker_Release(tempMk1);
+        }
+    }
+    else{
+        IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
+        IMoniker_Release(tempMk1);
+    }
+
+    /* count the number of elements in the enumerator after the common prefix */
+    IEnumMoniker_Clone(enumMoniker1,&enumMoniker3);
+
+    for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++)
+
+        IMoniker_Release(tempMk);;
+
+    if (nbRestMk==0)
+        return;
+
+    /* create a generic composite moniker with monikers located after the common prefix */
+    IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
+
+    if (nbRestMk==1){
+
+        *restMk= tempMk1;
+        return;
+    }
+    else {
+
+        IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
+
+        CreateGenericComposite(tempMk1,tempMk2,restMk);
+
+        IMoniker_Release(tempMk1);
+
+        IMoniker_Release(tempMk2);
+
+        while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){
+
+            CreateGenericComposite(*restMk,tempMk1,&tempMk2);
+
+            IMoniker_Release(tempMk1);
+
+            IMoniker_Release(*restMk);
+
+            *restMk=tempMk2;
+        }
+    }
+}
+/******************************************************************************
+ *        CompositeMoniker_RelativePathTo
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkRelPath)
+{
+    HRESULT res;
+    IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0;
+
+    TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath);
+
+    if (ppmkRelPath==NULL)
+        return E_POINTER;
+
+    *ppmkRelPath=0;
+
+    /* This method finds the common prefix of the two monikers and creates two monikers that consist     */
+    /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */
+    /* of this moniker and composes the remainder of the other moniker on the right of it.               */
+
+    /* finds the common prefix of the two monikers */
+    res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk);    
+
+    /* if there's no common prefix or the two moniker are equal the relative is the other moniker */
+    if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){
+
+        *ppmkRelPath=pmkOther;
+        IMoniker_AddRef(pmkOther);
+        return MK_S_HIM;
+    }
+
+    GetAfterCommonPrefix(iface,commonMk,&restThisMk);
+    GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk);
+
+    /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */
+    /* moniker when the common prefix is removed                                                           */
+    if (res==MK_S_HIM){
+
+        IMoniker_Inverse(restThisMk,ppmkRelPath);
+        IMoniker_Release(restThisMk);
+    }
+    /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */
+    /* when the common prefix is removed                                                                     */
+    else if (res==MK_S_ME){
+
+        *ppmkRelPath=restOtherMk;
+        IMoniker_AddRef(restOtherMk);
+    }
+    /* the relative path is the inverse for the remainder of this moniker and the remainder of the other  */
+    /* moniker on the right of it.                                                                        */
+    else if (res==S_OK){
+
+        IMoniker_Inverse(restThisMk,&invRestThisMk);
+        IMoniker_Release(restThisMk);
+        CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath);
+        IMoniker_Release(invRestThisMk);
+        IMoniker_Release(restOtherMk);
+    }
+    return S_OK;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_GetDisplayName
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_GetDisplayName(IMoniker* iface,
+                                                   IBindCtx* pbc,
+                                                   IMoniker* pmkToLeft,
+                                                   LPOLESTR *ppszDisplayName)
+{
+    ULONG lengthStr=1;
+    IEnumMoniker *enumMoniker;
+    IMoniker* tempMk;
+    LPOLESTR tempStr;
+
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
+
+    if (ppszDisplayName==NULL)
+        return E_POINTER;
+    
+    *ppszDisplayName=(WCHAR*)CoTaskMemAlloc(sizeof(WCHAR));
+
+    if (*ppszDisplayName==NULL)
+        return E_OUTOFMEMORY;
+
+    /* This method returns the concatenation of the display names returned by each component moniker of */
+    /* the composite */
+
+    **ppszDisplayName=0;
+
+    IMoniker_Enum(iface,TRUE,&enumMoniker);
+    
+    while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
+
+        IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr);
+
+        lengthStr+=lstrlenW(tempStr);
+
+        *ppszDisplayName=(WCHAR*)CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));
+
+        if (*ppszDisplayName==NULL)
+            return E_OUTOFMEMORY;
+
+        lstrcatW(*ppszDisplayName,tempStr);
+
+        CoTaskMemFree(tempStr);
+        IMoniker_Release(tempMk);
+    }
+
+    IEnumMoniker_Release(enumMoniker);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_ParseDisplayName
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_ParseDisplayName(IMoniker* iface,
+                                                     IBindCtx* pbc,
+                                                     IMoniker* pmkToLeft,
+                                                     LPOLESTR pszDisplayName,
+                                                     ULONG* pchEaten,
+                                                     IMoniker** ppmkOut)
+{
+    IEnumMoniker *enumMoniker;
+    IMoniker *tempMk,*mostRigthMk,*antiMk;
+    /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/
+    /* passing everything else as the pmkToLeft parameter for that call. */
+
+    /* get the most rigth moniker */
+    IMoniker_Enum(iface,FALSE,&enumMoniker);
+    IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
+    IEnumMoniker_Release(enumMoniker);
+
+    /* get the left  moniker */
+    CreateAntiMoniker(&antiMk);
+    IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
+    IMoniker_Release(antiMk);
+
+    return IMoniker_ParseDisplayName(mostRigthMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut);
+}
+
+/******************************************************************************
+ *        CompositeMoniker_IsSystemMonker
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
+{
+    TRACE("(%p,%p)\n",iface,pwdMksys);
+
+    if (!pwdMksys)
+        return E_POINTER;
+    
+    (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
+
+    return S_OK;
+}
+
+/*******************************************************************************
+ *        CompositeMonikerIROTData_QueryInterface
+ *******************************************************************************/
+HRESULT WINAPI CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
+{
+
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+
+    TRACE("(%p,%p,%p)\n",iface,riid,ppvObject);
+
+    return CompositeMonikerImpl_QueryInterface(This, riid, ppvObject);
+}
+
+/***********************************************************************
+ *        CompositeMonikerIROTData_AddRef
+ */
+ULONG   WINAPI CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
+{
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+
+    TRACE("(%p)\n",iface);
+
+    return CompositeMonikerImpl_AddRef(This);
+}
+
+/***********************************************************************
+ *        CompositeMonikerIROTData_Release
+ */
+ULONG   WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
+{
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+    
+    TRACE("(%p)\n",iface);
+
+    return CompositeMonikerImpl_Release(This);
+}
+
+/******************************************************************************
+ *        CompositeMonikerIROTData_GetComparaisonData
+ ******************************************************************************/
+HRESULT WINAPI CompositeMonikerROTDataImpl_GetComparaisonData(IROTData* iface,
+                                                              BYTE* pbData,
+                                                              ULONG cbMax,
+                                                              ULONG* pcbData)
+{
+    FIXME("(),stub!\n");
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_QueryInterface
+ ******************************************************************************/
+HRESULT WINAPI EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
+{
+    ICOM_THIS(EnumMonikerImpl,iface);
+  
+    TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
+
+    /* Perform a sanity check on the parameters.*/
+    if ( (This==0) || (ppvObject==0) )
+	return E_INVALIDARG;
+  
+    /* Initialize the return parameter */
+    *ppvObject = 0;
+
+    /* Compare the riid with the interface IDs implemented by this object.*/
+    if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
+        *ppvObject = iface;
+
+    /* Check that we obtained an interface.*/
+    if ((*ppvObject)==0)
+        return E_NOINTERFACE;
+
+    /* Query Interface always increases the reference count by one when it is successful */
+    EnumMonikerImpl_AddRef(iface);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_AddRef
+ ******************************************************************************/
+ULONG   WINAPI EnumMonikerImpl_AddRef(IEnumMoniker* iface)
+{
+    ICOM_THIS(EnumMonikerImpl,iface);
+
+    TRACE("(%p)\n",This);
+
+    return ++(This->ref);
+
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_Release
+ ******************************************************************************/
+ULONG   WINAPI EnumMonikerImpl_Release(IEnumMoniker* iface)
+{
+    ICOM_THIS(EnumMonikerImpl,iface);
+    ULONG i
+        ;
+    TRACE("(%p)\n",This);
+
+    This->ref--;
+
+    /* destroy the object if there's no more reference on it */
+    if (This->ref==0){
+        
+        for(i=0;i<This->tabSize;i++)
+            IMoniker_Release(This->tabMoniker[i]);
+
+        HeapFree(GetProcessHeap(),0,This->tabMoniker);
+        HeapFree(GetProcessHeap(),0,This);
+
+        return 0;
+    }
+    return This->ref;;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_Next
+ ******************************************************************************/
+HRESULT WINAPI EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt, ULONG* pceltFethed){
+
+    ICOM_THIS(EnumMonikerImpl,iface);
+    ULONG i;
+
+    /* retrieve the requested number of moniker from the current position */
+    for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++)
+
+        rgelt[i]=This->tabMoniker[This->currentPos++];
+
+    if (pceltFethed!=NULL)
+        *pceltFethed= i;
+    
+    if (i==celt)
+        return S_OK;
+    else
+        return S_FALSE;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_Skip
+ ******************************************************************************/
+HRESULT WINAPI EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt){
+
+    ICOM_THIS(EnumMonikerImpl,iface);
+
+    if ((This->currentPos+celt) >= This->tabSize)
+        return S_FALSE;
+
+    This->currentPos+=celt;
+    
+    return S_OK;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_Reset
+ ******************************************************************************/
+HRESULT WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface){
+
+    ICOM_THIS(EnumMonikerImpl,iface);
+
+    This->currentPos=0;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_Clone
+ ******************************************************************************/
+HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum){
+
+    ICOM_THIS(EnumMonikerImpl,iface);
+
+    return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_CreateEnumMoniker
+ ******************************************************************************/
+HRESULT WINAPI EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,
+                                                 ULONG tabSize,
+                                                 ULONG currentPos,
+                                                 BOOL leftToRigth,
+                                                 IEnumMoniker ** ppmk)
+{
+    EnumMonikerImpl* newEnumMoniker;
+    int i;
+
+
+    newEnumMoniker = (EnumMonikerImpl*)HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
+
+    if (newEnumMoniker == 0)
+        return STG_E_INSUFFICIENTMEMORY;
+
+    if (currentPos > tabSize)
+        return E_INVALIDARG;
+    
+    /* Initialize the virtual function table. */
+    newEnumMoniker->lpvtbl      = &VT_EnumMonikerImpl;
+    newEnumMoniker->ref          = 0;
+
+    newEnumMoniker->tabSize=tabSize;
+    newEnumMoniker->currentPos=currentPos;
+
+    newEnumMoniker->tabMoniker=(IMoniker**)HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(IMoniker));
+
+    if (newEnumMoniker->tabMoniker==NULL)
+        return E_OUTOFMEMORY;
+
+    if (leftToRigth)
+        for (i=0;i<tabSize;i++){
+
+            newEnumMoniker->tabMoniker[i]=tabMoniker[i];
+            IMoniker_AddRef(tabMoniker[i]);
+        }
+    else
+        for (i=tabSize-1;i>=0;i--){
+
+            newEnumMoniker->tabMoniker[tabSize-i-1]=tabMoniker[i];
+            IMoniker_AddRef(tabMoniker[i]);
+        }
+
+    *ppmk=(IEnumMoniker*)newEnumMoniker;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        CreateCompositeMoniker	[OLE.55]
+ ******************************************************************************/
+HRESULT WINAPI CreateGenericComposite(LPMONIKER pmkFirst, LPMONIKER pmkRest, LPMONIKER* ppmkComposite)
+{
+    CompositeMonikerImpl* newCompositeMoniker = 0;
+    HRESULT        hr = S_OK;
+
+    TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite);
+
+    if (ppmkComposite==NULL)
+        return E_POINTER;
+    
+    *ppmkComposite=0;
+
+    if (pmkFirst==NULL && pmkRest!=NULL){
+
+        *ppmkComposite=pmkRest;
+        return S_OK;
+    }
+    else if (pmkFirst!=NULL && pmkRest==NULL){
+        *ppmkComposite=pmkFirst;
+        return S_OK;
+    }
+    else  if (pmkFirst==NULL && pmkRest==NULL)
+        return S_OK;
+
+    newCompositeMoniker = (CompositeMonikerImpl*)HeapAlloc(GetProcessHeap(), 0,sizeof(CompositeMonikerImpl));
+
+    if (newCompositeMoniker == 0)
+        return STG_E_INSUFFICIENTMEMORY;
+
+    hr = CompositeMonikerImpl_Construct(newCompositeMoniker,pmkFirst,pmkRest);
+
+    if (FAILED(hr)){
+
+        HeapFree(GetProcessHeap(),0,newCompositeMoniker);
+        return hr;
+    }
+    if (newCompositeMoniker->tabLastIndex==1)
+
+        hr = IMoniker_QueryInterface(newCompositeMoniker->tabMoniker[0],&IID_IMoniker,(void**)ppmkComposite);
+    else
+
+        hr = CompositeMonikerImpl_QueryInterface((IMoniker*)newCompositeMoniker,&IID_IMoniker,(void**)ppmkComposite);
+
+    return hr;
+}
+
+/******************************************************************************
+ *        MonikerCommonPrefixWith	[OLE.55]
+ ******************************************************************************/
+HRESULT WINAPI MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
+{
+    FIXME("(),stub!\n");
+    return E_NOTIMPL;
+}
+
+
Index: trunk/src/ole32/new/datacache.cpp
===================================================================
--- trunk/src/ole32/new/datacache.cpp	(revision 3456)
+++ trunk/src/ole32/new/datacache.cpp	(revision 3456)
@@ -0,0 +1,1891 @@
+/* $Id: datacache.cpp,v 1.1 2000-04-27 22:18:16 davidr Exp $ */
+/* 
+ *  OLE 2 Data cache
+ * 
+ * 21/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *   Copyright 1999  Francis Beaudet
+ *
+ * NOTES:
+ *    The OLE2 data cache supports a whole whack of
+ *    interfaces including:
+ *       IDataObject, IPersistStorage, IViewObject2,
+ *       IOleCache2 and IOleCacheControl.
+ *
+ *    Most of the implementation details are taken from: Inside OLE
+ *    second edition by Kraig Brockschmidt,
+ *
+ * NOTES
+ *  -  This implementation of the datacache will let your application
+ *     load documents that have embedded OLE objects in them and it will
+ *     also retrieve the metafile representation of those objects. 
+ *  -  This implementation of the datacache will also allow your
+ *     application to save new documents with OLE objects in them.
+ *  -  The main thing that it doesn't do is allow you to activate 
+ *     or modify the OLE objects in any way.
+ *  -  I haven't found any good documentation on the real usage of
+ *     the streams created by the data cache. In particular, How to
+ *     determine what the XXX stands for in the stream name
+ *     "\002OlePresXXX". I have an intuition that This is related to
+ *     the cached aspect of the object but I'm not sure it could
+ *     just be a counter.
+ *  -  Also, I don't know the real content of the presentation stream
+ *     header. I was able to figure-out where the extent of the object 
+ *     was stored but that's about it.
+ */
+
+#include "ole32.h"
+#include "heapstring.h"
+#include "debugtools.h"
+
+#include <assert.h>
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+/****************************************************************************
+ * PresentationDataHeader
+ *
+ * This structure represents the header of the \002OlePresXXX stream in
+ * the OLE object strorage.
+ *
+ * Most fields are still unknown.
+ */
+typedef struct PresentationDataHeader
+{
+  DWORD unknown1;
+  DWORD unknown2;
+  DWORD unknown3;
+  DWORD unknown4;
+  DWORD unknown5;
+
+  DWORD unknown6;
+  DWORD unknown7;
+  DWORD objectExtentX;
+  DWORD objectExtentY;
+  DWORD unknown8;
+} PresentationDataHeader;
+
+/****************************************************************************
+ * DataCache
+ */
+struct DataCache
+{
+  /*
+   * List all interface VTables here
+   */
+  ICOM_VTABLE(IDataObject)*      lpvtbl1; 
+  ICOM_VTABLE(IUnknown)*         lpvtbl2;
+  ICOM_VTABLE(IPersistStorage)*  lpvtbl3;
+  ICOM_VTABLE(IViewObject2)*     lpvtbl4;  
+  ICOM_VTABLE(IOleCache2)*       lpvtbl5;
+  ICOM_VTABLE(IOleCacheControl)* lpvtbl6;
+
+  /*
+   * Reference count of This object
+   */
+  ULONG ref;
+
+  /*
+   * IUnknown implementation of the outer object.
+   */
+  IUnknown* outerUnknown;
+
+  /*
+   * This storage pointer is set through a call to
+   * IPersistStorage_Load. This is where the visual
+   * representation of the object is stored.
+   */
+  IStorage* presentationStorage;
+
+  /*
+   * The user of This object can setup ONE advise sink
+   * connection with the object. These parameters describe
+   * that connection.
+   */
+  DWORD        sinkAspects;
+  DWORD        sinkAdviseFlag;
+  IAdviseSink* sinkInterface;
+
+};
+
+typedef struct DataCache DataCache;
+
+/*
+ * Here, I define utility macros to help with the casting of the 
+ * "This" parameter.
+ * There is a version to accomodate all of the VTables implemented
+ * by This object.
+ */
+#define _ICOM_THIS_From_IDataObject(class,name)       class* This = (class*)name;
+#define _ICOM_THIS_From_NDIUnknown(class, name)       class* This = (class*)(((char*)name)-sizeof(void*)); 
+#define _ICOM_THIS_From_IPersistStorage(class, name)  class* This = (class*)(((char*)name)-2*sizeof(void*)); 
+#define _ICOM_THIS_From_IViewObject2(class, name)     class* This = (class*)(((char*)name)-3*sizeof(void*)); 
+#define _ICOM_THIS_From_IOleCache2(class, name)       class* This = (class*)(((char*)name)-4*sizeof(void*)); 
+#define _ICOM_THIS_From_IOleCacheControl(class, name) class* This = (class*)(((char*)name)-5*sizeof(void*)); 
+
+/*
+ * Prototypes for the methods of the DataCache class.
+ */
+static DataCache* DataCache_Construct(REFCLSID  clsid,
+				      LPUNKNOWN pUnkOuter);
+static void       DataCache_Destroy(DataCache* ptrToDestroy);
+static HRESULT    DataCache_ReadPresentationData(DataCache*              This,
+						 DWORD                   drawAspect,
+						 PresentationDataHeader* header);
+static HRESULT    DataCache_FindPresStreamName(DataCache* This,
+					       DWORD      drawAspect,
+					       OLECHAR*   buffer);
+static HMETAFILE  DataCache_ReadPresMetafile(DataCache* This,
+					     DWORD      drawAspect);
+static void       DataCache_FireOnViewChange(DataCache* This,
+					     DWORD      aspect,
+					     LONG       lindex);
+
+/*
+ * Prototypes for the methods of the DataCache class
+ * that implement non delegating IUnknown methods.
+ */
+static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
+            IUnknown*      iface,
+            REFIID         riid,
+            void**         ppvObject);
+static ULONG WINAPI DataCache_NDIUnknown_AddRef( 
+            IUnknown*      iface);
+static ULONG WINAPI DataCache_NDIUnknown_Release( 
+            IUnknown*      iface);
+
+/*
+ * Prototypes for the methods of the DataCache class
+ * that implement IDataObject methods.
+ */
+static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
+            IDataObject*     iface,
+            REFIID           riid,
+            void**           ppvObject);
+static ULONG WINAPI DataCache_IDataObject_AddRef( 
+            IDataObject*     iface);
+static ULONG WINAPI DataCache_IDataObject_Release( 
+            IDataObject*     iface);
+static HRESULT WINAPI DataCache_GetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetcIn, 
+	    STGMEDIUM*       pmedium);
+static HRESULT WINAPI DataCache_GetDataHere(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatetc,
+	    STGMEDIUM*       pmedium);
+static HRESULT WINAPI DataCache_QueryGetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc);
+static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatectIn, 
+	    LPFORMATETC      pformatetcOut);
+static HRESULT WINAPI DataCache_IDataObject_SetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc, 
+	    STGMEDIUM*       pmedium, 
+	    BOOL             fRelease);
+static HRESULT WINAPI DataCache_EnumFormatEtc(
+	    IDataObject*     iface,       
+	    DWORD            dwDirection,
+	    IEnumFORMATETC** ppenumFormatEtc);
+static HRESULT WINAPI DataCache_DAdvise(
+	    IDataObject*     iface, 
+	    FORMATETC*       pformatetc, 
+	    DWORD            advf, 
+	    IAdviseSink*     pAdvSink, 
+	    DWORD*           pdwConnection);
+static HRESULT WINAPI DataCache_DUnadvise(
+	    IDataObject*     iface,
+	    DWORD            dwConnection);
+static HRESULT WINAPI DataCache_EnumDAdvise(
+	    IDataObject*     iface,
+	    IEnumSTATDATA**  ppenumAdvise);
+
+/*
+ * Prototypes for the methods of the DataCache class
+ * that implement IPersistStorage methods.
+ */
+static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
+            IPersistStorage* iface,
+            REFIID           riid,
+            void**           ppvObject);
+static ULONG WINAPI DataCache_IPersistStorage_AddRef( 
+            IPersistStorage* iface);
+static ULONG WINAPI DataCache_IPersistStorage_Release( 
+            IPersistStorage* iface);
+static HRESULT WINAPI DataCache_GetClassID( 
+            IPersistStorage* iface,
+	    CLSID*           pClassID);
+static HRESULT WINAPI DataCache_IsDirty( 
+            IPersistStorage* iface);
+static HRESULT WINAPI DataCache_InitNew( 
+            IPersistStorage* iface, 
+	    IStorage*        pStg);
+static HRESULT WINAPI DataCache_Load( 
+            IPersistStorage* iface,
+	    IStorage*        pStg);
+static HRESULT WINAPI DataCache_Save( 
+            IPersistStorage* iface,
+	    IStorage*        pStg, 
+	    BOOL             fSameAsLoad);
+static HRESULT WINAPI DataCache_SaveCompleted( 
+            IPersistStorage* iface,  
+	    IStorage*        pStgNew);
+static HRESULT WINAPI DataCache_HandsOffStorage(
+            IPersistStorage* iface);
+
+/*
+ * Prototypes for the methods of the DataCache class
+ * that implement IViewObject2 methods.
+ */
+static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
+            IViewObject2* iface,
+            REFIID           riid,
+            void**           ppvObject);
+static ULONG WINAPI DataCache_IViewObject2_AddRef( 
+            IViewObject2* iface);
+static ULONG WINAPI DataCache_IViewObject2_Release( 
+            IViewObject2* iface);
+static HRESULT WINAPI DataCache_Draw(
+            IViewObject2*    iface,
+	    DWORD            dwDrawAspect,
+	    LONG             lindex,
+	    void*            pvAspect,
+	    DVTARGETDEVICE*  ptd, 
+	    HDC              hdcTargetDev, 
+	    HDC              hdcDraw,
+	    LPCRECTL         lprcBounds,
+	    LPCRECTL         lprcWBounds,
+	    IVO_ContCallback pfnContinue,
+	    DWORD            dwContinue);
+static HRESULT WINAPI DataCache_GetColorSet(
+            IViewObject2*   iface, 
+	    DWORD           dwDrawAspect, 
+	    LONG            lindex, 
+	    void*           pvAspect, 
+	    DVTARGETDEVICE* ptd, 
+	    HDC             hicTargetDevice, 
+	    tagLOGPALETTE**    ppColorSet);
+static HRESULT WINAPI DataCache_Freeze(
+            IViewObject2*   iface,
+	    DWORD           dwDrawAspect,
+	    LONG            lindex,
+	    void*           pvAspect, 
+	    DWORD*          pdwFreeze);
+static HRESULT WINAPI DataCache_Unfreeze(
+            IViewObject2*   iface,
+	    DWORD           dwFreeze);
+static HRESULT WINAPI DataCache_SetAdvise(
+            IViewObject2*   iface,
+	    DWORD           aspects, 
+	    DWORD           advf, 
+	    IAdviseSink*    pAdvSink);
+static HRESULT WINAPI DataCache_GetAdvise(
+            IViewObject2*   iface, 
+	    DWORD*          pAspects, 
+	    DWORD*          pAdvf, 
+	    IAdviseSink**   ppAdvSink);
+static HRESULT WINAPI DataCache_GetExtent(
+            IViewObject2*   iface, 
+	    DWORD           dwDrawAspect, 
+	    LONG            lindex, 
+	    DVTARGETDEVICE* ptd, 
+	    LPSIZEL         lpsizel);
+
+/*
+ * Prototypes for the methods of the DataCache class
+ * that implement IOleCache2 methods.
+ */
+static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
+            IOleCache2*     iface,
+            REFIID          riid,
+            void**          ppvObject);
+static ULONG WINAPI DataCache_IOleCache2_AddRef( 
+            IOleCache2*     iface);
+static ULONG WINAPI DataCache_IOleCache2_Release( 
+            IOleCache2*     iface);
+static HRESULT WINAPI DataCache_Cache(
+            IOleCache2*     iface,
+	    FORMATETC*      pformatetc,
+	    DWORD           advf,
+	    DWORD*          pdwConnection);
+static HRESULT WINAPI DataCache_Uncache(
+	    IOleCache2*     iface,
+	    DWORD           dwConnection);
+static HRESULT WINAPI DataCache_EnumCache(
+            IOleCache2*     iface,
+	    IEnumSTATDATA** ppenumSTATDATA);
+static HRESULT WINAPI DataCache_InitCache(
+	    IOleCache2*     iface,
+	    IDataObject*    pDataObject);
+static HRESULT WINAPI DataCache_IOleCache2_SetData(
+            IOleCache2*     iface,
+	    FORMATETC*      pformatetc,
+	    STGMEDIUM*      pmedium,
+	    BOOL            fRelease);
+static HRESULT WINAPI DataCache_UpdateCache(
+            IOleCache2*     iface,
+	    LPDATAOBJECT    pDataObject, 
+	    DWORD           grfUpdf,
+	    LPVOID          pReserved);
+static HRESULT WINAPI DataCache_DiscardCache(
+            IOleCache2*     iface,
+	    DWORD           dwDiscardOptions);
+
+/*
+ * Prototypes for the methods of the DataCache class
+ * that implement IOleCacheControl methods.
+ */
+static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
+            IOleCacheControl* iface,
+            REFIID            riid,
+            void**            ppvObject);
+static ULONG WINAPI DataCache_IOleCacheControl_AddRef( 
+            IOleCacheControl* iface);
+static ULONG WINAPI DataCache_IOleCacheControl_Release( 
+            IOleCacheControl* iface);
+static HRESULT WINAPI DataCache_OnRun(
+	    IOleCacheControl* iface,
+	    LPDATAOBJECT      pDataObject);
+static HRESULT WINAPI DataCache_OnStop(
+	    IOleCacheControl* iface);
+
+/*
+ * Virtual function tables for the DataCache class.
+ */
+static ICOM_VTABLE(IUnknown) DataCache_NDIUnknown_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DataCache_NDIUnknown_QueryInterface,
+  DataCache_NDIUnknown_AddRef,
+  DataCache_NDIUnknown_Release
+};
+
+static ICOM_VTABLE(IDataObject) DataCache_IDataObject_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DataCache_IDataObject_QueryInterface,
+  DataCache_IDataObject_AddRef,
+  DataCache_IDataObject_Release,
+  DataCache_GetData,
+  DataCache_GetDataHere,
+  DataCache_QueryGetData,
+  DataCache_GetCanonicalFormatEtc,
+  DataCache_IDataObject_SetData,
+  DataCache_EnumFormatEtc,
+  DataCache_DAdvise,
+  DataCache_DUnadvise,
+  DataCache_EnumDAdvise
+};
+
+static ICOM_VTABLE(IPersistStorage) DataCache_IPersistStorage_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DataCache_IPersistStorage_QueryInterface,
+  DataCache_IPersistStorage_AddRef,
+  DataCache_IPersistStorage_Release,
+  DataCache_GetClassID,
+  DataCache_IsDirty,
+  DataCache_InitNew,
+  DataCache_Load,
+  DataCache_Save,
+  DataCache_SaveCompleted,
+  DataCache_HandsOffStorage
+};
+
+static ICOM_VTABLE(IViewObject2) DataCache_IViewObject2_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DataCache_IViewObject2_QueryInterface,
+  DataCache_IViewObject2_AddRef,
+  DataCache_IViewObject2_Release,
+  DataCache_Draw,
+  DataCache_GetColorSet,
+  DataCache_Freeze,
+  DataCache_Unfreeze,
+  DataCache_SetAdvise,
+  DataCache_GetAdvise,
+  DataCache_GetExtent
+};
+
+static ICOM_VTABLE(IOleCache2) DataCache_IOleCache2_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DataCache_IOleCache2_QueryInterface,
+  DataCache_IOleCache2_AddRef,
+  DataCache_IOleCache2_Release,
+  DataCache_Cache,
+  DataCache_Uncache,
+  DataCache_EnumCache,
+  DataCache_InitCache,
+  DataCache_IOleCache2_SetData,
+  DataCache_UpdateCache,
+  DataCache_DiscardCache
+};
+
+static ICOM_VTABLE(IOleCacheControl) DataCache_IOleCacheControl_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DataCache_IOleCacheControl_QueryInterface,
+  DataCache_IOleCacheControl_AddRef,
+  DataCache_IOleCacheControl_Release,
+  DataCache_OnRun,
+  DataCache_OnStop
+};
+
+/******************************************************************************
+ *              CreateDataCache        [OLE32.54]
+ */
+HRESULT WINAPI CreateDataCache(
+  LPUNKNOWN pUnkOuter, 
+  REFCLSID  rclsid, 
+  REFIID    riid, 
+  LPVOID*   ppvObj)
+{
+  DataCache* newCache = NULL;
+  HRESULT    hr       = S_OK;
+  char       xclsid[50];
+  char       xriid[50];
+
+  WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
+  WINE_StringFromCLSID((LPCLSID)riid,xriid);
+
+  TRACE("(%s, %p, %s, %p)\n", xclsid, pUnkOuter, xriid, ppvObj);
+
+  /*
+   * Sanity check
+   */
+  if (ppvObj==0)
+    return E_POINTER;
+
+  *ppvObj = 0;
+
+  /*
+   * If This cache is constructed for aggregation, make sure
+   * the caller is requesting the IUnknown interface.
+   * This is necessary because it's the only time the non-delegating
+   * IUnknown pointer can be returned to the outside.
+   */
+  if ( (pUnkOuter!=NULL) && 
+       (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) )
+    return CLASS_E_NOAGGREGATION;
+
+  /*
+   * Try to construct a new instance of the class.
+   */
+  newCache = DataCache_Construct(rclsid, 
+				 pUnkOuter);
+
+  if (newCache == 0)
+    return E_OUTOFMEMORY;
+
+  /*
+   * Make sure it supports the interface required by the caller.
+   */
+  hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtbl2), riid, ppvObj);
+
+  /*
+   * Release the reference obtained in the constructor. If
+   * the QueryInterface was unsuccessful, it will free the class.
+   */
+  IUnknown_Release((IUnknown*)&(newCache->lpvtbl2));
+
+  return hr;
+}
+
+/*********************************************************
+ * Method implementation for DataCache class.
+ */
+static DataCache* DataCache_Construct(
+  REFCLSID  clsid,
+  LPUNKNOWN pUnkOuter)
+{
+  DataCache* newObject = 0;
+
+  /*
+   * Allocate space for the object.
+   */
+  newObject = (DataCache *)HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache));
+
+  if (newObject==0)
+    return newObject;
+  
+  /*
+   * Initialize the virtual function table.
+   */
+  newObject->lpvtbl1 = &DataCache_IDataObject_VTable;
+  newObject->lpvtbl2 = &DataCache_NDIUnknown_VTable;
+  newObject->lpvtbl3 = &DataCache_IPersistStorage_VTable;
+  newObject->lpvtbl4 = &DataCache_IViewObject2_VTable;
+  newObject->lpvtbl5 = &DataCache_IOleCache2_VTable;
+  newObject->lpvtbl6 = &DataCache_IOleCacheControl_VTable;
+  
+  /*
+   * Start with one reference count. The caller of This function 
+   * must release the interface pointer when it is done.
+   */
+  newObject->ref = 1;
+
+  /*
+   * Initialize the outer unknown
+   * We don't keep a reference on the outer unknown since, the way 
+   * aggregation works, our lifetime is at least as large as it's
+   * lifetime.
+   */
+  if (pUnkOuter==NULL)
+    pUnkOuter = (IUnknown*)&(newObject->lpvtbl2);
+
+  newObject->outerUnknown = pUnkOuter;
+
+  /*
+   * Initialize the other members of the structure.
+   */
+  newObject->presentationStorage = NULL;
+  newObject->sinkAspects = 0;
+  newObject->sinkAdviseFlag = 0;
+  newObject->sinkInterface = 0;
+
+  return newObject;
+}
+
+static void DataCache_Destroy(
+  DataCache* ptrToDestroy)
+{
+  TRACE("()\n");
+
+  if (ptrToDestroy->sinkInterface != NULL)
+  {
+    IAdviseSink_Release(ptrToDestroy->sinkInterface);
+    ptrToDestroy->sinkInterface = NULL;
+  }
+
+  if (ptrToDestroy->presentationStorage != NULL)
+  {
+    IStorage_Release(ptrToDestroy->presentationStorage);
+    ptrToDestroy->presentationStorage = NULL;
+  }
+
+  /*
+   * Free the datacache pointer.
+   */
+  HeapFree(GetProcessHeap(), 0, ptrToDestroy);
+}
+
+/************************************************************************
+ * DataCache_ReadPresentationData
+ *
+ * This method will read information for the requested presentation 
+ * into the given structure.
+ *
+ * Param:
+ *   This       - Pointer to the DataCache object
+ *   drawAspect - The aspect of the object that we wish to draw.
+ *   header     - The structure containing information about This
+ *                aspect of the object.
+ */
+static HRESULT DataCache_ReadPresentationData(
+  DataCache*              This,
+  DWORD                   drawAspect,
+  PresentationDataHeader* header)
+{
+  IStream* presStream = NULL;
+  OLECHAR  streamName[20];
+  HRESULT  hres;
+
+  /*
+   * Get the name for the presentation stream.
+   */
+  hres = DataCache_FindPresStreamName(
+           This,
+	   drawAspect,
+	   streamName);
+
+  if (FAILED(hres))
+    return hres;
+
+  /*
+   * Open the stream and read the header.
+   */
+  hres = IStorage_OpenStream(
+           This->presentationStorage,
+	   streamName,
+	   NULL,
+	   STGM_READ | STGM_SHARE_EXCLUSIVE,
+	   0,
+	   &presStream);
+
+  if (FAILED(hres))
+    return hres;
+
+  hres = IStream_Read(
+           presStream,
+	   header,
+	   sizeof(PresentationDataHeader),
+	   NULL);
+
+  /*
+   * Cleanup.
+   */
+  IStream_Release(presStream);
+
+  /*
+   * We don't want to propagate any other error
+   * code than a failure.
+   */
+  if (hres!=S_OK)
+    hres = E_FAIL;
+
+  return hres;
+}
+
+/************************************************************************
+ * DataCache_FireOnViewChange
+ *
+ * This method will fire an OnViewChange notification to the advise
+ * sink registered with the datacache.
+ *
+ * See IAdviseSink::OnViewChange for more details.
+ */
+static void DataCache_FireOnViewChange(
+  DataCache* This,
+  DWORD      aspect,
+  LONG       lindex)
+{
+  TRACE("(%p, %lx, %ld)\n", This, aspect, lindex);
+
+  /*
+   * The sink supplies a filter when it registers
+   * we make sure we only send the notifications when that
+   * filter matches.
+   */
+  if ((This->sinkAspects & aspect) != 0)
+  {
+    if (This->sinkInterface != NULL)
+    {
+      IAdviseSink_OnViewChange(This->sinkInterface,
+			       aspect,
+			       lindex);
+
+      /*
+       * Some sinks want to be unregistered automatically when
+       * the first notification goes out.
+       */
+      if ( (This->sinkAdviseFlag & ADVF_ONLYONCE) != 0)
+      {
+	IAdviseSink_Release(This->sinkInterface);
+
+	This->sinkInterface  = NULL;
+	This->sinkAspects    = 0;
+	This->sinkAdviseFlag = 0;
+      }
+    }
+  }
+}
+
+/************************************************************************
+ * DataCache_ReadPresentationData
+ *
+ * This method will read information for the requested presentation 
+ * into the given structure.
+ *
+ * Param:
+ *   This       - Pointer to the DataCache object
+ *   drawAspect - The aspect of the object that we wish to draw.
+ *   header     - The structure containing information about This
+ *                aspect of the object.
+ *
+ * NOTE:
+ *   This method only supports the DVASPECT_CONTENT aspect.
+ */
+static HRESULT DataCache_FindPresStreamName(
+  DataCache* This,
+  DWORD      drawAspect,
+  OLECHAR*   buffer)
+{
+  OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
+
+  if (drawAspect!=DVASPECT_CONTENT)
+    return E_FAIL;
+
+  memcpy(buffer, name, sizeof(name));
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DataCache_ReadPresentationData
+ *
+ * This method will read information for the requested presentation 
+ * into the given structure.
+ *
+ * Param:
+ *   This       - Pointer to the DataCache object
+ *   drawAspect - The aspect of the object that we wish to draw.
+ *
+ * Returns:
+ *   This method returns a metafile handle if it is successful.
+ *   it will return 0 if not.
+ */
+static HMETAFILE DataCache_ReadPresMetafile(
+  DataCache* This,
+  DWORD      drawAspect)
+{
+  LARGE_INTEGER offset;
+  IStream*      presStream = NULL;
+  OLECHAR       streamName[20];
+  HRESULT       hres;
+  void*         metafileBits;
+  STATSTG       streamInfo;
+  HMETAFILE     newMetafile = 0;
+
+  /*
+   * Get the name for the presentation stream.
+   */
+  hres = DataCache_FindPresStreamName(
+           This, 
+	   drawAspect,
+	   streamName);
+
+  if (FAILED(hres))
+    return hres;
+
+  /*
+   * Open the stream and read the header.
+   */
+  hres = IStorage_OpenStream(
+           This->presentationStorage,
+	   streamName,
+	   NULL,
+	   STGM_READ | STGM_SHARE_EXCLUSIVE,
+	   0,
+	   &presStream);
+
+  if (FAILED(hres))
+    return hres;
+
+  /*
+   * Get the size of the stream.
+   */
+  hres = IStream_Stat(presStream,
+		      &streamInfo,
+		      STATFLAG_NONAME);
+
+  /*
+   * Skip the header
+   */
+  offset.HighPart = 0;
+  offset.LowPart  = sizeof(PresentationDataHeader);
+
+  hres = IStream_Seek(
+           presStream,
+	   offset,
+	   STREAM_SEEK_SET,
+	   NULL);
+
+  /*
+   * Allocate a buffer for the metafile bits.
+   */
+  metafileBits = HeapAlloc(GetProcessHeap(), 
+			   0, 
+			   streamInfo.cbSize.LowPart);
+
+  /*
+   * Read the metafile bits.
+   */
+  hres = IStream_Read(
+	   presStream,
+	   metafileBits,
+	   streamInfo.cbSize.LowPart,
+	   NULL);
+
+  /*
+   * Create a metafile with those bits.
+   */
+  if (SUCCEEDED(hres))
+  {
+    newMetafile = SetMetaFileBitsEx(streamInfo.cbSize.LowPart, (const BYTE *)metafileBits);
+  }
+
+  /*
+   * Cleanup.
+   */
+  HeapFree(GetProcessHeap(), 0, metafileBits);
+  IStream_Release(presStream);
+
+  if (newMetafile==0)
+    hres = E_FAIL;
+
+  return newMetafile;
+}
+
+/*********************************************************
+ * Method implementation for the  non delegating IUnknown
+ * part of the DataCache class.
+ */
+
+/************************************************************************
+ * DataCache_NDIUnknown_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ *
+ * This version of QueryInterface will not delegate it's implementation
+ * to the outer unknown.
+ */
+static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface(
+            IUnknown*      iface,
+            REFIID         riid,
+            void**         ppvObject)
+{
+  _ICOM_THIS_From_NDIUnknown(DataCache, iface);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppvObject==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+
+  /*
+   * Compare the riid with the interface IDs implemented by This object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = iface;
+  }
+  else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) 
+  {
+    *ppvObject = (IDataObject*)&(This->lpvtbl1);
+  }
+  else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0)  ||
+	    (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) )
+  {
+    *ppvObject = (IPersistStorage*)&(This->lpvtbl3);
+  }
+  else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) ||
+	    (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) )
+  {
+    *ppvObject = (IViewObject2*)&(This->lpvtbl4);
+  }
+  else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) ||
+	    (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) )
+  {
+    *ppvObject = (IOleCache2*)&(This->lpvtbl5);
+  }
+  else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0) 
+  {
+    *ppvObject = (IOleCacheControl*)&(This->lpvtbl6);
+  }
+
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+  {
+    char clsid[50];
+
+    WINE_StringFromCLSID((LPCLSID)riid,clsid);
+    
+    WARN(
+	 "() : asking for un supported interface %s\n", 
+	 clsid);
+
+    return E_NOINTERFACE;
+  }
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful. 
+   */
+  IUnknown_AddRef((IUnknown*)*ppvObject);
+
+  return S_OK;;  
+}
+
+/************************************************************************
+ * DataCache_NDIUnknown_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ *
+ * This version of QueryInterface will not delegate it's implementation
+ * to the outer unknown.
+ */
+static ULONG WINAPI DataCache_NDIUnknown_AddRef( 
+            IUnknown*      iface)
+{
+  _ICOM_THIS_From_NDIUnknown(DataCache, iface);
+
+  This->ref++;
+
+  return This->ref;
+}
+
+/************************************************************************
+ * DataCache_NDIUnknown_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ *
+ * This version of QueryInterface will not delegate it's implementation
+ * to the outer unknown.
+ */
+static ULONG WINAPI DataCache_NDIUnknown_Release( 
+            IUnknown*      iface)
+{
+  _ICOM_THIS_From_NDIUnknown(DataCache, iface);
+
+  /*
+   * Decrease the reference count on This object.
+   */
+  This->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (This->ref==0)
+  {
+    DataCache_Destroy(This);
+
+    return 0;
+  }
+  
+  return This->ref;
+}
+
+/*********************************************************
+ * Method implementation for the IDataObject
+ * part of the DataCache class.
+ */
+
+/************************************************************************
+ * DataCache_IDataObject_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI DataCache_IDataObject_QueryInterface(
+            IDataObject*     iface,
+            REFIID           riid,
+            void**           ppvObject)
+{
+  _ICOM_THIS_From_IDataObject(DataCache, iface);
+
+  return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject);  
+}
+
+/************************************************************************
+ * DataCache_IDataObject_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataCache_IDataObject_AddRef( 
+            IDataObject*     iface)
+{
+  _ICOM_THIS_From_IDataObject(DataCache, iface);
+
+  return IUnknown_AddRef(This->outerUnknown);  
+}
+
+/************************************************************************
+ * DataCache_IDataObject_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataCache_IDataObject_Release( 
+            IDataObject*     iface)
+{
+  _ICOM_THIS_From_IDataObject(DataCache, iface);
+
+  return IUnknown_Release(This->outerUnknown);  
+}
+
+static HRESULT WINAPI DataCache_GetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetcIn, 
+	    STGMEDIUM*       pmedium)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_GetDataHere(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatetc,
+	    STGMEDIUM*       pmedium)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_QueryGetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * DataCache_EnumFormatEtc (IDataObject)
+ *
+ * The data cache doesn't implement This method.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DataCache_GetCanonicalFormatEtc(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatectIn, 
+	    LPFORMATETC      pformatetcOut)
+{
+  TRACE("()\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * DataCache_IDataObject_SetData (IDataObject)
+ *
+ * This method is delegated to the IOleCache2 implementation.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DataCache_IDataObject_SetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc, 
+	    STGMEDIUM*       pmedium, 
+	    BOOL             fRelease)
+{
+  IOleCache2* oleCache = NULL;
+  HRESULT     hres;
+
+  TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
+
+  hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache);
+
+  if (FAILED(hres))
+    return E_UNEXPECTED;
+
+  hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease);
+
+  IOleCache2_Release(oleCache);
+
+  return hres;;
+}
+
+/************************************************************************
+ * DataCache_EnumFormatEtc (IDataObject)
+ *
+ * The data cache doesn't implement This method.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DataCache_EnumFormatEtc(
+	    IDataObject*     iface,       
+	    DWORD            dwDirection,
+	    IEnumFORMATETC** ppenumFormatEtc)
+{
+  TRACE("()\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * DataCache_DAdvise (IDataObject)
+ *
+ * The data cache doesn't support connections.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DataCache_DAdvise(
+	    IDataObject*     iface, 
+	    FORMATETC*       pformatetc, 
+	    DWORD            advf, 
+	    IAdviseSink*     pAdvSink, 
+	    DWORD*           pdwConnection)
+{
+  TRACE("()\n");
+  return OLE_E_ADVISENOTSUPPORTED;
+}
+
+/************************************************************************
+ * DataCache_DUnadvise (IDataObject)
+ *
+ * The data cache doesn't support connections.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DataCache_DUnadvise(
+	    IDataObject*     iface,
+	    DWORD            dwConnection)
+{
+  TRACE("()\n");
+  return OLE_E_NOCONNECTION;
+}
+
+/************************************************************************
+ * DataCache_EnumDAdvise (IDataObject)
+ *
+ * The data cache doesn't support connections.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DataCache_EnumDAdvise(
+	    IDataObject*     iface,
+	    IEnumSTATDATA**  ppenumAdvise)
+{
+  TRACE("()\n");
+  return OLE_E_ADVISENOTSUPPORTED;
+}
+
+/*********************************************************
+ * Method implementation for the IDataObject
+ * part of the DataCache class.
+ */
+
+/************************************************************************
+ * DataCache_IPersistStorage_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface(
+            IPersistStorage* iface,
+            REFIID           riid,
+            void**           ppvObject)
+{
+  _ICOM_THIS_From_IPersistStorage(DataCache, iface);
+
+  return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject);  
+}
+
+/************************************************************************
+ * DataCache_IPersistStorage_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataCache_IPersistStorage_AddRef( 
+            IPersistStorage* iface)
+{
+  _ICOM_THIS_From_IPersistStorage(DataCache, iface);
+
+  return IUnknown_AddRef(This->outerUnknown);  
+}
+
+/************************************************************************
+ * DataCache_IPersistStorage_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataCache_IPersistStorage_Release( 
+            IPersistStorage* iface)
+{
+  _ICOM_THIS_From_IPersistStorage(DataCache, iface);
+
+  return IUnknown_Release(This->outerUnknown);  
+}
+
+/************************************************************************
+ * DataCache_GetClassID (IPersistStorage)
+ *
+ * The data cache doesn't implement This method.
+ *
+ * See Windows documentation for more details on IPersistStorage methods.
+ */
+static HRESULT WINAPI DataCache_GetClassID( 
+            IPersistStorage* iface,
+	    CLSID*           pClassID)
+{
+  TRACE("(%p, %p)\n", iface, pClassID);
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * DataCache_IsDirty (IPersistStorage)
+ *
+ * Until we actully connect to a running object and retrieve new 
+ * information to it, we never get dirty.
+ *
+ * See Windows documentation for more details on IPersistStorage methods.
+ */
+static HRESULT WINAPI DataCache_IsDirty( 
+            IPersistStorage* iface)
+{
+  TRACE("(%p)\n", iface);
+
+  return S_FALSE;
+}
+
+/************************************************************************
+ * DataCache_InitNew (IPersistStorage)
+ *
+ * The data cache implementation of IPersistStorage_InitNew simply stores
+ * the storage pointer.
+ *
+ * See Windows documentation for more details on IPersistStorage methods.
+ */
+static HRESULT WINAPI DataCache_InitNew( 
+            IPersistStorage* iface, 
+	    IStorage*        pStg)
+{
+  TRACE("(%p, %p)\n", iface, pStg);
+
+  return DataCache_Load(iface, pStg);
+}
+
+/************************************************************************
+ * DataCache_Load (IPersistStorage)
+ *
+ * The data cache implementation of IPersistStorage_Load doesn't 
+ * actually load anything. Instead, it holds on to the storage pointer
+ * and it will load the presentation information when the 
+ * IDataObject_GetData or IViewObject2_Draw methods are called.
+ *
+ * See Windows documentation for more details on IPersistStorage methods.
+ */
+static HRESULT WINAPI DataCache_Load( 
+            IPersistStorage* iface,
+	    IStorage*        pStg)
+{
+  _ICOM_THIS_From_IPersistStorage(DataCache, iface);
+
+  TRACE("(%p, %p)\n", iface, pStg);
+
+  if (This->presentationStorage != NULL)
+  {
+    IStorage_Release(This->presentationStorage);
+  }
+
+  This->presentationStorage = pStg;
+
+  if (This->presentationStorage != NULL)
+  {
+    IStorage_AddRef(This->presentationStorage);
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DataCache_Save (IPersistStorage)
+ *
+ * Until we actully connect to a running object and retrieve new 
+ * information to it, we never have to save anything. However, it is
+ * our responsability to copy the information when saving to a new
+ * storage.
+ *
+ * See Windows documentation for more details on IPersistStorage methods.
+ */
+static HRESULT WINAPI DataCache_Save( 
+            IPersistStorage* iface,
+	    IStorage*        pStg, 
+	    BOOL             fSameAsLoad)
+{
+  _ICOM_THIS_From_IPersistStorage(DataCache, iface);
+
+  TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad);
+
+  if ( (!fSameAsLoad) && 
+       (This->presentationStorage!=NULL) )
+  {
+    return IStorage_CopyTo(This->presentationStorage,
+			   0,
+			   NULL,
+			   NULL,
+			   pStg);
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DataCache_SaveCompleted (IPersistStorage)
+ *
+ * This method is called to tell the cache to release the storage
+ * pointer it's currentlu holding.
+ *
+ * See Windows documentation for more details on IPersistStorage methods.
+ */
+static HRESULT WINAPI DataCache_SaveCompleted( 
+            IPersistStorage* iface,  
+	    IStorage*        pStgNew)
+{
+  TRACE("(%p, %p)\n", iface, pStgNew);
+
+  if (pStgNew)
+  {
+      /*
+       * First, make sure we get our hands off any storage we have.
+       */
+      DataCache_HandsOffStorage(iface);
+
+      /*
+       * Then, attach to the new storage.
+       */
+      DataCache_Load(iface, pStgNew);
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DataCache_HandsOffStorage (IPersistStorage)
+ *
+ * This method is called to tell the cache to release the storage
+ * pointer it's currentlu holding.
+ *
+ * See Windows documentation for more details on IPersistStorage methods.
+ */
+static HRESULT WINAPI DataCache_HandsOffStorage(
+            IPersistStorage* iface)
+{
+  _ICOM_THIS_From_IPersistStorage(DataCache, iface);
+
+  TRACE("(%p)\n", iface);
+
+  if (This->presentationStorage != NULL)
+  {
+    IStorage_Release(This->presentationStorage);
+    This->presentationStorage = NULL;
+  }
+
+  return S_OK;
+}
+
+/*********************************************************
+ * Method implementation for the IViewObject2
+ * part of the DataCache class.
+ */
+
+/************************************************************************
+ * DataCache_IViewObject2_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI DataCache_IViewObject2_QueryInterface(
+            IViewObject2* iface,
+            REFIID           riid,
+            void**           ppvObject)
+{
+  _ICOM_THIS_From_IViewObject2(DataCache, iface);
+
+  return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject);  
+}
+
+/************************************************************************
+ * DataCache_IViewObject2_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataCache_IViewObject2_AddRef( 
+            IViewObject2* iface)
+{
+  _ICOM_THIS_From_IViewObject2(DataCache, iface);
+
+  return IUnknown_AddRef(This->outerUnknown);  
+}
+
+/************************************************************************
+ * DataCache_IViewObject2_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataCache_IViewObject2_Release( 
+            IViewObject2* iface)
+{
+  _ICOM_THIS_From_IViewObject2(DataCache, iface);
+
+  return IUnknown_Release(This->outerUnknown);  
+}
+
+/************************************************************************
+ * DataCache_Draw (IViewObject2)
+ *
+ * This method will draw the cached representation of the object
+ * to the given device context.
+ *
+ * See Windows documentation for more details on IViewObject2 methods.
+ */
+static HRESULT WINAPI DataCache_Draw(
+            IViewObject2*    iface,
+	    DWORD            dwDrawAspect,
+	    LONG             lindex,
+	    void*            pvAspect,
+	    DVTARGETDEVICE*  ptd, 
+	    HDC              hdcTargetDev, 
+	    HDC              hdcDraw,
+	    LPCRECTL         lprcBounds,
+	    LPCRECTL         lprcWBounds,
+	    IVO_ContCallback pfnContinue,
+	    DWORD            dwContinue)
+{
+  PresentationDataHeader presData;
+  HMETAFILE              presMetafile = 0;
+  HRESULT                hres;
+
+  _ICOM_THIS_From_IViewObject2(DataCache, iface);
+
+  TRACE("(%p, %lx, %ld, %p, %x, %x, %p, %p, %p, %lx)\n",
+	iface,
+	dwDrawAspect,
+	lindex,
+	pvAspect,
+	hdcTargetDev, 
+	hdcDraw,
+	lprcBounds,
+	lprcWBounds,
+	pfnContinue,
+	dwContinue);
+
+  /*
+   * Sanity check
+   */
+  if (lprcBounds==NULL)
+    return E_INVALIDARG;
+
+/** Hack for WPO2000 release. */
+  if (dwDrawAspect != DVASPECT_CONTENT)
+  {
+      FIXME("only CONTENT aspect implemented\n");
+      dwDrawAspect = DVASPECT_CONTENT;
+  }
+/***/
+
+  /*
+   * First, we need to retrieve the dimensions of the
+   * image in the metafile.
+   */
+  hres = DataCache_ReadPresentationData(This,
+					dwDrawAspect,
+					&presData);
+
+  if (FAILED(hres))
+    return hres;
+
+  /*
+   * Then, we can extract the metafile itself from the cached
+   * data.
+   */
+  presMetafile = DataCache_ReadPresMetafile(This,
+					    dwDrawAspect);
+
+  /*
+   * If we have a metafile, just draw baby...
+   * We have to be careful not to modify the state of the
+   * DC.
+   */
+  if (presMetafile!=0)
+  {
+    INT   prevMapMode = SetMapMode(hdcDraw, MM_ANISOTROPIC);
+    SIZE  oldWindowExt;
+    SIZE  oldViewportExt;
+    POINT oldViewportOrg;
+
+    SetWindowExtEx(hdcDraw,
+		   presData.objectExtentX,
+		   presData.objectExtentY,
+		   &oldWindowExt);
+
+    SetViewportExtEx(hdcDraw, 
+		     lprcBounds->right - lprcBounds->left,
+		     lprcBounds->bottom - lprcBounds->top,
+		     &oldViewportExt);
+
+    SetViewportOrgEx(hdcDraw,
+		     lprcBounds->left,
+		     lprcBounds->top,
+		     &oldViewportOrg);
+
+    PlayMetaFile(hdcDraw, presMetafile);
+
+    SetWindowExtEx(hdcDraw,
+		   oldWindowExt.cx,
+		   oldWindowExt.cy,
+		   NULL);
+
+    SetViewportExtEx(hdcDraw, 
+		     oldViewportExt.cx,
+		     oldViewportExt.cy,
+		     NULL);
+
+    SetViewportOrgEx(hdcDraw,
+		     oldViewportOrg.x,
+		     oldViewportOrg.y,
+		     NULL);
+
+    SetMapMode(hdcDraw, prevMapMode);
+
+    DeleteMetaFile(presMetafile);
+  }
+
+  return S_OK;
+}
+
+static HRESULT WINAPI DataCache_GetColorSet(
+            IViewObject2*   iface, 
+	    DWORD           dwDrawAspect, 
+	    LONG            lindex, 
+	    void*           pvAspect, 
+	    DVTARGETDEVICE* ptd, 
+	    HDC             hicTargetDevice, 
+	    tagLOGPALETTE**    ppColorSet)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_Freeze(
+            IViewObject2*   iface,
+	    DWORD           dwDrawAspect,
+	    LONG            lindex,
+	    void*           pvAspect, 
+	    DWORD*          pdwFreeze)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_Unfreeze(
+            IViewObject2*   iface,
+	    DWORD           dwFreeze)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * DataCache_SetAdvise (IViewObject2)
+ *
+ * This sets-up an advisory sink with the data cache. When the object's
+ * view changes, This sink is called.
+ *
+ * See Windows documentation for more details on IViewObject2 methods.
+ */
+static HRESULT WINAPI DataCache_SetAdvise(
+            IViewObject2*   iface,
+	    DWORD           aspects, 
+	    DWORD           advf, 
+	    IAdviseSink*    pAdvSink)
+{
+  _ICOM_THIS_From_IViewObject2(DataCache, iface);
+
+  TRACE("(%p, %lx, %lx, %p)\n", iface, aspects, advf, pAdvSink);
+
+  /*
+   * A call to This function removes the previous sink
+   */
+  if (This->sinkInterface != NULL)
+  {
+    IAdviseSink_Release(This->sinkInterface);
+    This->sinkInterface  = NULL;
+    This->sinkAspects    = 0; 
+    This->sinkAdviseFlag = 0;
+  }
+
+  /*
+   * Now, setup the new one.
+   */
+  if (pAdvSink!=NULL)
+  {
+    This->sinkInterface  = pAdvSink;
+    This->sinkAspects    = aspects; 
+    This->sinkAdviseFlag = advf;    
+
+    IAdviseSink_AddRef(This->sinkInterface);
+  }
+
+  /*
+   * When the ADVF_PRIMEFIRST flag is set, we have to advise the
+   * sink immediately.
+   */
+  if (advf & ADVF_PRIMEFIRST)
+  {
+    DataCache_FireOnViewChange(This,
+			       DVASPECT_CONTENT,
+			       -1);
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DataCache_GetAdvise (IViewObject2)
+ *
+ * This method queries the current state of the advise sink 
+ * installed on the data cache.
+ *
+ * See Windows documentation for more details on IViewObject2 methods.
+ */
+static HRESULT WINAPI DataCache_GetAdvise(
+            IViewObject2*   iface, 
+	    DWORD*          pAspects, 
+	    DWORD*          pAdvf, 
+	    IAdviseSink**   ppAdvSink)
+{
+  _ICOM_THIS_From_IViewObject2(DataCache, iface);
+
+  TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink);
+
+  /*
+   * Just copy all the requested values.
+   */
+  if (pAspects!=NULL)
+    *pAspects = This->sinkAspects;
+
+  if (pAdvf!=NULL)
+    *pAdvf = This->sinkAdviseFlag;
+
+  if (ppAdvSink!=NULL)
+  {
+    IAdviseSink_QueryInterface(This->sinkInterface, 
+			       &IID_IAdviseSink, 
+			       (void**)ppAdvSink);
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DataCache_GetExtent (IViewObject2)
+ *
+ * This method retrieves the "natural" size of This cached object.
+ *
+ * See Windows documentation for more details on IViewObject2 methods.
+ */
+static HRESULT WINAPI DataCache_GetExtent(
+            IViewObject2*   iface, 
+	    DWORD           dwDrawAspect, 
+	    LONG            lindex, 
+	    DVTARGETDEVICE* ptd, 
+	    LPSIZEL         lpsizel)
+{
+  PresentationDataHeader presData;
+  HRESULT                hres = E_FAIL;
+
+  _ICOM_THIS_From_IViewObject2(DataCache, iface);
+
+  TRACE("(%p, %lx, %ld, %p, %p)\n", 
+	iface, dwDrawAspect, lindex, ptd, lpsizel);
+
+  /*
+   * Sanity check
+   */
+  if (lpsizel==NULL)
+    return E_POINTER;
+
+  /*
+   * Initialize the out parameter.
+   */
+  lpsizel->cx = 0;
+  lpsizel->cy = 0;
+
+  /*
+   * This flag should be set to -1.
+   */
+  if (lindex!=-1)
+    FIXME("Unimplemented flag lindex = %ld\n", lindex);
+
+  /*
+   * Right now, we suport only the callback from
+   * the default handler.
+   */
+  if (ptd!=NULL)
+    FIXME("Unimplemented ptd = %p\n", ptd);
+  
+  /*
+   * Get the presentation information from the 
+   * cache.
+   */
+  hres = DataCache_ReadPresentationData(This,
+					dwDrawAspect,
+					&presData);
+
+  if (SUCCEEDED(hres))
+  {
+    lpsizel->cx = presData.objectExtentX;
+    lpsizel->cy = presData.objectExtentY;
+  }
+
+  /*
+   * This method returns OLE_E_BLANK when it fails.
+   */
+  if (FAILED(hres))
+    hres = OLE_E_BLANK;
+
+  return hres;
+}
+
+
+/*********************************************************
+ * Method implementation for the IOleCache2
+ * part of the DataCache class.
+ */
+
+/************************************************************************
+ * DataCache_IOleCache2_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI DataCache_IOleCache2_QueryInterface(
+            IOleCache2*     iface,
+            REFIID          riid,
+            void**          ppvObject)
+{
+  _ICOM_THIS_From_IOleCache2(DataCache, iface);
+
+  return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject);  
+}
+
+/************************************************************************
+ * DataCache_IOleCache2_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataCache_IOleCache2_AddRef( 
+            IOleCache2*     iface)
+{
+  _ICOM_THIS_From_IOleCache2(DataCache, iface);
+
+  return IUnknown_AddRef(This->outerUnknown);  
+}
+
+/************************************************************************
+ * DataCache_IOleCache2_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataCache_IOleCache2_Release( 
+            IOleCache2*     iface)
+{
+  _ICOM_THIS_From_IOleCache2(DataCache, iface);
+
+  return IUnknown_Release(This->outerUnknown);  
+}
+
+static HRESULT WINAPI DataCache_Cache(
+            IOleCache2*     iface,
+	    FORMATETC*      pformatetc,
+	    DWORD           advf,
+	    DWORD*          pdwConnection)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_Uncache(
+	    IOleCache2*     iface,
+	    DWORD           dwConnection)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_EnumCache(
+            IOleCache2*     iface,
+	    IEnumSTATDATA** ppenumSTATDATA)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_InitCache(
+	    IOleCache2*     iface,
+	    IDataObject*    pDataObject)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_IOleCache2_SetData(
+            IOleCache2*     iface,
+	    FORMATETC*      pformatetc,
+	    STGMEDIUM*      pmedium,
+	    BOOL            fRelease)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_UpdateCache(
+            IOleCache2*     iface,
+	    LPDATAOBJECT    pDataObject, 
+	    DWORD           grfUpdf,
+	    LPVOID          pReserved)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_DiscardCache(
+            IOleCache2*     iface,
+	    DWORD           dwDiscardOptions)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+
+/*********************************************************
+ * Method implementation for the IOleCacheControl
+ * part of the DataCache class.
+ */
+
+/************************************************************************
+ * DataCache_IOleCacheControl_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface(
+            IOleCacheControl* iface,
+            REFIID            riid,
+            void**            ppvObject)
+{
+  _ICOM_THIS_From_IOleCacheControl(DataCache, iface);
+
+  return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject);  
+}
+
+/************************************************************************
+ * DataCache_IOleCacheControl_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataCache_IOleCacheControl_AddRef( 
+            IOleCacheControl* iface)
+{
+  _ICOM_THIS_From_IOleCacheControl(DataCache, iface);
+
+  return IUnknown_AddRef(This->outerUnknown);  
+}
+
+/************************************************************************
+ * DataCache_IOleCacheControl_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataCache_IOleCacheControl_Release( 
+            IOleCacheControl* iface)
+{
+  _ICOM_THIS_From_IOleCacheControl(DataCache, iface);
+
+  return IUnknown_Release(This->outerUnknown);  
+}
+
+static HRESULT WINAPI DataCache_OnRun(
+	    IOleCacheControl* iface,
+	    LPDATAOBJECT      pDataObject)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DataCache_OnStop(
+	    IOleCacheControl* iface)
+{
+  FIXME("stub\n");
+  return E_NOTIMPL;
+}
+
+
Index: trunk/src/ole32/new/defaulthandler.cpp
===================================================================
--- trunk/src/ole32/new/defaulthandler.cpp	(revision 3456)
+++ trunk/src/ole32/new/defaulthandler.cpp	(revision 3456)
@@ -0,0 +1,1670 @@
+/* $Id: defaulthandler.cpp,v 1.1 2000-04-27 22:18:16 davidr Exp $ */
+/* 
+ *  OLE 2 default object handler
+ * 
+ * 21/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *   Copyright 1999  Francis Beaudet
+ *
+ * NOTES:
+ *    The OLE2 default object handler supports a whole whack of
+ *    interfaces including:
+ *       IOleObject, IDataObject, IPersistStorage, IViewObject2,
+ *       IRunnableObject, IOleCache2, IOleCacheControl and much more.
+ *
+ *    All the implementation details are taken from: Inside OLE
+ *    second edition by Kraig Brockschmidt,
+ *
+ * TODO
+ * - This implementation of the default handler does not launch the
+ *   server in the DoVerb, Update, GetData, GetDataHere and Run
+ *   methods. When it is fixed to do so, all the methods will have
+ *   to be  revisited to allow delegating to the running object
+ *
+ * - All methods in the class that use the class ID should be
+ *   aware that it is possible for a class to be treated as
+ *   another one and go into emulation mode. Nothing has been
+ *   done in This area.
+ *
+ * - Some functions still return E_NOTIMPL they have to be 
+ *   implemented. Most of those are related to the running of the
+ *   actual server.
+ *
+ * - All the methods related to notification and advise sinks are
+ *   in place but no notifications are sent to the sinks yet.
+ */
+
+#include "ole32.h"
+#include "heapstring.h"
+#include "oleauto.h"
+#include "debugtools.h"
+
+#include <assert.h>
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+/****************************************************************************
+ * DefaultHandler
+ *
+ */
+struct DefaultHandler
+{
+  /*
+   * List all interface VTables here
+   */
+  ICOM_VTABLE(IOleObject)*      lpvtbl1; 
+  ICOM_VTABLE(IUnknown)*        lpvtbl2;
+  ICOM_VTABLE(IDataObject)*     lpvtbl3;
+  ICOM_VTABLE(IRunnableObject)* lpvtbl4;
+
+  /*
+   * Reference count of This object
+   */
+  ULONG ref;
+
+  /*
+   * IUnknown implementation of the outer object.
+   */
+  IUnknown* outerUnknown;
+
+  /*
+   * Class Id that This handler object represents.
+   */
+  CLSID clsid;
+
+  /*
+   * IUnknown implementation of the datacache.
+   */
+  IUnknown* dataCache;
+
+  /*
+   * Client site for the embedded object.
+   */
+  IOleClientSite* clientSite;
+
+  /*
+   * The IOleAdviseHolder maintains the connections
+   * on behalf of the default handler.
+   */
+  IOleAdviseHolder* oleAdviseHolder;
+
+  /*
+   * The IDataAdviseHolder maintains the data 
+   * connections on behalf of the default handler.
+   */
+  IDataAdviseHolder* dataAdviseHolder;
+
+  /*
+   * Name of the container and object contained
+   */
+  BSTR containerApp; 
+  BSTR containerObj;
+
+};
+
+typedef struct DefaultHandler DefaultHandler;
+
+/*
+ * Here, I define utility macros to help with the casting of the 
+ * "This" parameter.
+ * There is a version to accomodate all of the VTables implemented
+ * by This object.
+ */
+#define _ICOM_THIS_From_IOleObject(class,name)       class* This = (class*)name;
+#define _ICOM_THIS_From_NDIUnknown(class, name)      class* This = (class*)(((char*)name)-sizeof(void*)); 
+#define _ICOM_THIS_From_IDataObject(class, name)     class* This = (class*)(((char*)name)-2*sizeof(void*)); 
+#define _ICOM_THIS_From_IRunnableObject(class, name) class* This = (class*)(((char*)name)-3*sizeof(void*)); 
+
+/*
+ * Prototypes for the methods of the DefaultHandler class.
+ */
+static DefaultHandler* DefaultHandler_Construct(REFCLSID  clsid,
+						LPUNKNOWN pUnkOuter);
+static void            DefaultHandler_Destroy(DefaultHandler* ptrToDestroy);
+
+/*
+ * Prototypes for the methods of the DefaultHandler class
+ * that implement non delegating IUnknown methods.
+ */
+static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface(
+            IUnknown*      iface,
+            REFIID         riid,
+            void**         ppvObject);
+static ULONG WINAPI DefaultHandler_NDIUnknown_AddRef( 
+            IUnknown*      iface);
+static ULONG WINAPI DefaultHandler_NDIUnknown_Release( 
+            IUnknown*      iface);
+
+/*
+ * Prototypes for the methods of the DefaultHandler class
+ * that implement IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_QueryInterface(
+            IOleObject*      iface,
+            REFIID           riid,
+            void**           ppvObject);
+static ULONG WINAPI DefaultHandler_AddRef( 
+            IOleObject*        iface);
+static ULONG WINAPI DefaultHandler_Release( 
+            IOleObject*        iface);
+static HRESULT WINAPI DefaultHandler_SetClientSite(
+	    IOleObject*        iface,
+	    IOleClientSite*    pClientSite);
+static HRESULT WINAPI DefaultHandler_GetClientSite(
+	    IOleObject*        iface,
+	    IOleClientSite**   ppClientSite);
+static HRESULT WINAPI DefaultHandler_SetHostNames(
+	    IOleObject*        iface,
+	    LPCOLESTR          szContainerApp, 
+	    LPCOLESTR          szContainerObj);
+static HRESULT WINAPI DefaultHandler_Close(
+	    IOleObject*        iface, 
+	    DWORD              dwSaveOption);
+static HRESULT WINAPI DefaultHandler_SetMoniker(
+	    IOleObject*        iface, 
+	    DWORD              dwWhichMoniker,
+	    IMoniker*          pmk);
+static HRESULT WINAPI DefaultHandler_GetMoniker(
+	    IOleObject*        iface,
+	    DWORD              dwAssign,
+	    DWORD              dwWhichMoniker,
+	    IMoniker**         ppmk);
+static HRESULT WINAPI DefaultHandler_InitFromData(
+	    IOleObject*        iface, 
+	    IDataObject*       pDataObject, 
+	    BOOL               fCreation,
+	    DWORD              dwReserved);
+static HRESULT WINAPI DefaultHandler_GetClipboardData(
+	    IOleObject*        iface, 
+	    DWORD              dwReserved, 
+	    IDataObject**      ppDataObject);
+static HRESULT WINAPI DefaultHandler_DoVerb(
+	    IOleObject*        iface, 
+	    LONG               iVerb, 
+	    LPMSG              lpmsg, 
+	    IOleClientSite*    pActiveSite, 
+	    LONG               lindex, 
+	    HWND               hwndParent, 
+	    LPCRECT            lprcPosRect);
+static HRESULT WINAPI DefaultHandler_EnumVerbs(
+	    IOleObject*        iface, 
+	    IEnumOLEVERB**     ppEnumOleVerb);
+static HRESULT WINAPI DefaultHandler_Update(
+	    IOleObject*        iface);
+static HRESULT WINAPI DefaultHandler_IsUpToDate(
+	    IOleObject*        iface);
+static HRESULT WINAPI DefaultHandler_GetUserClassID(
+	    IOleObject*        iface, 
+	    CLSID*             pClsid);
+static HRESULT WINAPI DefaultHandler_GetUserType(
+	    IOleObject*        iface, 
+	    DWORD              dwFormOfType, 
+	    LPOLESTR*          pszUserType);
+static HRESULT WINAPI DefaultHandler_SetExtent(
+	    IOleObject*        iface, 
+	    DWORD              dwDrawAspect, 
+	    SIZEL*             psizel);
+static HRESULT WINAPI DefaultHandler_GetExtent(
+	    IOleObject*        iface, 
+	    DWORD              dwDrawAspect, 
+	    SIZEL*             psizel);
+static HRESULT WINAPI DefaultHandler_Advise(
+	    IOleObject*        iface, 
+	    IAdviseSink*       pAdvSink, 
+	    DWORD*             pdwConnection);
+static HRESULT WINAPI DefaultHandler_Unadvise(
+	    IOleObject*        iface, 
+	    DWORD              dwConnection);
+static HRESULT WINAPI DefaultHandler_EnumAdvise(
+	    IOleObject*        iface, 
+	    IEnumSTATDATA**    ppenumAdvise);
+static HRESULT WINAPI DefaultHandler_GetMiscStatus(
+	    IOleObject*        iface, 
+	    DWORD              dwAspect, 
+	    DWORD*             pdwStatus);
+static HRESULT WINAPI DefaultHandler_SetColorScheme(
+	    IOleObject*           iface,
+	    LOGPALETTE*	       pLogpal);
+
+/*
+ * Prototypes for the methods of the DefaultHandler class
+ * that implement IDataObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_IDataObject_QueryInterface(
+            IDataObject*     iface,
+            REFIID           riid,
+            void**           ppvObject);
+static ULONG WINAPI DefaultHandler_IDataObject_AddRef( 
+            IDataObject*     iface);
+static ULONG WINAPI DefaultHandler_IDataObject_Release( 
+            IDataObject*     iface);
+static HRESULT WINAPI DefaultHandler_GetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetcIn, 
+	    STGMEDIUM*       pmedium);
+static HRESULT WINAPI DefaultHandler_GetDataHere(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatetc,
+	    STGMEDIUM*       pmedium);
+static HRESULT WINAPI DefaultHandler_QueryGetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc);
+static HRESULT WINAPI DefaultHandler_GetCanonicalFormatEtc(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatectIn, 
+	    LPFORMATETC      pformatetcOut);
+static HRESULT WINAPI DefaultHandler_SetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc, 
+	    STGMEDIUM*       pmedium, 
+	    BOOL             fRelease);
+static HRESULT WINAPI DefaultHandler_EnumFormatEtc(
+	    IDataObject*     iface,       
+	    DWORD            dwDirection,
+	    IEnumFORMATETC** ppenumFormatEtc);
+static HRESULT WINAPI DefaultHandler_DAdvise(
+	    IDataObject*     iface, 
+	    FORMATETC*       pformatetc, 
+	    DWORD            advf, 
+	    IAdviseSink*     pAdvSink, 
+	    DWORD*           pdwConnection);
+static HRESULT WINAPI DefaultHandler_DUnadvise(
+	    IDataObject*     iface,
+	    DWORD            dwConnection);
+static HRESULT WINAPI DefaultHandler_EnumDAdvise(
+	    IDataObject*     iface,
+	    IEnumSTATDATA**  ppenumAdvise);
+
+/*
+ * Prototypes for the methods of the DefaultHandler class
+ * that implement IRunnableObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_IRunnableObject_QueryInterface(
+            IRunnableObject*     iface,
+            REFIID               riid,
+            void**               ppvObject);
+static ULONG WINAPI DefaultHandler_IRunnableObject_AddRef( 
+            IRunnableObject*     iface);
+static ULONG WINAPI DefaultHandler_IRunnableObject_Release( 
+            IRunnableObject*     iface);
+static HRESULT WINAPI DefaultHandler_GetRunningClass( 
+            IRunnableObject*     iface,   
+	    LPCLSID              lpClsid);
+static HRESULT WINAPI DefaultHandler_Run( 
+            IRunnableObject*     iface,
+	    IBindCtx*            pbc);
+static BOOL    WINAPI DefaultHandler_IsRunning( 
+            IRunnableObject*     iface);
+static HRESULT WINAPI DefaultHandler_LockRunning( 
+            IRunnableObject*     iface, 
+	    BOOL                 fLock, 
+	    BOOL                 fLastUnlockCloses);
+static HRESULT WINAPI DefaultHandler_SetContainedObject( 
+            IRunnableObject*     iface, 
+	    BOOL                 fContained);
+
+
+/*
+ * Virtual function tables for the DefaultHandler class.
+ */
+static ICOM_VTABLE(IOleObject) DefaultHandler_IOleObject_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DefaultHandler_QueryInterface,
+  DefaultHandler_AddRef,
+  DefaultHandler_Release,
+  DefaultHandler_SetClientSite,
+  DefaultHandler_GetClientSite,
+  DefaultHandler_SetHostNames,
+  DefaultHandler_Close,
+  DefaultHandler_SetMoniker,
+  DefaultHandler_GetMoniker,
+  DefaultHandler_InitFromData,
+  DefaultHandler_GetClipboardData,
+  DefaultHandler_DoVerb,
+  DefaultHandler_EnumVerbs,
+  DefaultHandler_Update,
+  DefaultHandler_IsUpToDate,
+  DefaultHandler_GetUserClassID,
+  DefaultHandler_GetUserType,
+  DefaultHandler_SetExtent,
+  DefaultHandler_GetExtent,
+  DefaultHandler_Advise,
+  DefaultHandler_Unadvise,
+  DefaultHandler_EnumAdvise,
+  DefaultHandler_GetMiscStatus,
+  DefaultHandler_SetColorScheme
+};
+
+static ICOM_VTABLE(IUnknown) DefaultHandler_NDIUnknown_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DefaultHandler_NDIUnknown_QueryInterface,
+  DefaultHandler_NDIUnknown_AddRef,
+  DefaultHandler_NDIUnknown_Release,
+};
+
+static ICOM_VTABLE(IDataObject) DefaultHandler_IDataObject_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DefaultHandler_IDataObject_QueryInterface,
+  DefaultHandler_IDataObject_AddRef,
+  DefaultHandler_IDataObject_Release,
+  DefaultHandler_GetData,
+  DefaultHandler_GetDataHere,
+  DefaultHandler_QueryGetData,
+  DefaultHandler_GetCanonicalFormatEtc,
+  DefaultHandler_SetData,
+  DefaultHandler_EnumFormatEtc,
+  DefaultHandler_DAdvise,
+  DefaultHandler_DUnadvise,
+  DefaultHandler_EnumDAdvise
+};
+
+static ICOM_VTABLE(IRunnableObject) DefaultHandler_IRunnableObject_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DefaultHandler_IRunnableObject_QueryInterface,
+  DefaultHandler_IRunnableObject_AddRef,
+  DefaultHandler_IRunnableObject_Release,
+  DefaultHandler_GetRunningClass,
+  DefaultHandler_Run,
+  DefaultHandler_IsRunning,
+  DefaultHandler_LockRunning,
+  DefaultHandler_SetContainedObject
+};
+
+/******************************************************************************
+ * OleCreateDefaultHandler [OLE32.90]
+ */
+HRESULT WINAPI OleCreateDefaultHandler(
+  REFCLSID  clsid,
+  LPUNKNOWN pUnkOuter,
+  REFIID    riid,
+  LPVOID*   ppvObj)
+{
+  DefaultHandler* newHandler = NULL;
+  HRESULT         hr         = S_OK;
+  char            xclsid[50];
+  char            xriid[50];
+
+  WINE_StringFromCLSID((LPCLSID)clsid,xclsid);
+  WINE_StringFromCLSID((LPCLSID)riid,xriid);
+
+  TRACE("(%s, %p, %s, %p)\n", xclsid, pUnkOuter, xriid, ppvObj);
+
+  /*
+   * Sanity check
+   */
+  if (ppvObj==0)
+    return E_POINTER;
+
+  *ppvObj = 0;
+
+  /*
+   * If This handler is constructed for aggregation, make sure
+   * the caller is requesting the IUnknown interface.
+   * This is necessary because it's the only time the non-delegating
+   * IUnknown pointer can be returned to the outside.
+   */
+  if ( (pUnkOuter!=NULL) && 
+       (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) )
+    return CLASS_E_NOAGGREGATION;
+
+  /*
+   * Try to construct a new instance of the class.
+   */
+  newHandler = DefaultHandler_Construct(clsid, 
+					pUnkOuter);
+
+  if (newHandler == 0)
+    return E_OUTOFMEMORY;
+
+  /*
+   * Make sure it supports the interface required by the caller.
+   */
+  hr = IUnknown_QueryInterface((IUnknown*)&(newHandler->lpvtbl2), riid, ppvObj);
+
+  /*
+   * Release the reference obtained in the constructor. If
+   * the QueryInterface was unsuccessful, it will free the class.
+   */
+  IUnknown_Release((IUnknown*)&(newHandler->lpvtbl2));
+
+  return hr;
+}
+
+/*********************************************************
+ * Methods implementation for the DefaultHandler class.
+ */
+static DefaultHandler* DefaultHandler_Construct(
+  REFCLSID  clsid,
+  LPUNKNOWN pUnkOuter)
+{
+  DefaultHandler* newObject = 0;
+
+  /*
+   * Allocate space for the object.
+   */
+  newObject = (DefaultHandler*)HeapAlloc(GetProcessHeap(), 0, sizeof(DefaultHandler));
+
+  if (newObject==0)
+    return newObject;
+  
+  /*
+   * Initialize the virtual function table.
+   */
+  newObject->lpvtbl1 = &DefaultHandler_IOleObject_VTable;
+  newObject->lpvtbl2 = &DefaultHandler_NDIUnknown_VTable;
+  newObject->lpvtbl3 = &DefaultHandler_IDataObject_VTable;
+  newObject->lpvtbl4 = &DefaultHandler_IRunnableObject_VTable;
+
+  /*
+   * Start with one reference count. The caller of This function 
+   * must release the interface pointer when it is done.
+   */
+  newObject->ref = 1;
+
+  /*
+   * Initialize the outer unknown
+   * We don't keep a reference on the outer unknown since, the way 
+   * aggregation works, our lifetime is at least as large as it's
+   * lifetime.
+   */
+  if (pUnkOuter==NULL)
+    pUnkOuter = (IUnknown*)&(newObject->lpvtbl2);
+
+  newObject->outerUnknown = pUnkOuter;
+
+  /*
+   * Create a datacache object.
+   * We aggregate with the datacache. Make sure we pass our outer
+   * unknown as the datacache's outer unknown. 
+   */
+  CreateDataCache(newObject->outerUnknown,
+		  clsid,
+		  &IID_IUnknown,
+		  (void**)&newObject->dataCache);
+
+  /*
+   * Initialize the other data members of the class.
+   */
+  memcpy(&(newObject->clsid), clsid, sizeof(CLSID));
+  newObject->clientSite = NULL;
+  newObject->oleAdviseHolder = NULL;
+  newObject->dataAdviseHolder = NULL;
+  newObject->containerApp = NULL;
+  newObject->containerObj = NULL;
+
+  return newObject;
+}
+
+static void DefaultHandler_Destroy(
+  DefaultHandler* ptrToDestroy)
+{
+  /*
+   * Free the strings idenfitying the object
+   */
+  if (ptrToDestroy->containerApp!=NULL)
+  {
+    SysFreeString(ptrToDestroy->containerApp);
+    ptrToDestroy->containerApp = NULL;
+  }
+
+  if (ptrToDestroy->containerObj!=NULL)
+  {
+    SysFreeString(ptrToDestroy->containerObj);
+    ptrToDestroy->containerObj = NULL;
+  }
+  
+  /*
+   * Release our reference to the data cache.
+   */
+  if (ptrToDestroy->dataCache!=NULL)
+  {
+    IUnknown_Release(ptrToDestroy->dataCache);
+    ptrToDestroy->dataCache = NULL;
+  }
+
+  /*
+   * Same thing for the client site.
+   */
+  if (ptrToDestroy->clientSite!=NULL)
+  {
+    IOleClientSite_Release(ptrToDestroy->clientSite);
+    ptrToDestroy->clientSite = NULL;
+  }
+
+  /*
+   * And the advise holder.
+   */
+  if (ptrToDestroy->oleAdviseHolder!=NULL)
+  {
+    IOleClientSite_Release(ptrToDestroy->oleAdviseHolder);
+    ptrToDestroy->oleAdviseHolder = NULL;
+  }
+
+  /*
+   * And the data advise holder.
+   */
+  if (ptrToDestroy->dataAdviseHolder!=NULL)
+  {
+    IOleClientSite_Release(ptrToDestroy->dataAdviseHolder);
+    ptrToDestroy->dataAdviseHolder = NULL;
+  }
+
+
+  /*
+   * Free the actual default handler structure.
+   */
+  HeapFree(GetProcessHeap(), 0, ptrToDestroy);
+}
+
+/*********************************************************
+ * Method implementation for the  non delegating IUnknown
+ * part of the DefaultHandler class.
+ */
+
+/************************************************************************
+ * DefaultHandler_NDIUnknown_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ *
+ * This version of QueryInterface will not delegate it's implementation
+ * to the outer unknown.
+ */
+static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface(
+            IUnknown*      iface,
+            REFIID         riid,
+            void**         ppvObject)
+{
+  _ICOM_THIS_From_NDIUnknown(DefaultHandler, iface);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppvObject==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+
+  /*
+   * Compare the riid with the interface IDs implemented by This object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = iface;
+  }
+  else if (memcmp(&IID_IOleObject, riid, sizeof(IID_IOleObject)) == 0) 
+  {
+    *ppvObject = (IOleObject*)&(This->lpvtbl1);
+  }
+  else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) 
+  {
+    *ppvObject = (IDataObject*)&(This->lpvtbl3);
+  }
+  else if (memcmp(&IID_IRunnableObject, riid, sizeof(IID_IRunnableObject)) == 0) 
+  {
+    *ppvObject = (IRunnableObject*)&(This->lpvtbl4);
+  }
+  else
+  {
+    /*
+     * Blind aggregate the data cache to "inherit" it's interfaces.
+     */
+    IUnknown_QueryInterface(This->dataCache, riid, ppvObject);
+  }
+  
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+  {
+    char clsid[50];
+
+    WINE_StringFromCLSID((LPCLSID)riid,clsid);
+    
+    WARN(
+	 "() : asking for un supported interface %s\n", 
+	 clsid);
+
+    return E_NOINTERFACE;
+  }
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful. 
+   */
+  IUnknown_AddRef((IUnknown*)*ppvObject);
+
+  return S_OK;;  
+}
+
+/************************************************************************
+ * DefaultHandler_NDIUnknown_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ *
+ * This version of QueryInterface will not delegate it's implementation
+ * to the outer unknown.
+ */
+static ULONG WINAPI DefaultHandler_NDIUnknown_AddRef( 
+            IUnknown*      iface)
+{
+  _ICOM_THIS_From_NDIUnknown(DefaultHandler, iface);
+
+  This->ref++;
+
+  return This->ref;
+}
+
+/************************************************************************
+ * DefaultHandler_NDIUnknown_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ *
+ * This version of QueryInterface will not delegate it's implementation
+ * to the outer unknown.
+ */
+static ULONG WINAPI DefaultHandler_NDIUnknown_Release( 
+            IUnknown*      iface)
+{
+  _ICOM_THIS_From_NDIUnknown(DefaultHandler, iface);
+
+  /*
+   * Decrease the reference count on This object.
+   */
+  This->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (This->ref==0)
+  {
+    DefaultHandler_Destroy(This);
+
+    return 0;
+  }
+  
+  return This->ref;
+}
+
+/*********************************************************
+ * Methods implementation for the IOleObject part of
+ * the DefaultHandler class.
+ */
+
+/************************************************************************
+ * DefaultHandler_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI DefaultHandler_QueryInterface(
+            IOleObject*      iface,
+            REFIID           riid,
+            void**           ppvObject)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject);  
+}
+
+/************************************************************************
+ * DefaultHandler_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DefaultHandler_AddRef( 
+            IOleObject*        iface)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  return IUnknown_AddRef(This->outerUnknown);
+}
+
+/************************************************************************
+ * DefaultHandler_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DefaultHandler_Release( 
+            IOleObject*        iface)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  return IUnknown_Release(This->outerUnknown);
+}
+
+/************************************************************************
+ * DefaultHandler_SetClientSite (IOleObject)
+ *
+ * The default handler's implementation of This method only keeps the
+ * client site pointer for future reference.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_SetClientSite(
+	    IOleObject*        iface,
+	    IOleClientSite*    pClientSite)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  TRACE("(%p, %p)\n", iface, pClientSite);
+
+  /*
+   * Make sure we release the previous client site if there
+   * was one.
+   */
+  if (This->clientSite!=NULL)
+  {
+    IOleClientSite_Release(This->clientSite);
+  }
+
+  This->clientSite = pClientSite;
+
+  if (This->clientSite!=NULL)
+  {
+    IOleClientSite_AddRef(This->clientSite);
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DefaultHandler_GetClientSite (IOleObject)
+ *
+ * The default handler's implementation of This method returns the
+ * last pointer set in IOleObject_SetClientSite.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_GetClientSite(
+	    IOleObject*        iface,
+	    IOleClientSite**   ppClientSite)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  /*
+   * Sanity check.
+   */
+  if (ppClientSite == NULL)
+    return E_POINTER;
+
+  *ppClientSite = This->clientSite;
+
+  if (*ppClientSite!=NULL)
+  {
+    IOleClientSite_Release(*ppClientSite);
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DefaultHandler_SetHostNames (IOleObject)
+ *
+ * The default handler's implementation of This method just stores
+ * the strings and returns S_OK.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_SetHostNames(
+	    IOleObject*        iface,
+	    LPCOLESTR          szContainerApp, 
+	    LPCOLESTR          szContainerObj)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  TRACE("(%p, %s, %s)\n",
+	iface,
+	debugstr_w(szContainerApp), 
+	debugstr_w(szContainerObj));
+
+  /*
+   * Be sure to cleanup before re-assinging the strings.
+   */ 
+  if (This->containerApp!=NULL)
+  {
+    SysFreeString(This->containerApp);
+    This->containerApp = NULL;
+  }
+
+  if (This->containerObj!=NULL)
+  {
+    SysFreeString(This->containerObj);
+    This->containerObj = NULL;
+  }
+
+  /*
+   * Copy the string supplied.
+   */
+  if (szContainerApp != NULL)
+    This->containerApp = SysAllocString(szContainerApp);
+
+  if (szContainerObj != NULL)
+    This->containerObj = SysAllocString(szContainerObj);
+ 
+  return S_OK;
+}
+
+/************************************************************************
+ * DefaultHandler_Close (IOleObject)
+ *
+ * The default handler's implementation of This method is meaningless
+ * without a running server so it does nothing.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_Close(
+	    IOleObject*        iface, 
+	    DWORD              dwSaveOption)
+{
+  TRACE("()\n");
+  return S_OK;
+}
+
+/************************************************************************
+ * DefaultHandler_SetMoniker (IOleObject)
+ *
+ * The default handler's implementation of This method does nothing.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_SetMoniker(
+	    IOleObject*        iface, 
+	    DWORD              dwWhichMoniker,
+	    IMoniker*          pmk)
+{
+  TRACE("(%p, %ld, %p)\n",
+	iface, 
+	dwWhichMoniker, 
+	pmk);
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DefaultHandler_GetMoniker (IOleObject)
+ *
+ * Delegate This request to the client site if we have one.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_GetMoniker(
+	    IOleObject*        iface,
+	    DWORD              dwAssign,
+	    DWORD              dwWhichMoniker,
+	    IMoniker**         ppmk)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  TRACE("(%p, %ld, %ld, %p)\n",
+	iface, dwAssign, dwWhichMoniker, ppmk);
+
+  if (This->clientSite)
+  {
+    return IOleClientSite_GetMoniker(This->clientSite,
+				     dwAssign,
+				     dwWhichMoniker,
+				     ppmk);
+			      
+  }
+
+  return E_UNSPEC;
+}
+
+/************************************************************************
+ * DefaultHandler_InitFromData (IOleObject)
+ *
+ * This method is meaningless if the server is not running
+ * 
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_InitFromData(
+	    IOleObject*        iface, 
+	    IDataObject*       pDataObject, 
+	    BOOL               fCreation,
+	    DWORD              dwReserved)
+{
+  TRACE("(%p, %p, %d, %ld)\n",
+	iface, pDataObject, fCreation, dwReserved);
+
+  return OLE_E_NOTRUNNING;
+}
+
+/************************************************************************
+ * DefaultHandler_GetClipboardData (IOleObject)
+ *
+ * This method is meaningless if the server is not running
+ * 
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_GetClipboardData(
+	    IOleObject*        iface, 
+	    DWORD              dwReserved, 
+	    IDataObject**      ppDataObject)
+{
+  TRACE("(%p, %ld, %p)\n",
+	iface, dwReserved, ppDataObject);
+
+  return OLE_E_NOTRUNNING;
+}
+
+static HRESULT WINAPI DefaultHandler_DoVerb(
+	    IOleObject*        iface, 
+	    LONG               iVerb, 
+	    LPMSG              lpmsg, 
+	    IOleClientSite*    pActiveSite, 
+	    LONG               lindex, 
+	    HWND               hwndParent, 
+	    LPCRECT            lprcPosRect)
+{
+  FIXME(": Stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * DefaultHandler_EnumVerbs (IOleObject)
+ *
+ * The default handler implementation of This method simply delegates
+ * to OleRegEnumVerbs
+ * 
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_EnumVerbs(
+	    IOleObject*        iface, 
+	    IEnumOLEVERB**     ppEnumOleVerb)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  TRACE("(%p, %p)\n", iface, ppEnumOleVerb);
+
+  return OleRegEnumVerbs(&This->clsid, ppEnumOleVerb);
+}
+
+static HRESULT WINAPI DefaultHandler_Update(
+	    IOleObject*        iface)
+{
+  FIXME(": Stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * DefaultHandler_IsUpToDate (IOleObject)
+ *
+ * This method is meaningless if the server is not running
+ * 
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_IsUpToDate(
+	    IOleObject*        iface)
+{
+  TRACE("(%p)\n", iface);
+
+  return OLE_E_NOTRUNNING;
+}
+
+/************************************************************************
+ * DefaultHandler_GetUserClassID (IOleObject)
+ *
+ * TODO: Map to a new class ID if emulation is active.
+ * 
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_GetUserClassID(
+	    IOleObject*        iface, 
+	    CLSID*             pClsid)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  TRACE("(%p, %p)\n", iface, pClsid);
+
+  /*
+   * Sanity check.
+   */
+  if (pClsid==NULL)
+    return E_POINTER;
+
+  memcpy(pClsid, &This->clsid, sizeof(CLSID));
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DefaultHandler_GetUserType (IOleObject)
+ *
+ * The default handler implementation of This method simply delegates
+ * to OleRegGetUserType
+ * 
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_GetUserType(
+	    IOleObject*        iface, 
+	    DWORD              dwFormOfType, 
+	    LPOLESTR*          pszUserType)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  TRACE("(%p, %ld, %p)\n", iface, dwFormOfType, pszUserType);
+
+  return OleRegGetUserType(&This->clsid, dwFormOfType, pszUserType);
+}
+
+/************************************************************************
+ * DefaultHandler_SetExtent (IOleObject)
+ *
+ * This method is meaningless if the server is not running
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_SetExtent(
+	    IOleObject*        iface, 
+	    DWORD              dwDrawAspect, 
+	    SIZEL*             psizel)
+{
+  TRACE("(%p, %lx, (%d,%d))\n", iface, dwDrawAspect, psizel->cx, psizel->cy);
+  return OLE_E_NOTRUNNING;
+}
+
+/************************************************************************
+ * DefaultHandler_GetExtent (IOleObject)
+ *
+ * The default handler's implementation of This method returns uses
+ * the cache to locate the aspect and extract the extent from it.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_GetExtent(
+	    IOleObject*        iface, 
+	    DWORD              dwDrawAspect, 
+	    SIZEL*             psizel)
+{
+  DVTARGETDEVICE* targetDevice;
+  IViewObject2*   cacheView = NULL;
+  HRESULT         hres;
+
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);  
+
+  TRACE("(%p, %lx, %p)\n", iface, dwDrawAspect, psizel);
+
+  hres = IUnknown_QueryInterface(This->dataCache, &IID_IViewObject2, (void**)&cacheView);
+
+  if (FAILED(hres))
+    return E_UNEXPECTED;
+
+  /*
+   * Prepare the call to the cache's GetExtent method.
+   *
+   * Here we would build a valid DVTARGETDEVICE structure
+   * but, since we are calling into the data cache, we 
+   * know it's implementation and we'll skip This 
+   * extra work until later.
+   */
+  targetDevice = NULL;
+
+  hres = IViewObject2_GetExtent(cacheView,
+				dwDrawAspect,
+				-1,
+				targetDevice,
+				psizel);
+
+  /*
+   * Cleanup
+   */
+  IViewObject2_Release(cacheView);
+
+  return hres;
+}
+
+/************************************************************************
+ * DefaultHandler_Advise (IOleObject)
+ *
+ * The default handler's implementation of This method simply
+ * delegates to the OleAdviseHolder.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_Advise(
+	    IOleObject*        iface, 
+	    IAdviseSink*       pAdvSink, 
+	    DWORD*             pdwConnection)
+{
+  HRESULT hres = S_OK;
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);  
+
+  TRACE("(%p, %p, %p)\n", iface, pAdvSink, pdwConnection);
+
+  /*
+   * Make sure we have an advise holder before we start.
+   */
+  if (This->oleAdviseHolder==NULL)
+  {
+    hres = CreateOleAdviseHolder(&This->oleAdviseHolder);
+  }
+
+  if (SUCCEEDED(hres))
+  {
+    hres = IOleAdviseHolder_Advise(This->oleAdviseHolder, 
+				   pAdvSink, 
+				   pdwConnection);
+  }
+
+  return hres;
+}
+
+/************************************************************************
+ * DefaultHandler_Unadvise (IOleObject)
+ *
+ * The default handler's implementation of This method simply
+ * delegates to the OleAdviseHolder.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_Unadvise(
+	    IOleObject*        iface, 
+	    DWORD              dwConnection)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);  
+
+  TRACE("(%p, %ld)\n", iface, dwConnection);
+
+  /*
+   * If we don't have an advise holder yet, it means we don't have
+   * a connection.
+   */
+  if (This->oleAdviseHolder==NULL)
+    return OLE_E_NOCONNECTION;
+
+  return IOleAdviseHolder_Unadvise(This->oleAdviseHolder,
+				   dwConnection);
+}
+
+/************************************************************************
+ * DefaultHandler_EnumAdvise (IOleObject)
+ *
+ * The default handler's implementation of This method simply
+ * delegates to the OleAdviseHolder.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_EnumAdvise(
+	    IOleObject*        iface, 
+	    IEnumSTATDATA**    ppenumAdvise)
+{
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);  
+
+  TRACE("(%p, %p)\n", iface, ppenumAdvise);
+
+  /*
+   * Sanity check
+   */
+  if (ppenumAdvise==NULL)
+    return E_POINTER;
+
+  /*
+   * Initialize the out parameter.
+   */
+  *ppenumAdvise = NULL;
+
+  if (This->oleAdviseHolder==NULL)
+    return IOleAdviseHolder_EnumAdvise(This->oleAdviseHolder,
+				       ppenumAdvise);
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DefaultHandler_GetMiscStatus (IOleObject)
+ *
+ * The default handler's implementation of This method simply delegates
+ * to OleRegGetMiscStatus.
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_GetMiscStatus(
+	    IOleObject*        iface, 
+	    DWORD              dwAspect, 
+	    DWORD*             pdwStatus)
+{
+  HRESULT hres;
+  _ICOM_THIS_From_IOleObject(DefaultHandler, iface);
+
+  TRACE("(%p, %lx, %p)\n", iface, dwAspect, pdwStatus);
+
+  hres = OleRegGetMiscStatus(&(This->clsid), dwAspect, pdwStatus);
+
+  if (FAILED(hres))
+    *pdwStatus = 0;
+
+  return S_OK;
+}
+
+/************************************************************************
+ * DefaultHandler_SetExtent (IOleObject)
+ *
+ * This method is meaningless if the server is not running
+ *
+ * See Windows documentation for more details on IOleObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_SetColorScheme(
+	    IOleObject*           iface,
+	    LOGPALETTE* pLogpal)
+{
+  TRACE("(%p, %p))\n", iface, pLogpal);
+  return OLE_E_NOTRUNNING;
+}
+
+/*********************************************************
+ * Methods implementation for the IDataObject part of
+ * the DefaultHandler class.
+ */
+
+/************************************************************************
+ * DefaultHandler_IDataObject_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI DefaultHandler_IDataObject_QueryInterface(
+            IDataObject*     iface, 
+           REFIID           riid,
+            void**           ppvObject)
+{
+  _ICOM_THIS_From_IDataObject(DefaultHandler, iface);
+
+  return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject);  
+}
+
+/************************************************************************
+ * DefaultHandler_IDataObject_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DefaultHandler_IDataObject_AddRef( 
+            IDataObject*     iface)
+{
+  _ICOM_THIS_From_IDataObject(DefaultHandler, iface);
+
+  return IUnknown_AddRef(This->outerUnknown);  
+}
+
+/************************************************************************
+ * DefaultHandler_IDataObject_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DefaultHandler_IDataObject_Release( 
+            IDataObject*     iface)
+{
+  _ICOM_THIS_From_IDataObject(DefaultHandler, iface);
+
+  return IUnknown_Release(This->outerUnknown);  
+}
+
+static HRESULT WINAPI DefaultHandler_GetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetcIn, 
+	    STGMEDIUM*       pmedium)
+{
+  FIXME(": Stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DefaultHandler_GetDataHere(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatetc,
+	    STGMEDIUM*       pmedium)
+{
+  FIXME(": Stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * DefaultHandler_QueryGetData (IDataObject)
+ *
+ * The default handler's implementation of This method delegates to 
+ * the cache.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_QueryGetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc)
+{
+  IDataObject* cacheDataObject = NULL;
+  HRESULT      hres;
+
+  _ICOM_THIS_From_IDataObject(DefaultHandler, iface);
+
+  TRACE("(%p, %p)\n", iface, pformatetc);
+
+  hres = IUnknown_QueryInterface(This->dataCache, 
+				 &IID_IDataObject,
+				 (void**)&cacheDataObject);
+
+  if (FAILED(hres))
+    return E_UNEXPECTED;
+
+  hres = IDataObject_QueryGetData(cacheDataObject,
+				  pformatetc);
+
+  IDataObject_Release(cacheDataObject);
+  
+  return hres;
+}
+
+/************************************************************************
+ * DefaultHandler_GetCanonicalFormatEtc (IDataObject)
+ *
+ * This method is meaningless if the server is not running
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_GetCanonicalFormatEtc(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatectIn, 
+	    LPFORMATETC      pformatetcOut)
+{
+  FIXME("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut);
+
+  return OLE_E_NOTRUNNING;
+}
+
+/************************************************************************
+ * DefaultHandler_SetData (IDataObject)
+ *
+ * The default handler's implementation of This method delegates to 
+ * the cache.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_SetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc, 
+	    STGMEDIUM*       pmedium, 
+	    BOOL             fRelease)
+{
+  IDataObject* cacheDataObject = NULL;
+  HRESULT      hres;
+
+  _ICOM_THIS_From_IDataObject(DefaultHandler, iface);
+
+  TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease);
+
+  hres = IUnknown_QueryInterface(This->dataCache, 
+				 &IID_IDataObject,
+				 (void**)&cacheDataObject);
+
+  if (FAILED(hres))
+    return E_UNEXPECTED;
+
+  hres = IDataObject_SetData(cacheDataObject,
+			     pformatetc,
+			     pmedium,
+			     fRelease);
+  
+  IDataObject_Release(cacheDataObject);
+  
+  return hres;
+}
+
+/************************************************************************
+ * DefaultHandler_EnumFormatEtc (IDataObject)
+ *
+ * The default handler's implementation of This method simply delegates
+ * to OleRegEnumFormatEtc.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_EnumFormatEtc(
+	    IDataObject*     iface,       
+	    DWORD            dwDirection,
+	    IEnumFORMATETC** ppenumFormatEtc)
+{
+  HRESULT hres;
+  _ICOM_THIS_From_IDataObject(DefaultHandler, iface);
+
+  TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc);
+
+  hres = OleRegEnumFormatEtc(&(This->clsid), dwDirection, ppenumFormatEtc);
+
+  return hres;
+}
+
+/************************************************************************
+ * DefaultHandler_DAdvise (IDataObject)
+ *
+ * The default handler's implementation of This method simply
+ * delegates to the DataAdviseHolder.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_DAdvise(
+	    IDataObject*     iface, 
+	    FORMATETC*       pformatetc, 
+	    DWORD            advf, 
+	    IAdviseSink*     pAdvSink, 
+	    DWORD*           pdwConnection)
+{
+  HRESULT hres = S_OK;
+  _ICOM_THIS_From_IDataObject(DefaultHandler, iface);  
+
+  TRACE("(%p, %p, %ld, %p, %p)\n", 
+	iface, pformatetc, advf, pAdvSink, pdwConnection);
+
+  /*
+   * Make sure we have a data advise holder before we start.
+   */
+  if (This->dataAdviseHolder==NULL)
+  {
+    hres = CreateDataAdviseHolder(&This->dataAdviseHolder);
+  }
+
+  if (SUCCEEDED(hres))
+  {
+    hres = IDataAdviseHolder_Advise(This->dataAdviseHolder, 
+				    iface,
+				    pformatetc, 
+				    advf, 
+				    pAdvSink, 
+				    pdwConnection);
+  }
+
+  return hres;
+}
+
+/************************************************************************
+ * DefaultHandler_DUnadvise (IDataObject)
+ *
+ * The default handler's implementation of This method simply
+ * delegates to the DataAdviseHolder.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_DUnadvise(
+	    IDataObject*     iface,
+	    DWORD            dwConnection)
+{
+  _ICOM_THIS_From_IDataObject(DefaultHandler, iface);  
+
+  TRACE("(%p, %ld)\n", iface, dwConnection);
+
+  /*
+   * If we don't have a data advise holder yet, it means that
+   * we don't have any connections..
+   */
+  if (This->dataAdviseHolder==NULL)
+  {
+    return OLE_E_NOCONNECTION;
+  }
+
+  return IDataAdviseHolder_Unadvise(This->dataAdviseHolder, 
+				    dwConnection);
+}
+
+/************************************************************************
+ * DefaultHandler_EnumDAdvise (IDataObject)
+ *
+ * The default handler's implementation of This method simply
+ * delegates to the DataAdviseHolder.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_EnumDAdvise(
+	    IDataObject*     iface,
+	    IEnumSTATDATA**  ppenumAdvise)
+{
+  _ICOM_THIS_From_IDataObject(DefaultHandler, iface);  
+
+  TRACE("(%p, %p)\n", iface, ppenumAdvise);
+
+  /*
+   * Sanity check
+   */
+  if (ppenumAdvise == NULL)
+    return E_POINTER;
+
+  /*
+   * Initialize the out parameter.
+   */
+  *ppenumAdvise = NULL;
+
+  /*
+   * If we have a data advise holder object, delegate.
+   */
+  if (This->dataAdviseHolder!=NULL)
+  {
+    return IDataAdviseHolder_EnumAdvise(This->dataAdviseHolder, 
+					ppenumAdvise);
+  }
+
+  return S_OK;
+}
+
+/*********************************************************
+ * Methods implementation for the IRunnableObject part 
+ * of the DefaultHandler class.
+ */
+
+/************************************************************************
+ * DefaultHandler_IRunnableObject_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI DefaultHandler_IRunnableObject_QueryInterface(
+            IRunnableObject*     iface,
+            REFIID               riid,
+            void**               ppvObject)
+{
+  _ICOM_THIS_From_IRunnableObject(DefaultHandler, iface);
+
+  return IUnknown_QueryInterface(This->outerUnknown, riid, ppvObject);  
+}
+
+/************************************************************************
+ * DefaultHandler_IRunnableObject_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DefaultHandler_IRunnableObject_AddRef( 
+            IRunnableObject*     iface)
+{
+  _ICOM_THIS_From_IRunnableObject(DefaultHandler, iface);
+
+  return IUnknown_AddRef(This->outerUnknown);
+}
+
+/************************************************************************
+ * DefaultHandler_IRunnableObject_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DefaultHandler_IRunnableObject_Release( 
+            IRunnableObject*     iface)
+{
+  _ICOM_THIS_From_IRunnableObject(DefaultHandler, iface);
+
+  return IUnknown_Release(This->outerUnknown);
+}
+
+/************************************************************************
+ * DefaultHandler_GetRunningClass (IRunnableObject)
+ *
+ * According to Brockscmidt, Chapter 19, the default handler's 
+ * implementation of IRunnableobject does nothing until the object
+ * is actually running.
+ *
+ * See Windows documentation for more details on IRunnableObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_GetRunningClass( 
+            IRunnableObject*     iface,   
+	    LPCLSID              lpClsid)
+{
+  TRACE("()\n");
+  return S_OK;
+}
+
+static HRESULT WINAPI DefaultHandler_Run( 
+            IRunnableObject*     iface,
+	    IBindCtx*            pbc)
+{
+  FIXME(": Stub\n");
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * DefaultHandler_IsRunning (IRunnableObject)
+ *
+ * According to Brockscmidt, Chapter 19, the default handler's 
+ * implementation of IRunnableobject does nothing until the object
+ * is actually running.
+ *
+ * See Windows documentation for more details on IRunnableObject methods.
+ */
+static BOOL    WINAPI DefaultHandler_IsRunning( 
+            IRunnableObject*     iface)
+{
+  TRACE("()\n");
+  return S_FALSE;
+}
+
+/************************************************************************
+ * DefaultHandler_LockRunning (IRunnableObject)
+ *
+ * According to Brockscmidt, Chapter 19, the default handler's 
+ * implementation of IRunnableobject does nothing until the object
+ * is actually running.
+ *
+ * See Windows documentation for more details on IRunnableObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_LockRunning( 
+            IRunnableObject*     iface, 
+	    BOOL                 fLock, 
+	    BOOL                 fLastUnlockCloses)
+{
+  TRACE("()\n");
+  return S_OK;
+}
+
+/************************************************************************
+ * DefaultHandler_SetContainedObject (IRunnableObject)
+ *
+ * According to Brockscmidt, Chapter 19, the default handler's 
+ * implementation of IRunnableobject does nothing until the object
+ * is actually running.
+ *
+ * See Windows documentation for more details on IRunnableObject methods.
+ */
+static HRESULT WINAPI DefaultHandler_SetContainedObject( 
+            IRunnableObject*     iface, 
+	    BOOL                 fContained)
+{
+  TRACE("()\n");
+  return S_OK;
+}
+
Index: trunk/src/ole32/new/filemoniker.cpp
===================================================================
--- trunk/src/ole32/new/filemoniker.cpp	(revision 3456)
+++ trunk/src/ole32/new/filemoniker.cpp	(revision 3456)
@@ -0,0 +1,1428 @@
+/* $Id: filemoniker.cpp,v 1.1 2000-04-27 22:18:16 davidr Exp $ */
+/* 
+ *  FileMonikers functions.
+ * 
+ * 20/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *   Copyright 1999  Noomen Hamza
+ */
+
+#include "ole32.h"
+#include "heapstring.h"
+#include "debugtools.h"
+#include "filemoniker.h"
+#include "winnls.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+/********************************************************************************/
+/* FileMoniker prototype functions :                                            */
+
+/* IUnknown prototype functions */
+static HRESULT WINAPI FileMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject);
+static ULONG   WINAPI FileMonikerImpl_AddRef(IMoniker* iface);
+static ULONG   WINAPI FileMonikerImpl_Release(IMoniker* iface);
+
+/* IPersist prototype functions */
+static HRESULT WINAPI FileMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID);
+
+/* IPersistStream prototype functions */
+static HRESULT WINAPI FileMonikerImpl_IsDirty(IMoniker* iface);
+static HRESULT WINAPI FileMonikerImpl_Load(IMoniker* iface, IStream* pStm);
+static HRESULT WINAPI FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty);
+static HRESULT WINAPI FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize);
+
+/* IMoniker prototype functions */
+static HRESULT WINAPI FileMonikerImpl_BindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult);
+static HRESULT WINAPI FileMonikerImpl_BindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult);
+static HRESULT WINAPI FileMonikerImpl_Reduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced);
+static HRESULT WINAPI FileMonikerImpl_ComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite);
+static HRESULT WINAPI FileMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker);
+static HRESULT WINAPI FileMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker);
+static HRESULT WINAPI FileMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash);
+static HRESULT WINAPI FileMonikerImpl_IsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning);
+static HRESULT WINAPI FileMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pFileTime);
+static HRESULT WINAPI FileMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk);
+static HRESULT WINAPI FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix);
+static HRESULT WINAPI FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath);
+static HRESULT WINAPI FileMonikerImpl_GetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName);
+static HRESULT WINAPI FileMonikerImpl_ParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut);
+static HRESULT WINAPI FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys);
+
+/********************************************************************************/
+/* IROTData prototype functions                                                 */
+
+/* IUnknown prototype functions */
+static HRESULT WINAPI FileMonikerROTDataImpl_QueryInterface(IROTData* iface,REFIID riid,VOID** ppvObject);
+static ULONG   WINAPI FileMonikerROTDataImpl_AddRef(IROTData* iface);
+static ULONG   WINAPI FileMonikerROTDataImpl_Release(IROTData* iface);
+
+/* IROTData prototype function */
+static HRESULT WINAPI FileMonikerROTDataImpl_GetComparaisonData(IROTData* iface,BYTE* pbData,ULONG cbMax,ULONG* pcbData);
+
+
+/********************************************************************************/
+/* Virtual function table for the FileMonikerImpl class witch  include Ipersist,*/
+/* IPersistStream and IMoniker functions.                                       */
+static ICOM_VTABLE(IMoniker) VT_FileMonikerImpl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    FileMonikerImpl_QueryInterface,
+    FileMonikerImpl_AddRef,
+    FileMonikerImpl_Release,
+    FileMonikerImpl_GetClassID,
+    FileMonikerImpl_IsDirty,
+    FileMonikerImpl_Load,
+    FileMonikerImpl_Save,
+    FileMonikerImpl_GetSizeMax,
+    FileMonikerImpl_BindToObject,
+    FileMonikerImpl_BindToStorage,
+    FileMonikerImpl_Reduce,
+    FileMonikerImpl_ComposeWith,
+    FileMonikerImpl_Enum,
+    FileMonikerImpl_IsEqual,
+    FileMonikerImpl_Hash,
+    FileMonikerImpl_IsRunning,
+    FileMonikerImpl_GetTimeOfLastChange,
+    FileMonikerImpl_Inverse,
+    FileMonikerImpl_CommonPrefixWith,
+    FileMonikerImpl_RelativePathTo,
+    FileMonikerImpl_GetDisplayName,
+    FileMonikerImpl_ParseDisplayName,
+    FileMonikerImpl_IsSystemMoniker
+};
+
+/********************************************************************************/
+/* Virtual function table for the IROTData class.                               */
+static ICOM_VTABLE(IROTData) VT_ROTDataImpl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    FileMonikerROTDataImpl_QueryInterface,
+    FileMonikerROTDataImpl_AddRef,
+    FileMonikerROTDataImpl_Release,
+    FileMonikerROTDataImpl_GetComparaisonData
+};
+
+/*******************************************************************************
+ *        FileMoniker_QueryInterface
+ *******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
+{
+    ICOM_THIS(FileMonikerImpl,iface);
+  
+  TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
+
+    /* Perform a sanity check on the parameters.*/
+    if ( (This==0) || (ppvObject==0) )
+	return E_INVALIDARG;
+  
+    /* Initialize the return parameter */
+  *ppvObject = 0;
+
+    /* Compare the riid with the interface IDs implemented by this object.*/
+    if (IsEqualIID(&IID_IUnknown, riid)      ||
+        IsEqualIID(&IID_IPersist, riid)      ||
+        IsEqualIID(&IID_IPersistStream,riid) ||
+        IsEqualIID(&IID_IMoniker, riid)
+       )
+        *ppvObject = iface;
+    
+    else if (IsEqualIID(&IID_IROTData, riid))
+        *ppvObject = (IROTData*)&(This->lpvtbl2);
+
+    /* Check that we obtained an interface.*/
+    if ((*ppvObject)==0)
+        return E_NOINTERFACE;
+  
+    /* Query Interface always increases the reference count by one when it is successful */
+  FileMonikerImpl_AddRef(iface);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        FileMoniker_AddRef
+ ******************************************************************************/
+ULONG WINAPI FileMonikerImpl_AddRef(IMoniker* iface)
+{
+    ICOM_THIS(FileMonikerImpl,iface);
+
+    TRACE("(%p)\n",iface);
+
+    return ++(This->ref);
+}
+
+/******************************************************************************
+ *        FileMoniker_Release
+ ******************************************************************************/
+ULONG WINAPI FileMonikerImpl_Release(IMoniker* iface)
+{
+    ICOM_THIS(FileMonikerImpl,iface);
+
+    TRACE("(%p)\n",iface);
+
+    This->ref--;
+
+    /* destroy the object if there's no more reference on it */
+    if (This->ref==0){
+
+        FileMonikerImpl_Destroy(This);
+
+        return 0;
+    }
+    return This->ref;;
+}
+
+/******************************************************************************
+ *        FileMoniker_GetClassID
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_GetClassID(IMoniker* iface,
+                                          CLSID *pClassID)/* Pointer to CLSID of object */
+{
+    TRACE("(%p,%p),stub!\n",iface,pClassID);
+
+    if (pClassID==NULL)
+        return E_POINTER;
+
+    *pClassID = CLSID_FileMoniker;
+        
+    return S_OK;
+}
+
+/******************************************************************************
+ *        FileMoniker_IsDirty
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_IsDirty(IMoniker* iface)
+{
+    /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
+       method in the OLE-provided moniker interfaces always return S_FALSE because
+       their internal state never changes. */
+
+    TRACE("(%p)\n",iface);
+
+    return S_FALSE;
+}
+
+/******************************************************************************
+ *        FileMoniker_Load
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_Load(IMoniker* iface,IStream* pStm)
+{
+    HRESULT res;
+    CHAR* filePathA=NULL;
+    WCHAR* filePathW=NULL;
+    ULONG bread;
+    WORD  wbuffer;
+    DWORD i;
+    DWORD dwAnsiLength, dwUnicodeLength;
+    DWORD dwOffsetToEndUnicodeStr; 
+    WCHAR tempUnicodePath[MAX_PATH];
+    ICOM_THIS(FileMonikerImpl,iface);
+
+    TRACE("(%p,%p)\n",iface,pStm);
+
+    /* this function locate and read from the stream the filePath string writen by FileMonikerImpl_Save */
+
+    /* first WORD is non significative */
+    res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
+    if (bread!=sizeof(WORD) || wbuffer!=0)
+        return E_FAIL;
+    
+    /* read filePath string length (plus one) */
+    res=IStream_Read(pStm,&dwAnsiLength,sizeof(DWORD),&bread);
+    if (bread != sizeof(DWORD))
+        return E_FAIL;
+
+    if(dwAnsiLength > 0)
+    {
+        /* read filePath string */
+        filePathA=(CHAR *)HeapAlloc(GetProcessHeap(),0,dwAnsiLength);
+        res=IStream_Read(pStm,filePathA,dwAnsiLength,&bread);
+        if (bread != dwAnsiLength)
+            return E_FAIL;
+    }
+    tempUnicodePath[0] = 0;
+    if(filePathA != NULL)
+    {
+        MultiByteToWideChar(CP_ACP, 0, filePathA, -1, tempUnicodePath, MAX_PATH);
+    }
+    FileMonikerImpl_CheckFileFormat(This, tempUnicodePath);
+
+    IStream_Read(pStm, &(This->wNetworkDomainLenght), sizeof(WORD), &bread);
+    if(bread != sizeof(WORD))
+    {
+        return E_FAIL;
+    }
+    /* read the first constant */
+    IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
+    if (bread != sizeof(WORD) || wbuffer != 0xDEAD)
+        return E_FAIL;
+	
+    for(i=0;i<10;i++){
+        res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
+        if (bread!=sizeof(WORD) || wbuffer!=0)
+            return E_FAIL;
+    }
+    
+    res=IStream_Read(pStm,&dwOffsetToEndUnicodeStr,sizeof(DWORD),&bread);
+    if (bread != sizeof(DWORD))
+        return E_FAIL;
+    if(dwOffsetToEndUnicodeStr != 0)
+    {
+        res=IStream_Read(pStm,&dwUnicodeLength,sizeof(DWORD),&bread);
+        if (bread!=sizeof(DWORD))
+            return E_FAIL;
+
+
+        res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread);
+        if (bread!=sizeof(WORD) || wbuffer!=0x3)
+            return E_FAIL;
+
+        if(dwUnicodeLength > 0)
+        {
+            filePathW=(WCHAR *)HeapAlloc(GetProcessHeap(),0,dwUnicodeLength + sizeof(WCHAR));
+            res=IStream_Read(pStm, filePathW, dwUnicodeLength,&bread);
+            filePathW[dwAnsiLength-1]=0;
+            if (bread!=dwUnicodeLength)
+                return E_FAIL;
+        }
+    }
+    else
+    {
+        if(filePathA != NULL)
+        {
+            filePathW=(WCHAR *)HeapAlloc(GetProcessHeap(),0,dwAnsiLength*sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, filePathA, -1, filePathW, dwAnsiLength); 
+            filePathW[dwAnsiLength-1]=0;
+        }
+    }
+
+    if (This->filePathName!=NULL)
+        HeapFree(GetProcessHeap(),0,This->filePathName);
+
+    This->filePathName=filePathW;
+
+    if(filePathA != NULL)
+    {
+        HeapFree(GetProcessHeap(),0,filePathA);
+    }
+    
+    return res;
+}
+
+/******************************************************************************
+ *        FileMoniker_Save
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_Save(IMoniker* iface,
+                                    IStream* pStm,/* poniter to the stream where the object is to be saved */
+                                    BOOL fClearDirty)/* Specifies whether to clear the dirty flag */
+{
+    /* this function saves data of this object. In the begining I thougth that I have just to write
+     * the filePath string on Stream. But, when I tested this function whith windows programs samples !
+     * I noted that it was not the case. So I analysed data writen by this function on Windows system and 
+     * what did this function do exactly ! but I have no idear a bout its logic !
+     * I guessed data who must be writen on stream wich is:
+     * 1) WORD constant:zero 2) length of the path string ("\0" included) 3) path string type A
+     * 4) DWORD constant : 0xDEADFFFF 5) ten WORD constant: zero  6) DWORD: double-length of the the path
+     * string type W ("\0" not included) 7) WORD constant: 0x3 8) filePath unicode string.
+     *  if the length(filePath) > 8 or.length(filePath) == 8 stop at step 5)
+     */
+
+    ICOM_THIS(FileMonikerImpl,iface);        
+
+    HRESULT res;
+    LPOLESTR filePathW=This->filePathName;
+    CHAR*     filePathA=NULL;
+    DWORD  len=0;
+
+    WORD  constant1 = 0xDEAD; /* these constants are detected after analysing the data structure writen by */
+    WORD   constant2 = 0x3;        /* FileMoniker_Save function in a windows program system */
+    WORD wUnicodeLen=0xFFFF;  
+    DWORD dwOffsetToEndUnicodeStr=0; 
+
+    WORD   zero=0;
+    DWORD doubleLenHex;
+    int i=0;
+    WCHAR temp = 0;
+
+
+    TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
+
+    if (pStm==NULL)
+        return E_POINTER;
+    if(filePathW == NULL)
+    {
+        return S_FALSE;  /* TODO: Check what windows returns */
+    }
+
+    doubleLenHex=lstrlenW(filePathW) * sizeof(WCHAR); /* Doesn't include the "\0" */
+    len = lstrlenW(filePathW)+1;
+    filePathA=(CHAR *)HeapAlloc(GetProcessHeap(), 0,len);
+    lstrcpyWtoA(filePathA,filePathW);
+    
+    if(!This->bIsLongFileName && len > 1)
+    {
+        
+        dwOffsetToEndUnicodeStr = sizeof(DWORD) + sizeof(WORD) + doubleLenHex;
+    }
+
+    /* write a DWORD seted to 0 : constant */
+    /* TODO: Not Sure, but I believe that this is a constant for  char types */
+    /* eg. 0000 for Ansi, 0003 for Unicode, will need to verify this  */
+    res=IStream_Write(pStm,&zero,sizeof(WORD),NULL);
+
+    /* write length of filePath string ( "\0" included )*/
+    res=IStream_Write(pStm,&len,sizeof(DWORD),NULL);
+
+    /* write filePath string type A */
+    res=IStream_Write(pStm,filePathA,len,NULL);
+
+    /*When the file path is a network path, it fills this value with */
+    /*Lenght in of the domain/share drive name */
+    res=IStream_Write(pStm, &(This->wNetworkDomainLenght), sizeof(wUnicodeLen), NULL);
+    /* write a WORD seted to 0xDEAD: constant */
+    res=IStream_Write(pStm,&constant1,sizeof(constant1),NULL);
+	
+    len--;
+    /* write 10 times a WORD seted to 0 : constants */
+    for(i=0;i<10;i++)
+        res=IStream_Write(pStm,&zero,sizeof(WORD),NULL);
+
+    /* when a file path is a file or network path that doesn't fallow the dos 8.3 format  */
+    /* it creates the unicode data.  This value is offset */
+    /* where the Unicode string ends.  If the file is a long dos filename (or network containing a long filename)*/
+    /* it doesn't create it's unicode counterpart */    
+    res=IStream_Write(pStm, &dwOffsetToEndUnicodeStr, sizeof(DWORD), NULL);
+    if(dwOffsetToEndUnicodeStr != 0)
+    {
+        /* write double-length (hexa representation) of the path string*/
+        res=IStream_Write(pStm, &doubleLenHex, sizeof(DWORD),NULL);
+        /* write a WORD seted to 0x3: constant */
+        /* TODO: (same as above) Not Sure, but I believe that this is a constant for  char types */
+        /* eg. 0000 for Ansi, 0003 for Unicode, will need to verify this  */
+        res=IStream_Write(pStm, &constant2, sizeof(WORD),NULL);
+        /* write path unicode string */
+        if(doubleLenHex > 0)
+        {
+            res=IStream_Write(pStm, filePathW, doubleLenHex,NULL);
+        }
+    }
+    if(filePathA != NULL)
+    {
+        HeapFree(GetProcessHeap(),0,filePathA);
+    }
+    return res;
+}
+
+/******************************************************************************
+ *        FileMoniker_GetSizeMax
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_GetSizeMax(IMoniker* iface,
+                                          ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */
+{
+    ICOM_THIS(FileMonikerImpl,iface);
+    DWORD len=lstrlenW(This->filePathName);
+    DWORD sizeMAx;
+
+    TRACE("(%p,%p)\n",iface,pcbSize);
+
+    if (pcbSize==NULL)
+        return E_POINTER;
+
+    /* for more details see FileMonikerImpl_Save coments */
+    
+    sizeMAx =  sizeof(WORD) +           /* first WORD is 0 */
+               sizeof(DWORD)+           /* length of filePath including "\0" in the end of the string */
+               (len+1)+                 /* filePath string */
+               sizeof(DWORD)+           /* constant : 0xDEADFFFF */
+               10*sizeof(WORD)+         /* 10 zero WORD */
+               sizeof(DWORD);           /* size of the unicode filePath: "\0" not included */
+
+    if(!This->bIsLongFileName)
+    {
+        
+        sizeMAx += sizeof(DWORD)+           /* size of the unicode filePath: "\0" not included */
+                   sizeof(WORD)+            /* constant : 0x3 */
+                   len*sizeof(WCHAR);       /* unicde filePath string */
+    }
+    
+    pcbSize->LowPart=sizeMAx;
+    pcbSize->HighPart=0;
+
+    return S_OK;
+}
+
+void WINAPI FileMonikerImpl_CheckFileFormat(FileMonikerImpl* This, LPCOLESTR lpszPathName)
+{
+    int len;
+    WCHAR tempShortPath[MAX_PATH];
+
+    This->bIsNetworkPath = FALSE;
+    This->bIsLongFileName = FALSE;
+    This->wNetworkDomainLenght = 0xFFFF;
+
+    /* TODO: Not handling invalid filesname  and invalid UNC Filenames */
+    /* Filenames that doesn't conform to dos 8.3, are handled diffently when saving and loading */
+    /* Same applies to network path, but only after the \\Domain\Share path */
+
+    if(lpszPathName == NULL)
+    {
+        return;
+    }
+    len = lstrlenW(lpszPathName);
+    if(len == 0)
+    {
+        return;
+    }
+
+    if( len >= 2)
+    {
+        /* Is this a network path */
+        if(lpszPathName[0] == '\\' && lpszPathName[1] == '\\')
+        {
+            int i=2; /* Skip the \\ */
+            int j=0;
+            This->bIsNetworkPath = TRUE;
+            /* Skip Domain name \ share drive name */
+            for(j =0; j < 2; j++)
+            {
+                for(; i < len && lpszPathName[i] != '\\'; i++)
+                {
+                }
+                i++;
+            }
+            This->wNetworkDomainLenght = i-1;
+            if( i < len)
+            {
+                /* Check to see if the file fallows the dos file format (8.3)*/
+                GetShortPathNameW(&(lpszPathName[i]), tempShortPath, MAX_PATH);
+                if(lstrcmpiW(&(lpszPathName[i]), tempShortPath) != 0)
+                {
+                    This->bIsLongFileName = TRUE;
+                }
+            }
+        }
+        
+        else
+        {
+            GetShortPathNameW(lpszPathName, tempShortPath, MAX_PATH);
+            if(lstrcmpiW(lpszPathName, tempShortPath) != 0)
+            {
+                This->bIsLongFileName = TRUE;
+            }
+        }
+    }
+}
+/******************************************************************************
+ *         FileMoniker_Construct (local function)
+ *******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_Construct(FileMonikerImpl* This, LPCOLESTR lpszPathName)
+{
+    int nb=0,i;
+    int sizeStr=lstrlenW(lpszPathName);
+    LPOLESTR *tabStr=0;
+    WCHAR twoPoint[]={'.','.',0};
+    WCHAR bkSlash[]={'\\',0};
+    BYTE addBkSlash;
+    
+    TRACE("(%p,%p)\n",This,lpszPathName);
+
+    /* Initialize the virtual fgunction table. */
+    This->lpvtbl1      = &VT_FileMonikerImpl;
+    This->lpvtbl2      = &VT_ROTDataImpl;
+    This->ref          = 0;
+
+    This->filePathName=(WCHAR *)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr+1));
+
+    if (This->filePathName==NULL)
+        return E_OUTOFMEMORY;
+
+    lstrcpyW(This->filePathName,lpszPathName);
+
+    nb=FileMonikerImpl_DecomposePath(This->filePathName,&tabStr);
+
+    if (nb > 0 ){
+
+        addBkSlash=1;
+        if (lstrcmpW(tabStr[0],twoPoint)!=0)
+            addBkSlash=0;
+        else
+            for(i=0;i<nb;i++){
+
+                if ( (lstrcmpW(tabStr[i],twoPoint)!=0) && (lstrcmpW(tabStr[i],bkSlash)!=0) ){
+                    addBkSlash=0;
+                    break;
+                }
+                else
+
+                    if (lstrcmpW(tabStr[i],bkSlash)==0 && i<nb-1 && lstrcmpW(tabStr[i+1],bkSlash)==0){
+                        *tabStr[i]=0;
+                        sizeStr--;
+                        addBkSlash=0;
+                        break;
+                    }
+            }
+
+        if (lstrcmpW(tabStr[nb-1],bkSlash)==0)
+            addBkSlash=0;
+
+        This->filePathName=(WCHAR *)HeapReAlloc(GetProcessHeap(),0,This->filePathName,(sizeStr+1)*sizeof(WCHAR));
+
+        *This->filePathName=0;
+    
+        for(i=0;tabStr[i]!=NULL;i++)
+            lstrcatW(This->filePathName,tabStr[i]);
+    
+        if (addBkSlash)
+            lstrcatW(This->filePathName,bkSlash);
+    }
+
+    FileMonikerImpl_CheckFileFormat(This, This->filePathName);
+    for(i=0; tabStr[i]!=NULL;i++)
+        CoTaskMemFree(tabStr[i]);
+    CoTaskMemFree(tabStr);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        FileMoniker_Destroy (local function)
+ *******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* This)
+{
+    TRACE("(%p)\n",This);
+
+    if (This->filePathName!=NULL)
+            HeapFree(GetProcessHeap(),0,This->filePathName);
+
+    HeapFree(GetProcessHeap(),0,This);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *                  FileMoniker_BindToObject
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_BindToObject(IMoniker* iface,
+                                            IBindCtx* pbc,
+                                            IMoniker* pmkToLeft,
+                                            REFIID riid,
+                                            VOID** ppvResult)
+{
+    HRESULT   res=E_FAIL;
+    CLSID     clsID;
+    IUnknown* pObj=0;
+    IRunningObjectTable *prot=0;
+    IPersistFile  *ppf=0;
+    IClassFactory *pcf=0;
+    IClassActivator *pca=0;
+    
+    ICOM_THIS(FileMonikerImpl,iface);    
+
+    *ppvResult=0;
+
+    TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
+
+    if(pmkToLeft==NULL){
+        
+        res=IBindCtx_GetRunningObjectTable(pbc,&prot);
+
+        if (SUCCEEDED(res)){
+            /* if the requested class was loaded befor ! we dont need to reload it */
+            res = IRunningObjectTable_GetObject(prot,iface,&pObj);
+
+            if (res==S_FALSE){
+                /* first activation of this class */
+                res=GetClassFile(This->filePathName,&clsID);
+                if (SUCCEEDED(res)){
+
+                    res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IPersistFile,(void**)&ppf);
+                    if (SUCCEEDED(res)){
+
+                        res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
+                        if (SUCCEEDED(res)){
+
+                            pObj=(IUnknown*)ppf;
+                            IUnknown_AddRef(pObj);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    else{
+        res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassFactory,(void**)&pcf);
+
+        if (res==E_NOINTERFACE){
+
+            res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassActivator,(void**)&pca);
+        
+            if (res==E_NOINTERFACE)
+                return MK_E_INTERMEDIATEINTERFACENOTSUPPORTED;
+        }
+        if (pcf!=NULL){
+
+            IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)ppf);
+
+            res=IPersistFile_Load(ppf,This->filePathName,STGM_READ);
+
+            if (SUCCEEDED(res)){
+
+                pObj=(IUnknown*)ppf;
+                IUnknown_AddRef(pObj);
+            }
+        }
+        if (pca!=NULL){
+
+            FIXME("()");
+            
+            /*res=GetClassFile(This->filePathName,&clsID);
+
+            if (SUCCEEDED(res)){
+
+                res=IClassActivator_GetClassObject(pca,&clsID,CLSCTX_ALL,0,&IID_IPersistFile,(void**)&ppf);
+
+                if (SUCCEEDED(res)){
+
+                    pObj=(IUnknown*)ppf;
+                    IUnknown_AddRef(pObj);
+                }
+            }*/
+        }
+}
+
+    if (pObj!=NULL){
+        /* get the requested interface from the loaded class */
+        res= IUnknown_QueryInterface(pObj,riid,ppvResult);
+
+        IBindCtx_RegisterObjectBound(pbc,(IUnknown*)*ppvResult);
+
+        IUnknown_Release(pObj);
+    }
+
+    if (prot!=NULL)
+        IRunningObjectTable_Release(prot);
+
+    if (ppf!=NULL)
+        IPersistFile_Release(ppf);
+
+    if (pca!=NULL)
+        IClassActivator_Release(pca);
+
+    if (pcf!=NULL)
+        IClassFactory_Release(pcf);
+    
+    return res;
+}
+
+/******************************************************************************
+ *        FileMoniker_BindToStorage
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_BindToStorage(IMoniker* iface,
+                                             IBindCtx* pbc,
+                                             IMoniker* pmkToLeft,
+                                             REFIID riid,
+                                             VOID** ppvObject)
+{
+    LPOLESTR filePath=0;
+    IStorage *pstg=0;
+    HRESULT res;
+
+    TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvObject);
+
+    if (pmkToLeft==NULL){
+
+        if (IsEqualIID(&IID_IStorage, riid)){
+
+            /* get the file name */
+            FileMonikerImpl_GetDisplayName(iface,pbc,pmkToLeft,&filePath);
+
+            /* verifie if the file contains a storage object */
+            res=StgIsStorageFile(filePath);
+
+            if(res==S_OK){
+
+                res=StgOpenStorage(filePath,NULL,STGM_READWRITE|STGM_SHARE_DENY_WRITE,NULL,0,&pstg);
+
+                if (SUCCEEDED(res)){
+
+                    *ppvObject=pstg;
+
+                    IStorage_AddRef(pstg);
+
+                    return res;
+                }
+            }
+            CoTaskMemFree(filePath);
+        }
+        else
+            if ( (IsEqualIID(&IID_IStream, riid)) || (IsEqualIID(&IID_ILockBytes, riid)) )
+
+                return E_UNSPEC;
+            else
+
+                return E_NOINTERFACE;
+    }
+    else {
+
+        FIXME("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvObject);
+
+    return E_NOTIMPL;
+}
+    return res;
+}
+
+/******************************************************************************
+ *        FileMoniker_Reduce
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_Reduce(IMoniker* iface,
+                                      IBindCtx* pbc,
+                                      DWORD dwReduceHowFar,
+                                      IMoniker** ppmkToLeft,
+                                      IMoniker** ppmkReduced)
+{
+    TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
+
+    if (ppmkReduced==NULL)
+        return E_POINTER;
+
+    FileMonikerImpl_AddRef(iface);
+
+    *ppmkReduced=iface;
+
+    return MK_S_REDUCED_TO_SELF;
+}
+/******************************************************************************
+ *        FileMoniker_ComposeWith
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_ComposeWith(IMoniker* iface,
+                                           IMoniker* pmkRight,
+                                           BOOL fOnlyIfNotGeneric,
+                                           IMoniker** ppmkComposite)
+{
+    HRESULT res;
+    LPOLESTR str1=0,str2=0,*strDec1=0,*strDec2=0,newStr=0;
+    WCHAR twoPoint[]={'.','.',0};
+    WCHAR bkSlash[]={'\\',0};
+    IBindCtx *bind=0;
+    int i=0,j=0,lastIdx1=0,lastIdx2=0;
+    DWORD mkSys;
+
+    TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
+
+    if (ppmkComposite==NULL)
+        return E_POINTER;
+
+    if (pmkRight==NULL)
+	return E_INVALIDARG;
+
+    *ppmkComposite=0;
+    
+    IMoniker_IsSystemMoniker(pmkRight,&mkSys);
+
+    /* check if we have two filemonikers to compose or not */
+    if(mkSys==MKSYS_FILEMONIKER){
+
+        CreateBindCtx(0,&bind);
+
+        FileMonikerImpl_GetDisplayName(iface,bind,NULL,&str1);
+        IMoniker_GetDisplayName(pmkRight,bind,NULL,&str2);
+
+        /* decompose pathnames of the two monikers : (to prepare the path merge operation ) */
+        lastIdx1=FileMonikerImpl_DecomposePath(str1,&strDec1)-1;
+        lastIdx2=FileMonikerImpl_DecomposePath(str2,&strDec2)-1;
+
+        if ((lastIdx1==-1 && lastIdx2>-1)||(lastIdx1==1 && lstrcmpW(strDec1[0],twoPoint)==0))
+            return MK_E_SYNTAX;
+
+        if(lstrcmpW(strDec1[lastIdx1],bkSlash)==0)
+            lastIdx1--;
+
+        /* for etch "..\" in the left of str2 remove the right element from str1 */
+        for(i=0; ( (lastIdx1>=0) && (strDec2[i]!=NULL) && (lstrcmpW(strDec2[i],twoPoint)==0) ) ;i+=2){
+
+            lastIdx1-=2;
+        }
+
+        /* the length of the composed path string  is raised by the sum of the two paths lengths  */
+        newStr=(WCHAR *)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(lstrlenW(str1)+lstrlenW(str2)+1));
+	
+	  if (newStr==NULL)
+		return E_OUTOFMEMORY;
+
+        /* new path is the concatenation of the rest of str1 and str2 */
+        for(*newStr=0,j=0;j<=lastIdx1;j++)
+            lstrcatW(newStr,strDec1[j]);
+
+        if ((strDec2[i]==NULL && lastIdx1>-1 && lastIdx2>-1) || lstrcmpW(strDec2[i],bkSlash)!=0)
+            lstrcatW(newStr,bkSlash);
+            
+        for(j=i;j<=lastIdx2;j++)
+            lstrcatW(newStr,strDec2[j]);
+        
+        /* create a new moniker with the new string */
+        res=CreateFileMoniker(newStr,ppmkComposite);
+
+        /* free all strings space memory used by this function */
+        HeapFree(GetProcessHeap(),0,newStr);
+
+        for(i=0; strDec1[i]!=NULL;i++)
+            CoTaskMemFree(strDec1[i]);
+        for(i=0; strDec2[i]!=NULL;i++)
+            CoTaskMemFree(strDec2[i]);
+        CoTaskMemFree(strDec1);
+        CoTaskMemFree(strDec2);
+
+        CoTaskMemFree(str1);
+        CoTaskMemFree(str2);
+
+        return res;
+    }
+    else if(mkSys==MKSYS_ANTIMONIKER){
+
+        *ppmkComposite=NULL;
+        return S_OK;
+    }
+    else if (fOnlyIfNotGeneric){
+
+        *ppmkComposite=NULL;
+        return MK_E_NEEDGENERIC;
+    }
+    else
+
+        return CreateGenericComposite(iface,pmkRight,ppmkComposite);
+}
+
+/******************************************************************************
+ *        FileMoniker_Enum
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
+{
+    TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
+
+    if (ppenumMoniker == NULL)
+        return E_POINTER;
+
+    *ppenumMoniker = NULL;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        FileMoniker_IsEqual
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
+{
+    ICOM_THIS(FileMonikerImpl,iface);
+    CLSID clsid;
+    LPOLESTR filePath;
+    IBindCtx* bind;
+    HRESULT res;
+
+    TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
+
+    if (pmkOtherMoniker==NULL)
+        return S_FALSE;
+
+    IMoniker_GetClassID(pmkOtherMoniker,&clsid);
+
+    if (!IsEqualCLSID(&clsid,&CLSID_FileMoniker))
+
+        return S_FALSE;
+
+    res=CreateBindCtx(0,&bind);
+    if (FAILED(res))
+        return res;
+
+    IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&filePath);
+    
+    if (lstrcmpiW(filePath,
+                  This->filePathName)!=0)
+
+        return S_FALSE;
+    
+    return S_OK;
+}
+
+/******************************************************************************
+ *        FileMoniker_Hash
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
+{
+    ICOM_THIS(FileMonikerImpl,iface);
+
+    int  h = 0,i,skip,len;
+    int  off = 0;
+    LPOLESTR val;
+
+    if (pdwHash==NULL)
+        return E_POINTER;
+    
+    val =  This->filePathName;
+    len = lstrlenW(val);
+
+    if (len < 16) {
+        for (i = len ; i > 0; i--) {
+            h = (h * 37) + val[off++];
+ 	}
+    } else {
+        /* only sample some characters */
+ 	skip = len / 8;
+ 	for (i = len ; i > 0; i -= skip, off += skip) {
+            h = (h * 39) + val[off];
+ 	}
+}
+
+    *pdwHash=h;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        FileMoniker_IsRunning
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_IsRunning(IMoniker* iface,
+                                         IBindCtx* pbc,
+                                         IMoniker* pmkToLeft,
+                                         IMoniker* pmkNewlyRunning)
+{
+    IRunningObjectTable* rot;
+    HRESULT res;
+
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
+
+    if ( (pmkNewlyRunning!=NULL) && (IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK) )
+        return S_OK;
+
+    if (pbc==NULL)
+        return E_POINTER;
+
+    res=IBindCtx_GetRunningObjectTable(pbc,&rot);
+
+    if (FAILED(res))
+        return res;
+
+    res = IRunningObjectTable_IsRunning(rot,iface);
+
+    IRunningObjectTable_Release(rot);
+
+    return res;
+}
+
+/******************************************************************************
+ *        FileMoniker_GetTimeOfLastChange
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_GetTimeOfLastChange(IMoniker* iface,
+                                                   IBindCtx* pbc,
+                                                   IMoniker* pmkToLeft,
+                                                   FILETIME* pFileTime)
+{
+    ICOM_THIS(FileMonikerImpl,iface);
+    IRunningObjectTable* rot;
+    HRESULT res;
+    WIN32_FILE_ATTRIBUTE_DATA info;
+
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pFileTime);
+
+    if (pFileTime==NULL)
+        return E_POINTER;
+
+    if (pmkToLeft!=NULL)
+        return E_INVALIDARG;
+
+    res=IBindCtx_GetRunningObjectTable(pbc,&rot);
+
+    if (FAILED(res))
+        return res;
+
+    res= IRunningObjectTable_GetTimeOfLastChange(rot,iface,pFileTime);
+
+    if (FAILED(res))
+    { /* the moniker is not registred */
+
+        if (!GetFileAttributesExW(This->filePathName, GetFileExInfoStandard, &info))
+            return MK_E_NOOBJECT;
+        
+        *pFileTime=info.ftLastWriteTime;
+    }
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        FileMoniker_Inverse
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
+{
+
+    TRACE("(%p,%p)\n",iface,ppmk);
+
+    return CreateAntiMoniker(ppmk);
+}
+
+/******************************************************************************
+ *        FileMoniker_CommonPrefixWith
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
+{
+
+    LPOLESTR pathThis,pathOther,*stringTable1,*stringTable2,commonPath;
+    IBindCtx *pbind;
+    DWORD mkSys;
+    ULONG nb1,nb2,i,sameIdx;
+    BOOL machimeNameCase=FALSE;
+
+    if (ppmkPrefix==NULL)
+        return E_POINTER;
+
+    if (pmkOther==NULL)
+        return E_INVALIDARG;
+    
+    *ppmkPrefix=0;
+    
+    /* check if we have the same type of moniker */
+    IMoniker_IsSystemMoniker(pmkOther,&mkSys);
+
+    if(mkSys==MKSYS_FILEMONIKER){
+
+        CreateBindCtx(0,&pbind);
+
+        /* create a string based on common part of the two paths */
+
+        IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis);
+        IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther);
+
+        nb1=FileMonikerImpl_DecomposePath(pathThis,&stringTable1);
+        nb2=FileMonikerImpl_DecomposePath(pathOther,&stringTable2);
+
+        if (nb1==0 || nb2==0)
+            return MK_E_NOPREFIX;
+
+        commonPath=(WCHAR *)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1));
+
+        *commonPath=0;
+        
+        for(sameIdx=0; ( (stringTable1[sameIdx]!=NULL) &&
+                         (stringTable2[sameIdx]!=NULL) &&
+                         (lstrcmpiW(stringTable1[sameIdx],stringTable2[sameIdx])==0)); sameIdx++);
+
+        if (sameIdx > 1 && *stringTable1[0]=='\\' && *stringTable2[1]=='\\'){
+
+            machimeNameCase=TRUE;
+
+            for(i=2;i<sameIdx;i++)
+
+                if( (*stringTable1[i]=='\\') && (i+1 < sameIdx) && (*stringTable1[i+1]=='\\') ){
+                    machimeNameCase=FALSE;
+                    break;
+}
+        }
+
+        if (machimeNameCase && *stringTable1[sameIdx-1]=='\\')
+            sameIdx--;
+        
+        if (machimeNameCase && (sameIdx<=3) && (nb1 > 3 || nb2 > 3) )
+            return MK_E_NOPREFIX;
+
+        for(i=0;i<sameIdx;i++)
+            lstrcatW(commonPath,stringTable1[i]);
+        
+        for(i=0;i<nb1;i++)
+            CoTaskMemFree(stringTable1[i]);
+
+        CoTaskMemFree(stringTable1);
+
+        for(i=0;i<nb2;i++)
+            CoTaskMemFree(stringTable2[i]);
+
+        CoTaskMemFree(stringTable2);
+
+        HeapFree(GetProcessHeap(),0,commonPath);
+        
+        return CreateFileMoniker(commonPath,ppmkPrefix);
+    }
+    else
+        return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix);
+}
+
+/******************************************************************************
+ *        DecomposePath (local function)
+ ******************************************************************************/
+int WINAPI FileMonikerImpl_DecomposePath(LPOLESTR str, LPOLESTR** stringTable)
+{
+    WCHAR bSlash[] = {'\\',0};
+    WCHAR word[MAX_PATH];
+    int i=0,j,tabIndex=0;
+    LPOLESTR *strgtable ;
+
+    int len=lstrlenW(str);
+
+    strgtable = (LPOLESTR *)CoTaskMemAlloc(len*sizeof(LPOLESTR));
+    
+    if (strgtable==NULL)
+	return E_OUTOFMEMORY;
+    
+    while(str[i]!=0){
+
+        if(str[i]==bSlash[0]){
+
+            strgtable[tabIndex]=(WCHAR *)CoTaskMemAlloc(2*sizeof(WCHAR));
+
+            if (strgtable[tabIndex]==NULL)
+	    	return E_OUTOFMEMORY;
+
+            lstrcpyW(strgtable[tabIndex++],bSlash);
+
+            i++;
+
+        }
+        else {
+
+            for(j=0; str[i]!=0 && str[i]!=bSlash[0] ; i++,j++)
+                word[j]=str[i];
+
+            word[j]=0;
+
+            strgtable[tabIndex]=(WCHAR *)CoTaskMemAlloc(sizeof(WCHAR)*(j+1));
+
+            if (strgtable[tabIndex]==NULL)
+                return E_OUTOFMEMORY;
+
+            lstrcpyW(strgtable[tabIndex++],word);
+        }
+    }
+    strgtable[tabIndex]=NULL;
+    
+    *stringTable=strgtable;
+    
+    return tabIndex;
+}
+
+/******************************************************************************
+ *        FileMoniker_RelativePathTo
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
+{
+    IBindCtx *bind;
+    HRESULT res;
+    LPOLESTR str1=0,str2=0,*tabStr1=0,*tabStr2=0,relPath=0;
+    DWORD len1=0,len2=0,sameIdx=0,j=0;
+    WCHAR back[] ={'.','.','\\',0};
+    
+    TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
+
+    if (ppmkRelPath==NULL)
+        return E_POINTER;
+
+    if (pmOther==NULL)
+        return E_INVALIDARG;
+    
+    res=CreateBindCtx(0,&bind);
+    if (FAILED(res))
+	return res;
+
+    res=IMoniker_GetDisplayName(iface,bind,NULL,&str1);
+    if (FAILED(res))
+	return res;
+    res=IMoniker_GetDisplayName(pmOther,bind,NULL,&str2);
+    if (FAILED(res))
+	return res;
+
+    len1=FileMonikerImpl_DecomposePath(str1,&tabStr1);
+    len2=FileMonikerImpl_DecomposePath(str2,&tabStr2);
+
+    if (FAILED(len1) || FAILED(len2))
+	return E_OUTOFMEMORY;
+	
+    /* count the number of similar items from the begin of the two paths */
+    for(sameIdx=0; ( (tabStr1[sameIdx]!=NULL) &&
+		   (tabStr2[sameIdx]!=NULL) &&
+               (lstrcmpiW(tabStr1[sameIdx],tabStr2[sameIdx])==0)); sameIdx++);
+
+    /* begin the construction of relativePath */
+    /* if the two paths have a consecutive similar item from the begin ! the relativePath will be composed */
+    /* by "..\\" in the begin */
+    relPath=(WCHAR *)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(1+lstrlenW(str1)+lstrlenW(str2)));
+
+    *relPath=0;
+
+    if (len2>0 && !(len1==1 && len2==1 && sameIdx==0))
+        for(j=sameIdx;(tabStr1[j] != NULL); j++)
+            if (*tabStr1[j]!='\\')
+                lstrcatW(relPath,back);
+
+    /* add items of the second path (similar items with the first path are not included) to the relativePath */
+    for(j=sameIdx;tabStr2[j]!=NULL;j++)
+        lstrcatW(relPath,tabStr2[j]);
+    
+    res=CreateFileMoniker(relPath,ppmkRelPath);
+    
+    for(j=0; tabStr1[j]!=NULL;j++)
+        CoTaskMemFree(tabStr1[j]);
+    for(j=0; tabStr2[j]!=NULL;j++)
+        CoTaskMemFree(tabStr2[j]);
+    CoTaskMemFree(tabStr1);
+    CoTaskMemFree(tabStr2);
+    CoTaskMemFree(str1);
+    CoTaskMemFree(str2);
+    HeapFree(GetProcessHeap(),0,relPath);
+
+    if (len1==0 || len2==0 || (len1==1 && len2==1 && sameIdx==0))
+        return MK_S_HIM;
+
+    return res;
+}
+
+/******************************************************************************
+ *        FileMoniker_GetDisplayName
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_GetDisplayName(IMoniker* iface,
+                                              IBindCtx* pbc,
+                                              IMoniker* pmkToLeft,
+                                              LPOLESTR *ppszDisplayName)
+{
+    ICOM_THIS(FileMonikerImpl,iface);
+
+    int len=lstrlenW(This->filePathName);
+
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
+
+    if (ppszDisplayName==NULL)
+        return E_POINTER;
+
+    if (pmkToLeft!=NULL)
+        return E_INVALIDARG;
+
+    *ppszDisplayName=(WCHAR *)CoTaskMemAlloc(sizeof(WCHAR)*(len+1));
+    if (*ppszDisplayName==NULL)
+        return E_OUTOFMEMORY;
+
+    lstrcpyW(*ppszDisplayName,This->filePathName);
+    
+    return S_OK;
+}
+
+/******************************************************************************
+ *        FileMoniker_ParseDisplayName
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_ParseDisplayName(IMoniker* iface,
+                                                IBindCtx* pbc,
+                                                IMoniker* pmkToLeft,
+                                                LPOLESTR pszDisplayName,
+                                                ULONG* pchEaten,
+                                                IMoniker** ppmkOut)
+{
+    FIXME("(%p,%p,%p,%p,%p,%p),stub!\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut);
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        FileMoniker_IsSystemMonker
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
+{
+    TRACE("(%p,%p)\n",iface,pwdMksys);
+
+    if (!pwdMksys)
+        return E_POINTER;
+    
+    (*pwdMksys)=MKSYS_FILEMONIKER;
+
+    return S_OK;
+}
+
+/*******************************************************************************
+ *        FileMonikerIROTData_QueryInterface
+ *******************************************************************************/
+HRESULT WINAPI FileMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
+{
+
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+
+    TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
+
+    return FileMonikerImpl_QueryInterface(This, riid, ppvObject);
+}
+
+/***********************************************************************
+ *        FileMonikerIROTData_AddRef
+ */
+ULONG   WINAPI FileMonikerROTDataImpl_AddRef(IROTData *iface)
+{
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+
+    TRACE("(%p)\n",This);
+
+    return FileMonikerImpl_AddRef(This);
+}
+
+/***********************************************************************
+ *        FileMonikerIROTData_Release
+ */
+ULONG   WINAPI FileMonikerROTDataImpl_Release(IROTData* iface)
+{
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+    
+    TRACE("(%p)\n",This);
+
+    return FileMonikerImpl_Release(This);
+}
+
+/******************************************************************************
+ *        FileMonikerIROTData_GetComparaisonData
+ ******************************************************************************/
+HRESULT WINAPI FileMonikerROTDataImpl_GetComparaisonData(IROTData* iface,
+                                                         BYTE* pbData,
+                                                         ULONG cbMax,
+                                                         ULONG* pcbData)
+{
+    FIXME("(),stub!\n");
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        CreateFileMoniker16
+ ******************************************************************************/
+HRESULT WINAPI CreateFileMoniker16(LPCOLESTR16 lpszPathName,LPMONIKER* ppmk)
+{
+
+    FIXME("(%s,%p),stub!\n",lpszPathName,ppmk);
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        CreateFileMoniker
+ ******************************************************************************/
+HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, LPMONIKER * ppmk)
+{
+    FileMonikerImpl* newFileMoniker = 0;
+    HRESULT  hr = E_FAIL;
+    IID riid=IID_IMoniker;
+
+    TRACE("(%p,%p)\n",lpszPathName,ppmk);
+
+    if (ppmk==NULL)
+        return E_POINTER;
+
+    if(lpszPathName==NULL)
+        return MK_E_SYNTAX;
+            
+    *ppmk=0;
+        
+    newFileMoniker = (FileMonikerImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl));
+
+    if (newFileMoniker == 0)
+        return E_OUTOFMEMORY;
+
+    hr = FileMonikerImpl_Construct(newFileMoniker,lpszPathName);
+
+    if (SUCCEEDED(hr))
+	hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker,&riid,(void**)ppmk);
+    else
+        HeapFree(GetProcessHeap(),0,newFileMoniker);
+
+    return hr;
+}
Index: trunk/src/ole32/new/filemoniker.h
===================================================================
--- trunk/src/ole32/new/filemoniker.h	(revision 3456)
+++ trunk/src/ole32/new/filemoniker.h	(revision 3456)
@@ -0,0 +1,36 @@
+/* $Id: filemoniker.h,v 1.1 2000-04-27 22:21:36 davidr Exp $ */
+/*
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+#ifndef FILEMONIKER_INCLUDED
+#define FILEMONIKER_INCLUDED 1
+
+/* filemoniker data structure */
+typedef struct FileMonikerImpl{
+
+    ICOM_VTABLE(IMoniker)*  lpvtbl1;  /* VTable relative to the IMoniker interface.*/
+
+    /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether 
+     * two monikers are equal. That's whay IROTData interface is implemented by monikers.
+     */
+    ICOM_VTABLE(IROTData)*  lpvtbl2;  /* VTable relative to the IROTData interface.*/
+
+    ULONG ref; /* reference counter for this object */
+
+    LPOLESTR filePathName; /* path string identified by this filemoniker */
+    BOOL bIsLongFileName;  /* Is the path a valid dos 8.3 file */
+    BOOL bIsNetworkPath;   /* Is the path a network path */
+    WORD wNetworkDomainLenght;  /*Lenght of the \\Domain\share network name, otherwise 0xFFFF for regular file*/
+
+} FileMonikerImpl;
+
+/* Local function used by filemoniker implementation */
+HRESULT WINAPI FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName);
+HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* iface);
+int     WINAPI FileMonikerImpl_DecomposePath(LPOLESTR str, LPOLESTR** tabStr);
+void WINAPI FileMonikerImpl_CheckFileFormat(FileMonikerImpl* iface, LPCOLESTR lpszPathName);
+
+#endif /* FILEMONIKER_INCLUDED */
Index: trunk/src/ole32/new/guid.cpp
===================================================================
--- trunk/src/ole32/new/guid.cpp	(revision 3456)
+++ trunk/src/ole32/new/guid.cpp	(revision 3456)
@@ -0,0 +1,18 @@
+/* $Id: guid.cpp,v 1.1 2000-04-27 22:18:17 davidr Exp $ */
+/* 
+ * Concrete defintions of all IID's
+ * 
+ * 1/7/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+
+// This causes all the DEFINE_GUID macros to instantiate their GUID's
+#define INITGUID
+
+#include "ole32.h"
+
Index: trunk/src/ole32/new/hglobalstream.cpp
===================================================================
--- trunk/src/ole32/new/hglobalstream.cpp	(revision 3456)
+++ trunk/src/ole32/new/hglobalstream.cpp	(revision 3456)
@@ -0,0 +1,826 @@
+/* $Id: hglobalstream.cpp,v 1.1 2000-04-27 22:18:18 davidr Exp $ */
+/* 
+ *  HGLOBAL Stream implementation functions.
+ * 
+ * 20/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *   Copyright 1999 Francis Beaudet
+ */
+
+#include "ole32.h"
+#include "heapstring.h"
+#include "debugtools.h"
+#include <assert.h>
+
+DEFAULT_DEBUG_CHANNEL(storage)
+
+/****************************************************************************
+ * HGLOBALStreamImpl definition.
+ *
+ * This class imlements the IStream inteface and represents a stream
+ * supported by an HGLOBAL pointer.
+ */
+struct HGLOBALStreamImpl
+{
+  ICOM_VFIELD(IStream);  /* Needs to be the first item in the stuct
+				  * since we want to cast this in a IStream pointer */
+  
+  /*
+   * Reference count
+   */
+  ULONG		     ref;
+
+  /*
+   * Support for the stream
+   */
+  HGLOBAL supportHandle;
+
+  /*
+   * This flag is TRUE if the HGLOBAL is destroyed when the stream
+   * is finally released.
+   */
+  BOOL    deleteOnRelease;
+
+  /*
+   * Helper variable that contains the size of the stream
+   */
+  ULARGE_INTEGER     streamSize;
+
+  /*
+   * This is the current position of the cursor in the stream
+   */
+  ULARGE_INTEGER     currentPosition;
+};
+
+typedef struct HGLOBALStreamImpl HGLOBALStreamImpl;
+
+/*
+ * Method definition for the StgStreamImpl class.
+ */
+HGLOBALStreamImpl* HGLOBALStreamImpl_Construct(
+		HGLOBAL  hGlobal,
+		BOOL     fDeleteOnRelease);
+
+void HGLOBALStreamImpl_Destroy(
+                HGLOBALStreamImpl* This);
+
+void HGLOBALStreamImpl_OpenBlockChain(
+                HGLOBALStreamImpl* This);
+
+HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
+		IStream*      iface,
+		REFIID         riid,		/* [in] */          
+		void**         ppvObject);  /* [iid_is][out] */ 
+        
+ULONG WINAPI HGLOBALStreamImpl_AddRef(
+		IStream*      iface);
+        
+ULONG WINAPI HGLOBALStreamImpl_Release(
+		IStream*      iface);
+        
+HRESULT WINAPI HGLOBALStreamImpl_Read( 
+	        IStream*      iface,
+		void*          pv,        /* [length_is][size_is][out] */
+		ULONG          cb,        /* [in] */                     
+		ULONG*         pcbRead);  /* [out] */                    
+        
+HRESULT WINAPI HGLOBALStreamImpl_Write(
+		IStream*      iface,
+		const void*    pv,          /* [size_is][in] */ 
+		ULONG          cb,          /* [in] */          
+		ULONG*         pcbWritten); /* [out] */         
+        
+HRESULT WINAPI HGLOBALStreamImpl_Seek( 
+		IStream*      iface,
+		LARGE_INTEGER   dlibMove,         /* [in] */ 
+		DWORD           dwOrigin,         /* [in] */ 
+		ULARGE_INTEGER* plibNewPosition); /* [out] */
+        
+HRESULT WINAPI HGLOBALStreamImpl_SetSize( 
+	        IStream*      iface,
+		ULARGE_INTEGER  libNewSize);  /* [in] */ 
+        
+HRESULT WINAPI HGLOBALStreamImpl_CopyTo( 
+		IStream*      iface,
+		IStream*      pstm,         /* [unique][in] */ 
+		ULARGE_INTEGER  cb,           /* [in] */         
+		ULARGE_INTEGER* pcbRead,      /* [out] */        
+		ULARGE_INTEGER* pcbWritten);  /* [out] */        
+
+HRESULT WINAPI HGLOBALStreamImpl_Commit( 
+	    	IStream*      iface,
+		DWORD           grfCommitFlags); /* [in] */ 
+        
+HRESULT WINAPI HGLOBALStreamImpl_Revert( 
+		IStream*  iface);
+        
+HRESULT WINAPI HGLOBALStreamImpl_LockRegion( 
+		IStream*     iface,
+		ULARGE_INTEGER libOffset,   /* [in] */ 
+		ULARGE_INTEGER cb,          /* [in] */ 
+		DWORD          dwLockType); /* [in] */ 
+        
+HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion( 
+		IStream*     iface,
+		ULARGE_INTEGER libOffset,   /* [in] */ 
+	        ULARGE_INTEGER cb,          /* [in] */ 
+		DWORD          dwLockType); /* [in] */ 
+        
+HRESULT WINAPI HGLOBALStreamImpl_Stat( 
+		IStream*     iface,
+	        STATSTG*       pstatstg,     /* [out] */
+	        DWORD          grfStatFlag); /* [in] */ 
+        
+HRESULT WINAPI HGLOBALStreamImpl_Clone( 
+		IStream*     iface,
+		IStream**    ppstm);       /* [out] */ 
+
+
+/*
+ * Virtual function table for the HGLOBALStreamImpl class.
+ */
+static ICOM_VTABLE(IStream) HGLOBALStreamImpl_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    HGLOBALStreamImpl_QueryInterface,
+    HGLOBALStreamImpl_AddRef,
+    HGLOBALStreamImpl_Release,
+    HGLOBALStreamImpl_Read,
+    HGLOBALStreamImpl_Write,
+    HGLOBALStreamImpl_Seek,
+    HGLOBALStreamImpl_SetSize,
+    HGLOBALStreamImpl_CopyTo,
+    HGLOBALStreamImpl_Commit,
+    HGLOBALStreamImpl_Revert,
+    HGLOBALStreamImpl_LockRegion,
+    HGLOBALStreamImpl_UnlockRegion,
+    HGLOBALStreamImpl_Stat,
+    HGLOBALStreamImpl_Clone
+};
+
+/***********************************************************************
+ *           CreateStreamOnHGlobal     [OLE32.61]
+ */
+HRESULT WINAPI CreateStreamOnHGlobal(
+		HGLOBAL   hGlobal, 
+		BOOL      fDeleteOnRelease, 
+		LPSTREAM* ppstm)
+{
+  HGLOBALStreamImpl* newStream;
+
+  newStream = HGLOBALStreamImpl_Construct(hGlobal,
+					  fDeleteOnRelease);
+
+  if (newStream!=NULL)
+  {
+    return IUnknown_QueryInterface((IUnknown*)newStream, 
+				   &IID_IStream,
+				   (void**)ppstm);
+  }
+
+  return E_OUTOFMEMORY;
+}
+
+/***********************************************************************
+ *           GetHGlobalFromStream     [OLE32.71]
+ */
+HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal)
+{
+  HGLOBALStreamImpl* pStream;
+
+  if (pstm == NULL)
+    return E_INVALIDARG;
+
+  pStream = (HGLOBALStreamImpl*) pstm;
+
+  /*
+   * Verify that the stream object was created with CreateStreamOnHGlobal.
+   */
+  if (ICOM_VTBL(pStream) == &HGLOBALStreamImpl_Vtbl)
+    *phglobal = pStream->supportHandle;
+  else
+  {
+    *phglobal = 0;
+    return E_INVALIDARG;
+  }
+
+  return S_OK;
+}
+
+/******************************************************************************
+** HGLOBALStreamImpl implementation
+*/
+
+/***
+ * This is the constructor for the HGLOBALStreamImpl class.
+ *
+ * Params:
+ *    hGlobal          - Handle that will support the stream. can be NULL.
+ *    fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released 
+ *                       when the IStream object is destroyed.
+ */
+HGLOBALStreamImpl* HGLOBALStreamImpl_Construct(
+		HGLOBAL  hGlobal,
+		BOOL     fDeleteOnRelease)
+{
+  HGLOBALStreamImpl* newStream;
+
+  newStream = (HGLOBALStreamImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALStreamImpl));
+  
+  if (newStream!=0)
+  {
+    /*
+     * Set-up the virtual function table and reference count.
+     */
+    ICOM_VTBL(newStream) = &HGLOBALStreamImpl_Vtbl;
+    newStream->ref    = 0;
+    
+    /*
+     * Initialize the support.
+     */
+    newStream->supportHandle = hGlobal;
+    newStream->deleteOnRelease = fDeleteOnRelease;
+
+    /*
+     * This method will allocate a handle if one is not supplied.
+     */
+    if (newStream->supportHandle == NULL)
+    {
+      newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, 0);
+    }
+    
+    /*
+     * Start the stream at the begining.
+     */
+    newStream->currentPosition.HighPart = 0;
+    newStream->currentPosition.LowPart = 0;
+    
+    /*
+     * Initialize the size of the stream to the size of the handle.
+     */
+    newStream->streamSize.HighPart = 0;
+    newStream->streamSize.LowPart  = GlobalSize(newStream->supportHandle);
+  }
+  
+  return newStream;
+}
+
+/***
+ * This is the destructor of the HGLOBALStreamImpl class.
+ *
+ * This method will clean-up all the resources used-up by the given HGLOBALStreamImpl 
+ * class. The pointer passed-in to this function will be freed and will not
+ * be valid anymore.
+ */
+void HGLOBALStreamImpl_Destroy(HGLOBALStreamImpl* This)
+{
+  TRACE("(%p)\n", This);
+
+  /*
+   * Release the HGlobal if the constructor asked for that.
+   */
+  if (This->deleteOnRelease)
+  {
+    GlobalFree(This->supportHandle);
+    This->supportHandle=0;
+  }
+
+  /*
+   * Finally, free the memory used-up by the class.
+   */
+  HeapFree(GetProcessHeap(), 0, This);  
+}
+
+/***
+ * This implements the IUnknown method QueryInterface for this
+ * class
+ */
+HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
+		  IStream*     iface,
+		  REFIID         riid,	      /* [in] */          
+		  void**         ppvObject)   /* [iid_is][out] */ 
+{
+  HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (ppvObject==0)
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+  
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = (IStream*)This;
+  }
+  else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0) 
+  {
+    *ppvObject = (IStream*)This;
+  }
+  
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+    return E_NOINTERFACE;
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  HGLOBALStreamImpl_AddRef(iface);
+  
+  return S_OK;;
+}
+
+/***
+ * This implements the IUnknown method AddRef for this
+ * class
+ */
+ULONG WINAPI HGLOBALStreamImpl_AddRef(
+		IStream* iface)
+{
+  HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
+
+  This->ref++;
+  
+  return This->ref;
+}
+
+/***
+ * This implements the IUnknown method Release for this
+ * class
+ */
+ULONG WINAPI HGLOBALStreamImpl_Release(
+		IStream* iface)
+{
+  HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
+
+  ULONG newRef;
+  
+  This->ref--;
+  
+  newRef = This->ref;
+  
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (newRef==0)
+  {
+    HGLOBALStreamImpl_Destroy(This);
+  }
+  
+  return newRef;
+}
+
+/***
+ * This method is part of the ISequentialStream interface.
+ *
+ * If reads a block of information from the stream at the current
+ * position. It then moves the current position at the end of the
+ * read block
+ *
+ * See the documentation of ISequentialStream for more info.
+ */
+HRESULT WINAPI HGLOBALStreamImpl_Read( 
+		  IStream*     iface,
+		  void*          pv,        /* [length_is][size_is][out] */
+		  ULONG          cb,        /* [in] */                     
+		  ULONG*         pcbRead)   /* [out] */                    
+{
+  HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
+
+  void* supportBuffer;
+  ULONG bytesReadBuffer;
+  ULONG bytesToReadFromBuffer;
+
+  TRACE("(%p, %p, %ld, %p)\n", iface,
+	pv, cb, pcbRead);
+  
+  /* 
+   * If the caller is not interested in the nubmer of bytes read,
+   * we use another buffer to avoid "if" statements in the code.
+   */
+  if (pcbRead==0)
+    pcbRead = &bytesReadBuffer;
+  
+  /*
+   * Using the known size of the stream, calculate the number of bytes
+   * to read from the block chain
+   */
+  bytesToReadFromBuffer = MIN( This->streamSize.LowPart - This->currentPosition.LowPart, cb);
+
+  /*
+   * Lock the buffer in position and copy the data.
+   */
+  supportBuffer = GlobalLock(This->supportHandle);
+
+  memcpy(pv, (char *) supportBuffer+This->currentPosition.LowPart, bytesToReadFromBuffer);
+
+  /*
+   * Move the current position to the new position
+   */
+  This->currentPosition.LowPart+=bytesToReadFromBuffer;
+
+  /*
+   * Return the number of bytes read.
+   */
+  *pcbRead = bytesToReadFromBuffer;
+
+  /*
+   * Cleanup
+   */
+  GlobalUnlock(This->supportHandle);
+  
+  /*
+   * The function returns S_OK if the buffer was filled completely
+   * it returns S_FALSE if the end of the stream is reached before the
+   * buffer is filled
+   */
+  if(*pcbRead == cb)
+    return S_OK;
+  
+  return S_FALSE;
+}
+        
+/***
+ * This method is part of the ISequentialStream interface.
+ *
+ * It writes a block of information to the stream at the current
+ * position. It then moves the current position at the end of the
+ * written block. If the stream is too small to fit the block,
+ * the stream is grown to fit.
+ *
+ * See the documentation of ISequentialStream for more info.
+ */
+HRESULT WINAPI HGLOBALStreamImpl_Write(
+	          IStream*     iface,
+		  const void*    pv,          /* [size_is][in] */ 
+		  ULONG          cb,          /* [in] */          
+		  ULONG*         pcbWritten)  /* [out] */         
+{
+  HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
+
+  void*          supportBuffer;
+  ULARGE_INTEGER newSize;
+  ULONG          bytesWritten = 0;
+
+  TRACE("(%p, %p, %ld, %p)\n", iface,
+	pv, cb, pcbWritten);
+  
+  /*
+   * If the caller is not interested in the number of bytes written,
+   * we use another buffer to avoid "if" statements in the code.
+   */
+  if (pcbWritten == 0)
+    pcbWritten = &bytesWritten;
+  
+  if (cb == 0)
+  {
+    return S_OK;
+  }
+  else
+  {
+    newSize.HighPart = 0;
+    newSize.LowPart = This->currentPosition.LowPart + cb;
+  }
+  
+  /*
+   * Verify if we need to grow the stream
+   */
+  if (newSize.LowPart > This->streamSize.LowPart)
+  {
+    /* grow stream */
+   IStream_SetSize(iface, newSize);
+  }
+  
+  /*
+   * Lock the buffer in position and copy the data.
+   */
+  supportBuffer = GlobalLock(This->supportHandle);
+
+  memcpy((char *) supportBuffer+This->currentPosition.LowPart, pv, cb);  
+
+  /*
+   * Move the current position to the new position
+   */
+  This->currentPosition.LowPart+=cb;
+
+  /*
+   * Return the number of bytes read.
+   */
+  *pcbWritten = cb;
+
+  /*
+   * Cleanup
+   */
+  GlobalUnlock(This->supportHandle);
+  
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * It will move the current stream pointer according to the parameters
+ * given.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI HGLOBALStreamImpl_Seek( 
+		  IStream*      iface,
+		  LARGE_INTEGER   dlibMove,         /* [in] */ 
+		  DWORD           dwOrigin,         /* [in] */ 
+		  ULARGE_INTEGER* plibNewPosition) /* [out] */
+{
+  HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
+
+  ULARGE_INTEGER newPosition;
+
+  TRACE("(%p, %ld, %ld, %p)\n", iface,
+	dlibMove.LowPart, dwOrigin, plibNewPosition);
+
+  /* 
+   * The caller is allowed to pass in NULL as the new position return value.
+   * If it happens, we assign it to a dynamic variable to avoid special cases
+   * in the code below.
+   */
+  if (plibNewPosition == 0)
+  {
+    plibNewPosition = &newPosition;
+  }
+
+  /*
+   * The file pointer is moved depending on the given "function"
+   * parameter.
+   */
+  switch (dwOrigin)
+  {
+    case STREAM_SEEK_SET:
+      plibNewPosition->HighPart = 0;
+      plibNewPosition->LowPart  = 0;
+      break;
+    case STREAM_SEEK_CUR:
+      *plibNewPosition = This->currentPosition;
+      break;
+    case STREAM_SEEK_END:
+      *plibNewPosition = This->streamSize;
+      break;
+    default:
+      return STG_E_INVALIDFUNCTION;
+  }
+
+  /*
+   * We don't support files with offsets of 64 bits.
+   */
+  assert(dlibMove.HighPart == 0);
+
+  /*
+   * Check if we end-up before the beginning of the file. That should trigger an
+   * error.
+   */
+  if ( (dlibMove.LowPart<0) && (plibNewPosition->LowPart < (ULONG)(-dlibMove.LowPart)) )
+  {
+    /*
+     * I don't know what error to send there.
+     */
+    return E_FAIL;
+  }
+
+  /*
+   * Move the actual file pointer
+   * If the file pointer ends-up after the end of the stream, the next Write operation will
+   * make the file larger. This is how it is documented.
+   */
+  plibNewPosition->LowPart += dlibMove.LowPart;
+  This->currentPosition = *plibNewPosition;
+ 
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * It will change the size of a stream.
+ *
+ * TODO: Switch from small blocks to big blocks and vice versa.
+ *
+ * See the documentation of IStream for more info.
+ */
+HRESULT WINAPI HGLOBALStreamImpl_SetSize( 
+				     IStream*      iface,
+				     ULARGE_INTEGER  libNewSize)   /* [in] */ 
+{
+  HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
+
+  TRACE("(%p, %ld)\n", iface, libNewSize.LowPart);
+
+  /*
+   * As documented.
+   */
+  if (libNewSize.HighPart != 0)
+    return STG_E_INVALIDFUNCTION;
+  
+  if (This->streamSize.LowPart == libNewSize.LowPart)
+    return S_OK;
+
+  /*
+   * Re allocate the HGlobal to fit the new size of the stream.
+   */
+  This->supportHandle = GlobalReAlloc(This->supportHandle, 
+				      libNewSize.LowPart,
+				      0);
+
+  This->streamSize.LowPart = libNewSize.LowPart;
+  
+  return S_OK;
+}
+        
+/***
+ * This method is part of the IStream interface.
+ *
+ * It will copy the 'cb' Bytes to 'pstm' IStream.
+ *
+ * See the documentation of IStream for more info.
+ */
+HRESULT WINAPI HGLOBALStreamImpl_CopyTo( 
+				    IStream*      iface,
+				    IStream*      pstm,         /* [unique][in] */ 
+				    ULARGE_INTEGER  cb,           /* [in] */         
+				    ULARGE_INTEGER* pcbRead,      /* [out] */        
+				    ULARGE_INTEGER* pcbWritten)   /* [out] */        
+{
+  HRESULT        hr = S_OK;
+  BYTE           tmpBuffer[128];
+  ULONG          bytesRead, bytesWritten, copySize;
+  ULARGE_INTEGER totalBytesRead;
+  ULARGE_INTEGER totalBytesWritten;
+
+  TRACE("(%p, %p, %ld, %p, %p)\n", iface, pstm, 
+	cb.LowPart, pcbRead, pcbWritten);
+
+  /*
+   * Sanity check
+   */
+  if ( pstm == 0 )
+    return STG_E_INVALIDPOINTER;
+
+  totalBytesRead.LowPart = totalBytesRead.HighPart = 0;
+  totalBytesWritten.LowPart = totalBytesWritten.HighPart = 0;
+
+  /*
+   * use stack to store data temporarly
+   * there is surely more performant way of doing it, for now this basic
+   * implementation will do the job
+   */
+  while ( cb.LowPart > 0 )
+  {
+    if ( cb.LowPart >= 128 )
+      copySize = 128;
+    else
+      copySize = cb.LowPart;
+    
+    IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
+
+    totalBytesRead.LowPart += bytesRead;
+    
+    IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
+
+    totalBytesWritten.LowPart += bytesWritten;
+
+    /*
+     * Check that read & write operations were succesfull
+     */
+    if (bytesRead != bytesWritten)
+    {
+      hr = STG_E_MEDIUMFULL;
+      break;
+    }
+    
+    if (bytesRead!=copySize)
+      cb.LowPart = 0;
+    else
+      cb.LowPart -= bytesRead;
+  }
+
+  /*
+   * Update number of bytes read and written
+   */
+  if (pcbRead)
+  {
+    pcbRead->LowPart = totalBytesRead.LowPart;
+    pcbRead->HighPart = totalBytesRead.HighPart;
+  }
+
+  if (pcbWritten)
+  {
+    pcbWritten->LowPart = totalBytesWritten.LowPart;
+    pcbWritten->HighPart = totalBytesWritten.HighPart;
+  }
+  return hr;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * For streams supported by HGLOBALS, this function does nothing. 
+ * This is what the documentation tells us.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI HGLOBALStreamImpl_Commit( 
+		  IStream*      iface,
+		  DWORD         grfCommitFlags)  /* [in] */ 
+{
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * For streams supported by HGLOBALS, this function does nothing. 
+ * This is what the documentation tells us.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI HGLOBALStreamImpl_Revert( 
+		  IStream* iface)
+{
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * For streams supported by HGLOBALS, this function does nothing. 
+ * This is what the documentation tells us.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI HGLOBALStreamImpl_LockRegion( 
+		  IStream*       iface,
+		  ULARGE_INTEGER libOffset,   /* [in] */ 
+		  ULARGE_INTEGER cb,          /* [in] */ 
+		  DWORD          dwLockType)  /* [in] */ 
+{
+  return S_OK;
+}
+
+/*
+ * This method is part of the IStream interface.
+ *
+ * For streams supported by HGLOBALS, this function does nothing. 
+ * This is what the documentation tells us.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion( 
+		  IStream*       iface,
+		  ULARGE_INTEGER libOffset,   /* [in] */ 
+		  ULARGE_INTEGER cb,          /* [in] */ 
+		  DWORD          dwLockType)  /* [in] */ 
+{
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * This method returns information about the current
+ * stream.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI HGLOBALStreamImpl_Stat( 
+		  IStream*     iface,
+		  STATSTG*     pstatstg,     /* [out] */
+		  DWORD        grfStatFlag)  /* [in] */ 
+{
+  HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
+
+  memset(pstatstg, 0, sizeof(STATSTG));
+
+  pstatstg->pwcsName = NULL;
+  pstatstg->type     = STGTY_STREAM;
+  pstatstg->cbSize   = This->streamSize;
+
+  return S_OK;
+}
+        
+HRESULT WINAPI HGLOBALStreamImpl_Clone( 
+		  IStream*     iface,
+		  IStream**    ppstm) /* [out] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
Index: trunk/src/ole32/new/imessagefilter.cpp
===================================================================
--- trunk/src/ole32/new/imessagefilter.cpp	(revision 3456)
+++ trunk/src/ole32/new/imessagefilter.cpp	(revision 3456)
@@ -0,0 +1,182 @@
+/* $Id: imessagefilter.cpp,v 1.1 2000-04-27 22:18:19 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * Default Message Filter Implementation
+ * 
+ * 18/04/2000
+ * 
+ * Copyright 2000 David J. Raison
+ * 
+ */
+
+#include "ole32.h"
+#include "oString.h"
+
+// ======================================================================
+// Local Data
+// ======================================================================
+
+typedef struct
+{
+    /* IUnknown fields */
+    ICOM_VTABLE(IMessageFilter)*	lpvtbl;
+    DWORD                  		ref;
+} IMessageFilterImpl;
+
+static ULONG	WIN32API IMessageFilterImpl_AddRef(LPMESSAGEFILTER iface);
+static ULONG	WIN32API IMessageFilterImpl_Release(LPMESSAGEFILTER iface);
+static HRESULT	WIN32API IMessageFilterImpl_QueryInterface(LPMESSAGEFILTER iface,
+			    REFIID riid, LPVOID * ppvObject);
+static DWORD	WIN32API IMessageFilterImpl_HandleInComingCall(LPMESSAGEFILTER iface,
+			    DWORD dwCallType, HTASK htaskCaller, DWORD dwTickCount,
+			    LPINTERFACEINFO lpInterfaceInfo);
+static DWORD	WIN32API IMessageFilterImpl_RetryRejectedCall(LPMESSAGEFILTER iface,
+			    HTASK htaskCallee, DWORD dwTickCount, DWORD dwRejectType);
+static DWORD	WIN32API IMessageFilterImpl_MessagePending(LPMESSAGEFILTER iface,
+			    HTASK htaskCallee, DWORD dwTickCount, DWORD dwRejectType);
+
+static ICOM_VTABLE(IMessageFilter) IMessageFilterVt = 
+{
+    IMessageFilterImpl_QueryInterface,
+    IMessageFilterImpl_AddRef,
+    IMessageFilterImpl_Release,
+    IMessageFilterImpl_HandleInComingCall,
+    IMessageFilterImpl_RetryRejectedCall,
+    IMessageFilterImpl_MessagePending
+};
+
+// ======================================================================
+// Local Methods
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// IMessageFilterImpl_Constructor
+// ----------------------------------------------------------------------
+LPMESSAGEFILTER IMessageFilterImpl_Constructor()
+{
+    IMessageFilterImpl *	pObject;
+
+    pObject = (IMessageFilterImpl*)HeapAlloc(GetProcessHeap(), 0, sizeof(IMessageFilterImpl));
+    pObject->lpvtbl	= &IMessageFilterVt;
+    pObject->ref	= 1;
+
+    return (LPMESSAGEFILTER)pObject;
+}
+
+// ----------------------------------------------------------------------
+// IMessageFilterImpl_AddRef
+// ----------------------------------------------------------------------
+static ULONG WIN32API IMessageFilterImpl_AddRef(LPMESSAGEFILTER iface)
+{ 
+    ICOM_THIS(IMessageFilterImpl, iface);
+
+    dprintf(("OLE32: IMessageFilter(%p)->AddRef()", This));
+
+    return ++(This->ref);
+}
+
+// ----------------------------------------------------------------------
+// IMessageFilterImpl_Release
+// ----------------------------------------------------------------------
+static ULONG WIN32API IMessageFilterImpl_Release(LPMESSAGEFILTER iface)
+{
+    ICOM_THIS(IMessageFilterImpl, iface);
+
+    dprintf(("OLE32: IMessageFilter(%p)->Release()\n", This));
+
+    if (--(This->ref) == 0)
+    {
+	HeapFree(GetProcessHeap(), 0, This);
+	return 0;
+    }
+    return This->ref;
+}
+
+// ----------------------------------------------------------------------
+// IMessageFilterImpl_QueryInterface
+// ----------------------------------------------------------------------
+static HRESULT WIN32API IMessageFilterImpl_QueryInterface(LPMESSAGEFILTER iface,
+				REFIID riid, LPVOID *ppvObject)
+{
+    ICOM_THIS(IMessageFilterImpl, iface);
+
+#ifdef DEBUG
+    oStringA	tRiid(riid);
+    dprintf(("OLE32: IMessageFilter(%p)->QueryInterface(%s)\n", This, (char *)tRiid));
+#endif
+
+    if (IsEqualIID(&IID_IUnknown, riid))
+    {
+        dprintf(("       ->IUnknown"));
+	*ppvObject = &(This->lpvtbl);
+    }
+    else if (IsEqualIID(&IID_IMessageFilter, riid))
+    {
+        dprintf(("       ->IMessageFilter"));
+	*ppvObject = &(This->lpvtbl);
+    }
+    else
+    {
+        dprintf(("       ->E_NOINTERFACE"));
+	return E_NOINTERFACE; 
+    }
+
+    // Query Interface always increases the reference count by one...
+    IMessageFilterImpl_AddRef(iface);
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// IMessageFilterImpl_HandleInComingCall
+// ----------------------------------------------------------------------
+static DWORD	WIN32API IMessageFilterImpl_HandleInComingCall(LPMESSAGEFILTER iface,
+			    DWORD dwCallType, HTASK htaskCaller, DWORD dwTickCount,
+			    LPINTERFACEINFO lpInterfaceInfo)
+{
+    ICOM_THIS(IMessageFilterImpl, iface);
+
+    dprintf(("OLE32: IMessageFilter(%p)->HandleInComingCall()\n", This));
+    return E_NOTIMPL;
+}
+
+
+// ----------------------------------------------------------------------
+// IMessageFilterImpl_RetryRejectedCall
+// ----------------------------------------------------------------------
+static DWORD	WIN32API IMessageFilterImpl_RetryRejectedCall(LPMESSAGEFILTER iface,
+			    HTASK htaskCallee, DWORD dwTickCount, DWORD dwRejectType)
+{
+    ICOM_THIS(IMessageFilterImpl, iface);
+
+    dprintf(("OLE32: IMessageFilter(%p)->RetryRejectedCall()\n", This));
+    return E_NOTIMPL;
+}
+
+// ----------------------------------------------------------------------
+// IMessageFilterImpl_MessagePending
+// ----------------------------------------------------------------------
+static DWORD	WIN32API IMessageFilterImpl_MessagePending(LPMESSAGEFILTER iface,
+			    HTASK htaskCallee, DWORD dwTickCount, DWORD dwRejectType)
+{
+    ICOM_THIS(IMessageFilterImpl, iface);
+
+    dprintf(("OLE32: IMessageFilter(%p)->MessagePending()\n", This));
+    return E_NOTIMPL;
+}
+
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoRegisterMessageFilter(LPMESSAGEFILTER lpMessageFilter,
+                                            LPMESSAGEFILTER *lplpMessageFilter)
+{
+    dprintf(("OLE32: CoRegisterMessageFilter - stub"));
+    if (lplpMessageFilter)
+	*lplpMessageFilter = NULL;
+    return S_FALSE;
+}
+
Index: trunk/src/ole32/new/initialise.cpp
===================================================================
--- trunk/src/ole32/new/initialise.cpp	(revision 3456)
+++ trunk/src/ole32/new/initialise.cpp	(revision 3456)
@@ -0,0 +1,251 @@
+/* $Id: initialise.cpp,v 1.1 2000-04-27 22:18:20 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * COM/OLE Startup shutdown.
+ * 
+ * 1/7/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Some portions from Wine Implementation
+ *   Copyright 1995  Martin von Loewis
+ *   Copyright 1998  Justin Bradford
+ *   Copyright 1999  Francis Beaudet
+ *   Copyright 1999  Sylvain St-Germain
+ */
+
+#include "ole32.h"
+#include <vmutex.h>
+
+#include "oString.h"
+#include "oTls.h"
+#include "apartment.h"
+#include "moniker.h"		// RunningObjectTableImpl_***
+#include "filemoniker.h"	// FileMonikerImpl_***
+
+extern void COM_RevokeAllClasses();
+extern void COM_ExternalLockFreeList();
+
+// Process wide variables
+Apartment *		g_pAptMT;
+Apartment *		g_pAptTN;
+Apartment *		g_pAptMain;
+Apartment *		g_pAptHost;
+
+VMutex			g_AptMutex;
+
+LONG			g_ComRef = 0;
+VMutex			g_ComRefMutex;
+
+// Thread level variables
+oTlsValue<ThreadInfo *>	t_pThreadInfo;	// ThreadLevel Information
+
+// ----------------------------------------------------------------------
+// CoInitialize()
+// ----------------------------------------------------------------------
+HRESULT WIN32API CoInitialize(LPVOID lpReserved)
+{
+    dprintf(("OLE32: CoInitialize\n"));
+
+    return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED);
+}
+
+// ----------------------------------------------------------------------
+// CreateHost
+// ----------------------------------------------------------------------
+static Apartment * CreateHost(void )
+{
+    // Thread Sync. protocol required here.
+    // CreateThread(blah, &g_pAptHost)
+    return new Apartment(APT_HOST);
+}
+
+// ----------------------------------------------------------------------
+// GetDistinguishedApt()
+// ----------------------------------------------------------------------
+static Apartment * GetDistinguishedApt(enAptType aptType)
+{
+    switch (aptType)
+    {
+	case APT_MT:
+	    g_AptMutex.enter();
+	    if (g_pAptMT == NULL)
+	    {
+		g_pAptMT = new Apartment(APT_MT);
+	    }
+	    g_AptMutex.leave();
+
+	    return g_pAptMT;
+
+	case APT_TN:
+	    g_AptMutex.enter();
+	    if (g_pAptTN == NULL)
+	    {
+		g_pAptTN = new Apartment(APT_TN);
+	    }
+	    g_AptMutex.leave();
+
+	    return g_pAptTN;
+
+	case APT_HOST:
+	    g_AptMutex.enter();
+	    if (g_pAptHost == NULL)
+	    {
+		g_pAptHost = CreateHost();
+		if (g_pAptMain == NULL)
+		{
+		    g_pAptMain = g_pAptHost;
+		}
+	    }
+	    g_AptMutex.leave();
+
+	    return g_pAptHost;
+
+	case APT_MAIN:
+	{
+	    g_AptMutex.enter();
+	    if (g_pAptMain == NULL)
+	    {
+		g_pAptMain = CreateHost();
+	    }
+	    g_AptMutex.leave();
+
+	    return g_pAptMain;
+	}
+    }
+
+    return NULL;
+}
+
+// ----------------------------------------------------------------------
+// GetSingleThreadedApt()
+// ----------------------------------------------------------------------
+static Apartment * GetSingleThreadedApt()
+{
+    Apartment *	retObj;
+
+    g_AptMutex.enter();
+
+    // If Main not defined yet we become main...
+    if (g_pAptMain == NULL)
+    {
+	g_pAptMain = new Apartment(APT_MAIN);
+	retObj = g_pAptMain;
+    }
+    else
+	retObj = new Apartment(APT_ST);
+
+    g_AptMutex.leave();
+    return retObj;
+}
+
+// ----------------------------------------------------------------------
+// CoInitializeEx()
+// ----------------------------------------------------------------------
+HRESULT WIN32API CoInitializeEx(
+	LPVOID 	lpReserved,	// [in] pointer to win32 malloc interface
+	DWORD 	dwCoInit)	// [in] A value from COINIT specifies the thread
+{
+    HRESULT		hr;
+
+    dprintf(("OLE32: CoInitializeEx(%p, %lx)\n", lpReserved, dwCoInit));
+
+    // Does com require initialisation?
+    g_ComRefMutex.enter();
+
+    if (++g_ComRef == 1)
+	RunningObjectTableImpl_Initialize();
+
+    g_ComRefMutex.leave();
+
+    // Does this thread require initialisation?
+    if (t_pThreadInfo == NULL)	// 1'st time through
+    {
+	ThreadInfo *	l_pThreadInfo;
+
+	l_pThreadInfo = new ThreadInfo;
+
+	if (dwCoInit == COINIT_APARTMENTTHREADED)
+	{
+	    l_pThreadInfo->SetHomeApt(GetSingleThreadedApt());
+	}
+	else if (dwCoInit == COINIT_MULTITHREADED)
+	{
+	    l_pThreadInfo->SetHomeApt(GetDistinguishedApt(APT_MT));
+	}
+	else
+	{
+	    delete l_pThreadInfo;
+	    return E_INVALIDARG;
+	}
+
+	// Initialise the current object context...
+	l_pThreadInfo->SetCurContext(l_pThreadInfo->GetHomeApt()->GetDefaultContext());
+
+	t_pThreadInfo.SetValue(l_pThreadInfo);	// Stash in TLS
+
+	hr = S_OK;
+    }
+    else	// Subsequent call for this thread...
+    {
+	if (dwCoInit == COINIT_APARTMENTTHREADED)
+	{
+	    if (t_pThreadInfo->GetHomeApt()->GetAptType() == APT_MT)
+		return RPC_E_CHANGED_MODE;
+	}
+	else if (dwCoInit == COINIT_MULTITHREADED)
+	{
+	    if (t_pThreadInfo->GetHomeApt()->GetAptType() != APT_MT)
+		return RPC_E_CHANGED_MODE;
+	}
+	else
+	    return E_INVALIDARG;
+
+	t_pThreadInfo->AddRef();
+
+	hr = S_FALSE;
+    }
+
+    return hr;
+}
+
+// ----------------------------------------------------------------------
+// CoUninitialize()
+// ----------------------------------------------------------------------
+void WIN32API CoUninitialize(void)
+{
+    dprintf(("OLE32: CoUninitialize"));
+
+    // Does thread require termination?
+    if (t_pThreadInfo == NULL)
+	return;
+
+    if (t_pThreadInfo->Release() == 0)
+    {
+        ThreadInfo *    l_ThreadInfo = t_pThreadInfo;
+
+	delete l_ThreadInfo;
+
+	t_pThreadInfo.SetValue(NULL);
+    }
+
+    // Does com require termination?
+    g_ComRefMutex.enter();
+    if (--g_ComRef == 0)
+    {
+	dprintf(("OLE32: Releasing COM libraries"));
+
+	RunningObjectTableImpl_UnInitialize();
+
+	COM_RevokeAllClasses();
+
+	CoFreeAllLibraries();
+	
+	COM_ExternalLockFreeList();
+    }
+    g_ComRefMutex.leave();
+}
Index: trunk/src/ole32/new/initterm.cpp
===================================================================
--- trunk/src/ole32/new/initterm.cpp	(revision 3456)
+++ trunk/src/ole32/new/initterm.cpp	(revision 3456)
@@ -0,0 +1,111 @@
+/* $Id: initterm.cpp,v 1.1 2000-04-27 22:18:21 davidr Exp $ */
+
+/*
+ * DLL entry point
+ *
+ * Copyright 1998 Sander van Leeuwen
+ * Copyright 1998 Peter Fitzsimmons
+ *
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+/*-------------------------------------------------------------*/
+/* INITERM.C -- Source for a custom dynamic link library       */
+/*              initialization and termination (_DLL_InitTerm) */
+/*              function.                                      */
+/*                                                             */
+/* When called to perform initialization, this sample function */
+/* gets storage for an array of integers, and initializes its  */
+/* elements with random integers.  At termination time, it     */
+/* frees the array.  Substitute your own special processing.   */
+/*-------------------------------------------------------------*/
+
+
+/* Include files */
+#define  INCL_DOSMODULEMGR
+#define  INCL_DOSPROCESS
+#include <os2wrap.h>    //Odin32 OS/2 api wrappers
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <odin.h>
+#include <win32type.h>
+#include <winconst.h>
+#include <odinlx.h>
+#include <misc.h>       /*PLF Wed  98-03-18 23:18:15*/
+
+extern "C" {
+void CDECL _ctordtorInit( void );
+void CDECL _ctordtorTerm( void );
+
+ //Win32 resource table (produced by wrc)
+ extern DWORD _Resource_PEResTab;
+}
+
+//******************************************************************************
+//******************************************************************************
+BOOL WINAPI LibMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
+{
+   switch (fdwReason)
+   {
+   case DLL_PROCESS_ATTACH:
+	return TRUE;
+
+   case DLL_THREAD_ATTACH:
+   case DLL_THREAD_DETACH:
+	return TRUE;
+
+   case DLL_PROCESS_DETACH:
+	_ctordtorTerm();
+	return TRUE;
+   }
+   return FALSE;
+}
+/****************************************************************************/
+/* _DLL_InitTerm is the function that gets called by the operating system   */
+/* loader when it loads and frees this DLL for each process that accesses   */
+/* this DLL.  However, it only gets called the first time the DLL is loaded */
+/* and the last time it is freed for a particular process.  The system      */
+/* linkage convention MUST be used because the operating system loader is   */
+/* calling this function.                                                   */
+/****************************************************************************/
+unsigned long SYSTEM _DLL_InitTerm(unsigned long hModule, unsigned long
+                                   ulFlag)
+{
+   size_t i;
+   APIRET rc;
+
+   /*-------------------------------------------------------------------------*/
+   /* If ulFlag is zero then the DLL is being loaded so initialization should */
+   /* be performed.  If ulFlag is 1 then the DLL is being freed so            */
+   /* termination should be performed.                                        */
+   /*-------------------------------------------------------------------------*/
+
+   switch (ulFlag) {
+      case 0 :
+         _ctordtorInit();
+
+         CheckVersionFromHMOD(PE2LX_VERSION, hModule); /*PLF Wed  98-03-18 05:28:48*/
+
+         /*******************************************************************/
+         /* A DosExitList routine must be used to clean up if runtime calls */
+         /* are required and the runtime is dynamically linked.             */
+         /*******************************************************************/
+
+	 if(RegisterLxDll(hModule, LibMain, (PVOID)&_Resource_PEResTab) == FALSE) 
+		return 0UL;
+         break;
+      case 1 :
+	 UnregisterLxDll(hModule);
+         break;
+      default  :
+         return 0UL;
+   }
+
+   /***********************************************************/
+   /* A non-zero value must be returned to indicate success.  */
+   /***********************************************************/
+   return 1UL;
+}
Index: trunk/src/ole32/new/itemmoniker.cpp
===================================================================
--- trunk/src/ole32/new/itemmoniker.cpp	(revision 3456)
+++ trunk/src/ole32/new/itemmoniker.cpp	(revision 3456)
@@ -0,0 +1,950 @@
+/* $Id: itemmoniker.cpp,v 1.1 2000-04-27 22:18:22 davidr Exp $ */
+/* 
+ *  ItemMonikers implementation
+ * 
+ * 21/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *   Copyright 1999  Noomen Hamza
+ */
+#include "ole32.h"
+#include "heapstring.h"
+#include "debugtools.h"
+#include <assert.h>
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+/* ItemMoniker data structure */
+typedef struct ItemMonikerImpl{
+
+    ICOM_VTABLE(IMoniker)*  lpvtbl1;  /* VTable relative to the IMoniker interface.*/
+
+    /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether 
+     * two monikers are equal. That's whay IROTData interface is implemented by monikers.
+     */
+    ICOM_VTABLE(IROTData)*  lpvtbl2;  /* VTable relative to the IROTData interface.*/
+
+    ULONG ref; /* reference counter for this object */
+
+    LPOLESTR itemName; /* item name identified by this ItemMoniker */
+
+    LPOLESTR itemDelimiter; /* Delimiter string */
+    
+} ItemMonikerImpl;
+
+/********************************************************************************/
+/* ItemMoniker prototype functions :                                            */
+
+/* IUnknown prototype functions */
+static HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject);
+static ULONG   WINAPI ItemMonikerImpl_AddRef(IMoniker* iface);
+static ULONG   WINAPI ItemMonikerImpl_Release(IMoniker* iface);
+
+/* IPersist prototype functions */
+static HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID);
+
+/* IPersistStream prototype functions */
+static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface);
+static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface, IStream* pStm);
+static HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty);
+static HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize);
+
+/* IMoniker prototype functions */
+static HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult);
+static HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult);
+static HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced);
+static HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite);
+static HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker);
+static HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker);
+static HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash);
+static HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning);
+static HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pItemTime);
+static HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk);
+static HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix);
+static HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath);
+static HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName);
+static HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut);
+static HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys);
+
+/* Local function used by ItemMoniker implementation */
+HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* iface, LPCOLESTR lpszDelim,LPCOLESTR lpszPathName);
+HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* iface);
+
+/********************************************************************************/
+/* IROTData prototype functions                                                 */
+
+/* IUnknown prototype functions */
+static HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData* iface,REFIID riid,VOID** ppvObject);
+static ULONG   WINAPI ItemMonikerROTDataImpl_AddRef(IROTData* iface);
+static ULONG   WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface);
+
+/* IROTData prototype function */
+static HRESULT WINAPI ItemMonikerROTDataImpl_GetComparaisonData(IROTData* iface,BYTE* pbData,ULONG cbMax,ULONG* pcbData);
+
+/********************************************************************************/
+/* Virtual function table for the ItemMonikerImpl class witch  include Ipersist,*/
+/* IPersistStream and IMoniker functions.                                       */
+static ICOM_VTABLE(IMoniker) VT_ItemMonikerImpl =
+    {
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    ItemMonikerImpl_QueryInterface,
+    ItemMonikerImpl_AddRef,
+    ItemMonikerImpl_Release,
+    ItemMonikerImpl_GetClassID,
+    ItemMonikerImpl_IsDirty,
+    ItemMonikerImpl_Load,
+    ItemMonikerImpl_Save,
+    ItemMonikerImpl_GetSizeMax,
+    ItemMonikerImpl_BindToObject,
+    ItemMonikerImpl_BindToStorage,
+    ItemMonikerImpl_Reduce,
+    ItemMonikerImpl_ComposeWith,
+    ItemMonikerImpl_Enum,
+    ItemMonikerImpl_IsEqual,
+    ItemMonikerImpl_Hash,
+    ItemMonikerImpl_IsRunning,
+    ItemMonikerImpl_GetTimeOfLastChange,
+    ItemMonikerImpl_Inverse,
+    ItemMonikerImpl_CommonPrefixWith,
+    ItemMonikerImpl_RelativePathTo,
+    ItemMonikerImpl_GetDisplayName,
+    ItemMonikerImpl_ParseDisplayName,
+    ItemMonikerImpl_IsSystemMoniker
+};
+
+/********************************************************************************/
+/* Virtual function table for the IROTData class.                               */
+static ICOM_VTABLE(IROTData) VT_ROTDataImpl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    ItemMonikerROTDataImpl_QueryInterface,
+    ItemMonikerROTDataImpl_AddRef,
+    ItemMonikerROTDataImpl_Release,
+    ItemMonikerROTDataImpl_GetComparaisonData
+};
+
+/*******************************************************************************
+ *        ItemMoniker_QueryInterface
+ *******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
+{
+    ICOM_THIS(ItemMonikerImpl,iface);
+
+  TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
+
+  /* Perform a sanity check on the parameters.*/
+    if ( (This==0) || (ppvObject==0) )
+	return E_INVALIDARG;
+  
+  /* Initialize the return parameter */
+  *ppvObject = 0;
+
+  /* Compare the riid with the interface IDs implemented by this object.*/
+  if (IsEqualIID(&IID_IUnknown, riid) ||
+      IsEqualIID(&IID_IPersist, riid) ||
+      IsEqualIID(&IID_IPersistStream, riid) ||
+      IsEqualIID(&IID_IMoniker, riid)
+     )
+      *ppvObject = iface;
+  
+    else if (IsEqualIID(&IID_IROTData, riid))
+        *ppvObject = (IROTData*)&(This->lpvtbl2);
+
+  /* Check that we obtained an interface.*/
+    if ((*ppvObject)==0)
+        return E_NOINTERFACE;
+  
+   /* Query Interface always increases the reference count by one when it is successful */
+  ItemMonikerImpl_AddRef(iface);
+
+  return S_OK;
+}
+
+/******************************************************************************
+ *        ItemMoniker_AddRef
+ ******************************************************************************/
+ULONG WINAPI ItemMonikerImpl_AddRef(IMoniker* iface)
+{
+    ICOM_THIS(ItemMonikerImpl,iface);
+
+    TRACE("(%p)\n",This);
+
+    return ++(This->ref);
+}
+
+/******************************************************************************
+ *        ItemMoniker_Release
+ ******************************************************************************/
+ULONG WINAPI ItemMonikerImpl_Release(IMoniker* iface)
+{
+    ICOM_THIS(ItemMonikerImpl,iface);
+
+    TRACE("(%p)\n",This);
+
+    This->ref--;
+
+    /* destroy the object if there's no more reference on it */
+    if (This->ref==0){
+
+        ItemMonikerImpl_Destroy(This);
+
+        return 0;
+    }
+    return This->ref;;
+}
+
+/******************************************************************************
+ *        ItemMoniker_GetClassID
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
+{
+    TRACE("(%p,%p),stub!\n",iface,pClassID);
+
+    if (pClassID==NULL)
+        return E_POINTER;
+            
+    *pClassID = CLSID_ItemMoniker;
+        
+    return S_OK;
+}
+
+/******************************************************************************
+ *        ItemMoniker_IsDirty
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface)
+{
+    /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
+       method in the OLE-provided moniker interfaces always return S_FALSE because
+       their internal state never changes. */
+
+    TRACE("(%p)\n",iface);
+
+    return S_FALSE;
+}
+
+/******************************************************************************
+ *        ItemMoniker_Load
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm)
+{
+
+    ICOM_THIS(ItemMonikerImpl,iface);
+    HRESULT res;
+    DWORD delimiterLength,nameLength;
+    CHAR *itemNameA,*itemDelimiterA;
+    ULONG bread;
+
+    /* for more details about data read by this function see coments of ItemMonikerImpl_Save function */
+
+    /* read item delimiter string length + 1 */
+    res=IStream_Read(pStm,&delimiterLength,sizeof(DWORD),&bread);
+    if (bread != sizeof(DWORD))
+        return E_FAIL;
+
+    /* read item delimiter string */
+    itemDelimiterA= (CHAR *)HeapAlloc(GetProcessHeap(),0,delimiterLength);
+    res=IStream_Read(pStm,itemDelimiterA,delimiterLength,&bread);
+    if (bread != delimiterLength)
+        return E_FAIL;
+
+    This->itemDelimiter= (WCHAR *)HeapReAlloc(GetProcessHeap(),0,This->itemDelimiter,delimiterLength*sizeof(WCHAR));
+    if (!This->itemDelimiter)
+        return E_OUTOFMEMORY;
+    
+    lstrcpyAtoW(This->itemDelimiter,itemDelimiterA);
+
+    /* read item name string length + 1*/
+    res=IStream_Read(pStm,&nameLength,sizeof(DWORD),&bread);
+    if (bread != sizeof(DWORD))
+        return E_FAIL;
+
+    /* read item name string */
+    itemNameA= (CHAR *)HeapAlloc(GetProcessHeap(),0,nameLength);
+    res=IStream_Read(pStm,itemNameA,nameLength,&bread);
+    if (bread != nameLength)
+        return E_FAIL;
+
+    This->itemName= (WCHAR *)HeapReAlloc(GetProcessHeap(),0,This->itemName,nameLength*sizeof(WCHAR));
+    if (!This->itemName)
+        return E_OUTOFMEMORY;
+    
+    lstrcpyAtoW(This->itemName,itemNameA);
+
+    return res;
+}
+
+/******************************************************************************
+ *        ItemMoniker_Save
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface,
+                                    IStream* pStm,/* pointer to the stream where the object is to be saved */
+                                    BOOL fClearDirty)/* Specifies whether to clear the dirty flag */
+{
+    ICOM_THIS(ItemMonikerImpl,iface);
+    HRESULT res;
+    DWORD delimiterLength=lstrlenW(This->itemDelimiter)+1;
+    DWORD nameLength=lstrlenW(This->itemName)+1;
+    CHAR *itemNameA,*itemDelimiterA;
+
+    /* data writen by this function are : 1) DWORD : size of item delimiter string ('\0' included ) */
+    /*                                    2) String (type A): item delimiter string ('\0' included)          */
+    /*                                    3) DWORD : size of item name string ('\0' included)       */
+    /*                                    4) String (type A): item name string ('\0' included)               */
+
+    itemNameA= (CHAR *)HeapAlloc(GetProcessHeap(),0,nameLength);
+    itemDelimiterA= (CHAR *)HeapAlloc(GetProcessHeap(),0,delimiterLength);
+    lstrcpyWtoA(itemNameA,This->itemName);
+    lstrcpyWtoA(itemDelimiterA,This->itemDelimiter);
+
+    res=IStream_Write(pStm,&delimiterLength,sizeof(DWORD),NULL);
+    res=IStream_Write(pStm,itemDelimiterA,delimiterLength * sizeof(CHAR),NULL);
+    res=IStream_Write(pStm,&nameLength,sizeof(DWORD),NULL);
+    res=IStream_Write(pStm,itemNameA,nameLength * sizeof(CHAR),NULL);
+
+    return res;
+}
+
+/******************************************************************************
+ *        ItemMoniker_GetSizeMax
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface,
+                                          ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */
+{
+    ICOM_THIS(ItemMonikerImpl,iface);
+    DWORD delimiterLength=lstrlenW(This->itemDelimiter)+1;
+    DWORD nameLength=lstrlenW(This->itemName)+1;
+
+    TRACE("(%p,%p)\n",iface,pcbSize);
+
+    if (pcbSize!=NULL)
+        return E_POINTER;
+
+    /* for more details see ItemMonikerImpl_Save coments */
+    
+    pcbSize->LowPart =  sizeof(DWORD) + /* DWORD witch contains delimiter length */
+                        delimiterLength + /* item delimiter string */
+                        sizeof(DWORD) + /* DWORD witch contains item name length */
+                        nameLength + /* item name string */
+                        34; /* this constant was added ! because when I tested this function it usually */
+                            /*  returns 34 bytes more than the number of bytes used by IMoniker::Save function */
+    pcbSize->HighPart=0;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *         ItemMoniker_Construct (local function)
+ *******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* This, LPCOLESTR lpszDelim,LPCOLESTR lpszItem)
+{
+
+    int sizeStr1=lstrlenW(lpszItem);
+    int sizeStr2=lstrlenW(lpszDelim);
+
+    TRACE("(%p,%p)\n",This,lpszItem);
+
+    /* Initialize the virtual fgunction table. */
+    This->lpvtbl1      = &VT_ItemMonikerImpl;
+    This->lpvtbl2      = &VT_ROTDataImpl;
+    This->ref          = 0;
+
+    This->itemName= (WCHAR *)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr1+1));
+    This->itemDelimiter= (WCHAR *)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr2+1));
+
+    if ((This->itemName==NULL)||(This->itemDelimiter==NULL))
+        return E_OUTOFMEMORY;
+
+    lstrcpyW(This->itemName,lpszItem);
+    lstrcpyW(This->itemDelimiter,lpszDelim);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        ItemMoniker_Destroy (local function)
+ *******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* This)
+{
+    TRACE("(%p)\n",This);
+
+    if (This->itemName)
+        HeapFree(GetProcessHeap(),0,This->itemName);
+
+    if (This->itemDelimiter)
+        HeapFree(GetProcessHeap(),0,This->itemDelimiter);
+
+    HeapFree(GetProcessHeap(),0,This);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *                  ItemMoniker_BindToObject
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface,
+                                            IBindCtx* pbc,
+                                            IMoniker* pmkToLeft,
+                                            REFIID riid,
+                                            VOID** ppvResult)
+{
+    ICOM_THIS(ItemMonikerImpl,iface);
+    
+    HRESULT   res;
+    IID    refid=IID_IOleItemContainer;
+    IOleItemContainer *poic=0;
+
+    TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
+
+    if(ppvResult ==NULL)
+        return E_POINTER;
+
+    if(pmkToLeft==NULL)
+        return E_INVALIDARG;
+
+    *ppvResult=0;
+
+    res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&refid,(void**)&poic);
+
+    if (SUCCEEDED(res)){
+
+        res=IOleItemContainer_GetObject(poic,This->itemName,BINDSPEED_MODERATE,pbc,riid,ppvResult);
+
+        IOleItemContainer_Release(poic);
+    }
+
+    return res;
+}
+
+/******************************************************************************
+ *        ItemMoniker_BindToStorage
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface,
+                                             IBindCtx* pbc,
+                                             IMoniker* pmkToLeft,
+                                             REFIID riid,
+                                             VOID** ppvResult)
+{
+    ICOM_THIS(ItemMonikerImpl,iface);
+
+    HRESULT   res;
+    IOleItemContainer *poic=0;
+
+    TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
+
+    *ppvResult=0;
+
+    if(pmkToLeft==NULL)
+        return E_INVALIDARG;
+        
+    res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic);
+
+    if (SUCCEEDED(res)){
+
+        res=IOleItemContainer_GetObjectStorage(poic,This->itemName,pbc,riid,ppvResult);
+
+        IOleItemContainer_Release(poic);
+    }
+
+    return res;
+}
+
+/******************************************************************************
+ *        ItemMoniker_Reduce
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface,
+                                      IBindCtx* pbc,
+                                      DWORD dwReduceHowFar,
+                                      IMoniker** ppmkToLeft,
+                                      IMoniker** ppmkReduced)
+{
+    TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
+
+    if (ppmkReduced==NULL)
+        return E_POINTER;
+
+    ItemMonikerImpl_AddRef(iface);
+
+    *ppmkReduced=iface;
+    
+    return MK_S_REDUCED_TO_SELF;
+}
+/******************************************************************************
+ *        ItemMoniker_ComposeWith
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface,
+                                           IMoniker* pmkRight,
+                                           BOOL fOnlyIfNotGeneric,
+                                           IMoniker** ppmkComposite)
+{
+    HRESULT res=S_OK;
+    DWORD mkSys,mkSys2;
+    IEnumMoniker* penumMk=0;
+    IMoniker *pmostLeftMk=0;
+    IMoniker* tempMkComposite=0;
+
+    TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
+
+    if ((ppmkComposite==NULL)||(pmkRight==NULL))
+	return E_POINTER;
+
+    *ppmkComposite=0;
+    
+    IMoniker_IsSystemMoniker(pmkRight,&mkSys);
+
+    /* If pmkRight is an anti-moniker, the returned moniker is NULL */
+    if(mkSys==MKSYS_ANTIMONIKER)
+        return res;
+
+    else
+        /* if pmkRight is a composite whose leftmost component is an anti-moniker,           */
+        /* the returned moniker is the composite after the leftmost anti-moniker is removed. */
+        
+         if(mkSys==MKSYS_GENERICCOMPOSITE){
+
+            res=IMoniker_Enum(pmkRight,TRUE,&penumMk);
+
+            if (FAILED(res))
+                return res;
+
+            res=IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL);
+
+            IMoniker_IsSystemMoniker(pmostLeftMk,&mkSys2);
+
+            if(mkSys2==MKSYS_ANTIMONIKER){
+
+                IMoniker_Release(pmostLeftMk);
+
+                tempMkComposite=iface;
+                IMoniker_AddRef(iface);
+                
+                while(IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL)==S_OK){
+
+                    res=CreateGenericComposite(tempMkComposite,pmostLeftMk,ppmkComposite);
+
+                    IMoniker_Release(tempMkComposite);
+                    IMoniker_Release(pmostLeftMk);
+
+                    tempMkComposite=*ppmkComposite;
+                    IMoniker_AddRef(tempMkComposite);
+}
+                return res;
+            }
+            else
+                return CreateGenericComposite(iface,pmkRight,ppmkComposite);
+         }
+         /* If pmkRight is not an anti-moniker, the method combines the two monikers into a generic
+          composite if fOnlyIfNotGeneric is FALSE; if fOnlyIfNotGeneric is TRUE, the method returns
+          a NULL moniker and a return value of MK_E_NEEDGENERIC */
+          else
+            if (!fOnlyIfNotGeneric)
+                return CreateGenericComposite(iface,pmkRight,ppmkComposite);
+
+            else
+                return MK_E_NEEDGENERIC;
+}
+
+/******************************************************************************
+ *        ItemMoniker_Enum
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
+{
+    TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
+
+    if (ppenumMoniker == NULL)
+        return E_POINTER;
+
+    *ppenumMoniker = NULL;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        ItemMoniker_IsEqual
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
+{
+
+    CLSID clsid;
+    LPOLESTR dispName1,dispName2;
+    IBindCtx* bind;
+    HRESULT res;
+
+    TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
+
+    if (pmkOtherMoniker==NULL)
+        return S_FALSE;
+    
+    /* This method returns S_OK if both monikers are item monikers and their display names are */
+    /* identical (using a case-insensitive comparison); otherwise, the method returns S_FALSE. */
+
+    IMoniker_GetClassID(pmkOtherMoniker,&clsid);
+
+    if (!IsEqualCLSID(&clsid,&CLSID_ItemMoniker))
+        return S_FALSE;
+
+    res=CreateBindCtx(0,&bind);
+    if (FAILED(res))
+        return res;
+
+    IMoniker_GetDisplayName(iface,bind,NULL,&dispName1);
+    IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&dispName2);
+    
+    if (lstrcmpW(dispName1,dispName2)!=0)
+        return S_FALSE;
+    
+    return S_OK;
+}
+
+/******************************************************************************
+ *        ItemMoniker_Hash
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
+{
+    ICOM_THIS(ItemMonikerImpl,iface);
+
+    int  h = 0,i,skip,len;
+    int  off = 0;
+    LPOLESTR val;
+
+    if (pdwHash==NULL)
+        return E_POINTER;
+    
+    val =  This->itemName;
+    len = lstrlenW(val);
+
+    if (len < 16) {
+        for (i = len ; i > 0; i--) {
+            h = (h * 37) + val[off++];
+}
+    } else {
+        /* only sample some characters */
+ 	skip = len / 8;
+ 	for (i = len ; i > 0; i -= skip, off += skip) {
+            h = (h * 39) + val[off];
+ 	}
+    }
+
+    *pdwHash=h;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        ItemMoniker_IsRunning
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface,
+                                         IBindCtx* pbc,
+                                         IMoniker* pmkToLeft,
+                                         IMoniker* pmkNewlyRunning)
+{
+    IRunningObjectTable* rot;
+    HRESULT res;
+    IOleItemContainer *poic=0;
+    ICOM_THIS(ItemMonikerImpl,iface);
+
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
+
+    /* If pmkToLeft is NULL, this method returns TRUE if pmkNewlyRunning is non-NULL and is equal to this */
+    /* moniker. Otherwise, the method checks the ROT to see whether this moniker is running.              */
+    if (pmkToLeft==NULL)
+        if ((pmkNewlyRunning!=NULL)&&(IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK))
+            return S_OK;
+        else {
+            if (pbc==NULL)
+                return E_POINTER;
+
+            res=IBindCtx_GetRunningObjectTable(pbc,&rot);
+
+            if (FAILED(res))
+                return res;
+
+            res = IRunningObjectTable_IsRunning(rot,iface);
+
+            IRunningObjectTable_Release(rot);
+        }
+    else{
+
+        /* If pmkToLeft is non-NULL, the method calls IMoniker::BindToObject on the pmkToLeft parameter,         */
+        /* requesting an IOleItemContainer interface pointer. The method then calls IOleItemContainer::IsRunning,*/
+        /* passing the string contained within this moniker. */
+        
+        res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic);
+
+        if (SUCCEEDED(res)){
+
+            res=IOleItemContainer_IsRunning(poic,This->itemName);
+
+            IOleItemContainer_Release(poic);
+        }
+    }
+
+    return res;
+}
+
+/******************************************************************************
+ *        ItemMoniker_GetTimeOfLastChange
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface,
+                                                   IBindCtx* pbc,
+                                                   IMoniker* pmkToLeft,
+                                                   FILETIME* pItemTime)
+{
+    IRunningObjectTable* rot;
+    HRESULT res;
+    IMoniker *compositeMk;
+
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pItemTime);
+
+    if (pItemTime==NULL)
+        return E_INVALIDARG;
+
+    /* If pmkToLeft is NULL, this method returns MK_E_NOTBINDABLE */
+    if (pmkToLeft==NULL)
+
+        return MK_E_NOTBINDABLE;
+    else {
+
+        /* Otherwise, the method creates a composite of pmkToLeft and this moniker and uses the ROT to access  */
+        /* the time of last change. If the object is not in the ROT, the method calls                          */
+        /* IMoniker::GetTimeOfLastChange on the pmkToLeft parameter.                                            */
+
+        res=CreateGenericComposite(pmkToLeft,iface,&compositeMk);
+
+        res=IBindCtx_GetRunningObjectTable(pbc,&rot);
+
+        if (IRunningObjectTable_GetTimeOfLastChange(rot,compositeMk,pItemTime)!=S_OK)
+
+            res=IMoniker_GetTimeOfLastChange(pmkToLeft,pbc,NULL,pItemTime);
+
+        IMoniker_Release(compositeMk);
+}
+
+    return res;
+}
+
+/******************************************************************************
+ *        ItemMoniker_Inverse
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
+{
+    TRACE("(%p,%p)\n",iface,ppmk);
+
+    if (ppmk==NULL)
+        return E_POINTER;
+
+    return CreateAntiMoniker(ppmk);
+}
+
+/******************************************************************************
+ *        ItemMoniker_CommonPrefixWith
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix)
+{
+    DWORD mkSys;
+    IMoniker_IsSystemMoniker(pmkOther,&mkSys);
+    /* If the other moniker is an item moniker that is equal to this moniker, this method sets *ppmkPrefix */
+    /* to this moniker and returns MK_S_US */
+
+    if((mkSys==MKSYS_ITEMMONIKER) && (IMoniker_IsEqual(iface,pmkOther)==S_OK) ){
+
+        *ppmkPrefix=iface;
+        
+        IMoniker_AddRef(iface);
+        
+        return MK_S_US;
+    }
+    else
+        /* otherwise, the method calls the MonikerCommonPrefixWith function. This function correctly handles */
+        /* the case where the other moniker is a generic composite. */
+        return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix);
+}
+
+/******************************************************************************
+ *        ItemMoniker_RelativePathTo
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath)
+{
+    TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath);
+
+    if (ppmkRelPath==NULL)
+        return E_POINTER;
+
+    *ppmkRelPath=0;
+    
+    return MK_E_NOTBINDABLE;
+}
+
+/******************************************************************************
+ *        ItemMoniker_GetDisplayName
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface,
+                                              IBindCtx* pbc,
+                                              IMoniker* pmkToLeft,
+                                              LPOLESTR *ppszDisplayName)
+{
+    ICOM_THIS(ItemMonikerImpl,iface);
+
+    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
+
+    if (ppszDisplayName==NULL)
+        return E_POINTER;
+
+    if (pmkToLeft!=NULL){
+        return E_INVALIDARG;
+    }
+
+    *ppszDisplayName=(WCHAR *)CoTaskMemAlloc(sizeof(WCHAR)*(lstrlenW(This->itemDelimiter)+lstrlenW(This->itemName)+1));
+
+    if (*ppszDisplayName==NULL)
+        return E_OUTOFMEMORY;
+
+    lstrcpyW(*ppszDisplayName,This->itemDelimiter);
+    lstrcatW(*ppszDisplayName,This->itemName);
+    
+    return S_OK;
+}
+
+/******************************************************************************
+ *        ItemMoniker_ParseDisplayName
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface,
+                                                IBindCtx* pbc,
+                                                IMoniker* pmkToLeft,
+                                                LPOLESTR pszDisplayName,
+                                                ULONG* pchEaten,
+                                                IMoniker** ppmkOut)
+{
+    IOleItemContainer* poic=0;
+    IParseDisplayName* ppdn=0;
+    LPOLESTR displayName;
+    HRESULT res;
+    ICOM_THIS(ItemMonikerImpl,iface);
+
+    /* If pmkToLeft is NULL, this method returns MK_E_SYNTAX */
+    if (pmkToLeft==NULL)
+
+        return MK_E_SYNTAX;
+
+    else{
+        /* Otherwise, the method calls IMoniker::BindToObject on the pmkToLeft parameter, requesting an */
+        /* IParseDisplayName interface pointer to the object identified by the moniker, and passes the display */        /* name to IParseDisplayName::ParseDisplayName */
+        res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic);
+
+        if (SUCCEEDED(res)){
+
+            res=IOleItemContainer_GetObject(poic,This->itemName,BINDSPEED_MODERATE,pbc,&IID_IParseDisplayName,(void**)&ppdn);
+
+            res=IMoniker_GetDisplayName(iface,pbc,NULL,&displayName);
+
+            res=IParseDisplayName_ParseDisplayName(ppdn,pbc,displayName,pchEaten,ppmkOut);
+
+            IOleItemContainer_Release(poic);
+            IParseDisplayName_Release(ppdn);
+        }
+}
+    return res;
+}
+
+/******************************************************************************
+ *        ItemMoniker_IsSystemMonker
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
+{
+    TRACE("(%p,%p)\n",iface,pwdMksys);
+
+    if (!pwdMksys)
+        return E_POINTER;
+    
+    (*pwdMksys)=MKSYS_ITEMMONIKER;
+
+    return S_OK;
+}
+
+/*******************************************************************************
+ *        ItemMonikerIROTData_QueryInterface
+ *******************************************************************************/
+HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject)
+{
+
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+
+    TRACE("(%p,%p,%p)\n",iface,riid,ppvObject);
+
+    return ItemMonikerImpl_QueryInterface(This, riid, ppvObject);
+}
+
+/***********************************************************************
+ *        ItemMonikerIROTData_AddRef
+ */
+ULONG   WINAPI ItemMonikerROTDataImpl_AddRef(IROTData *iface)
+{
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+
+    TRACE("(%p)\n",iface);
+
+    return ItemMonikerImpl_AddRef(This);
+}
+
+/***********************************************************************
+ *        ItemMonikerIROTData_Release
+ */
+ULONG   WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface)
+{
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+    
+    TRACE("(%p)\n",iface);
+
+    return ItemMonikerImpl_Release(This);
+}
+
+/******************************************************************************
+ *        ItemMonikerIROTData_GetComparaisonData
+ ******************************************************************************/
+HRESULT WINAPI ItemMonikerROTDataImpl_GetComparaisonData(IROTData* iface,
+                                                         BYTE* pbData,
+                                                         ULONG cbMax,
+                                                         ULONG* pcbData)
+{
+    FIXME("(),stub!\n");
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        CreateItemMoniker16	[OLE2.28]
+ ******************************************************************************/
+HRESULT WINAPI CreateItemMoniker16(LPCOLESTR16 lpszDelim,LPCOLESTR  lpszItem,LPMONIKER* ppmk)
+{
+
+    FIXME("(%s,%p),stub!\n",lpszDelim,ppmk);
+    *ppmk = NULL;
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        CreateItemMoniker	[OLE.55]
+ ******************************************************************************/
+HRESULT WINAPI CreateItemMoniker(LPCOLESTR lpszDelim,LPCOLESTR  lpszItem, LPMONIKER * ppmk)
+{
+    ItemMonikerImpl* newItemMoniker = 0;
+    HRESULT        hr = S_OK;
+    IID riid=IID_IMoniker;
+
+    TRACE("(%p,%p,%p)\n",lpszDelim,lpszItem,ppmk);
+
+    newItemMoniker = (ItemMonikerImpl*)HeapAlloc(GetProcessHeap(), 0, sizeof(ItemMonikerImpl));
+
+    if (newItemMoniker == 0)
+        return STG_E_INSUFFICIENTMEMORY;
+
+    hr = ItemMonikerImpl_Construct(newItemMoniker,lpszDelim,lpszItem);
+
+    if (FAILED(hr)){
+
+        HeapFree(GetProcessHeap(),0,newItemMoniker);
+    return hr;
+    }
+
+    return ItemMonikerImpl_QueryInterface((IMoniker*)newItemMoniker,&riid,(void**)ppmk);
+}
Index: trunk/src/ole32/new/iunknown.cpp
===================================================================
--- trunk/src/ole32/new/iunknown.cpp	(revision 3456)
+++ trunk/src/ole32/new/iunknown.cpp	(revision 3456)
@@ -0,0 +1,119 @@
+/* $Id: iunknown.cpp,v 1.1 2000-04-27 22:18:23 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * ClassID Manipulation.
+ * 
+ * 18/7/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Some portions from Wine Implementation
+ *   Copyright 1997 Marcus Meissner
+ */
+
+#include "ole32.h"
+
+#include "oString.h"
+
+// ======================================================================
+// Local Data
+// ======================================================================
+
+typedef struct
+{
+    ICOM_VTABLE(IUnknown)* lpvtbl;
+    DWORD                  ref;
+} IUnknownImpl;
+
+static ULONG	WIN32API IUnknownImpl_AddRef(LPUNKNOWN iface);
+static ULONG	WIN32API IUnknownImpl_Release(LPUNKNOWN iface);
+static HRESULT	WIN32API IUnknownImpl_QueryInterface(LPUNKNOWN iface,
+				REFIID riid, LPVOID * ppvObject);
+
+static ICOM_VTABLE(IUnknown) IUnknownVt = 
+{
+    IUnknownImpl_QueryInterface,
+    IUnknownImpl_AddRef,
+    IUnknownImpl_Release
+};
+
+// ======================================================================
+// Local Methods
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// IUnknownImpl_AddRef
+// ----------------------------------------------------------------------
+static ULONG WIN32API IUnknownImpl_AddRef(LPUNKNOWN iface)
+{ 
+    ICOM_THIS(IUnknownImpl, iface);
+
+    dprintf(("OLE32: IUnknown(%p)->AddRef()", This));
+
+    return ++(This->ref);
+}
+
+// ----------------------------------------------------------------------
+// IUnknownImpl_Release
+// ----------------------------------------------------------------------
+static ULONG WIN32API IUnknownImpl_Release(LPUNKNOWN iface)
+{
+    ICOM_THIS(IUnknownImpl, iface);
+
+    dprintf(("OLE32: IUnknown(%p)->Release()\n", This));
+
+    if (--(This->ref) == 0)
+    {
+	HeapFree(GetProcessHeap(), 0, This);
+	return 0;
+    }
+    return This->ref;
+}
+
+// ----------------------------------------------------------------------
+// IUnknownImpl_QueryInterface
+// ----------------------------------------------------------------------
+static HRESULT WIN32API IUnknownImpl_QueryInterface(LPUNKNOWN iface, REFIID riid, LPVOID *ppvObject)
+{
+    ICOM_THIS(IUnknownImpl, iface);
+
+#ifdef DEBUG
+    oStringA	tRiid(riid);
+    dprintf(("OLE32: IUnknown(%p)->QueryInterface(%s)\n", This, (char *)tRiid));
+#endif
+
+    if (IsEqualIID(&IID_IUnknown, riid))
+    {
+        dprintf(("       ->IUnknown"));
+	*ppvObject = &(This->lpvtbl);
+    }
+    else
+    {
+        dprintf(("       ->E_NOINTERFACE"));
+	return E_NOINTERFACE; 
+    }
+
+    // Query Interface always increases the reference count by one...
+    IUnknownImpl_AddRef(iface);
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// IUnknownImpl_Constructor
+// ----------------------------------------------------------------------
+LPUNKNOWN IUnknownImpl_Constructor()
+{
+    IUnknownImpl *	unk;
+
+    unk = (IUnknownImpl*)HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
+    unk->lpvtbl	= &IUnknownVt;
+    unk->ref	= 1;
+    return (LPUNKNOWN)unk;
+}
+
+
Index: trunk/src/ole32/new/library.cpp
===================================================================
--- trunk/src/ole32/new/library.cpp	(revision 3456)
+++ trunk/src/ole32/new/library.cpp	(revision 3456)
@@ -0,0 +1,191 @@
+/* $Id: library.cpp,v 1.1 2000-04-27 22:18:23 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * COM/OLE misc. functions.
+ * 
+ * 1/7/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Some portions from Wine Implementation
+ *   Copyright 1995  Martin von Loewis
+ *   Copyright 1998  Justin Bradford
+ *   Copyright 1999  Francis Beaudet
+ *   Copyright 1999  Sylvain St-Germain
+ */
+
+#include "ole32.h"
+
+#include "oString.h"
+#include "moniker.h"	// RunningObjectTableImpl_***
+
+// ======================================================================
+// Local Data
+// ======================================================================
+
+/*
+ * this open DLL table belongs in a per process table, but my guess is that
+ * it shouldn't live in the kernel, so I'll put them out here in DLL
+ * space assuming that there is one OLE32 per process.
+ */
+typedef struct tagOpenDll 
+{
+    char *	DllName;                /* really only needed for debugging */
+    HINSTANCE	hLibrary;       
+    struct tagOpenDll * next;
+} OpenDll;
+
+static OpenDll * openDllList = NULL;	/* linked list of open dlls */
+
+// ======================================================================
+// Public API's
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// CoLoadLibrary
+// ----------------------------------------------------------------------
+HINSTANCE WIN32API CoLoadLibrary(LPSTR lpszLibName, BOOL bAutoFree)
+{
+    HINSTANCE 	hLibrary;
+    OpenDll *	ptr;
+    OpenDll *	tmp;
+    HANDLE	hdl = GetProcessHeap();
+  
+    dprintf(("OLE32: CoLoadLibrary(%s)", lpszLibName));
+
+    hLibrary = LoadLibraryA(lpszLibName);
+
+    if (!bAutoFree)
+	return hLibrary;
+
+    if (openDllList == NULL)
+    {
+        /* empty list -- add first node */
+        openDllList = (OpenDll*)HeapAlloc(hdl, 0, sizeof(OpenDll));
+	openDllList->DllName = (char *)HeapAlloc(hdl, 0, strlen(lpszLibName));
+	strcpy(openDllList->DllName, lpszLibName);
+	openDllList->hLibrary = hLibrary;
+	openDllList->next = NULL;
+    }
+    else
+    {
+        /* search for this dll */
+        int found = FALSE;
+        for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next)
+        {
+  	    if (ptr->hLibrary == hLibrary)
+  	    {
+	        found = TRUE;
+		break;
+	    }
+        }
+	if (!found)
+	{
+	    /* dll not found, add it */
+ 	    tmp = openDllList;
+	    openDllList = (OpenDll*)HeapAlloc(hdl, 0, sizeof(OpenDll));
+	    openDllList->DllName = (char *)HeapAlloc(hdl, 0, strlen(lpszLibName));
+	    strcpy(openDllList->DllName, lpszLibName);
+	    openDllList->hLibrary = hLibrary;
+	    openDllList->next = tmp;
+	}
+    }
+     
+    return hLibrary;
+}
+
+// ----------------------------------------------------------------------
+// CoFreeAllLibraries
+// ----------------------------------------------------------------------
+void WIN32API CoFreeAllLibraries()
+{
+    OpenDll *	ptr;
+    OpenDll *	tmp;
+
+    dprintf(("OLE32: CoFreeAllLibraries"));
+
+    for (ptr = openDllList; ptr != NULL; )
+    {
+	tmp=ptr->next;
+	CoFreeLibrary(ptr->hLibrary);
+	ptr = tmp;
+    }
+}
+
+// ----------------------------------------------------------------------
+// CoFreeLibrary
+// ----------------------------------------------------------------------
+void WIN32API CoFreeLibrary(HINSTANCE hLibrary)
+{
+    OpenDll *	ptr;
+    OpenDll *	prev;
+    OpenDll *	tmp;
+
+    dprintf(("OLE32: CoFreeLibrary"));
+
+    /* lookup library in linked list */
+    prev = NULL;
+    for (ptr = openDllList; ptr != NULL; ptr=ptr->next)
+    {
+	if (ptr->hLibrary == hLibrary)
+	    break;
+
+	prev = ptr;
+    }
+
+    if (ptr == NULL)
+	return;
+
+    /* assert: ptr points to the library entry to free */
+
+    /* free library and remove node from list */
+    FreeLibrary(hLibrary);
+    if (ptr == openDllList)
+    {
+	tmp = openDllList->next;
+	HeapFree(GetProcessHeap(), 0, openDllList->DllName);
+	HeapFree(GetProcessHeap(), 0, openDllList);
+	openDllList = tmp;
+    }
+    else
+    {
+	tmp = ptr->next;
+	HeapFree(GetProcessHeap(), 0, ptr->DllName);
+	HeapFree(GetProcessHeap(), 0, ptr);
+	prev->next = tmp;
+    }
+
+}
+
+// ----------------------------------------------------------------------
+// CoFreeUnusedLibraries
+// ----------------------------------------------------------------------
+void WIN32API CoFreeUnusedLibraries()
+{
+    OpenDll *ptr, *tmp;
+    typedef HRESULT(*DllCanUnloadNowFunc)(void);
+    DllCanUnloadNowFunc DllCanUnloadNow;
+
+    dprintf(("OLE32: CoFreeUnusedLibraries"));
+
+    for (ptr = openDllList; ptr != NULL; )
+    {
+	DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(ptr->hLibrary, "DllCanUnloadNow");
+	
+	if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) )
+	{
+	    tmp=ptr->next;
+	    CoFreeLibrary(ptr->hLibrary);
+	    ptr = tmp;
+	}
+	else
+	{
+	    ptr=ptr->next;
+	}
+    }
+}
+
Index: trunk/src/ole32/new/makefile
===================================================================
--- trunk/src/ole32/new/makefile	(revision 3456)
+++ trunk/src/ole32/new/makefile	(revision 3456)
@@ -0,0 +1,131 @@
+# $Id: makefile,v 1.1 2000-04-27 22:21:36 davidr Exp $
+
+#
+# Odin32 API
+#
+#       ole32.dll makefile
+#
+
+
+# Directory macros.
+PDWIN32_INCLUDE = ..\..\..\include
+PDWIN32_LIB     = ..\..\..\lib
+PDWIN32_BIN     = ..\..\..\$(OBJDIR)
+PDWIN32_TOOLS   = ..\..\..\tools\bin
+
+
+# Compiler, tools, and interference rules.
+!include $(PDWIN32_INCLUDE)/pdwin32.mk
+
+
+# Flag overloads and local macros.
+CLEANEXTRAS = ole32rsrc.asm $(PDWIN32_BIN)\regsvr32.exe
+
+
+# Object files. All objects should be prefixed with $(OBJDIR)!
+OBJS = \
+$(OBJDIR)\initterm.obj \
+$(OBJDIR)\apartment.obj \
+$(OBJDIR)\objectcontext.obj \
+$(OBJDIR)\ole32.obj \
+$(OBJDIR)\antimoniker.obj \
+$(OBJDIR)\bindctx.obj \
+$(OBJDIR)\clsid.obj \
+$(OBJDIR)\compositemoniker.obj \
+$(OBJDIR)\datacache.obj \
+$(OBJDIR)\defaulthandler.obj \
+$(OBJDIR)\filemoniker.obj \
+$(OBJDIR)\guid.obj \
+$(OBJDIR)\hglobalstream.obj \
+$(OBJDIR)\initialise.obj \
+$(OBJDIR)\itemmoniker.obj \
+$(OBJDIR)\iunknown.obj \
+$(OBJDIR)\imessagefilter.obj \
+$(OBJDIR)\library.obj \
+$(OBJDIR)\memlockbytes.obj \
+$(OBJDIR)\moniker.obj \
+$(OBJDIR)\oString.obj \
+$(OBJDIR)\ole2impl.obj \
+$(OBJDIR)\ole2.obj \
+$(OBJDIR)\oleobj.obj \
+$(OBJDIR)\oleClip.obj \
+$(OBJDIR)\oleDrag.obj \
+$(OBJDIR)\oleMenu.obj \
+$(OBJDIR)\stg_bigblockfile.obj \
+$(OBJDIR)\stg_stream.obj \
+$(OBJDIR)\storage.obj \
+$(OBJDIR)\stubs.obj \
+$(OBJDIR)\taskmem.obj \
+$(OBJDIR)\ole32rsrc.obj
+
+
+# Target and original target names - names of the dll without extention and path
+TARGET      = ole32os2
+ORGTARGET   = ole32
+
+
+# All rule - build objs, target dll, copies dll to bin and makes libs.
+all:    $(OBJDIR) \
+        $(OBJDIR)\$(TARGET).dll \
+        $(PDWIN32_BIN)\$(TARGET).dll \
+        lib \
+        $(OBJDIR)\regsvr32.exe \
+        $(PDWIN32_BIN)\regsvr32.exe
+
+
+# Lib rule - build importlibrary (and evt. other libs)
+lib: $(ORGTARGET).lib $(PDWIN32_LIB)\$(ORGTARGET).lib
+
+
+# Dll rule - builds the target dll.
+$(OBJDIR)\$(TARGET).dll: $(OBJS) $(ORGTARGET).def $(OBJDIR)\$(TARGET).lrf
+    $(LD2) $(LD2FLAGS) @$(OBJDIR)\$(TARGET).lrf
+
+
+# Linker file - creates the parameter file passed on to the linker.
+$(OBJDIR)\$(TARGET).lrf: makefile
+    @echo Creating file <<$@
+/OUT:$(OBJDIR)\$(TARGET).dll
+/MAP:$(OBJDIR)\$(TARGET).map
+$(OBJS)
+$(PDWIN32_LIB)/rpcrt4.lib
+$(PDWIN32_LIB)/user32.lib
+$(PDWIN32_LIB)/gdi32.lib
+$(PDWIN32_LIB)/comctl32.lib
+$(PDWIN32_LIB)/advapi32.lib
+$(PDWIN32_LIB)/kernel32.lib
+$(PDWIN32_LIB)/oleaut32.lib
+$(PDWIN32_LIB)/odincrt.lib
+OS2386.LIB
+$(RTLLIB_O)
+$(ORGTARGET).def
+<<keep
+
+
+
+#
+# Regsrv32.exe rules.
+#
+$(OBJDIR)\regsvr32.obj:   regsvr32.cpp
+    $(CC) -C $(CXXFLAGS) -Ge+ -Tm+ -Fo$@ regsvr32.cpp
+
+$(OBJDIR)\regsvr32.exe:   $(OBJDIR)\regsvr32.obj regsvr32.def \
+                $(PDWIN32_LIB)/user32.lib \
+                $(PDWIN32_LIB)/kernel32.lib \
+                $(PDWIN32_LIB)/ole32.lib
+    $(LD) $(LDFLAGS) -Ge+ -Fm -Fe$@ $** \
+        $(PDWIN32_LIB)/odincrt.lib OS2386.LIB $(RTLLIB_O)
+
+$(PDWIN32_BIN)\regsvr32.exe: $(OBJDIR)\regsvr32.exe
+    $(CP) $** $@
+
+
+# Dep rule - makes depenencies for C, C++ and Asm files.
+dep:
+    $(DEPEND) -I$(PDWIN32_INCLUDE);$(PDWIN32_INCLUDE)\win;. \
+        *.c *.cpp *.h *.asm *.inc $(PDWIN32_INCLUDE)\*.h
+
+
+# Includes the common rules.
+!include $(PDWIN32_INCLUDE)/pdwin32.post
+
Index: trunk/src/ole32/new/memlockbytes.cpp
===================================================================
--- trunk/src/ole32/new/memlockbytes.cpp	(revision 3456)
+++ trunk/src/ole32/new/memlockbytes.cpp	(revision 3456)
@@ -0,0 +1,579 @@
+/* $Id: memlockbytes.cpp,v 1.1 2000-04-27 22:18:24 davidr Exp $ */
+/* 
+ * Global memory implementation of ILockBytes.
+ * 
+ * 21/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *   Copyright 1999 Thuy Nguyen
+ */
+
+#include "ole32.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+/******************************************************************************
+ * HGLOBALLockBytesImpl definition.
+ *
+ * This class imlements the ILockBytes inteface and represents a byte array
+ * object supported by an HGLOBAL pointer.
+ */
+struct HGLOBALLockBytesImpl
+{
+  /*
+   * Needs to be the first item in the stuct 
+   * since we want to cast this in an ILockBytes pointer
+   */
+  ICOM_VTABLE(ILockBytes) *lpvtbl;
+
+  /*
+   * Reference count
+   */
+  ULONG        ref;
+
+  /*
+   * Support for the LockBytes object
+   */
+  HGLOBAL supportHandle;
+
+  /*
+   * This flag is TRUE if the HGLOBAL is destroyed when the object
+   * is finally released.
+   */
+  BOOL    deleteOnRelease;
+
+  /*
+   * Helper variable that contains the size of the byte array
+   */
+  ULARGE_INTEGER     byteArraySize;
+};
+
+typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl;
+
+/*
+ * Method definition for the HGLOBALLockBytesImpl class.
+ */
+HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(
+    HGLOBAL  hGlobal,
+    BOOL     fDeleteOnRelease);
+
+void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This);
+
+HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
+    ILockBytes*   iface,
+    REFIID        riid,        /* [in] */
+    void**        ppvObject);  /* [iid_is][out] */
+
+ULONG WINAPI HGLOBALLockBytesImpl_AddRef(
+    ILockBytes*   iface);
+
+ULONG WINAPI HGLOBALLockBytesImpl_Release(
+    ILockBytes*   iface);
+
+HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
+    ILockBytes*    iface,
+    ULARGE_INTEGER ulOffset,  /* [in] */
+    void*          pv,        /* [length_is][size_is][out] */
+    ULONG          cb,        /* [in] */
+    ULONG*         pcbRead);  /* [out] */
+
+HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
+    ILockBytes*    iface,
+    ULARGE_INTEGER ulOffset,    /* [in] */
+    const void*    pv,          /* [size_is][in] */
+    ULONG          cb,          /* [in] */
+    ULONG*         pcbWritten); /* [out] */
+
+HRESULT WINAPI HGLOBALLockBytesImpl_Flush(
+    ILockBytes*     iface);
+
+HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
+    ILockBytes*     iface,
+    ULARGE_INTEGER  libNewSize);  /* [in] */
+
+HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
+    ILockBytes*    iface,
+    ULARGE_INTEGER libOffset,   /* [in] */
+    ULARGE_INTEGER cb,          /* [in] */
+    DWORD          dwLockType); /* [in] */
+
+HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
+    ILockBytes*    iface,
+    ULARGE_INTEGER libOffset,   /* [in] */
+    ULARGE_INTEGER cb,          /* [in] */
+    DWORD          dwLockType); /* [in] */
+
+HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
+    ILockBytes*    iface,
+    STATSTG*       pstatstg,     /* [out] */
+    DWORD          grfStatFlag); /* [in]  */
+
+/*
+ * Virtual function table for the HGLOBALLockBytesImpl class.
+ */
+static ICOM_VTABLE(ILockBytes) HGLOBALLockBytesImpl_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    HGLOBALLockBytesImpl_QueryInterface,
+    HGLOBALLockBytesImpl_AddRef,
+    HGLOBALLockBytesImpl_Release,
+    HGLOBALLockBytesImpl_ReadAt,
+    HGLOBALLockBytesImpl_WriteAt,
+    HGLOBALLockBytesImpl_Flush,
+    HGLOBALLockBytesImpl_SetSize,
+    HGLOBALLockBytesImpl_LockRegion,
+    HGLOBALLockBytesImpl_UnlockRegion,
+    HGLOBALLockBytesImpl_Stat,
+};
+
+/******************************************************************************
+ *           CreateILockBytesOnHGlobal     [OLE32.57]
+ */
+HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL      hGlobal,
+                                         BOOL         fDeleteOnRelease,
+                                         LPLOCKBYTES* ppLkbyt)
+{
+  HGLOBALLockBytesImpl* newLockBytes;
+
+  newLockBytes = HGLOBALLockBytesImpl_Construct(hGlobal, fDeleteOnRelease);
+
+  if (newLockBytes != NULL)
+  {
+    return IUnknown_QueryInterface((IUnknown*)newLockBytes,
+                                   &IID_ILockBytes,
+                                   (void**)ppLkbyt);
+  }
+
+  return E_OUTOFMEMORY;
+}
+
+/******************************************************************************
+ *           GetHGlobalFromILockBytes     [OLE32.70]
+ */
+HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* plkbyt, HGLOBAL* phglobal)
+{
+  HGLOBALLockBytesImpl* const pMemLockBytes = (HGLOBALLockBytesImpl*)plkbyt;
+
+  if (pMemLockBytes->lpvtbl == &HGLOBALLockBytesImpl_Vtbl)
+    *phglobal = pMemLockBytes->supportHandle;
+  else
+    *phglobal = 0;
+
+  if (*phglobal == 0)
+    return E_INVALIDARG;
+
+  return S_OK;
+}
+
+/******************************************************************************
+ *
+ * HGLOBALLockBytesImpl implementation
+ *
+ */
+
+/******************************************************************************
+ * This is the constructor for the HGLOBALLockBytesImpl class.
+ *
+ * Params:
+ *    hGlobal          - Handle that will support the stream. can be NULL.
+ *    fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released
+ *                       when the IStream object is destroyed.
+ */
+HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(HGLOBAL hGlobal,
+                                                     BOOL    fDeleteOnRelease)
+{
+  HGLOBALLockBytesImpl* newLockBytes;
+  newLockBytes = (HGLOBALLockBytesImpl*)HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl));
+ 
+  if (newLockBytes!=0)
+  {
+    /*
+     * Set up the virtual function table and reference count.
+     */
+    newLockBytes->lpvtbl = &HGLOBALLockBytesImpl_Vtbl;
+    newLockBytes->ref    = 0;
+  
+    /*
+     * Initialize the support.
+     */
+    newLockBytes->supportHandle = hGlobal;
+    newLockBytes->deleteOnRelease = fDeleteOnRelease;
+
+    /*
+     * This method will allocate a handle if one is not supplied.
+     */
+    if (newLockBytes->supportHandle == 0)
+    {
+      newLockBytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE |
+                                                GMEM_NODISCARD,
+                                                0);
+    }
+
+    /*
+     * Initialize the size of the array to the size of the handle.
+     */
+    newLockBytes->byteArraySize.HighPart = 0;
+    newLockBytes->byteArraySize.LowPart  = GlobalSize(
+                                              newLockBytes->supportHandle);
+  }
+
+  return newLockBytes;
+}
+
+/******************************************************************************
+ * This is the destructor of the HGLOBALStreamImpl class.
+ *
+ * This method will clean-up all the resources used-up by the given
+ * HGLOBALLockBytesImpl class. The pointer passed-in to this function will be
+ * freed and will not be valid anymore.
+ */
+void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This)
+{
+  /*
+   * Release the HGlobal if the constructor asked for that.
+   */
+  if (This->deleteOnRelease)
+  {
+    GlobalFree(This->supportHandle);
+    This->supportHandle = 0;
+  }
+
+  /*
+   * Finally, free the memory used-up by the class.
+   */
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ * This implements the IUnknown method QueryInterface for this
+ * class
+ */
+HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
+      ILockBytes*  iface,
+      REFIID       riid,        /* [in] */
+      void**       ppvObject)   /* [iid_is][out] */
+{
+  HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (ppvObject==0)
+    return E_INVALIDARG;
+
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
+  {
+    *ppvObject = (ILockBytes*)This;
+  }
+  else if (memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) == 0)
+  {
+    *ppvObject = (ILockBytes*)This;
+  }
+
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+    return E_NOINTERFACE;
+
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  HGLOBALLockBytesImpl_AddRef(iface);
+
+  return S_OK;;
+}
+
+/******************************************************************************
+ * This implements the IUnknown method AddRef for this
+ * class
+ */
+ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface)
+{
+  HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
+
+  This->ref++;
+
+  return This->ref;
+}
+
+/******************************************************************************
+ * This implements the IUnknown method Release for this
+ * class
+ */
+ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface)
+{
+  HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
+
+  ULONG newRef;
+
+  This->ref--;
+
+  newRef = This->ref;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (newRef==0)
+  {
+    HGLOBALLockBytesImpl_Destroy(This);
+  }
+
+  return newRef;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * It reads a block of information from the byte array at the specified
+ * offset.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
+      ILockBytes*    iface,
+      ULARGE_INTEGER ulOffset,  /* [in] */
+      void*          pv,        /* [length_is][size_is][out] */
+      ULONG          cb,        /* [in] */
+      ULONG*         pcbRead)   /* [out] */
+{
+  HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
+
+  void* supportBuffer;
+  ULONG bytesReadBuffer = 0;
+  ULONG bytesToReadFromBuffer;
+
+  /*
+   * If the caller is not interested in the number of bytes read,
+   * we use another buffer to avoid "if" statements in the code.
+   */
+  if (pcbRead == 0)
+    pcbRead = &bytesReadBuffer;
+
+  /*
+   * Make sure the offset is valid.
+   */
+  if (ulOffset.LowPart > This->byteArraySize.LowPart)
+    return E_FAIL;
+
+  /*
+   * Using the known size of the array, calculate the number of bytes
+   * to read.
+   */
+  bytesToReadFromBuffer = MIN(This->byteArraySize.LowPart -
+                              ulOffset.LowPart, cb);
+
+  /*
+   * Lock the buffer in position and copy the data.
+   */
+  supportBuffer = GlobalLock(This->supportHandle);
+
+  memcpy(pv,
+         (char *) supportBuffer + ulOffset.LowPart,
+         bytesToReadFromBuffer);
+
+  /*
+   * Return the number of bytes read.
+   */
+  *pcbRead = bytesToReadFromBuffer;
+
+  /*
+   * Cleanup
+   */
+  GlobalUnlock(This->supportHandle);
+
+  /*
+   * The function returns S_OK if the specified number of bytes were read
+   * or the end of the array was reached.
+   * It returns STG_E_READFAULT if the number of bytes to read does not equal 
+   * the number of bytes actually read.
+   */
+  if(*pcbRead == cb)
+    return S_OK;
+
+  return STG_E_READFAULT;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * It writes the specified bytes at the specified offset.
+ * position. If the array is too small, it will be resized.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
+      ILockBytes*    iface,
+      ULARGE_INTEGER ulOffset,    /* [in] */
+      const void*    pv,          /* [size_is][in] */
+      ULONG          cb,          /* [in] */
+      ULONG*         pcbWritten)  /* [out] */
+{
+  HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
+
+  void*          supportBuffer;
+  ULARGE_INTEGER newSize;
+  ULONG          bytesWritten = 0;
+
+  /*
+   * If the caller is not interested in the number of bytes written,
+   * we use another buffer to avoid "if" statements in the code.
+   */
+  if (pcbWritten == 0)
+    pcbWritten = &bytesWritten;
+
+  if (cb == 0)
+  {
+    return S_OK;
+  }
+  else
+  {
+    newSize.HighPart = 0;
+    newSize.LowPart = ulOffset.LowPart + cb;
+  }
+
+  /*
+   * Verify if we need to grow the stream
+   */
+  if (newSize.LowPart > This->byteArraySize.LowPart)
+  {
+    /* grow stream */
+    if (HGLOBALLockBytesImpl_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
+      return STG_E_MEDIUMFULL;
+  }
+
+  /*
+   * Lock the buffer in position and copy the data.
+   */
+  supportBuffer = GlobalLock(This->supportHandle);
+
+  memcpy((char *) supportBuffer + ulOffset.LowPart, pv, cb);
+
+  /*
+   * Return the number of bytes written.
+   */
+  *pcbWritten = cb;
+
+  /*
+   * Cleanup
+   */
+  GlobalUnlock(This->supportHandle);
+
+  return S_OK;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface)
+{
+  return S_OK;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * It will change the size of the byte array.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
+      ILockBytes*     iface,
+      ULARGE_INTEGER  libNewSize)   /* [in] */
+{
+  HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
+
+  /*
+   * As documented.
+   */
+  if (libNewSize.HighPart != 0)
+    return STG_E_INVALIDFUNCTION;
+ 
+  if (This->byteArraySize.LowPart == libNewSize.LowPart)
+    return S_OK;
+
+  /*
+   * Re allocate the HGlobal to fit the new size of the stream.
+   */
+  This->supportHandle = GlobalReAlloc(This->supportHandle,
+                                      libNewSize.LowPart,
+                                      0);
+
+  if (This->supportHandle == 0)
+    return STG_E_MEDIUMFULL;
+
+  This->byteArraySize.LowPart = libNewSize.LowPart;
+ 
+  return S_OK;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * The global memory implementation of ILockBytes does not support locking.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
+      ILockBytes*    iface,
+      ULARGE_INTEGER libOffset,   /* [in] */
+      ULARGE_INTEGER cb,          /* [in] */
+      DWORD          dwLockType)  /* [in] */
+{
+  return STG_E_INVALIDFUNCTION;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * The global memory implementation of ILockBytes does not support locking.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
+      ILockBytes*    iface,
+      ULARGE_INTEGER libOffset,   /* [in] */
+      ULARGE_INTEGER cb,          /* [in] */
+      DWORD          dwLockType)  /* [in] */
+{
+  return STG_E_INVALIDFUNCTION;
+}
+
+/******************************************************************************
+ * This method is part of the ILockBytes interface.
+ *
+ * This method returns information about the current
+ * byte array object.
+ *
+ * See the documentation of ILockBytes for more info.
+ */
+HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
+      ILockBytes*  iface,
+      STATSTG*     pstatstg,     /* [out] */
+      DWORD        grfStatFlag)  /* [in] */
+{
+  HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface;
+
+  memset(pstatstg, 0, sizeof(STATSTG));
+
+  pstatstg->pwcsName = NULL;
+  pstatstg->type     = STGTY_LOCKBYTES;
+  pstatstg->cbSize   = This->byteArraySize;
+
+  return S_OK;
+}
+
Index: trunk/src/ole32/new/moniker.cpp
===================================================================
--- trunk/src/ole32/new/moniker.cpp	(revision 3456)
+++ trunk/src/ole32/new/moniker.cpp	(revision 3456)
@@ -0,0 +1,446 @@
+/* $Id: moniker.cpp,v 1.1 2000-04-27 22:18:25 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * COM Monikers.
+ * 
+ * 1/7/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Some portions from Wine Implementation
+ *   Copyright 1998  Marcus Meissner
+ *   Copyright 1999  Noomen Hamza
+ */
+
+#include "ole32.h"
+
+#include "moniker.h"
+
+// ======================================================================
+// DATA
+// ======================================================================
+
+// Singleton instance of ROT
+RunningObjectTableImpl * runningObjectTableInstance = 0;
+
+// VTABLE instance
+static ICOM_VTABLE(IRunningObjectTable) VT_RunningObjectTableImpl =
+{
+    RunningObjectTableImpl_QueryInterface, 
+    RunningObjectTableImpl_AddRef, 
+    RunningObjectTableImpl_Release, 
+    RunningObjectTableImpl_Register, 
+    RunningObjectTableImpl_Revoke, 
+    RunningObjectTableImpl_IsRunning, 
+    RunningObjectTableImpl_GetObject, 
+    RunningObjectTableImpl_NoteChangeTime, 
+    RunningObjectTableImpl_GetTimeOfLastChange, 
+    RunningObjectTableImpl_EnumRunning
+};
+
+// ======================================================================
+// Local Methods
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// Initialize
+// ----------------------------------------------------------------------
+HRESULT RunningObjectTableImpl_Initialize()
+{
+    // create singleton ROT
+    runningObjectTableInstance = (RunningObjectTableImpl *)
+			    HeapAlloc(GetProcessHeap(), 0, sizeof(RunningObjectTableImpl));
+
+    if (runningObjectTableInstance == 0)
+	return E_OUTOFMEMORY;
+
+    /* initialize the virtual table function */
+    runningObjectTableInstance->lpvtbl = &VT_RunningObjectTableImpl;
+    runningObjectTableInstance->ref = 1;
+    runningObjectTableInstance->runObjTabSize = ROT_BLOCK_SIZE;
+    runningObjectTableInstance->runObjTabRegister = 0;
+    runningObjectTableInstance->runObjTabLastIndx = 0;
+    runningObjectTableInstance->runObjTab = (RunObject *)
+			HeapAlloc(GetProcessHeap(), 0, sizeof(RunObject[ROT_BLOCK_SIZE]));
+
+    if (runningObjectTableInstance->runObjTab == NULL)
+	return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// UnInitialize
+// ----------------------------------------------------------------------
+HRESULT RunningObjectTableImpl_UnInitialize()
+{
+    RunningObjectTableImpl_Release((IRunningObjectTable * )runningObjectTableInstance);
+    Destroy();
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// Destroy
+// ----------------------------------------------------------------------
+static HRESULT Destroy()
+{
+    HeapFree(GetProcessHeap(), 0, runningObjectTableInstance->runObjTab);
+    HeapFree(GetProcessHeap(), 0, runningObjectTableInstance);
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// GetObjectIndex
+// ----------------------------------------------------------------------
+static HRESULT GetObjectIndex(RunningObjectTableImpl * This, DWORD identReg,
+						 IMoniker * pmk, DWORD * indx)
+{
+    DWORD i;
+
+    if (pmk != NULL)
+        /* search object identified by a moniker*/
+        for(i = 0; (i < This->runObjTabLastIndx) && (!IMoniker_IsEqual(This->runObjTab[i].pmkObj, pmk) == S_OK); i++)
+	    ;
+    else
+        /* search object identified by a register identifier*/
+        for(i = 0; ((i<This->runObjTabLastIndx) && (This->runObjTab[i].identRegObj != identReg)); i++)
+	    ;
+    
+    if (i == This->runObjTabLastIndx)
+	return S_FALSE;
+
+    if (indx != NULL)
+	*indx = i;
+
+    return S_OK;
+}
+
+// ======================================================================
+// COM INTERFACE FUNCTIONS
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// RunningObjectTableImpl_QueryInterface
+// ----------------------------------------------------------------------
+HRESULT WIN32API RunningObjectTableImpl_QueryInterface
+   (IRunningObjectTable * iface,
+   REFIID riid,
+   void**ppvObject)
+{
+    ICOM_THIS(RunningObjectTableImpl, iface);
+
+    dprintf(("OLE32: RunningObjectTableImpl_QueryInterface(%p, %p, %p)", This, riid, ppvObject));
+
+    /* validate arguments*/
+    if (This == 0)
+        return CO_E_NOTINITIALIZED;
+
+    if (ppvObject == 0)
+        return E_INVALIDARG;
+
+    * ppvObject = 0;
+
+    if (IsEqualIID(&IID_IUnknown, riid))
+        * ppvObject = (IRunningObjectTable * )This;
+    else
+        if (IsEqualIID(&IID_IRunningObjectTable, riid))
+            * ppvObject = (IRunningObjectTable * )This;
+
+    if ((* ppvObject) == 0)
+        return E_NOINTERFACE;
+
+    RunningObjectTableImpl_AddRef(iface);
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// RunningObjectTableImpl_AddRef
+// ----------------------------------------------------------------------
+ULONG   WIN32API RunningObjectTableImpl_AddRef
+   (IRunningObjectTable * iface)
+{
+    ICOM_THIS(RunningObjectTableImpl, iface);
+
+    dprintf(("OLE32: RunningObjectTableImpl_AddRef(%p)", This));
+
+    return ++(This->ref);
+}
+
+// ----------------------------------------------------------------------
+// RunningObjectTableImpl_Release
+// ----------------------------------------------------------------------
+ULONG   WIN32API RunningObjectTableImpl_Release
+   (IRunningObjectTable * iface)
+{
+    ICOM_THIS(RunningObjectTableImpl, iface);
+
+    DWORD	i;
+
+    dprintf(("OLE32: RunningObjectTableImpl_Release(%p)", This));
+
+    This->ref--;
+
+    /* unitialize ROT structure if there's no more reference to it*/
+    if (This->ref == 0){
+
+        /* release all registred objects */
+        for( i = 0; i < This->runObjTabLastIndx; i++)
+        {
+            if (( This->runObjTab[i].regTypeObj & ROTFLAGS_REGISTRATIONKEEPSALIVE) != 0)
+                IUnknown_Release(This->runObjTab[i].pObj);
+ 
+            IMoniker_Release(This->runObjTab[i].pmkObj);
+        }
+
+       /*
+        * RunningObjectTable data structure will be not destroyed here !
+        * The destruction will be done only
+        * when RunningObjectTableImpl_UnInitialize function is called
+        */
+
+        /* there's no more elements in the table */
+        This->runObjTabRegister = 0;
+        This->runObjTabLastIndx = 0;
+
+        return 0;
+    }
+
+    return This->ref;
+}
+
+// ----------------------------------------------------------------------
+// RunningObjectTableImpl_Register
+// ----------------------------------------------------------------------
+HRESULT WIN32API RunningObjectTableImpl_Register
+   (IRunningObjectTable * iface, 
+    DWORD grfFlags,           /* Registration options */
+    IUnknown * punkObject,     /* Pointer to the object being registered */
+    IMoniker * pmkObjectName,  /* Pointer to the moniker of the object being registered */
+    DWORD * pdwRegister)       /* Pointer to the value identifying the  registration */
+{
+    ICOM_THIS(RunningObjectTableImpl, iface);
+
+    dprintf(("OLE32: RunningObjectTableImpl_Register(%p, %ld, %p, %p, %p)", This, grfFlags, punkObject, pmkObjectName, pdwRegister));
+
+    HRESULT res = S_OK;
+
+    /* there's only two types of register : strong and or weak registration (only one must be passed on parameter) */
+    if ( ( (grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) || !(grfFlags & ROTFLAGS_ALLOWANYCLIENT)) &&
+         (!(grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) ||  (grfFlags & ROTFLAGS_ALLOWANYCLIENT)) &&
+         (grfFlags) )
+        return E_INVALIDARG;
+
+    if ((punkObject == NULL) || (pmkObjectName == NULL) || (pdwRegister == NULL))
+        return E_INVALIDARG;
+
+    /* verify if the object to be registred was registred befor */
+    if (GetObjectIndex(This, -1, pmkObjectName, NULL) == S_OK)
+        res = MK_S_MONIKERALREADYREGISTERED;
+
+    /* put the new registred object in the first free element in the table */
+    This->runObjTab[This->runObjTabLastIndx].pObj = punkObject;
+    This->runObjTab[This->runObjTabLastIndx].pmkObj = pmkObjectName;
+    This->runObjTab[This->runObjTabLastIndx].regTypeObj = grfFlags;
+    This->runObjTab[This->runObjTabLastIndx].identRegObj = This->runObjTabRegister;
+    CoFileTimeNow(&(This->runObjTab[This->runObjTabLastIndx].lastModifObj));
+    
+    /* gives a registration identifier to the registred object*/
+    (* pdwRegister)= This->runObjTabRegister;
+
+    if (This->runObjTabRegister == 0xFFFFFFFF)
+    {
+        WriteLog("OLE32: Rot_Impl_Register() - runObjTabRegister: %ld overflow! ", This->runObjTabRegister);
+	return E_FAIL;
+    }
+    This->runObjTabRegister++;
+    This->runObjTabLastIndx++;
+    
+    if (This->runObjTabLastIndx == This->runObjTabSize)
+    { /* table is full ! so it must be resized */
+
+        This->runObjTabSize += ROT_BLOCK_SIZE; /* newsize table */
+        This->runObjTab = (RunObject *)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->runObjTab, 
+                        This->runObjTabSize * sizeof(RunObject));
+        if (!This->runObjTab)
+            return E_OUTOFMEMORY;
+    }
+    /* add a reference to the object in the strong registration case */
+    if ((grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) != 0 )
+        IUnknown_AddRef(punkObject);
+
+    IMoniker_AddRef(pmkObjectName);
+    
+    return res;
+}
+
+// ----------------------------------------------------------------------
+// RunningObjectTableImpl_Revoke
+// ----------------------------------------------------------------------
+HRESULT WIN32API RunningObjectTableImpl_Revoke
+   (IRunningObjectTable * iface, 
+    DWORD dwRegister)  /* Value identifying registration to be revoked*/
+{
+
+    ICOM_THIS(RunningObjectTableImpl, iface);
+
+    dprintf(("OLE32: RunningObjectTableImpl_Revoke(%p, %ld)", This, dwRegister));
+
+    DWORD index, j;
+
+    /* verify if the object to be revoked was registred befor or not */
+    if (GetObjectIndex(This, dwRegister, NULL, &index) == S_FALSE)
+        return E_INVALIDARG;
+
+    /* release the object if it was registred with a strong registrantion option */
+    if ((This->runObjTab[index].regTypeObj & ROTFLAGS_REGISTRATIONKEEPSALIVE) != 0)
+        IUnknown_Release(This->runObjTab[index].pObj);
+
+    IMoniker_Release(This->runObjTab[index].pmkObj);
+    
+    /* remove the object from the table */
+    for(j = index; j < This->runObjTabLastIndx - 1; j++)
+        This->runObjTab[j]= This->runObjTab[j + 1];
+    
+    This->runObjTabLastIndx--;
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// RunningObjectTableImpl_IsRunning
+// ----------------------------------------------------------------------
+HRESULT WIN32API RunningObjectTableImpl_IsRunning
+   (IRunningObjectTable * iface, 
+    IMoniker * pmkObjectName)  /* Pointer to the moniker of the object whose status is desired */
+{
+    ICOM_THIS(RunningObjectTableImpl, iface);
+
+    dprintf(("OLE32: RunningObjectTableImpl_IsRunning(%p, %p)", This, pmkObjectName));
+
+    return GetObjectIndex(This, -1, pmkObjectName, NULL);
+}
+
+// ----------------------------------------------------------------------
+// RunningObjectTableImpl_GetObject
+// ----------------------------------------------------------------------
+HRESULT WIN32API RunningObjectTableImpl_GetObject
+   (IRunningObjectTable * iface, 
+    IMoniker * pmkObjectName, /* Pointer to the moniker on the object */
+    IUnknown **ppunkObject) /* Address of output variable that receives the IUnknown interface pointer */
+{
+    ICOM_THIS(RunningObjectTableImpl, iface);
+
+    dprintf(("OLE32: RunningObjectTableImpl_GetObject(%p, %p, %p)", This, pmkObjectName, ppunkObject));
+
+    DWORD index;
+
+    if (ppunkObject == NULL)
+        return E_POINTER;
+    
+    *ppunkObject = 0;
+
+    /* verify if the object was registred befor or not */
+    if (GetObjectIndex(This, -1, pmkObjectName, &index) == S_FALSE)
+        return MK_E_UNAVAILABLE;
+
+    /* add a reference to the object then set output object argument */
+    IUnknown_AddRef(This->runObjTab[index].pObj);
+    *ppunkObject = This->runObjTab[index].pObj;
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// RunningObjectTableImpl_NoteChangeTime
+// ----------------------------------------------------------------------
+HRESULT WIN32API RunningObjectTableImpl_NoteChangeTime
+   (IRunningObjectTable * iface, 
+    DWORD dwRegister,  /* Value identifying registration being updated */
+    FILETIME * pfiletime) /* Pointer to structure containing object's last change time */
+{
+    ICOM_THIS(RunningObjectTableImpl, iface);
+
+    dprintf(( "OLE32: RunningObjectTableImpl_NoteChangeTime(%p, %ld, %p)", This, dwRegister, pfiletime));
+
+    DWORD index=-1;
+
+    /* verify if the object to be changed was registred befor or not */
+    if (GetObjectIndex(This, dwRegister, NULL, &index) == S_FALSE)
+        return E_INVALIDARG;
+
+    /* set the new value of the last time change */
+    This->runObjTab[index].lastModifObj = (* pfiletime);
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// RunningObjectTableImpl_GetTimeOfLastChange
+// ----------------------------------------------------------------------
+HRESULT WIN32API RunningObjectTableImpl_GetTimeOfLastChange
+   (IRunningObjectTable * iface, 
+    IMoniker * pmkObjectName,  /* Pointer to moniker on the object whose status is desired */
+    FILETIME * pfiletime)       /* Pointer to structure that receives object's last change time */
+{
+    ICOM_THIS(RunningObjectTableImpl, iface);
+
+    dprintf(( "OLE32: RunningObjectTableImpl_GetTimeOfLastChange(%p, %p, %p)", This, pmkObjectName, pfiletime));
+
+    DWORD index = -1;
+
+    if (pmkObjectName == NULL || pfiletime == NULL)
+        return E_INVALIDARG;
+
+    /* verify if the object was registred befor or not */
+    if (GetObjectIndex(This, -1, pmkObjectName, &index) == S_FALSE)
+        return MK_E_UNAVAILABLE;;
+
+    (* pfiletime)= This->runObjTab[index].lastModifObj;
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// RunningObjectTableImpl_EnumRunning
+// ----------------------------------------------------------------------
+HRESULT WIN32API RunningObjectTableImpl_EnumRunning
+   (IRunningObjectTable * iface, 
+    IEnumMoniker **ppenumMoniker) /* Address of output variable that receives the IEnumMoniker interface pointer */
+{
+    dprintf(( "OLE32: RunningObjectTableImpl_EnumRunning - stub"));
+    return E_NOTIMPL;
+}
+
+// ======================================================================
+// API Methods
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// GetRunningObjectTable
+// ----------------------------------------------------------------------
+HRESULT WIN32API GetRunningObjectTable(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot)
+{
+    IID		riid = IID_IRunningObjectTable;
+    HRESULT	hr;
+
+    dprintf(("OLE32: GetRunningObjectTable"));
+
+    if (reserved != 0)
+	return E_UNEXPECTED;
+
+    if (runningObjectTableInstance == NULL)
+	return CO_E_NOTINITIALIZED;
+
+    hr = RunningObjectTableImpl_QueryInterface(
+		    (IRunningObjectTable*)runningObjectTableInstance, &riid, (void**)pprot);
+
+    return hr;
+}
+
Index: trunk/src/ole32/new/moniker.h
===================================================================
--- trunk/src/ole32/new/moniker.h	(revision 3456)
+++ trunk/src/ole32/new/moniker.h	(revision 3456)
@@ -0,0 +1,65 @@
+/* $Id: moniker.h,v 1.1 2000-04-27 22:21:36 davidr Exp $ */
+/*
+ * moniker.h [OLE32]
+ *
+ * Private include for Running Object Table (ROT) implementation class
+ */
+
+#if !defined(MONIKER_INCLUDED)
+#define MONIKER_INCLUDED
+
+#define ROT_BLOCK_SIZE	50
+
+// ROT Element
+struct RunObject
+{
+    IUnknown *	pObj;			// object
+    IMoniker *	pmkObj;			// moniker who identifies this object
+    FILETIME	lastModifObj;		// Last modified date/time
+    DWORD	identRegObj;		// registration key relative to this object
+    DWORD      	regTypeObj;		// registration type : strong or weak
+};
+
+// Implementation structure for ROT
+struct RunningObjectTableImpl
+{
+    ICOM_VTABLE(IRunningObjectTable)*  lpvtbl;
+    ULONG      	ref;
+
+    RunObject * runObjTab;            	// First object
+    DWORD      	runObjTabSize;		// ROT size
+    DWORD      	runObjTabLastIndx;	// First free ROT entry
+    DWORD      	runObjTabRegister;	// Registration key of the next registred object
+};
+
+// Initialisation
+extern HRESULT RunningObjectTableImpl_Initialize();
+extern HRESULT RunningObjectTableImpl_UnInitialize();
+
+static HRESULT Destroy();
+static HRESULT GetObjectIndex(RunningObjectTableImpl * This, DWORD identReg, IMoniker * pmk, DWORD * indx);
+
+static HRESULT WIN32API RunningObjectTableImpl_QueryInterface
+    (IRunningObjectTable * iface,REFIID riid,void** ppvObject);
+static ULONG   WIN32API RunningObjectTableImpl_AddRef
+    (IRunningObjectTable * iface);
+static ULONG   WIN32API RunningObjectTableImpl_Release
+    (IRunningObjectTable * iface);
+static HRESULT WIN32API RunningObjectTableImpl_Register
+    (IRunningObjectTable * iface, DWORD grfFlags, IUnknown * punkObject,
+     IMoniker * pmkObjectName, DWORD* pdwRegister);
+static HRESULT WIN32API RunningObjectTableImpl_Revoke
+    (IRunningObjectTable * iface, DWORD dwRegister);
+static HRESULT WIN32API RunningObjectTableImpl_IsRunning
+    (IRunningObjectTable * iface, IMoniker * pmkObjectName);
+static HRESULT WIN32API RunningObjectTableImpl_GetObject
+    (IRunningObjectTable * iface, IMoniker * pmkObjectName, IUnknown * * ppunkObject);
+static HRESULT WIN32API RunningObjectTableImpl_NoteChangeTime
+    (IRunningObjectTable * iface, DWORD dwRegister, FILETIME * pfiletime);
+static HRESULT WIN32API RunningObjectTableImpl_GetTimeOfLastChange
+    (IRunningObjectTable * iface, IMoniker * pmkObjectName, FILETIME * pfiletime);
+static HRESULT WIN32API RunningObjectTableImpl_EnumRunning
+    (IRunningObjectTable * iface, IEnumMoniker * * ppenumMoniker);
+
+#endif // MONIKER_INCLUDED
+
Index: trunk/src/ole32/new/oString.cpp
===================================================================
--- trunk/src/ole32/new/oString.cpp	(revision 3456)
+++ trunk/src/ole32/new/oString.cpp	(revision 3456)
@@ -0,0 +1,547 @@
+/* $Id: oString.cpp,v 1.1 2000-04-27 22:18:29 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * ClassID Manipulation.
+ * 
+ * 12/7/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ */
+
+#include "ole32.h"
+
+#include "oString.h"
+
+// ======================================================================
+// oStringBase - Base stuff for oString classes
+// ======================================================================
+
+// Block size.
+long oStringBase::blockSize = 32;
+
+// Initialise to nothing...
+oStringBase::oStringBase(long bytePerChar)
+{
+    m_bytePerChar = bytePerChar;
+    m_Heap = GetProcessHeap();
+}
+
+// Destructor
+oStringBase::~oStringBase()
+{
+    freeBuf();
+}
+
+// calculate the buffersize needed for this string (quantised to blockSize)
+long oStringBase::calcBufLen(long strLen)
+{
+    long	tmp;
+
+    tmp = ((strLen * m_bytePerChar) / blockSize) + 1;
+
+    return tmp * blockSize;
+}
+
+// Get a buffer of required length...
+void oStringBase::getBuf(long strLen)
+{
+    // Sanity check...
+    if (strLen < 1)
+    {
+    	dprintf(("oStringBase: Warning! ::getBuf - strlen < 1!"));
+    	strLen = 1;
+    }
+
+    // Allocate new buffer...
+    m_bufLen = calcBufLen(strLen);
+    m_strBuf = (LPSTR)HeapAlloc(m_Heap, 0, m_bufLen);
+    m_strLen = 1;
+    m_strBuf[0] = 0;	// Ensure terminated.
+}
+
+// Free buffer...
+void oStringBase::freeBuf()
+{
+    HeapFree(m_Heap, 0, m_strBuf);
+}
+
+// Re-allocate buffer if more space is required...
+void oStringBase::adjBuf(long strLen)
+{
+    if ((strLen * m_bytePerChar) > m_bufLen)
+    {
+	long	bufLen = calcBufLen(strLen);
+
+	// Allocate new buffer...
+	m_strBuf = (LPSTR)HeapReAlloc(m_Heap, 0, m_strBuf, bufLen);
+
+	// Save new buffer...
+	m_bufLen = bufLen;
+    }
+}
+
+// ======================================================================
+// oStringA - String manipulation based on ASCII
+// ======================================================================
+
+// Initialise to nothing...
+oStringA::oStringA( void) : oStringBase(sizeof(char))
+{
+    getBuf( 1);	// Incl. terminator...
+}
+
+// Initialise to a specified length...
+oStringA::oStringA(int defLen, int fill)   : oStringBase(sizeof(char))
+{
+    getBuf( defLen + 1);
+}
+
+// Initialise from Unicode string...
+oStringA::oStringA(LPCWSTR pUnicode)  : oStringBase(sizeof(char))
+{
+    long	strLen = lstrlenW(pUnicode) + 1;
+
+    getBuf( strLen);
+    UnicodeToAscii((LPWSTR)pUnicode, m_strBuf);
+    m_strLen = strLen;
+}
+
+// Initialise from ASCII string...
+oStringA::oStringA(LPCSTR pAscii)  : oStringBase(sizeof(char))
+{
+    long	strLen = strlen(pAscii) + 1;
+
+    getBuf( strLen);
+    strcpy(m_strBuf, pAscii);
+    m_strLen = strLen;
+}
+
+// Initialise from another oString
+oStringA::oStringA(const oStringA &ref)  : oStringBase(sizeof(char))
+{
+    getBuf( ref.m_strLen);
+    strcpy(m_strBuf, ref.m_strBuf);
+    m_strLen = ref.m_strLen;
+}
+
+// Initialise from CLSID
+oStringA::oStringA( REFCLSID pClsId)  : oStringBase(sizeof(char))
+{
+    getBuf( 50);	// Incl. terminator...
+
+    // Assign string...
+    operator=(pClsId);
+}
+
+oStringA::oStringA(const ULONG val)  : oStringBase(sizeof(char))
+{
+    getBuf( 30);	// Incl. terminator...
+    m_strLen = sprintf(m_strBuf, "%lu", val);
+}
+
+oStringA::oStringA(const LONG val)  : oStringBase(sizeof(char))
+{
+    getBuf( 30);	// Incl. terminator...
+    m_strLen = sprintf(m_strBuf, "%ld", val);
+}
+
+oStringA::oStringA(const USHORT val)  : oStringBase(sizeof(char))
+{
+    getBuf( 30);	// Incl. terminator...
+    m_strLen = sprintf(m_strBuf, "%u", val);
+}
+
+oStringA::oStringA(const SHORT val)  : oStringBase(sizeof(char))
+{
+    getBuf( 30);	// Incl. terminator...
+    m_strLen = sprintf(m_strBuf, "%d", val);
+}
+
+// Return pointer to string...
+oStringA::operator LPSTR()
+{
+    return (LPSTR)m_strBuf;
+}
+
+
+// Assign
+oStringA oStringA::operator =  (const oStringA & string)
+{
+    // Lose old string...
+    freeBuf();
+
+    // Setup new string...
+    getBuf( string.m_strLen);
+    strcpy(m_strBuf, string.m_strBuf);
+    m_strLen = string.m_strLen;
+    return *this;
+}
+
+oStringA oStringA::operator =  (LPCSTR pAscii)
+{
+    long	strLen = strlen(pAscii) + 1;
+
+    // Lose old string...
+    freeBuf();
+
+    // Setup new string...
+    getBuf( strLen);
+    strcpy(m_strBuf, pAscii);
+    m_strLen = strLen;
+    return *this;
+}
+
+oStringA oStringA::operator =  (LPCWSTR pUnicode)
+{
+    long	strLen = lstrlenW(pUnicode) + 1;
+
+    // Lose old string...
+    freeBuf();
+
+    // Setup new string...
+    getBuf( strLen);
+    UnicodeToAscii((LPWSTR)pUnicode, m_strBuf);
+    m_strLen = strLen;
+    return *this;
+}
+
+oStringA oStringA::operator =  (REFCLSID rClsId)
+{
+    // Lose old string...
+    freeBuf();
+
+    // Setup new string...
+    getBuf( 50);
+    WINE_StringFromCLSID(rClsId, m_strBuf);
+    m_strLen  = strlen(m_strBuf);
+
+    return *this;
+}
+
+// Add String to String
+oStringA oStringA::operator +  (const oStringA & string)
+{
+    // two terminators to account for...
+    oStringA	product(m_strLen + string.m_strLen - 1, 1);
+
+    memcpy(product.m_strBuf, m_strBuf, m_strLen);
+    strcpy(product.m_strBuf + m_strLen - 1, string.m_strBuf);
+    product.m_strLen = m_strLen + string.m_strLen - 1;
+
+    return product;
+}
+
+// Add String to ASCII string
+oStringA oStringA::operator +  (LPCSTR pAscii)
+{
+    long	strLen = m_strLen + strlen(pAscii);
+
+    oStringA	product(strLen, 1);
+
+    memcpy(product.m_strBuf, m_strBuf, m_strLen);
+    strcpy(product.m_strBuf + m_strLen - 1, pAscii);
+    product.m_strLen = strLen;
+
+    return product;
+}
+
+// Add String to UNICODE string
+oStringA oStringA::operator +  (LPCWSTR pUnicode)
+{
+    long	strLen = m_strLen + lstrlenW(pUnicode);
+
+    oStringA	product(strLen, 1);
+
+    memcpy(product.m_strBuf, m_strBuf, m_strLen);
+    UnicodeToAscii((LPWSTR)pUnicode, product.m_strBuf + m_strLen - 1);
+    product.m_strLen = strLen;
+
+    return product;
+}
+
+// Concatenate string object
+oStringA oStringA::operator += (const oStringA & string)
+{
+    // two terminators to account for...
+    long	strLen = m_strLen + string.m_strLen - 1;
+
+    adjBuf( strLen);
+    strcpy(m_strBuf + m_strLen - 1, string.m_strBuf);
+    m_strLen = strLen;
+
+    return *this;
+}
+
+// Concatenate Ascii string
+oStringA oStringA::operator +=  (LPCSTR pAscii)
+{
+    long	strLen = m_strLen + strlen(pAscii);
+
+    adjBuf( strLen);
+    strcpy(m_strBuf + m_strLen - 1, pAscii);
+    m_strLen = strLen;
+
+    return *this;
+}
+
+// Concatenate Unicode string
+oStringA oStringA::operator +=  (LPCWSTR pUnicode)
+{
+    long	strLen = m_strLen + lstrlenW(pUnicode);
+
+    adjBuf( strLen);
+    UnicodeToAscii((LPWSTR)pUnicode, m_strBuf + m_strLen - 1);
+    m_strLen = strLen;
+
+    return *this;
+}
+
+// ======================================================================
+// oStringW - String manipulation based on Unicode
+// ======================================================================
+
+// Initialise to nothing...
+oStringW::oStringW( void) : oStringBase(sizeof(WCHAR))
+{
+    getBuf( 1);	// Incl. terminator...
+}
+
+// Initialise to a specified length...
+oStringW::oStringW(int defLen, int fill) : oStringBase(sizeof(WCHAR))
+{
+    getBuf( defLen + 1);
+}
+
+// Initialise from Unicode string...
+oStringW::oStringW(LPCWSTR pUnicode) : oStringBase(sizeof(WCHAR))
+{
+    long	strLen = lstrlenW((const WCHAR *)pUnicode) + 1;
+
+    getBuf(strLen);
+    lstrcpyW((LPWSTR)m_strBuf, pUnicode);
+    m_strLen = strLen;
+}
+
+// Initialise from Unicode string...
+oStringW::oStringW(const wchar_t * pUnicode) : oStringBase(sizeof(WCHAR))
+{
+    long	strLen = lstrlenW((LPWSTR)pUnicode) + 1;
+
+    getBuf(strLen);
+    lstrcpyW((LPWSTR)m_strBuf, (LPCWSTR)pUnicode);
+    m_strLen = strLen;
+}
+
+// Initialise from ASCII string...
+oStringW::oStringW(LPCSTR pAscii) : oStringBase(sizeof(WCHAR))
+{
+    long	strLen = strlen(pAscii) + 1;
+
+    getBuf( strLen);
+    AsciiToUnicode((char *)pAscii, (LPWSTR)m_strBuf);
+    m_strLen = strLen;
+}
+
+// Initialise from another oString
+oStringW::oStringW(const oStringW &ref) : oStringBase(sizeof(WCHAR))
+{
+    getBuf( ref.m_strLen);
+    lstrcpyW((LPWSTR)m_strBuf, (LPWSTR)ref.m_strBuf);
+    m_strLen = ref.m_strLen;
+}
+
+// Initialise from CLSID
+oStringW::oStringW( REFCLSID pClsId) : oStringBase(sizeof(WCHAR))
+{
+    getBuf( 50);	// Incl. terminator...
+
+    // Assign string...
+    operator=(pClsId);
+}
+
+// Return pointer to string...
+oStringW::operator LPWSTR()
+{
+    return (LPWSTR)m_strBuf;
+}
+
+// Assign
+oStringW oStringW::operator =  (const oStringW & string)
+{
+    // Lose old string...
+    freeBuf();
+
+    // Setup new string...
+    getBuf( string.m_strLen);
+    lstrcpyW((LPWSTR)m_strBuf, (LPWSTR)string.m_strBuf);
+    m_strLen = string.m_strLen;
+    return *this;
+}
+
+oStringW oStringW::operator =  (LPCSTR pAscii)
+{
+    long	strLen = strlen(pAscii) + 1;
+
+    // Lose old string...
+    freeBuf();
+
+    // Setup new string...
+    getBuf( strLen);
+    AsciiToUnicode((char *)pAscii, (LPWSTR)m_strBuf);
+    m_strLen = strLen;
+    return *this;
+}
+
+oStringW oStringW::operator =  (LPCWSTR pUnicode)
+{
+    long	strLen = lstrlenW(pUnicode) + 1;
+
+    // Lose old string...
+    freeBuf();
+
+    // Setup new string...
+    getBuf( strLen);
+    lstrcpyW((LPWSTR)m_strBuf, pUnicode);
+    m_strLen = strLen;
+    return *this;
+}
+
+oStringW oStringW::operator =  (const wchar_t * pUnicode)
+{
+    long	strLen = lstrlenW((LPWSTR)pUnicode) + 1;
+
+    // Lose old string...
+    freeBuf();
+
+    // Setup new string...
+    getBuf( strLen);
+    lstrcpyW((LPWSTR)m_strBuf, (LPWSTR)pUnicode);
+    m_strLen = strLen;
+    return *this;
+}
+
+oStringW oStringW::operator =  (REFCLSID rClsId)
+{
+    char	tmp[50];
+
+    // Lose old string...
+    freeBuf();
+
+    // Setup new string...
+    getBuf( 50);
+    WINE_StringFromCLSID(rClsId, tmp);
+    m_strLen  = strlen(tmp);
+    AsciiToUnicode(tmp, (LPWSTR)m_strBuf);
+    return *this;
+}
+
+// Add String to String
+oStringW oStringW::operator +  (const oStringW & string)
+{
+    // two terminators to account for...
+    oStringW	product(m_strLen + string.m_strLen - 1, 1);
+
+    lstrcpyW((LPWSTR)product.m_strBuf, (LPWSTR)m_strBuf);
+    lstrcpyW((LPWSTR)product.m_strBuf + m_strLen - 1, (LPWSTR)string.m_strBuf);
+    product.m_strLen = m_strLen + string.m_strLen - 1;
+
+    return product;
+}
+
+// Add String to ASCII string
+oStringW oStringW::operator +  (LPCSTR pAscii)
+{
+    long	strLen = m_strLen + strlen(pAscii);
+
+    oStringW	product(strLen, 1);
+
+    lstrcpyW((LPWSTR)product.m_strBuf, (LPWSTR)m_strBuf);
+    AsciiToUnicode((char *)pAscii, (LPWSTR)product.m_strBuf + m_strLen - 1);
+    product.m_strLen = strLen;
+
+    return product;
+}
+
+// Add String to UNICODE string
+oStringW oStringW::operator +  (LPCWSTR pUnicode)
+{
+    long	strLen = m_strLen + lstrlenW(pUnicode);
+
+    oStringW	product(strLen, 1);
+
+    lstrcpyW((LPWSTR)product.m_strBuf, (LPWSTR)m_strBuf);
+    lstrcpyW((LPWSTR)product.m_strBuf + m_strLen - 1, (LPWSTR)pUnicode);
+    product.m_strLen = strLen;
+
+    return product;
+}
+
+// Add String to UNICODE string
+oStringW oStringW::operator +  (const wchar_t * pUnicode)
+{
+    long	strLen = m_strLen + lstrlenW((LPWSTR)pUnicode);
+
+    oStringW	product(strLen, 1);
+
+    lstrcpyW((LPWSTR)product.m_strBuf, (LPWSTR)m_strBuf);
+    lstrcpyW((LPWSTR)product.m_strBuf + m_strLen - 1, (LPWSTR)pUnicode);
+    product.m_strLen = strLen;
+
+    return product;
+}
+
+// Concatenate string object
+oStringW oStringW::operator += (const oStringW & string)
+{
+    // two terminators to account for...
+    long	strLen = m_strLen + string.m_strLen - 1;
+
+    adjBuf( strLen);
+    lstrcpyW((LPWSTR)m_strBuf + m_strLen - 1, (LPWSTR)string.m_strBuf);
+    m_strLen = strLen;
+
+    return *this;
+}
+
+// Concatenate Ascii string
+oStringW oStringW::operator +=  (LPCSTR pAscii)
+{
+    long	strLen = m_strLen + strlen(pAscii);
+
+    adjBuf( strLen);
+    AsciiToUnicode((char *)pAscii, (LPWSTR)m_strBuf + m_strLen - 1);
+    m_strLen = strLen;
+
+    return *this;
+}
+
+// Concatenate Unicode string
+oStringW oStringW::operator +=  (LPCWSTR pUnicode)
+{
+    long	strLen = m_strLen + lstrlenW(pUnicode);
+
+    adjBuf( strLen);
+    lstrcpyW((LPWSTR)m_strBuf + m_strLen - 1, (LPWSTR)pUnicode);
+    m_strLen = strLen;
+
+    return *this;
+}
+
+// Concatenate Unicode string
+oStringW oStringW::operator +=  (const wchar_t * pUnicode)
+{
+    long	strLen = m_strLen + lstrlenW((LPWSTR)pUnicode);
+
+    adjBuf( strLen);
+    lstrcpyW((LPWSTR)m_strBuf + m_strLen - 1, (LPWSTR)pUnicode);
+    m_strLen = strLen;
+
+    return *this;
+}
+
+
Index: trunk/src/ole32/new/oString.h
===================================================================
--- trunk/src/ole32/new/oString.h	(revision 3456)
+++ trunk/src/ole32/new/oString.h	(revision 3456)
@@ -0,0 +1,99 @@
+/* $Id: oString.h,v 1.1 2000-04-27 22:21:36 davidr Exp $ */
+
+#if !defined(OSTRING_INCLUDED)
+#define OSTRING_INCLUDED
+
+class oStringBase
+{
+protected:
+    char *	m_strBuf;	// Buffer.
+
+    long	m_bufLen;	// Current allocated length
+    				// of buffer (bytes)
+    				
+    long	m_bytePerChar;	// Number of bytes per character.
+    long	m_strLen;	// Length of string 
+    				// incl. zero terminator
+
+    HANDLE	m_Heap;		// heap handle.
+
+    static long blockSize;
+
+    oStringBase(long bytePerChar);
+    virtual ~oStringBase();
+
+    void freeBuf();
+    void getBuf(long newLen);
+    void adjBuf(long newLen);
+    long calcBufLen(long newLen);
+};
+
+class oStringA : public oStringBase
+{
+public:
+    oStringA(void);
+    oStringA(int defLen, int fill);
+    oStringA(LPCWSTR pUnicode);
+    oStringA(LPCSTR pAscii);
+    oStringA(REFCLSID pclsId);
+    oStringA(const oStringA &ref);
+    oStringA(const ULONG val);
+    oStringA(const LONG val);
+    oStringA(const USHORT val);
+    oStringA(const SHORT val);
+
+    operator LPSTR();
+
+    // Assignment
+    oStringA operator =  (const oStringA & string);
+    oStringA operator =  (LPCSTR pAscii);
+    oStringA operator =  (LPCWSTR pUnicode);
+    oStringA operator =  (REFCLSID pClsId);
+
+    // Concatenation
+    oStringA operator +  (const oStringA & string);
+    oStringA operator +  (LPCSTR pAscii);
+    oStringA operator +  (LPCWSTR pUnicode);
+
+    // Concatenation & Assignment.
+    oStringA operator += (const oStringA & string);
+    oStringA operator += (LPCSTR pAscii);
+    oStringA operator += (LPCWSTR pUnicode);
+
+};
+
+class oStringW : public oStringBase
+{
+public:
+    oStringW(void);
+    oStringW(int defLen, int fill);
+    oStringW(LPCWSTR pUnicode);
+    oStringW(const wchar_t * pUnicode);
+    oStringW(LPCSTR pAscii);
+    oStringW(REFCLSID pclsId);
+    oStringW(const oStringW &ref);
+
+    operator LPWSTR();
+
+    // Assignment
+    oStringW operator =  (const oStringW & string);
+    oStringW operator =  (LPCSTR pAscii);
+    oStringW operator =  (LPCWSTR pUnicode);
+    oStringW operator =  (const wchar_t * pUnicode);
+    oStringW operator =  (REFCLSID pClsId);
+
+    // Concatenation
+    oStringW operator +  (const oStringW & string);
+    oStringW operator +  (LPCSTR pAscii);
+    oStringW operator +  (LPCWSTR pUnicode);
+    oStringW operator +  (const wchar_t * pUnicode);
+
+    // Concatenation & Assignment.
+    oStringW operator += (const oStringW & string);
+    oStringW operator += (LPCSTR pAscii);
+    oStringW operator += (LPCWSTR pUnicode);
+    oStringW operator += (const wchar_t * pUnicode);
+
+};
+
+#endif // OSTRING_INCLUDED
Index: trunk/src/ole32/new/oTls.h
===================================================================
--- trunk/src/ole32/new/oTls.h	(revision 3456)
+++ trunk/src/ole32/new/oTls.h	(revision 3456)
@@ -0,0 +1,45 @@
+/* $Id: oTls.h,v 1.1 2000-04-27 22:21:36 davidr Exp $ */
+/*
+ * Wrapper for the WIN32 TLS functions...
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+
+#ifndef OTLS_INCLUDED
+#define OTLS_INCLUDED 1
+
+template <class VARPTR>
+class oTlsValue
+{
+private:
+    DWORD	m_Index;
+
+protected:
+
+public:
+    oTlsValue(VARPTR const defVal = 0) : m_Index(TlsAlloc())
+	{ dprintf(("OTLS: TlsAlloc %d", m_Index)); SetValue(defVal); }
+
+    virtual ~oTlsValue()
+	{ dprintf(("OTLS: TlsFree %d", m_Index)); TlsFree(m_Index); }
+
+    VARPTR const GetValue(void ) const
+	{ return (VARPTR const)TlsGetValue(m_Index); }
+
+    void SetValue(VARPTR const newVal )
+	{ TlsSetValue(m_Index, (LPVOID)newVal); }
+
+    operator VARPTR const () const
+	{ return GetValue(); }
+
+    VARPTR const operator -> () const
+	{ return GetValue(); }
+
+    oTlsValue<VARPTR> operator = (VARPTR const newVal)
+	{ SetValue(newVal); return *this; };
+
+};
+
+
+#endif /* OTLS_INCLUDED */
Index: trunk/src/ole32/new/objectcontext.cpp
===================================================================
--- trunk/src/ole32/new/objectcontext.cpp	(revision 3456)
+++ trunk/src/ole32/new/objectcontext.cpp	(revision 3456)
@@ -0,0 +1,42 @@
+/* $Id: objectcontext.cpp,v 1.1 2000-04-27 22:18:26 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * COM ObjectContext handling
+ * 
+ * 22/04/2000
+ * 
+ * Copyright 2000 David J. Raison
+ * 
+ */
+
+#include "ole32.h"
+#include "oString.h"
+#include "oTls.h"
+#include "apartment.h"
+#include "rpcdce.h"
+
+// ======================================================================
+// ObjectContext
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// ObjectContext::ObjectContext
+// ----------------------------------------------------------------------
+ObjectContext::ObjectContext()
+{
+    UuidCreate(&m_Guid);
+}
+
+// ----------------------------------------------------------------------
+// ObjectContext::IsCompatible
+// ----------------------------------------------------------------------
+BOOL		ObjectContext::IsCompatible(Attributes * const pTarget) const
+{
+    // Assume the object context is compatible, until we get into COM+ MTS objects.
+    return TRUE;
+}
+
Index: trunk/src/ole32/new/ole2.cpp
===================================================================
--- trunk/src/ole32/new/ole2.cpp	(revision 3456)
+++ trunk/src/ole32/new/ole2.cpp	(revision 3456)
@@ -0,0 +1,519 @@
+/* $Id: ole2.cpp,v 1.1 2000-04-27 22:18:26 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * OLE functions.
+ * 
+ * 2/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ *
+ * Some portions from Wine Implementation (2/9/99)
+ *   Copyright 1995  Martin von Loewis
+ *   Copyright 1999  Francis Beaudet
+ *   Copyright 1999  Noel Borthwick 
+ */
+
+#include "ole32.h"
+#include "commctrl.h"
+#include "oString.h"
+#include <assert.h>
+
+// ====================================================================== 
+// Local Data
+// ====================================================================== 
+
+/*
+ * This is the lock count on the OLE library. It is controlled by the
+ * OLEInitialize/OLEUninitialize methods.
+ */
+static ULONG OLE_moduleLockCount = 0;
+
+
+// ====================================================================== 
+// Prototypes.
+// ====================================================================== 
+static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
+
+// These are the prototypes of the utility methods used to manage a shared menu
+extern	void	OLEMenu_Initialize();
+extern	void	OLEMenu_UnInitialize();
+
+// These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c)
+extern	void	OLEClipbrd_UnInitialize();
+extern	void	OLEClipbrd_Initialize();
+
+// These are the prototypes of the utility methods used for OLE Drag n Drop
+extern	void	OLEDD_Initialize();
+extern	void	OLEDD_UnInitialize();
+
+// ====================================================================== 
+// Public API's
+// ====================================================================== 
+
+// ----------------------------------------------------------------------
+// OleBuildVersion()
+// ----------------------------------------------------------------------
+DWORD WIN32API OleBuildVersion(void)
+{
+    dprintf(("OLE32.OleBuildVersion"));
+    return (rmm<<16)+rup;
+}
+
+// ----------------------------------------------------------------------
+// OleInitialize()
+// ----------------------------------------------------------------------
+HRESULT WIN32API OleInitialize(LPVOID reserved)
+{
+    HRESULT hr;
+
+    dprintf(("OLE32: OleInitialize"));
+
+    // The first duty of the OleInitialize is to initialize the COM libraries.
+    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+    if (FAILED(hr))
+	return hr;    
+
+    // Then, it has to initialize the OLE specific modules.
+    // This includes:
+    //     Clipboard
+    //     Drag and Drop
+    //     Object linking and Embedding
+    //     In-place activation
+    if (++OLE_moduleLockCount == 1)
+    {
+	dprintf(("    First time through - Initializing"));
+
+	// OLE Clipboard
+	OLEClipbrd_Initialize();
+
+	// Drag and Drop
+	OLEDD_Initialize();
+
+	// OLE shared menu
+	OLEMenu_Initialize();
+    }
+
+    return hr;
+}
+
+// ----------------------------------------------------------------------
+// CoGetCurrentProcess()
+// ----------------------------------------------------------------------
+DWORD WIN32API CoGetCurrentProcess()
+{
+    dprintf(("OLE32: CoGetCurrentProcess"));
+    return GetCurrentProcessId();
+}
+
+// ----------------------------------------------------------------------
+// OleUninitialize()
+// ----------------------------------------------------------------------
+void WIN32API OleUninitialize(void)
+{
+    dprintf(("OLE32: OleUninitialize"));
+
+    // If we hit the bottom of the lock stack, free the libraries.
+    if (--OLE_moduleLockCount == 0)
+    {
+	dprintf(("    no more references - Terminating"));
+
+	// OLE Clipboard
+	OLEClipbrd_UnInitialize();
+
+	// Drag and Drop
+	OLEDD_UnInitialize();
+
+	// OLE shared menu
+	OLEMenu_UnInitialize();
+    }
+
+    // Then, uninitialize the COM libraries.
+    CoUninitialize();
+}
+
+// ----------------------------------------------------------------------
+// OleRegGetUserType()
+// ----------------------------------------------------------------------
+// This implementation of OleRegGetUserType ignores the dwFormOfType
+// parameter and always returns the full name of the object. This is
+// not too bad since this is the case for many objects because of the
+// way they are registered.
+// ----------------------------------------------------------------------
+HRESULT WIN32API OleRegGetUserType
+   (REFCLSID		clsid, 
+    DWORD		dwFormOfType,
+    LPOLESTR *		pszUserType)
+
+{
+    oStringA		tCLSID;
+    DWORD		dwKeyType;
+    DWORD		cbData;
+    HKEY 		clsidKey;
+    LONG 		hres;
+
+    dprintf(("OLE32: OleRegGetUserType"));
+
+    *pszUserType = NULL;
+
+    // Build the key name we're looking for
+    tCLSID = "CLSID\\";
+    tCLSID += clsid;
+    tCLSID += "\\";
+
+    // Open the class id Key
+    hres = RegOpenKeyA(HKEY_CLASSES_ROOT, tCLSID, &clsidKey);
+    if (hres != ERROR_SUCCESS)
+	return REGDB_E_CLASSNOTREG;
+
+    // Retrieve the size of the name string.
+    cbData = 0;
+    hres = RegQueryValueExA(clsidKey, "", NULL, &dwKeyType, NULL, &cbData);
+    if (hres != ERROR_SUCCESS)
+    {
+	RegCloseKey(clsidKey);
+	return REGDB_E_READREGDB;
+    }
+
+    // Allocate a buffer for the registry value.
+    *pszUserType = (LPOLESTR)CoTaskMemAlloc(cbData);
+
+    if (*pszUserType == NULL)
+    {
+	RegCloseKey(clsidKey);
+	return E_OUTOFMEMORY;
+    }
+
+    hres = RegQueryValueExA(HKEY_CLASSES_ROOT, "", NULL, &dwKeyType, (LPBYTE)*pszUserType, &cbData);
+    RegCloseKey(clsidKey);
+    if (hres != ERROR_SUCCESS)
+    {
+	CoTaskMemFree(*pszUserType);
+	*pszUserType = NULL;
+	return REGDB_E_READREGDB;
+    }
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// OleRegGetMiscStatus()
+// ----------------------------------------------------------------------
+HRESULT WIN32API OleRegGetMiscStatus
+   (REFCLSID		clsid,
+    DWORD		dwAspect,
+    DWORD *		pdwStatus)
+{
+    oStringA		tStr;
+    HKEY    		clsidKey;
+    HKEY    		miscStatusKey;
+    HKEY    		aspectKey;
+    LONG    		result;
+
+    dprintf(("OLE32: OleRegGetMiscStatus"));
+
+    // Initialize the out parameter.
+    *pdwStatus = 0;
+
+    // Build the key name we're looking for
+    tStr = "CLSID\\";
+    tStr += clsid;
+    tStr += "\\";
+    dprintf(("       Key   : %s", (char *)tStr));
+
+    // Open the class id Key
+    result = RegOpenKeyA(HKEY_CLASSES_ROOT, tStr, &clsidKey);
+
+    if (result != ERROR_SUCCESS)
+	return REGDB_E_CLASSNOTREG;
+
+    // Get the MiscStatus
+    result = RegOpenKeyA(clsidKey, "MiscStatus", &miscStatusKey);
+
+    if (result != ERROR_SUCCESS)
+    {
+	RegCloseKey(clsidKey);
+	return REGDB_E_READREGDB;
+    }
+
+    // Read the default value
+    OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus);
+
+    // Open the key specific to the requested aspect.
+    oStringA		tKey(dwAspect);
+    dprintf(("       Aspect: %s", (char *)tKey));
+
+    result = RegOpenKeyA(miscStatusKey, tKey, &aspectKey);
+
+    if (result == ERROR_SUCCESS)
+    {
+	OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus);
+	RegCloseKey(aspectKey);
+    }
+
+    // Cleanup
+    RegCloseKey(miscStatusKey);
+    RegCloseKey(clsidKey);
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// OleSetContainedObject()
+// ----------------------------------------------------------------------
+HRESULT WIN32API OleSetContainedObject
+   (LPUNKNOWN		pUnknown, 
+    BOOL      		fContained)
+{
+    IRunnableObject *	runnable = NULL;
+    HRESULT          	hres;
+
+    dprintf(("OLE32: OleSetContainedObject"));
+
+    hres = IUnknown_QueryInterface(pUnknown, &IID_IRunnableObject, (void**)&runnable);
+
+    if (SUCCEEDED(hres))
+    {
+	hres = IRunnableObject_SetContainedObject(runnable, fContained);
+
+	IRunnableObject_Release(runnable);
+
+	return hres;
+    }
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// OleLoad()
+// ----------------------------------------------------------------------
+HRESULT WIN32API OleLoad
+   (LPSTORAGE		pStg, 
+    REFIID          	riid, 
+    LPOLECLIENTSITE 	pClientSite, 
+    LPVOID *         	ppvObj)
+{
+    IPersistStorage *	persistStorage = NULL;
+    IOleObject *      	oleObject      = NULL;
+    STATSTG          	storageInfo;
+    HRESULT          	hres;
+
+    dprintf(("OLE32: OleLoad"));
+
+    // TODO, Conversion ... OleDoAutoConvert
+
+    // Get the class ID for the object.
+    hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME);
+
+    // Now, try and create the handler for the object
+    hres = CoCreateInstance(&storageInfo.clsid,
+    			    NULL,
+    			    CLSCTX_INPROC_HANDLER,
+    			    &IID_IOleObject,
+    			    (void**)&oleObject);
+
+    // If that fails, as it will most times, load the default OLE handler.
+    if (FAILED(hres))
+    {
+	hres = OleCreateDefaultHandler(&storageInfo.clsid,
+				       NULL,
+				       &IID_IOleObject,
+				       (void**)&oleObject);
+    }
+
+    // If we couldn't find a handler... this is bad. Abort the whole thing.
+    if (FAILED(hres))
+	return hres;
+
+    // Inform the new object of it's client site.
+    hres = IOleObject_SetClientSite(oleObject, pClientSite);
+
+    // Initialize the object with it's IPersistStorage interface.
+    hres = IOleObject_QueryInterface(oleObject, &IID_IPersistStorage, (void**)&persistStorage);
+
+    if (SUCCEEDED(hres)) 
+    {
+	IPersistStorage_Load(persistStorage, pStg);
+
+	IPersistStorage_Release(persistStorage);
+	persistStorage = NULL;
+    }
+
+    // Return the requested interface to the caller.
+    hres = IOleObject_QueryInterface(oleObject, riid, ppvObj);
+
+    // Cleanup interfaces used internally
+    IOleObject_Release(oleObject);
+
+    return hres;
+}
+
+// ----------------------------------------------------------------------
+// OleSave()
+// ----------------------------------------------------------------------
+HRESULT WIN32API OleSave
+   (LPPERSISTSTORAGE		pPS,
+    LPSTORAGE        		pStg,
+    BOOL             		fSameAsLoad)
+{
+    HRESULT			hres;
+    CLSID			objectClass;
+
+    dprintf(("OLE32: OleSave"));
+
+    // First, we transfer the class ID (if available)
+    hres = IPersistStorage_GetClassID(pPS, &objectClass);
+
+    if (SUCCEEDED(hres))
+	WriteClassStg(pStg, &objectClass);
+
+    // Then, we ask the object to save itself to the
+    // storage. If it is successful, we commit the storage.
+    hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad);
+
+    if (SUCCEEDED(hres))
+	IStorage_Commit(pStg, STGC_DEFAULT);
+
+    return hres;
+}
+
+// ----------------------------------------------------------------------
+// ReleaseStgMedium()
+// ----------------------------------------------------------------------
+void WIN32API ReleaseStgMedium(STGMEDIUM * pmedium)
+{
+    switch (pmedium->tymed)
+    {
+	case TYMED_HGLOBAL:
+	{
+	    if ( (pmedium->pUnkForRelease == 0) && (pmedium->u.hGlobal  != 0) )
+		GlobalFree(pmedium->u.hGlobal);
+
+	    pmedium->u.hGlobal = 0;
+	    break;
+	}
+	case TYMED_FILE:
+	{
+	    if (pmedium->u.lpszFileName != 0)
+	    {
+		if (pmedium->pUnkForRelease == 0)
+		    DeleteFileW(pmedium->u.lpszFileName);
+
+		CoTaskMemFree(pmedium->u.lpszFileName);
+	    }
+
+	    pmedium->u.lpszFileName = 0;
+	    break;
+	}
+	case TYMED_ISTREAM:
+	{
+	    if (pmedium->u.pstm != 0)
+		IStream_Release(pmedium->u.pstm);
+
+	    pmedium->u.pstm = 0;
+	    break;
+	}
+	case TYMED_ISTORAGE:
+	{
+	    if (pmedium->u.pstg != 0)
+		IStorage_Release(pmedium->u.pstg);
+
+	    pmedium->u.pstg = 0;
+	    break;
+	}
+	case TYMED_GDI:
+	{
+	    if ( (pmedium->pUnkForRelease == 0) && (pmedium->u.hGlobal != 0) )
+		DeleteObject(pmedium->u.hGlobal);
+
+	    pmedium->u.hGlobal = 0;
+	    break;
+	}
+	case TYMED_MFPICT:
+	{
+	    if ( (pmedium->pUnkForRelease == 0) && (pmedium->u.hMetaFilePict != 0) )
+	    {
+		DeleteMetaFile(pmedium->u.hMetaFilePict);
+		GlobalFree(pmedium->u.hMetaFilePict);
+	    }
+
+	    pmedium->u.hMetaFilePict = 0;
+	    break;
+	}
+	case TYMED_ENHMF:
+	{
+	    if ( (pmedium->pUnkForRelease == 0) && (pmedium->u.hEnhMetaFile != 0) )
+		DeleteEnhMetaFile(pmedium->u.hEnhMetaFile);
+
+	    pmedium->u.hEnhMetaFile = 0;
+	    break;
+	}
+	case TYMED_NULL:
+	    // Do nothing
+	    break;
+
+	default:
+	    break;
+    }
+
+    // After cleaning up, the unknown is released
+    if (pmedium->pUnkForRelease != 0)
+    {
+	IUnknown_Release(pmedium->pUnkForRelease);
+	pmedium->pUnkForRelease = 0;
+    }
+}
+
+// ====================================================================== 
+// Private functions.
+// ====================================================================== 
+
+/***
+ * OLEUTL_ReadRegistryDWORDValue
+ *
+ * This method will read the default value of the registry key in
+ * parameter and extract a DWORD value from it. The registry key value
+ * can be in a string key or a DWORD key.
+ *
+ * params:
+ *     regKey   - Key to read the default value from
+ *     pdwValue - Pointer to the location where the DWORD 
+ *                value is returned. This value is not modified
+ *                if the value is not found.
+ */
+
+static void OLEUTL_ReadRegistryDWORDValue(
+  HKEY   regKey, 
+  DWORD* pdwValue)
+{
+  char  buffer[20];
+  DWORD dwKeyType;
+  DWORD cbData = 20;
+  LONG  lres;
+
+  lres = RegQueryValueExA(regKey,
+			  "",
+			  NULL,
+			  &dwKeyType,
+			  (LPBYTE)buffer,
+			  &cbData);
+
+  if (lres == ERROR_SUCCESS)
+  {
+    switch (dwKeyType)
+    {
+      case REG_DWORD:
+	*pdwValue = *(DWORD*)buffer;
+	break;
+      case REG_EXPAND_SZ:
+      case REG_MULTI_SZ:
+      case REG_SZ:
+	*pdwValue = (DWORD)strtoul(buffer, NULL, 10);
+	break;
+    }
+  }
+}
+
Index: trunk/src/ole32/new/ole2impl.cpp
===================================================================
--- trunk/src/ole32/new/ole2impl.cpp	(revision 3456)
+++ trunk/src/ole32/new/ole2impl.cpp	(revision 3456)
@@ -0,0 +1,182 @@
+/* $Id: ole2impl.cpp,v 1.1 2000-04-27 22:18:27 davidr Exp $ */
+/*
+ * Ole 2 Create functions implementation
+ *
+ * Copyright (C) 1999-2000 Abey George
+ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * Ported from Wine 20/03/00
+ * 
+ * Copyright 1999 David J. Raison
+ *
+ */
+
+#include "ole32.h"
+#include <winerror.h>
+#include <olestd.h>
+#include "oString.h"
+#include <assert.h>
+
+#define MAX_CLIPFORMAT_NAME   80
+
+/******************************************************************************
+ * Function : OleQueryCreateFromData [OLE32.117]
+ * Author   : Abey George
+ * Checks whether an object can become an embedded object.
+ * the clipboard or OLE drag and drop.
+ * Returns  : S_OK - Format that supports Embedded object creation are present.
+ *            OLE_E_STATIC - Format that supports static object creation are present.
+ *            S_FALSE - No acceptable format is available.
+ */
+
+HRESULT WINAPI OleQueryCreateFromData(LPDATAOBJECT pSrcDataObject)
+{
+  IEnumFORMATETC *pfmt;
+  FORMATETC fmt;
+  CHAR szFmtName[MAX_CLIPFORMAT_NAME];
+  BOOL bFoundStatic = FALSE;
+
+  HRESULT hr = IDataObject_EnumFormatEtc(pSrcDataObject, DATADIR_GET, &pfmt);
+
+  if (hr == S_OK)
+    hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL);
+
+  while (hr == S_OK)
+  {
+    GetClipboardFormatNameA(fmt.cfFormat, szFmtName, MAX_CLIPFORMAT_NAME-1);
+
+    /* first, Check for Embedded Object, Embed Source or Filename */
+
+    if (!strcmp(szFmtName, CF_EMBEDDEDOBJECT) || !strcmp(szFmtName, CF_EMBEDSOURCE) || !strcmp(szFmtName, CF_FILENAME))
+      return S_OK;
+
+    /* Check for Metafile, Bitmap or DIB */
+
+    if (fmt.cfFormat == CF_METAFILEPICT || fmt.cfFormat == CF_BITMAP || fmt.cfFormat == CF_DIB)
+      bFoundStatic = TRUE;
+
+    hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL);
+  }
+
+  /* Found a static format, but no embed format */
+
+  if (bFoundStatic)
+    return OLE_S_STATIC;
+
+  return S_FALSE;
+}
+
+/******************************************************************************
+ * Function : OleCreateFromData        [OLE32.92]
+ * Author   : Abey George
+ * Creates an embedded object from data transfer object retrieved from
+ * the clipboard or OLE drag and drop.
+ * Returns  : S_OK - Embedded object was created successfully.
+ *            OLE_E_STATIC - OLE can create only a static object
+ *            DV_E_FORMATETC - No acceptable format is available (only error return code)
+ * TODO : CF_FILENAME, CF_EMBEDEDOBJECT formats. Parameter renderopt is currently ignored.
+ */
+
+HRESULT WINAPI OleCreateFromData(LPDATAOBJECT pSrcDataObject, REFIID riid,
+                DWORD renderopt, LPFORMATETC pFormatEtc,
+                LPOLECLIENTSITE pClientSite, LPSTORAGE pStg,
+                LPVOID* ppvObj)
+{
+  IEnumFORMATETC *pfmt;
+  FORMATETC fmt;
+  CHAR szFmtName[MAX_CLIPFORMAT_NAME];
+  STGMEDIUM std;
+  HRESULT hr;
+  HRESULT hr1;
+
+  hr = IDataObject_EnumFormatEtc(pSrcDataObject, DATADIR_GET, &pfmt);
+
+  if (hr == S_OK)
+  {
+    memset(&std, 0, sizeof(STGMEDIUM));
+
+    hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL);
+    while (hr == S_OK)
+    {
+      GetClipboardFormatNameA(fmt.cfFormat, szFmtName, MAX_CLIPFORMAT_NAME-1);
+
+      /* first, Check for Embedded Object, Embed Source or Filename */
+      /* TODO: Currently checks only for Embed Source. */
+
+      if (!strcmp(szFmtName, CF_EMBEDSOURCE))
+      {
+        std.tymed = TYMED_HGLOBAL;
+
+        if ((hr1 = IDataObject_GetData(pSrcDataObject, &fmt, &std)) == S_OK)
+        {
+          ILockBytes *ptrILockBytes = 0;
+          IStorage *pStorage = 0;
+          IOleObject *pOleObject = 0;
+          IPersistStorage *pPersistStorage = 0;
+          CLSID clsID;
+
+          /* Create ILock bytes */
+
+          hr1 = CreateILockBytesOnHGlobal(std.u.hGlobal, FALSE, &ptrILockBytes);
+
+          /* Open storage on the ILock bytes */
+
+          if (hr1 == S_OK)
+            hr1 = StgOpenStorageOnILockBytes(ptrILockBytes, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &pStorage);
+
+          /* Get Class ID from the opened storage */
+
+          if (hr1 == S_OK)
+            hr1 = ReadClassStg(pStorage, &clsID);
+
+          /* Create default handler for Persist storage */
+
+          if (hr1 == S_OK)
+            hr1 = OleCreateDefaultHandler(&clsID, NULL, &IID_IPersistStorage, (LPVOID *)&pPersistStorage);
+
+          /* Load the storage to Persist storage */
+
+          if (hr1 == S_OK)
+            hr1 = IPersistStorage_Load(pPersistStorage, pStorage);
+
+          /* Query for IOleObject */
+
+          if (hr1 == S_OK)
+            hr1 = IPersistStorage_QueryInterface(pPersistStorage, &IID_IOleObject, (LPVOID *)&pOleObject);
+
+          /* Set client site with the IOleObject */
+
+          if (hr1 == S_OK)
+            hr1 = IOleObject_SetClientSite(pOleObject, pClientSite);
+
+          IPersistStorage_Release(pPersistStorage);
+          /* Query for the requested interface */
+
+          if (hr1 == S_OK)
+            hr1 = IPersistStorage_QueryInterface(pPersistStorage, riid, ppvObj);
+
+          IPersistStorage_Release(pPersistStorage);
+
+          IStorage_Release(pStorage);
+
+          if (hr1 == S_OK)
+            return S_OK;
+        }
+
+        /* Return error */
+
+        return DV_E_FORMATETC;
+      }
+
+      hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL);
+    }
+  }
+
+  return DV_E_FORMATETC;
+}
+
Index: trunk/src/ole32/new/ole32.cpp
===================================================================
--- trunk/src/ole32/new/ole32.cpp	(revision 3456)
+++ trunk/src/ole32/new/ole32.cpp	(revision 3456)
@@ -0,0 +1,860 @@
+/* $Id: ole32.cpp,v 1.1 2000-04-27 22:18:28 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * COM/OLE misc. functions.
+ * 
+ * 1/7/99
+ * 
+ * Copyright 2000 David J. Raison
+ * 
+ * Some portions from Wine Implementation
+ *   Copyright 1995  Martin von Loewis
+ *   Copyright 1998  Justin Bradford
+ *   Copyright 1999  Francis Beaudet
+ *   Copyright 1999  Sylvain St-Germain
+ *
+ * STA model derived from MSJ House Of Com Article 09/99
+ */
+
+#include "ole32.h"
+
+#include "oString.h"
+#include "oTls.h"
+#include "filemoniker.h"	// FileMonikerImpl_***
+
+// ======================================================================
+// Local Data
+// ======================================================================
+
+
+typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
+
+/*
+ * This linked list contains the list of registered class objects. These
+ * are mostly used to register the factories for out-of-proc servers of OLE
+ * objects.
+ */
+typedef struct tagRegisteredClass
+{
+  CLSID     classIdentifier;
+  LPUNKNOWN classObject;
+  DWORD     runContext;
+  DWORD     connectFlags;
+  DWORD     dwCookie;
+  struct tagRegisteredClass* nextClass;
+} RegisteredClass;
+
+static RegisteredClass* firstRegisteredClass = NULL;
+
+/*
+ * COM External Lock structures and methods declaration
+ *
+ * This api provides a linked list to managed external references to
+ * COM objects.
+ *
+ */
+
+#define EL_END_OF_LIST 0
+#define EL_NOT_FOUND   0
+
+/*
+ * Declaration of the static structure that manage the
+ * external lock to COM  objects.
+ */
+typedef struct COM_ExternalLock     COM_ExternalLock;
+typedef struct COM_ExternalLockList COM_ExternalLockList;
+
+struct COM_ExternalLock
+{
+    IUnknown         *pUnk;     /* IUnknown referenced */
+    ULONG            uRefCount; /* external lock counter to IUnknown object*/
+    COM_ExternalLock *next;     /* Pointer to next element in list */
+};
+
+struct COM_ExternalLockList
+{
+    COM_ExternalLock *head;     /* head of list */
+};
+
+/*
+ * Declaration and initialization of the static structure that manages
+ * the external lock to COM objects.
+ */
+static COM_ExternalLockList elList = { EL_END_OF_LIST };
+
+// ======================================================================
+// Prototypes.
+// ======================================================================
+static HRESULT COM_GetRegisteredClassObject(
+	REFCLSID    	rclsid,
+	DWORD       	dwClsContext,
+	LPUNKNOWN * 	ppUnk);
+
+extern void COM_RevokeAllClasses();
+
+extern void COM_ExternalLockFreeList();
+
+static void COM_ExternalLockAddRef(
+	IUnknown * pUnk);
+
+static void COM_ExternalLockRelease(
+	IUnknown *	pUnk,
+	BOOL		bRelAll);
+
+static BOOL COM_ExternalLockInsert(
+	IUnknown * pUnk);
+
+static void COM_ExternalLockDelete(
+	COM_ExternalLock * element);
+
+static COM_ExternalLock * COM_ExternalLockFind(
+	IUnknown *	pUnk);
+
+static COM_ExternalLock * COM_ExternalLockLocate(
+	COM_ExternalLock * element,
+	IUnknown *	pUnk);
+
+// ======================================================================
+// Public API's
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// CoBuildVersion()
+// ----------------------------------------------------------------------
+DWORD WIN32API CoBuildVersion()
+{
+    dprintf(("OLE32.CoBuildVersion"));
+    return (rmm << 16) + rup;
+}
+
+// ----------------------------------------------------------------------
+// CoDosDateTimeToFileTime
+// ----------------------------------------------------------------------
+BOOL WIN32API CoDosDateTimeToFileTime(WORD nDosDate, WORD nDosTime,
+                                         FILETIME *lpFileTime)
+{
+    dprintf(("OLE32: CoDosDateTimeToFileTime"));
+
+    return DosDateTimeToFileTime(nDosDate, nDosTime, lpFileTime);
+}
+
+// ----------------------------------------------------------------------
+// CoDosDateTimeToFileTime
+// ----------------------------------------------------------------------
+HRESULT WIN32API CoFileTimeNow(FILETIME *lpFileTime)
+{
+    SYSTEMTIME systime;
+
+    dprintf(("OLE32: CoFileTimeNow"));
+
+    GetSystemTime(&systime);
+    return SystemTimeToFileTime(&systime, lpFileTime);
+}
+
+// ----------------------------------------------------------------------
+// CoDosDateTimeToFileTime
+// ----------------------------------------------------------------------
+BOOL WIN32API CoFileTimeToDosDateTime(FILETIME *lpFileTime, LPWORD lpDosDate,
+                                         LPWORD lpDosTime)
+{
+    dprintf(("OLE32: CoFileTimeToDosDateTime"));
+
+    return FileTimeToDosDateTime(lpFileTime, lpDosDate, lpDosTime);
+}
+
+
+// ----------------------------------------------------------------------
+// CoCreateInstance
+// ----------------------------------------------------------------------
+HRESULT WIN32API CoCreateInstance
+   (REFCLSID		rclsid,
+    LPUNKNOWN		pUnkOuter,
+    DWORD		dwClsContext,
+    REFIID		iid,
+    LPVOID *		ppv) 
+{
+    HRESULT hres;
+    LPCLASSFACTORY lpclf = 0;
+
+    oStringA		tCLSID(rclsid);
+    oStringA		tIId(iid);
+
+    dprintf(("OLE32: CoCreateInstance"));
+    dprintf(("       CLSID:%s", (char *)tCLSID));
+    dprintf(("       IID  :%s", (char *)tIId));
+
+    // Sanity check
+    if (ppv == 0)
+	return E_POINTER;
+
+    *ppv = 0;
+
+    // Get a class factory to construct the object we want.
+    hres = CoGetClassObject(rclsid, dwClsContext, NULL, &IID_IClassFactory, (LPVOID *)&lpclf);
+
+    if (FAILED(hres))
+	return hres;
+
+    // Create the object and don't forget to release the factory
+    hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv);
+    IClassFactory_Release(lpclf);
+
+    return hres;
+}
+
+// ----------------------------------------------------------------------
+// CoCreateInstanceEx
+// ----------------------------------------------------------------------
+HRESULT WIN32API CoCreateInstanceEx
+   (REFCLSID      	rclsid, 
+    LPUNKNOWN     	pUnkOuter,
+    DWORD         	dwClsContext, 
+    COSERVERINFO * 	pServerInfo,
+    ULONG         	cmq,
+    MULTI_QI *     	pResults)
+{
+    IUnknown * 		pUnk = NULL;
+    HRESULT   		hr;
+    ULONG     		index;
+    int       		successCount = 0;
+
+    oStringA		tCLSID(rclsid);
+
+    dprintf(("OLE32: CoCreateInstanceEx"));
+    dprintf(("       CLSID:%s", (char *)tCLSID));
+
+    // Sanity check
+    if ( (cmq == 0) || (pResults == NULL))
+	return E_INVALIDARG;
+
+    if (pServerInfo != NULL)
+	dprintf(("OLE32: CoCreateInstanceEx - pServerInfo not supported!"));
+
+    // Initialize all the "out" parameters.
+    for (index = 0; index < cmq; index++)
+    {
+	pResults[index].pItf = NULL;
+	pResults[index].hr   = E_NOINTERFACE;
+    }
+
+    /*
+    * Get the object and get it's IUnknown pointer.
+    */
+    hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, &IID_IUnknown, (VOID**)&pUnk);
+
+    if (hr)
+	return hr;
+
+    /*
+    * Then, query for all the interfaces requested.
+    */
+    for (index = 0; index < cmq; index++)
+    {
+	pResults[index].hr = IUnknown_QueryInterface(pUnk, pResults[index].pIID, (VOID**)&(pResults[index].pItf));
+
+	if (pResults[index].hr == S_OK)
+	    successCount++;
+    }
+
+    /*
+    * Release our temporary unknown pointer.
+    */
+    IUnknown_Release(pUnk);
+
+    if (successCount == 0)
+	return E_NOINTERFACE;
+
+    if (successCount != cmq)
+	return CO_S_NOTALLINTERFACES;
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// CoGetClassObject
+// ----------------------------------------------------------------------
+HRESULT WIN32API CoGetClassObject
+   (REFCLSID		rclsid,
+    DWORD		dwClsContext,
+    LPVOID		pvReserved,
+    REFIID		iid,
+    LPVOID *		ppv)
+{
+    LPUNKNOWN		regClassObject;
+    HRESULT		hres = E_UNEXPECTED;
+
+    char		dllName[MAX_PATH+1];
+    LONG		dllNameLen = sizeof(dllName);
+    HINSTANCE		hLibrary;
+
+    DllGetClassObjectFunc DllGetClassObject;
+    oStringA		tCLSID(rclsid);
+
+#ifdef DEBUG
+    oStringA		tIId(iid);
+    dprintf(("OLE32: CoGetClassObject"));
+    dprintf(("       CLSID:%s", (char *)tCLSID));
+    dprintf(("       IID  :%s", (char *)tIId));
+#endif
+
+    // First, try and see if we can't match the class ID with one of the 
+    // registered classes.
+    if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, &regClassObject))
+    {
+	// Get the required interface from the retrieved pointer.
+	hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
+
+	// Since QI got another reference on the pointer, we want to release the
+	// one we already have. If QI was unsuccessful, this will release the object. This
+	// is good since we are not returning it in the "out" parameter.
+	IUnknown_Release(regClassObject);
+
+	return hres;
+    }
+
+    // out of process and remote servers not supported yet...
+    if (dwClsContext & CLSCTX_LOCAL_SERVER)
+    {
+	dprintf(("OLE32: CoGetClassObject - CLSCTX_LOCAL_SERVER not supported!\n"));
+//	return E_ACCESSDENIED;
+	dwClsContext |= CLSCTX_INPROC_SERVER;	// Kludge as VB uses CLSCTX_LOCAL_SERVER
+    }
+
+    if (dwClsContext & CLSCTX_REMOTE_SERVER)
+    {
+	dprintf(("OLE32: CoGetClassObject - CLSCTX_REMOTE_SERVER not supported!\n"));
+	return E_ACCESSDENIED;
+    }
+
+    // Get down to the biz..
+    if (dwClsContext & (CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER))
+    {
+        HKEY	CLSIDkey;
+        HKEY	key;
+
+        /* lookup CLSID in registry key HKCR/CLSID */
+        hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &CLSIDkey);
+	if (hres != ERROR_SUCCESS)
+	    return REGDB_E_READREGDB;
+
+        hres = RegOpenKeyExA(CLSIDkey, tCLSID, 0, KEY_QUERY_VALUE, &key);
+	if (hres != ERROR_SUCCESS) 
+	{
+	    RegCloseKey(CLSIDkey);
+	    return REGDB_E_CLASSNOTREG;
+	}
+
+	hres = RegQueryValueA(key, "InprocServer32", dllName, &dllNameLen);
+	RegCloseKey(key);
+	RegCloseKey(CLSIDkey);
+	if (hres != ERROR_SUCCESS)
+	{
+	    dprintf(("OLE32: CoGetClassObject - InprocServer32 not found in registry"));
+	    return REGDB_E_READREGDB;
+	}
+
+	dprintf(("OLE32: CoGetClassObject - Registry reports InprocServer32 dll as %s\n", dllName));
+
+	/* open dll, call DllGetClassFactory */
+	hLibrary = CoLoadLibrary(dllName, TRUE);
+	if (hLibrary == 0)
+	{
+	    dprintf(("OLE32: CoGetClassObject - couldn't load %s\n", dllName));
+	    return E_ACCESSDENIED; /* or should this be CO_E_DLLNOTFOUND? */
+	}
+
+	DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject");
+	if (!DllGetClassObject) 
+	{
+	    dprintf(("OLE32: CoGetClassObject - couldn't function DllGetClassObject in %s\n", dllName));
+	    /* not sure if this should be called here CoFreeLibrary(hLibrary);*/
+	    return E_ACCESSDENIED;
+	}
+
+	// Ask the DLL for it's class object. (there was a note here about class
+	// factories but this is good.
+	return DllGetClassObject(rclsid, iid, ppv);
+    }
+    return hres;
+}
+
+// ----------------------------------------------------------------------
+// CoLockObjectExternal
+// ----------------------------------------------------------------------
+HRESULT WIN32API CoLockObjectExternal(IUnknown *pUnk, BOOL fLock, BOOL fLastUnlockReleases)
+{
+    dprintf(("OLE32: CoLockObjectExternal"));
+
+    if (fLock) 
+    {
+	/* 
+	 * Increment the external lock coutner, COM_ExternalLockAddRef also
+	 * increment the object's internal lock counter.
+	 */
+	COM_ExternalLockAddRef( pUnk); 
+    }
+    else
+    {
+	/* 
+	 * Decrement the external lock coutner, COM_ExternalLockRelease also
+	 * decrement the object's internal lock counter.
+	 */
+	COM_ExternalLockRelease( pUnk, fLastUnlockReleases);
+    }
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// CoRegisterClassObject
+// ----------------------------------------------------------------------
+HRESULT WIN32API CoRegisterClassObject(
+    REFCLSID		rclsid,
+    LPUNKNOWN		pUnk,
+    DWORD		dwClsContext, 	// Context in which to run the executable 
+    DWORD		flags,        	// how connections are made 
+    LPDWORD		lpdwRegister) 
+{
+    RegisteredClass *	newClass;
+    LPUNKNOWN       	foundObject;
+    HRESULT         	hr;
+    oStringA		tClsid(rclsid);
+
+    dprintf(("OLE32: CoRegisterClassObject(%s)", (char *)tClsid));
+
+    // Perform a sanity check on the parameters
+    if ((lpdwRegister == 0) || (pUnk == 0))
+	return E_INVALIDARG;
+
+    // Initialize the cookie (out parameter)
+    *lpdwRegister = 0;
+
+    // First, check if the class is already registered.
+    // If it is, this should cause an error.
+    hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject);
+    if (hr == S_OK)
+    {
+	// The COM_GetRegisteredClassObject increased the reference count on the
+	// object so it has to be released.
+	IUnknown_Release(foundObject);
+
+	return CO_E_OBJISREG;
+    }
+
+    // If it is not registered, we must create a new entry for this class and
+    // append it to the registered class list.
+    // We use the address of the chain node as the cookie since we are sure it's
+    // unique.
+    newClass = (RegisteredClass *)HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass));
+
+    // Initialize the node.
+    newClass->classIdentifier = *rclsid;
+    newClass->runContext      = dwClsContext;
+    newClass->connectFlags    = flags;
+    newClass->dwCookie        = (DWORD)newClass;
+    newClass->nextClass       = firstRegisteredClass;
+
+    // Since we're making a copy of the object pointer, we have to increase it's
+    // reference count.
+    newClass->classObject     = pUnk;
+    IUnknown_AddRef(newClass->classObject);
+
+    firstRegisteredClass = newClass;
+
+    // Assign the out parameter (cookie)
+    *lpdwRegister = newClass->dwCookie;
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// CoRevokeClassObject
+//
+// This method will remove a class object from the class registry
+// ----------------------------------------------------------------------
+HRESULT WIN32API CoRevokeClassObject(DWORD dwRegister) 
+{
+    RegisteredClass * *	prevClassLink;
+    RegisteredClass *	curClass;
+
+    dprintf(("OLE32: CoRevokeClassObject"));
+
+    // Iterate through the whole list and try to match the cookie.
+    curClass      = firstRegisteredClass;
+    prevClassLink = &firstRegisteredClass;
+
+    while (curClass != 0)
+    {
+	// Check if we have a match on the cookie.
+	if (curClass->dwCookie == dwRegister)
+	{
+	    // Remove the class from the chain.
+	    *prevClassLink = curClass->nextClass;
+
+	    // Release the reference to the class object.
+	    IUnknown_Release(curClass->classObject);
+
+	    // Free the memory used by the chain node.
+	    HeapFree(GetProcessHeap(), 0, curClass);
+
+	    return S_OK;
+	}
+
+	// Step to the next class in the list.
+	prevClassLink = &(curClass->nextClass);
+	curClass      = curClass->nextClass;
+    }
+
+    return E_INVALIDARG;
+}
+
+// ----------------------------------------------------------------------
+// GetClassFile
+//
+// This function supplies the CLSID associated with the given filename.
+// ----------------------------------------------------------------------
+HRESULT WIN32API GetClassFile(LPOLESTR filePathName, CLSID *pclsid)
+{
+    IStorage *	pstg = 0;
+    HRESULT 	res;
+    int 	nbElm = 0;
+    int		length = 0;
+    int		i = 0;
+    LONG 	sizeProgId = 20;
+    LPOLESTR *	pathDec = 0;
+    LPOLESTR	absFile = 0;
+    LPOLESTR	progId = 0;
+    WCHAR 	extention[100] = {0};
+
+    dprintf(("OLE32: GetClassFile"));
+
+    // if the file contain a storage object the return the CLSID
+    // writen by IStorage_SetClass method
+
+    if((StgIsStorageFile(filePathName)) == S_OK)
+    {
+	res = StgOpenStorage(filePathName, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &pstg);
+
+	if (SUCCEEDED(res))
+	    res = ReadClassStg(pstg, pclsid);
+
+	IStorage_Release(pstg);
+
+	return res;
+    }
+
+    /* if the obove strategies fail then search for the extension key in the registry */
+
+    /* get the last element (absolute file) in the path name */
+    nbElm = FileMonikerImpl_DecomposePath(filePathName, &pathDec);
+    absFile = pathDec[nbElm-1];
+
+    /* failed if the path represente a directory and not an absolute file name*/
+    if (lstrcmpW(absFile, (LPOLESTR)"\\"))
+	return MK_E_INVALIDEXTENSION;
+
+    /* get the extension of the file */
+    length = lstrlenW(absFile);
+    for(i = length-1; ( (i >= 0) && (extention[i] = absFile[i]) ); i--);
+	
+    /* get the progId associated to the extension */
+    progId = (WCHAR *)CoTaskMemAlloc(sizeProgId);
+
+    res = RegQueryValueW(HKEY_CLASSES_ROOT, extention, progId, &sizeProgId);
+
+    if (res == ERROR_MORE_DATA)
+    {
+	CoTaskMemRealloc(progId,sizeProgId);
+
+	res = RegQueryValueW(HKEY_CLASSES_ROOT, extention, progId, &sizeProgId);
+    }
+    if (res == ERROR_SUCCESS)
+	/* return the clsid associated to the progId */
+	res =  CLSIDFromProgID(progId, pclsid);
+
+    for(i = 0; pathDec[i] != NULL; i++)
+	CoTaskMemFree(pathDec[i]);
+
+    CoTaskMemFree(pathDec);
+
+    CoTaskMemFree(progId);
+
+    if (res == ERROR_SUCCESS)
+	return res;
+
+    return MK_E_INVALIDEXTENSION;
+}
+// ======================================================================
+// Private functions.
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// COM_GetRegisteredClassObject
+// ----------------------------------------------------------------------
+// This internal method is used to scan the registered class list to 
+// find a class object.
+//
+// Params: 
+//   rclsid        Class ID of the class to find.
+//   dwClsContext  Class context to match.
+//   ppv           [out] returns a pointer to the class object. Complying
+//                 to normal COM usage, this method will increase the
+//                 reference count on this object.
+static HRESULT COM_GetRegisteredClassObject
+   (REFCLSID		rclsid,
+    DWORD       	dwClsContext,
+    LPUNKNOWN *	  	ppUnk)
+{
+    RegisteredClass* curClass;
+
+    oStringA		tCLSID(rclsid);
+
+    dprintf(("OLE32: COM_GetRegisteredClassObject"));
+    dprintf(("       CLSID:%s", (char *)tCLSID));
+
+    // Sanity check
+    if (ppUnk == 0)
+	return E_POINTER;
+
+    // Iterate through the whole list and try to match the class ID.
+    curClass = firstRegisteredClass;
+
+    while (curClass != 0)
+    {
+	// Check if we have a match on the class ID.
+	if (IsEqualGUID(&curClass->classIdentifier, rclsid))
+	{
+	    // Since we don't do out-of process or DCOM just right away,
+	    // let's ignore the class context.
+
+	    // We have a match, return the pointer to the class object.
+	    *ppUnk = curClass->classObject;
+
+	    IUnknown_AddRef(curClass->classObject);
+
+	    return S_OK;
+	}
+
+    // Step to the next class in the list.
+    curClass = curClass->nextClass;
+    }
+
+    // If we get to here, we haven't found our class.
+    return S_FALSE;
+}
+
+// ----------------------------------------------------------------------
+// COM_RevokeAllClasses
+// ----------------------------------------------------------------------
+// This method is called when the COM libraries are uninitialized to 
+// release all the references to the class objects registered with
+// the library
+extern void COM_RevokeAllClasses()
+{
+    dprintf(("OLE32: COM_RevokeAllClasses"));
+
+    while (firstRegisteredClass != 0)
+    {
+	CoRevokeClassObject(firstRegisteredClass->dwCookie);
+    }
+}
+
+// ----------------------------------------------------------------------
+// COM_ExternalLockAddRef
+// ----------------------------------------------------------------------
+// Method that increments the count for a IUnknown* in the linked 
+// list.  The item is inserted if not already in the list.
+static void COM_ExternalLockAddRef(IUnknown * pUnk)
+{
+    dprintf(("OLE32: COM_ExternalLockAddRef"));
+
+    COM_ExternalLock *externalLock = COM_ExternalLockFind(pUnk);
+
+    /*
+     * Add an external lock to the object. If it was already externally
+     * locked, just increase the reference count. If it was not.
+     * add the item to the list.
+     */
+    if ( externalLock == EL_NOT_FOUND )
+	COM_ExternalLockInsert(pUnk);
+    else
+	externalLock->uRefCount++;
+
+    /*
+     * Add an internal lock to the object
+     */
+    IUnknown_AddRef(pUnk); 
+}
+
+// ----------------------------------------------------------------------
+// COM_ExternalLockRelease
+// ----------------------------------------------------------------------
+// Method that decrements the count for a IUnknown* in the linked 
+// list.  The item is removed from the list if its count end up at zero or if
+// bRelAll is TRUE.
+static void COM_ExternalLockRelease(IUnknown * pUnk, BOOL bRelAll)
+{
+    dprintf(("OLE32: COM_ExternalLockRelease"));
+
+    COM_ExternalLock * externalLock = COM_ExternalLockFind(pUnk);
+
+    if ( externalLock != EL_NOT_FOUND )
+    {
+	do
+	{
+	    externalLock->uRefCount--;  /* release external locks      */
+	    IUnknown_Release(pUnk);     /* release local locks as well */
+
+	    if ( bRelAll == FALSE ) 
+		break;  /* perform single release */
+
+	} while ( externalLock->uRefCount > 0 );  
+
+	if ( externalLock->uRefCount == 0 )  /* get rid of the list entry */
+	    COM_ExternalLockDelete(externalLock);
+    }
+}
+
+// ----------------------------------------------------------------------
+// COM_ExternalLockFreeList
+// ----------------------------------------------------------------------
+// Method that frees the content of the list.
+extern void COM_ExternalLockFreeList()
+{
+    dprintf(("OLE32: COM_ExternalLockFreeList"));
+
+    COM_ExternalLock *head;
+
+    head = elList.head;                 /* grab it by the head             */
+    while (head != EL_END_OF_LIST)
+    {
+	COM_ExternalLockDelete(head);     /* get rid of the head stuff       */
+
+	head = elList.head;               /* get the new head...             */ 
+    }
+}
+
+// ----------------------------------------------------------------------
+// COM_ExternalLockDump
+// ----------------------------------------------------------------------
+// Method that dump the content of the list.
+void COM_ExternalLockDump()
+{
+    dprintf(("OLE32: COM_ExternalLockDump"));
+
+    COM_ExternalLock *current = elList.head;
+
+    printf("External lock list:");
+
+    while ( current != EL_END_OF_LIST )
+    {
+	dprintf(("    %p with %lu references count.\n", current->pUnk, current->uRefCount));
+
+	/* Skip to the next item */ 
+	current = current->next;
+    } 
+}
+
+// ----------------------------------------------------------------------
+// COM_ExternalLockFind
+// ----------------------------------------------------------------------
+// Find a IUnknown* in the linked list
+static COM_ExternalLock * COM_ExternalLockFind(IUnknown *pUnk)
+{
+    dprintf(("OLE32: COM_ExternalLockFind"));
+
+    return COM_ExternalLockLocate(elList.head, pUnk);
+}
+
+// ----------------------------------------------------------------------
+// COM_ExternalLockLocate
+// ----------------------------------------------------------------------
+// Recursivity agent for IUnknownExternalLockList_Find
+static COM_ExternalLock * COM_ExternalLockLocate( COM_ExternalLock * element, IUnknown * pUnk)
+{
+  if ( element == EL_END_OF_LIST )  
+    return EL_NOT_FOUND;
+
+  else if ( element->pUnk == pUnk )    /* We found it */
+    return element;
+
+  else                                 /* Not the right guy, keep on looking */ 
+    return COM_ExternalLockLocate( element->next, pUnk);
+}
+
+// ----------------------------------------------------------------------
+// COM_ExternalLockInsert
+// ----------------------------------------------------------------------
+// Insert a new IUnknown* to the linked list
+static BOOL COM_ExternalLockInsert(IUnknown * pUnk)
+{
+    dprintf(("OLE32: COM_ExternalLockInsert"));
+
+    COM_ExternalLock *	newLock      = NULL;
+    COM_ExternalLock *	previousHead = NULL;
+
+    // Allocate space for the new storage object
+    newLock = (COM_ExternalLock *)HeapAlloc(GetProcessHeap(), 0, sizeof(COM_ExternalLock));
+
+    if (newLock != NULL)
+    {
+	if ( elList.head == EL_END_OF_LIST ) 
+	    elList.head = newLock;    /* The list is empty */
+	else 
+	{
+	    // insert does it at the head
+	    previousHead  = elList.head;
+	    elList.head = newLock;
+	}
+
+	/*
+	 * Set new list item data member 
+	 */
+	newLock->pUnk      = pUnk;
+	newLock->uRefCount = 1;
+	newLock->next      = previousHead;
+
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+// ----------------------------------------------------------------------
+// ExternalLockDelete
+// ----------------------------------------------------------------------
+// Method that removes an item from the linked list.
+static void COM_ExternalLockDelete(COM_ExternalLock * itemList)
+{
+    dprintf(("OLE32: ExternalLockDelete"));
+
+    COM_ExternalLock *current = elList.head;
+
+    if ( current == itemList )
+    {
+	// this section handles the deletion of the first node 
+	elList.head = itemList->next;
+	HeapFree( GetProcessHeap(), 0, itemList);  
+    }
+    else
+    {
+	do 
+	{
+	    if ( current->next == itemList )   /* We found the item to free  */
+	    {
+		current->next = itemList->next;  /* readjust the list pointers */
+
+		HeapFree( GetProcessHeap(), 0, itemList);  
+		break; 
+	    }
+
+	    /* Skip to the next item */ 
+	    current = current->next;
+
+	} while ( current != EL_END_OF_LIST );
+    }
+}
Index: trunk/src/ole32/new/ole32.def
===================================================================
--- trunk/src/ole32/new/ole32.def	(revision 3456)
+++ trunk/src/ole32/new/ole32.def	(revision 3456)
@@ -0,0 +1,182 @@
+;Created by BLAST for IBM's compiler
+LIBRARY OLE32OS2 INITINSTANCE
+DESCRIPTION 'OLE for ODIN'
+DATA MULTIPLE NONSHARED
+
+EXPORTS
+    BindMoniker                = _BindMoniker@16             @1
+    CLSIDFromProgID            = _CLSIDFromProgID@8          @2
+    CLSIDFromString            = _CLSIDFromString@8          @3
+    CoBuildVersion             = _CoBuildVersion@0           @4
+    CoCreateFreeThreadedMarshaler  = _CoCreateFreeThreadedMarshaler@8  @5
+    CoCreateGuid               = _CoCreateGuid@4             @6
+    CoCreateInstance           = _CoCreateInstance@20        @7
+    CoCreateInstanceEx         = _CoCreateInstanceEx@24	     @9999
+    CoDisconnectObject         = _CoDisconnectObject@8       @8
+    CoDosDateTimeToFileTime    = _CoDosDateTimeToFileTime@12 @9
+    CoFileTimeNow              = _CoFileTimeNow@4            @10
+    CoFileTimeToDosDateTime    = _CoFileTimeToDosDateTime@12 @11
+    CoFreeAllLibraries         = _CoFreeAllLibraries@0       @12
+    CoFreeLibrary              = _CoFreeLibrary@4            @13
+    CoFreeUnusedLibraries      = _CoFreeUnusedLibraries@0    @14
+    CoGetCallerTID             = _CoGetCallerTID@0           @15
+    CoGetClassObject           = _CoGetClassObject@20        @16
+    CoGetCurrentLogicalThreadId  = _CoGetCurrentLogicalThreadId@0  @17
+    CoGetCurrentProcess        = _CoGetCurrentProcess@0      @18
+    CoGetInterfaceAndReleaseStream  = _CoGetInterfaceAndReleaseStream@12 @19
+    CoGetMalloc                = _CoGetMalloc@8              @20
+    CoGetMarshalSizeMax        = _CoGetMarshalSizeMax@24     @21
+    CoGetPSClsid               = _CoGetPSClsid@8             @22
+    CoGetStandardMarshal       = _CoGetStandardMarshal@24    @23
+    CoGetState                 = _CoGetState@0               @24
+    CoGetTreatAsClass          = _CoGetTreatAsClass@8        @25
+    CoInitializeEx             = _CoInitializeEx@8           @9998
+    CoInitialize               = _CoInitialize@4             @26
+    CoInitializeWOW            = _CoInitializeWOW@0          @27
+    CoIsHandlerConnected       = _CoIsHandlerConnected@4     @28
+    CoIsOle1Class              = _CoIsOle1Class@4            @29
+    CoLoadLibrary              = _CoLoadLibrary@8            @30
+    CoLockObjectExternal       = _CoLockObjectExternal@12    @31
+    CoMarshalHresult           = _CoMarshalHresult@8         @32
+    CoMarshalInterThreadInterfaceInStream  = _CoMarshalInterThreadInterfaceInStream@12 @33
+    CoMarshalInterface         = _CoMarshalInterface@24      @34
+    CoQueryReleaseObject       = _CoQueryReleaseObject@0     @35
+    CoRegisterClassObject      = _CoRegisterClassObject@20   @36
+    CoRegisterMallocSpy        = _CoRegisterMallocSpy@4      @37
+    CoRegisterMessageFilter    = _CoRegisterMessageFilter@8  @38
+    CoReleaseMarshalData       = _CoReleaseMarshalData@4     @39
+    CoRevokeClassObject        = _CoRevokeClassObject@4      @40
+    CoRevokeMallocSpy          = _CoRevokeMallocSpy@0        @41
+    CoSetState                 = _CoSetState@4               @42
+    CoTaskMemAlloc             = _CoTaskMemAlloc@4           @43
+    CoTaskMemFree              = _CoTaskMemFree@4            @44
+    CoTaskMemRealloc           = _CoTaskMemRealloc@8         @45
+    CoTreatAsClass             = _CoTreatAsClass@8           @46
+    CoUninitialize             = _CoUninitialize@0           @47
+    CoUnloadingWOW             = _CoUnloadingWOW@0           @48
+    CoUnmarshalHresult         = _CoUnmarshalHresult@8       @49
+    CoUnmarshalInterface       = _CoUnmarshalInterface@12    @50
+    CreateAntiMoniker          = _CreateAntiMoniker@4        @51
+    CreateBindCtx              = _CreateBindCtx@8            @52
+    CreateDataAdviseHolder     = _CreateDataAdviseHolder@4   @53
+    CreateDataCache            = _CreateDataCache@16         @54
+    CreateFileMoniker          = _CreateFileMoniker@8        @55
+    CreateGenericComposite     = _CreateGenericComposite@12  @56
+    CreateILockBytesOnHGlobal  = _CreateILockBytesOnHGlobal@12 @57
+    CreateItemMoniker          = _CreateItemMoniker@12       @58
+    CreateOleAdviseHolder      = _CreateOleAdviseHolder@4    @59
+    CreatePointerMoniker       = _CreatePointerMoniker@8     @60
+    CreateStreamOnHGlobal      = _CreateStreamOnHGlobal@12   @61
+    DllDebugObjectRPCHook      = _DllDebugObjectRPCHook@0    @62
+    DllGetClassObject          = _DllGetClassObject@12       @63
+    DllGetClassObjectWOW       = _DllGetClassObjectWOW@0     @64
+    DoDragDrop                 = _DoDragDrop@16              @65
+    EnableHookObject           = _EnableHookObject@0         @66
+    GetClassFile               = _GetClassFile@8             @67
+    GetConvertStg              = _GetConvertStg@4            @68
+    GetDocumentBitStg          = _GetDocumentBitStg@0        @69
+    GetHGlobalFromILockBytes   = _GetHGlobalFromILockBytes@8  @70
+    GetHGlobalFromStream       = _GetHGlobalFromStream@8     @71
+    GetHookInterface           = _GetHookInterface@0         @72
+    GetRunningObjectTable      = _GetRunningObjectTable@8    @73
+    IIDFromString              = _IIDFromString@8            @74
+    IsAccelerator              = _IsAccelerator@16           @75
+    IsEqualGUID                = _CONCRETE_IsEqualGUID@8              @76
+    IsValidIid                 = _IsValidIid@4               @77
+    IsValidInterface           = _IsValidInterface@4         @78
+    IsValidPtrIn               = _IsValidPtrIn@4             @79
+    IsValidPtrOut              = _IsValidPtrOut@4            @80
+    MkParseDisplayName         = _MkParseDisplayName@16      @81
+    MonikerCommonPrefixWith    = _MonikerCommonPrefixWith@12 @82
+    MonikerRelativePathTo      = _MonikerRelativePathTo@16   @83
+    OleBuildVersion            = _OleBuildVersion@0          @84
+    OleConvertIStorageToOLESTREAM  = _OleConvertIStorageToOLESTREAM@8  @85
+    OleConvertIStorageToOLESTREAMEx  = _OleConvertIStorageToOLESTREAMEx@28 @86
+    OleConvertOLESTREAMToIStorage  = _OleConvertOLESTREAMToIStorage@12 @87
+    OleConvertOLESTREAMToIStorageEx  = _OleConvertOLESTREAMToIStorageEx@28 @88
+    OleCreate                  = _OleCreate@28               @89
+    OleCreateDefaultHandler    = _OleCreateDefaultHandler@16 @90
+    OleCreateEmbeddingHelper   = _OleCreateEmbeddingHelper@24 @91
+    OleCreateFromData          = _OleCreateFromData@28       @92
+    OleCreateFromFile          = _OleCreateFromFile@32       @93
+    OleCreateLink              = _OleCreateLink@28           @94
+    OleCreateLinkFromData      = _OleCreateLinkFromData@28   @95
+    OleCreateLinkToFile        = _OleCreateLinkToFile@28     @96
+    OleCreateMenuDescriptor    = _OleCreateMenuDescriptor@8  @97
+    OleCreateStaticFromData    = _OleCreateStaticFromData@28 @98
+    OleDestroyMenuDescriptor   = _OleDestroyMenuDescriptor@4  @99
+    OleDoAutoConvert           = _OleDoAutoConvert@8         @100
+    OleDraw                    = _OleDraw@16                 @101
+    OleDuplicateData           = _OleDuplicateData@12        @102
+    OleFlushClipboard          = _OleFlushClipboard@0        @103
+    OleGetAutoConvert          = _OleGetAutoConvert@8        @104
+    OleGetClipboard            = _OleGetClipboard@4          @105
+    OleGetIconOfClass          = _OleGetIconOfClass@12       @106
+    OleGetIconOfFile           = _OleGetIconOfFile@8         @107
+    OleInitialize              = _OleInitialize@4            @108
+    OleInitializeWOW           = _OleInitializeWOW@0         @109
+    OleIsCurrentClipboard      = _OleIsCurrentClipboard@4    @110
+    OleIsRunning               = _OleIsRunning@4             @111
+    OleLoad                    = _OleLoad@16                 @112
+    OleLoadFromStream          = _OleLoadFromStream@12       @113
+    OleLockRunning             = _OleLockRunning@12          @114
+    OleMetafilePictFromIconAndLabel  = _OleMetafilePictFromIconAndLabel@16 @115
+    OleNoteObjectVisible       = _OleNoteObjectVisible@8     @116
+    OleQueryCreateFromData     = _OleQueryCreateFromData@4   @117
+    OleQueryLinkFromData       = _OleQueryLinkFromData@4     @118
+    OleRegEnumFormatEtc        = _OleRegEnumFormatEtc@12     @119
+    OleRegEnumVerbs            = _OleRegEnumVerbs@8          @120
+    OleRegGetMiscStatus        = _OleRegGetMiscStatus@12     @121
+    OleRegGetUserType          = _OleRegGetUserType@12       @122
+    OleRun                     = _OleRun@4                   @123
+    OleSave                    = _OleSave@12                 @124
+    OleSaveToStream            = _OleSaveToStream@8          @125
+    OleSetAutoConvert          = _OleSetAutoConvert@8        @126
+    OleSetClipboard            = _OleSetClipboard@4          @127
+    OleSetContainedObject      = _OleSetContainedObject@8    @128
+    OleSetMenuDescriptor       = _OleSetMenuDescriptor@20    @129
+    OleTranslateAccelerator    = _OleTranslateAccelerator@12 @130
+    OleUninitialize            = _OleUninitialize@0          @131
+    OpenOrCreateStream         = _OpenOrCreateStream@0       @132
+    ProgIDFromCLSID            = _ProgIDFromCLSID@8          @133
+    ReadClassStg               = _ReadClassStg@8             @134
+    ReadClassStm               = _ReadClassStm@8             @135
+    ReadFmtUserTypeStg         = _ReadFmtUserTypeStg@12      @136
+    ReadOleStg                 = _ReadOleStg@0               @137
+    ReadStringStream           = _ReadStringStream@0         @138
+    RegisterDragDrop           = _RegisterDragDrop@8         @139
+    ReleaseStgMedium           = _ReleaseStgMedium@4         @140
+    RevokeDragDrop             = _RevokeDragDrop@4           @141
+    SetConvertStg              = _SetConvertStg@8            @142
+    SetDocumentBitStg          = _SetDocumentBitStg@0        @143
+    StgCreateDocfile           = _StgCreateDocfile@16        @144
+    StgCreateDocfileOnILockBytes  = _StgCreateDocfileOnILockBytes@16 @145
+    StgIsStorageFile           = _StgIsStorageFile@4         @146
+    StgIsStorageILockBytes     = _StgIsStorageILockBytes@4   @147
+    StgOpenStorage             = _StgOpenStorage@24           @148
+    StgOpenStorageOnILockBytes  = _StgOpenStorageOnILockBytes@24 @149
+    StgSetTimes                = _StgSetTimes@16             @150
+    StringFromCLSID            = _StringFromCLSID@8          @151
+    StringFromGUID2            = _StringFromGUID2@12         @152
+    StringFromIID              = _StringFromIID@8            @153
+    UtConvertDvtd16toDvtd32    = _UtConvertDvtd16toDvtd32@0  @154
+    UtConvertDvtd32toDvtd16    = _UtConvertDvtd32toDvtd16@0  @155
+    UtGetDvtd16Info            = _UtGetDvtd16Info@0          @156
+    UtGetDvtd32Info            = _UtGetDvtd32Info@0          @157
+    WriteClassStg              = _WriteClassStg@8            @158
+    WriteClassStm              = _WriteClassStm@8            @159
+    WriteFmtUserTypeStg        = _WriteFmtUserTypeStg@12     @160
+    WriteOleStg                = _WriteOleStg@0              @161
+    WriteStringStream          = _WriteStringStream@0        @162
+
+    CoImpersonateClient        = _CoImpersonateClient@0	     @997	; suppress warning
+    CoInitializeSecurity       = _CoInitializeSecurity@36    @998	; suppress warning
+    CoRegisterSurrogate        = _CoRegisterSurrogate@4	     @999	; suppress warning
+
+;
+;   Helper Functions
+;
+    WINE_StringFromCLSID       = _WINE_StringFromCLSID@8     @1000
+    CLSIDFromStringA           = _CLSIDFromStringA@8         @1001
+    CLSIDFromString16          = _CLSIDFromString16@8        @1002	; COMPOBJ.19
+
Index: trunk/src/ole32/new/ole32.h
===================================================================
--- trunk/src/ole32/new/ole32.h	(revision 3456)
+++ trunk/src/ole32/new/ole32.h	(revision 3456)
@@ -0,0 +1,49 @@
+/* $Id: ole32.h,v 1.1 2000-04-27 22:21:36 davidr Exp $ */
+/*
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+/*
+ * Win32 OLE stubs for OS/2
+ *
+ * 1998/06/12
+ *
+ * Copyright 1998 Sander van Leeuwen
+ */
+#ifndef __OLE32_H__
+#define __OLE32_H__
+
+// ><DJR 17.05.99 Force to use C-interfaces for now to prevent CALLBACK definition compiler error
+#define CINTERFACE 1
+
+// ><DJR 17.05.99 Move standard includes to before os2win.h [memcmp]
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <wchar.h>
+
+// ><DJR 17.05.99 Prevent CALLCONV becoming _System
+#include <win/wtypes.h>
+#include <winbase.h>
+//#include <uconv.h>
+#undef CALLCONV
+
+#include <os2win.h>
+#include <ole2ver.h>
+#include <ole.h>
+#include <ole2.h>
+#include <winreg.h>
+
+#include "objbase.h"
+#include "docobj.h"    /* for the IID_StdOleLink */
+
+#include "wine/obj_inplace.h"
+#include "wine/obj_oleobj.h"
+#include "wine/obj_surrogate.h"
+#include "wine/obj_oleview.h"
+#include "wine/obj_cache.h"
+
+#endif
Index: trunk/src/ole32/new/ole32exp.def
===================================================================
--- trunk/src/ole32/new/ole32exp.def	(revision 3456)
+++ trunk/src/ole32/new/ole32exp.def	(revision 3456)
@@ -0,0 +1,174 @@
+;Internal export definition file - autogenerated by ImpDef.
+LIBRARY OLE32OS2 INITINSTANCE
+DESCRIPTION 'OLE for ODIN'
+EXPORTS
+    _BindMoniker@16                           @1
+    _CLSIDFromProgID@8                        @2
+    _CLSIDFromString@8                        @3
+    _CoBuildVersion@0                         @4
+    _CoCreateFreeThreadedMarshaler@8          @5
+    _CoCreateGuid@4                           @6
+    _CoCreateInstance@20                      @7
+    _CoCreateInstanceEx@24                    @9999
+    _CoDisconnectObject@8                     @8
+    _CoDosDateTimeToFileTime@12               @9
+    _CoFileTimeNow@4                          @10
+    _CoFileTimeToDosDateTime@12               @11
+    _CoFreeAllLibraries@0                     @12
+    _CoFreeLibrary@4                          @13
+    _CoFreeUnusedLibraries@0                  @14
+    _CoGetCallerTID@0                         @15
+    _CoGetClassObject@20                      @16
+    _CoGetCurrentLogicalThreadId@0            @17
+    _CoGetCurrentProcess@0                    @18
+    _CoGetInterfaceAndReleaseStream@12        @19
+    _CoGetMalloc@8                            @20
+    _CoGetMarshalSizeMax@24                   @21
+    _CoGetPSClsid@8                           @22
+    _CoGetStandardMarshal@24                  @23
+    _CoGetState@0                             @24
+    _CoGetTreatAsClass@8                      @25
+    _CoInitializeEx@8                         @9998
+    _CoInitialize@4                           @26
+    _CoInitializeWOW@0                        @27
+    _CoIsHandlerConnected@4                   @28
+    _CoIsOle1Class@4                          @29
+    _CoLoadLibrary@8                          @30
+    _CoLockObjectExternal@12                  @31
+    _CoMarshalHresult@8                       @32
+    _CoMarshalInterThreadInterfaceInStream@12  @33
+    _CoMarshalInterface@24                    @34
+    _CoQueryReleaseObject@0                   @35
+    _CoRegisterClassObject@20                 @36
+    _CoRegisterMallocSpy@4                    @37
+    _CoRegisterMessageFilter@8                @38
+    _CoReleaseMarshalData@4                   @39
+    _CoRevokeClassObject@4                    @40
+    _CoRevokeMallocSpy@0                      @41
+    _CoSetState@4                             @42
+    _CoTaskMemAlloc@4                         @43
+    _CoTaskMemFree@4                          @44
+    _CoTaskMemRealloc@8                       @45
+    _CoTreatAsClass@8                         @46
+    _CoUninitialize@0                         @47
+    _CoUnloadingWOW@0                         @48
+    _CoUnmarshalHresult@8                     @49
+    _CoUnmarshalInterface@12                  @50
+    _CreateAntiMoniker@4                      @51
+    _CreateBindCtx@8                          @52
+    _CreateDataAdviseHolder@4                 @53
+    _CreateDataCache@16                       @54
+    _CreateFileMoniker@8                      @55
+    _CreateGenericComposite@12                @56
+    _CreateILockBytesOnHGlobal@12             @57
+    _CreateItemMoniker@12                     @58
+    _CreateOleAdviseHolder@4                  @59
+    _CreatePointerMoniker@8                   @60
+    _CreateStreamOnHGlobal@12                 @61
+    _DllDebugObjectRPCHook@0                  @62
+    _DllGetClassObject@12                     @63
+    _DllGetClassObjectWOW@0                   @64
+    _DoDragDrop@16                            @65
+    _EnableHookObject@0                       @66
+    _GetClassFile@8                           @67
+    _GetConvertStg@4                          @68
+    _GetDocumentBitStg@0                      @69
+    _GetHGlobalFromILockBytes@8               @70
+    _GetHGlobalFromStream@8                   @71
+    _GetHookInterface@0                       @72
+    _GetRunningObjectTable@8                  @73
+    _IIDFromString@8                          @74
+    _IsAccelerator@16                         @75
+    _IsEqualGUID@8                            @76
+    _IsValidIid@4                             @77
+    _IsValidInterface@4                       @78
+    _IsValidPtrIn@4                           @79
+    _IsValidPtrOut@4                          @80
+    _MkParseDisplayName@16                    @81
+    _MonikerCommonPrefixWith@12               @82
+    _MonikerRelativePathTo@16                 @83
+    _OleBuildVersion@0                        @84
+    _OleConvertIStorageToOLESTREAM@8          @85
+    _OleConvertIStorageToOLESTREAMEx@28       @86
+    _OleConvertOLESTREAMToIStorage@12         @87
+    _OleConvertOLESTREAMToIStorageEx@28       @88
+    _OleCreate@28                             @89
+    _OleCreateDefaultHandler@16               @90
+    _OleCreateEmbeddingHelper@24              @91
+    _OleCreateFromData@28                     @92
+    _OleCreateFromFile@32                     @93
+    _OleCreateLink@28                         @94
+    _OleCreateLinkFromData@28                 @95
+    _OleCreateLinkToFile@28                   @96
+    _OleCreateMenuDescriptor@8                @97
+    _OleCreateStaticFromData@28               @98
+    _OleDestroyMenuDescriptor@4               @99
+    _OleDoAutoConvert@8                       @100
+    _OleDraw@16                               @101
+    _OleDuplicateData@12                      @102
+    _OleFlushClipboard@0                      @103
+    _OleGetAutoConvert@8                      @104
+    _OleGetClipboard@4                        @105
+    _OleGetIconOfClass@12                     @106
+    _OleGetIconOfFile@8                       @107
+    _OleInitialize@4                          @108
+    _OleInitializeWOW@0                       @109
+    _OleIsCurrentClipboard@4                  @110
+    _OleIsRunning@4                           @111
+    _OleLoad@16                               @112
+    _OleLoadFromStream@12                     @113
+    _OleLockRunning@12                        @114
+    _OleMetafilePictFromIconAndLabel@16       @115
+    _OleNoteObjectVisible@8                   @116
+    _OleQueryCreateFromData@4                 @117
+    _OleQueryLinkFromData@4                   @118
+    _OleRegEnumFormatEtc@12                   @119
+    _OleRegEnumVerbs@8                        @120
+    _OleRegGetMiscStatus@12                   @121
+    _OleRegGetUserType@12                     @122
+    _OleRun@4                                 @123
+    _OleSave@12                               @124
+    _OleSaveToStream@8                        @125
+    _OleSetAutoConvert@8                      @126
+    _OleSetClipboard@4                        @127
+    _OleSetContainedObject@8                  @128
+    _OleSetMenuDescriptor@20                  @129
+    _OleTranslateAccelerator@12               @130
+    _OleUninitialize@0                        @131
+    _OpenOrCreateStream@0                     @132
+    _ProgIDFromCLSID@8                        @133
+    _ReadClassStg@8                           @134
+    _ReadClassStm@8                           @135
+    _ReadFmtUserTypeStg@12                    @136
+    _ReadOleStg@0                             @137
+    _ReadStringStream@0                       @138
+    _RegisterDragDrop@8                       @139
+    _ReleaseStgMedium@4                       @140
+    _RevokeDragDrop@4                         @141
+    _SetConvertStg@8                          @142
+    _SetDocumentBitStg@0                      @143
+    _StgCreateDocfile@16                      @144
+    _StgCreateDocfileOnILockBytes@16          @145
+    _StgIsStorageFile@4                       @146
+    _StgIsStorageILockBytes@4                 @147
+    _StgOpenStorage@24                        @148
+    _StgOpenStorageOnILockBytes@24            @149
+    _StgSetTimes@16                           @150
+    _StringFromCLSID@8                        @151
+    _StringFromGUID2@12                       @152
+    _StringFromIID@8                          @153
+    _UtConvertDvtd16toDvtd32@0                @154
+    _UtConvertDvtd32toDvtd16@0                @155
+    _UtGetDvtd16Info@0                        @156
+    _UtGetDvtd32Info@0                        @157
+    _WriteClassStg@8                          @158
+    _WriteClassStm@8                          @159
+    _WriteFmtUserTypeStg@12                   @160
+    _WriteOleStg@0                            @161
+    _WriteStringStream@0                      @162
+    _CoImpersonateClient@0                    @997
+    _CoInitializeSecurity@36                  @998
+    _CoRegisterSurrogate@4                    @999
+    _WINE_StringFromCLSID@8                   @1000
+    _CLSIDFromStringA@8                       @1001
+    _CLSIDFromString16@8                      @1002
Index: trunk/src/ole32/new/ole32rsrc.orc
===================================================================
--- trunk/src/ole32/new/ole32rsrc.orc	(revision 3456)
+++ trunk/src/ole32/new/ole32rsrc.orc	(revision 3456)
@@ -0,0 +1,41 @@
+/* $Id: ole32rsrc.orc,v 1.1 2000-04-27 22:21:36 davidr Exp $ */
+
+#include "winuser.h"
+#include "odinrsrc.h"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version (based on NT 4 SP4)
+//
+
+1 VERSIONINFO
+ FILEVERSION ODIN_FILEVERSION
+ PRODUCTVERSION ODIN_PRODUCTVERSION
+ FILEFLAGSMASK 0x3fL
+ FILEFLAGS 0xaL
+ FILEOS 0x10001L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904E4"
+        BEGIN
+            VALUE "Comments", "Odin32 System Dll\0"
+            VALUE "CompanyName", "Odin Team\0"
+            VALUE "FileDescription", "OLE32 System dll\0"
+            VALUE "FileVersion", "4.00\0"
+            VALUE "InternalName", "OLE32\0"
+            VALUE "LegalCopyright", "Copyright (C) 1999-2000\0"
+            VALUE "LegalTrademarks", "\0"
+            VALUE "OriginalFilename", "OLE32.DLL\0"
+            VALUE "ProductName", "Odin32 - OLE32\0"
+            VALUE "ProductVersion", "4.00\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+	VALUE "Translation", 0x409, 0x04E4
+    END
+END
Index: trunk/src/ole32/new/oleClip.cpp
===================================================================
--- trunk/src/ole32/new/oleClip.cpp	(revision 3456)
+++ trunk/src/ole32/new/oleClip.cpp	(revision 3456)
@@ -0,0 +1,1628 @@
+/* $Id: oleClip.cpp,v 1.1 2000-04-27 22:18:28 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * OLEClip functions.
+ * 
+ * 5/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ *
+ * Ported from Wine Implementation (2/9/99)
+ *   Copyright 1999  Noel Borthwick <noel@macadamian.com>
+ *
+ * NOTES:
+ *    This file contains the implementation for the OLE Clipboard and its
+ *    internal interfaces. The OLE clipboard interacts with an IDataObject
+ *    interface via the OleSetClipboard, OleGetClipboard and
+ *    OleIsCurrentClipboard API's. An internal IDataObject delegates
+ *    to a client supplied IDataObject or the WIN32 clipboard API depending
+ *    on whether OleSetClipboard has been invoked.
+ *    Here are some operating scenarios:
+ *
+ *    1. OleSetClipboard called: In this case the internal IDataObject
+ *       delegates to the client supplied IDataObject. Additionally OLE takes
+ *       ownership of the Windows clipboard and any HGLOCBAL IDataObject
+ *       items are placed on the Windows clipboard. This allows non OLE aware
+ *       applications to access these. A local WinProc fields WM_RENDERFORMAT
+ *       and WM_RENDERALLFORMATS messages in this case.
+ *
+ *    2. OleGetClipboard called without previous OleSetClipboard. Here the internal
+ *       IDataObject functionality wraps around the WIN32 clipboard API.
+ *
+ *    3. OleGetClipboard called after previous OleSetClipboard. Here the internal
+ *       IDataObject delegates to the source IDataObjects functionality directly,
+ *       thereby bypassing the Windows clipboard.
+ *
+ *    Implementation references : Inside OLE 2'nd  edition by Kraig Brockschmidt
+ *
+ * TODO:
+ *    - Support for pasting between different processes. OLE clipboard support
+ *      currently works only for in process copy and paste. Since we internally
+ *      store a pointer to the source's IDataObject and delegate to that, this
+ *      will fail if the IDataObject client belongs to a different process.
+ *    - IDataObject::GetDataHere is not implemented
+ *    - OleFlushClipboard needs to additionally handle TYMED_IStorage media
+ *      by copying the storage into global memory. Subsequently the default
+ *      data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
+ *      back to TYMED_IStorage.
+ *    - OLE1 compatibility formats to be synthesized from OLE2 formats and put on
+ *      clipboard in OleSetClipboard.
+ */
+
+#include "ole32.h"
+#include "commctrl.h"
+#include "oString.h"
+#include <assert.h>
+
+// ======================================================================
+// Local Data
+// ======================================================================
+
+#define HANDLE_ERROR(err) { hr = err; dprintf(("OLE32: ERR (HRESULT=%lx)\n", (HRESULT)err)); goto CLEANUP; }
+
+/* For CoGetMalloc (MEMCTX_TASK is currently ignored) */
+#ifndef MEMCTX_TASK
+  #define MEMCTX_TASK -1
+#endif
+
+/****************************************************************************
+ * OLEClipbrd
+ * DO NOT add any members before the VTables declaration!
+ */
+struct OLEClipbrd
+{
+  /*
+   * List all interface VTables here
+   */
+  ICOM_VTABLE(IDataObject)*  lpvtbl1;  /* IDataObject VTable */
+
+  /*
+   * The hidden OLE clipboard window. This window is used as the bridge between the 
+   * the OLE and windows clipboard API. (Windows creates one such window per process)
+   */
+  HWND                       hWndClipboard;
+
+  /*
+   * Pointer to the source data object (via OleSetClipboard)
+   */
+  IDataObject*               pIDataObjectSrc;
+
+  /*
+   * The registered DataObject clipboard format
+   */
+  UINT                       cfDataObj;
+
+  /*
+   * The handle to our ourself
+   */
+  UINT                       hSelf;
+
+  /*
+   * Reference count of this object
+   */
+  ULONG                      ref;
+};
+
+typedef struct OLEClipbrd OLEClipbrd;
+
+
+/****************************************************************************
+*   IEnumFORMATETC implementation
+*   DO NOT add any members before the VTables declaration!
+*/
+typedef struct 
+{
+  /* IEnumFORMATETC VTable */
+  ICOM_VTABLE(IEnumFORMATETC)* lpvtbl;
+  
+  /* IEnumFORMATETC fields */
+  UINT                         posFmt;    /* current enumerator position */
+  UINT                         countFmt;  /* number of EnumFORMATETC's in array */
+  LPFORMATETC                  pFmt;      /* array of EnumFORMATETC's */
+
+  /*
+   * Reference count of this object
+   */
+  DWORD                        ref;
+
+  /*
+   * IUnknown implementation of the parent data object.
+   */
+  IUnknown*                    pUnkDataObj;
+  
+} IEnumFORMATETCImpl;
+
+/*
+ * The one and only OLEClipbrd object which is created by OLEClipbrd_Initialize()
+ */
+static HGLOBAL hTheOleClipboard = 0;
+static OLEClipbrd* theOleClipboard = NULL;
+
+/*
+ * Prototypes for the methods of the OLEClipboard class.
+ */
+extern void OLEClipbrd_Initialize();
+extern void OLEClipbrd_UnInitialize();
+static OLEClipbrd* OLEClipbrd_Construct();
+static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy);
+static HWND OLEClipbrd_CreateWindow();
+static void OLEClipbrd_DestroyWindow(HWND hwnd);
+LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+static HRESULT OLEClipbrd_RenderFormat(LPFORMATETC pFormatetc);
+static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc );
+
+/*
+ * Prototypes for the methods of the OLEClipboard class
+ * that implement IDataObject methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IDataObject_QueryInterface(
+            IDataObject*     iface,
+            REFIID           riid,
+            void**           ppvObject);
+static ULONG WIN32API OLEClipbrd_IDataObject_AddRef( 
+            IDataObject*     iface);
+static ULONG WIN32API OLEClipbrd_IDataObject_Release( 
+            IDataObject*     iface);
+static HRESULT WIN32API OLEClipbrd_IDataObject_GetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetcIn, 
+	    STGMEDIUM*       pmedium);
+static HRESULT WIN32API OLEClipbrd_IDataObject_GetDataHere(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatetc,
+	    STGMEDIUM*       pmedium);
+static HRESULT WIN32API OLEClipbrd_IDataObject_QueryGetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc);
+static HRESULT WIN32API OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatectIn, 
+	    LPFORMATETC      pformatetcOut);
+static HRESULT WIN32API OLEClipbrd_IDataObject_SetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc, 
+	    STGMEDIUM*       pmedium, 
+	    BOOL             fRelease);
+static HRESULT WIN32API OLEClipbrd_IDataObject_EnumFormatEtc(
+	    IDataObject*     iface,       
+	    DWORD            dwDirection,
+	    IEnumFORMATETC** ppenumFormatEtc);
+static HRESULT WIN32API OLEClipbrd_IDataObject_DAdvise(
+	    IDataObject*     iface, 
+	    FORMATETC*       pformatetc, 
+	    DWORD            advf, 
+	    IAdviseSink*     pAdvSink, 
+	    DWORD*           pdwConnection);
+static HRESULT WIN32API OLEClipbrd_IDataObject_DUnadvise(
+	    IDataObject*     iface,
+	    DWORD            dwConnection);
+static HRESULT WIN32API OLEClipbrd_IDataObject_EnumDAdvise(
+	    IDataObject*     iface,
+	    IEnumSTATDATA**  ppenumAdvise);
+
+/*
+ * Prototypes for the IEnumFORMATETC methods.
+ */
+static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],
+                                                           LPUNKNOWN pUnkDataObj);
+static HRESULT WIN32API OLEClipbrd_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC iface, REFIID riid,
+                                                               LPVOID* ppvObj);
+static ULONG WIN32API OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface);
+static ULONG WIN32API OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface);
+static HRESULT WIN32API OLEClipbrd_IEnumFORMATETC_Next(LPENUMFORMATETC iface, ULONG celt,
+                                                     FORMATETC* rgelt, ULONG* pceltFethed);
+static HRESULT WIN32API OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt);
+static HRESULT WIN32API OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface);
+static HRESULT WIN32API OLEClipbrd_IEnumFORMATETC_Clone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum);
+
+
+/*
+ * Virtual function table for the OLEClipbrd's exposed IDataObject interface
+ */
+static ICOM_VTABLE(IDataObject) OLEClipbrd_IDataObject_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  OLEClipbrd_IDataObject_QueryInterface,
+  OLEClipbrd_IDataObject_AddRef,
+  OLEClipbrd_IDataObject_Release,
+  OLEClipbrd_IDataObject_GetData,
+  OLEClipbrd_IDataObject_GetDataHere,
+  OLEClipbrd_IDataObject_QueryGetData,
+  OLEClipbrd_IDataObject_GetCanonicalFormatEtc,
+  OLEClipbrd_IDataObject_SetData,
+  OLEClipbrd_IDataObject_EnumFormatEtc,
+  OLEClipbrd_IDataObject_DAdvise,
+  OLEClipbrd_IDataObject_DUnadvise,
+  OLEClipbrd_IDataObject_EnumDAdvise
+};
+
+/*
+ * Virtual function table for IEnumFORMATETC interface
+ */
+static struct ICOM_VTABLE(IEnumFORMATETC) efvt =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  OLEClipbrd_IEnumFORMATETC_QueryInterface,
+  OLEClipbrd_IEnumFORMATETC_AddRef,
+  OLEClipbrd_IEnumFORMATETC_Release,
+  OLEClipbrd_IEnumFORMATETC_Next,
+  OLEClipbrd_IEnumFORMATETC_Skip,
+  OLEClipbrd_IEnumFORMATETC_Reset,
+  OLEClipbrd_IEnumFORMATETC_Clone
+};
+
+/*
+ * Name of our registered OLE clipboard window class 
+ */
+CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS";
+
+/*
+ *  If we need to store state info we can store it here.
+ *  For now we dont need this functionality.
+ *
+typedef struct tagClipboardWindowInfo
+{
+} ClipboardWindowInfo;
+ */
+
+/*---------------------------------------------------------------------*
+ *           Win32 OLE clipboard API 
+ *---------------------------------------------------------------------*/
+
+/***********************************************************************
+ *           OleSetClipboard     [OLE32.127]
+ *  Places a pointer to the specified data object onto the clipboard,
+ *  making the data object accessible to the OleGetClipboard function.
+ *
+ * RETURNS:
+ *
+ *    S_OK                  IDataObject pointer placed on the clipboard
+ *    CLIPBRD_E_CANT_OPEN   OpenClipboard failed 
+ *    CLIPBRD_E_CANT_EMPTY  EmptyClipboard failed 
+ *    CLIPBRD_E_CANT_CLOSE  CloseClipboard failed
+ *    CLIPBRD_E_CANT_SET    SetClipboard failed
+ */
+HRESULT WIN32API OleSetClipboard(IDataObject* pDataObj)
+{
+    dprintf(("OLE32: OleSetClipboard(%p)\n", pDataObj));
+
+  HRESULT hr = S_OK;
+  IEnumFORMATETC* penumFormatetc = NULL;
+  FORMATETC rgelt;
+  BOOL bClipboardOpen = FALSE;
+/*
+  HGLOBAL hDataObject = 0;
+  OLEClipbrd **ppDataObject;
+*/
+  
+  
+  /*
+   * Make sure we have a clipboard object
+   */
+  OLEClipbrd_Initialize();
+
+  /*
+   * If the Ole clipboard window hasn't been created yet, create it now.
+   */
+  if ( !theOleClipboard->hWndClipboard )
+    theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow();
+
+  if ( !theOleClipboard->hWndClipboard ) /* sanity check */
+    HANDLE_ERROR( E_FAIL );
+
+  /*
+   * Open the Windows clipboard, associating it with our hidden window
+   */
+  if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
+    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
+
+  /*
+   * Empty the current clipboard and make our window the clipboard owner
+   * NOTE: This will trigger a WM_DESTROYCLIPBOARD message 
+   */
+  if ( !EmptyClipboard() )
+    HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );
+
+  /*
+   * If we are already holding on to an IDataObject first release that.
+   */
+  if ( theOleClipboard->pIDataObjectSrc )
+  {
+    IDataObject_Release(theOleClipboard->pIDataObjectSrc);
+    theOleClipboard->pIDataObjectSrc = NULL;
+  }
+
+  /*
+   * AddRef the data object passed in and save its pointer.
+   * A NULL value indicates that the clipboard should be emptied.
+   */
+  theOleClipboard->pIDataObjectSrc = pDataObj;
+  if ( pDataObj )
+  {
+    IDataObject_AddRef(theOleClipboard->pIDataObjectSrc);
+  }
+
+  /*
+   * Enumerate all HGLOBAL formats supported by the source and make 
+   * those formats available using delayed rendering using SetClipboardData.
+   * Only global memory based data items may be made available to non-OLE 
+   * applications via the standard Windows clipboard API. Data based on other 
+   * mediums(non TYMED_HGLOBAL) can only be accessed via the Ole Clipboard API.
+   *
+   * TODO: Do we need to additionally handle TYMED_IStorage media by copying
+   * the storage into global memory?
+   */
+  if ( pDataObj )
+  {
+    if ( FAILED(hr = IDataObject_EnumFormatEtc( pDataObj,
+                                                DATADIR_GET,
+                                                &penumFormatetc )))
+    {
+      HANDLE_ERROR( hr );
+    }
+      
+    while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
+    {
+      if ( rgelt.tymed == TYMED_HGLOBAL )
+      {
+        CHAR szFmtName[80];
+        dprintf(("OleSetClipboard(cfFormat=%d:%s)\n", rgelt.cfFormat,
+              GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
+                ? szFmtName : ""));
+  
+        SetClipboardData( rgelt.cfFormat, (HANDLE)NULL);
+      }
+    }
+    IEnumFORMATETC_Release(penumFormatetc);
+  }
+
+  /*
+   * Windows additionally creates a new "DataObject" clipboard format
+   * and stores in on the clipboard. We could possibly store a pointer 
+   * to our internal IDataObject interface on the clipboard. I'm not
+   * sure what the use of this is though.
+   * Enable the code below for this functionality.
+   */
+/*
+   theOleClipboard->cfDataObj = RegisterClipboardFormatA("DataObject");
+   hDataObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
+                             sizeof(OLEClipbrd *));
+   if (hDataObject==0)
+     HANDLE_ERROR( E_OUTOFMEMORY );
+   
+   ppDataObject = (OLEClipbrd**)GlobalLock(hDataObject);
+   *ppDataObject = theOleClipboard;
+   GlobalUnlock(hDataObject);
+
+   if ( !SetClipboardData( theOleClipboard->cfDataObj, hDataObject ) )
+     HANDLE_ERROR( CLIPBRD_E_CANT_SET );
+*/
+  
+  hr = S_OK;
+
+CLEANUP:
+
+  /*
+   * Close Windows clipboard (It remains associated with our window)
+   */
+  if ( bClipboardOpen && !CloseClipboard() )
+    hr = CLIPBRD_E_CANT_CLOSE;
+
+  /*
+   * Release the source IDataObject if something failed
+   */
+  if ( FAILED(hr) )
+  {
+    if (theOleClipboard->pIDataObjectSrc)
+    {
+      IDataObject_Release(theOleClipboard->pIDataObjectSrc);
+      theOleClipboard->pIDataObjectSrc = NULL;
+    }
+  }
+
+  return hr;
+}
+
+
+/***********************************************************************
+ * OleGetClipboard32 [OLE32.105]
+ * Returns a pointer to our internal IDataObject which represents the conceptual 
+ * state of the Windows clipboard. If the current clipboard already contains 
+ * an IDataObject, our internal IDataObject will delegate to this object.
+ */
+HRESULT WIN32API OleGetClipboard(IDataObject** ppDataObj)
+{
+    dprintf(("OLE32: OleGetClipboard"));
+
+  HRESULT hr = S_OK;
+    
+  /*
+   * Make sure we have a clipboard object
+   */
+  OLEClipbrd_Initialize();
+
+  if (!theOleClipboard)
+    return E_OUTOFMEMORY;
+
+  /* Return a reference counted IDataObject */
+  hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl1),
+                                   &IID_IDataObject,  (void**)ppDataObj);
+  return hr;
+}
+
+/******************************************************************************
+ *              OleFlushClipboard        [OLE32.103]
+ *  Renders the data from the source IDataObject into the windows clipboard
+ *
+ *  TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media
+ *  by copying the storage into global memory. Subsequently the default
+ *  data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL
+ *  back to TYMED_IStorage.
+ */
+HRESULT WIN32API OleFlushClipboard()
+{
+    dprintf(("OLE32: OleFlushClipboard"));
+
+  IEnumFORMATETC* penumFormatetc = NULL;
+  FORMATETC rgelt;
+  HRESULT hr = S_OK;
+  BOOL bClipboardOpen = FALSE;
+  
+
+  /*
+   * Make sure we have a clipboard object
+   */
+  OLEClipbrd_Initialize();
+
+  /*
+   * Already flushed or no source DataObject? Nothing to do.
+   */
+  if (!theOleClipboard->pIDataObjectSrc)
+    return S_OK;
+
+  /*
+   * Open the Windows clipboard
+   */
+  if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) )
+    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
+
+  /*
+   * Empty the current clipboard
+   */
+  if ( !EmptyClipboard() )
+    HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY );
+
+  /*
+   * Render all HGLOBAL formats supported by the source into
+   * the windows clipboard.
+   */
+  if ( FAILED( hr = IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl1),
+                                               DATADIR_GET,
+                                               &penumFormatetc) ))
+  {
+    HANDLE_ERROR( hr );
+  }
+
+  while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
+  {
+    if ( rgelt.tymed == TYMED_HGLOBAL )
+    {
+      CHAR szFmtName[80];
+      dprintf(("OleFlushClipboard(cfFormat=%d:%s)\n", rgelt.cfFormat,
+            GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1)
+              ? szFmtName : ""));
+
+      /*
+       * Render the clipboard data
+       */
+      if ( FAILED(OLEClipbrd_RenderFormat( &rgelt )) )
+        continue;
+    }
+  }
+  
+  IEnumFORMATETC_Release(penumFormatetc);
+  
+  /*
+   * Release the data object we are holding on to
+   */
+  if ( theOleClipboard->pIDataObjectSrc )
+  {
+    IDataObject_Release(theOleClipboard->pIDataObjectSrc);
+    theOleClipboard->pIDataObjectSrc = NULL;
+  }
+
+CLEANUP:
+
+  /*
+   * Close Windows clipboard (It remains associated with our window)
+   */
+  if ( bClipboardOpen && !CloseClipboard() )
+    hr = CLIPBRD_E_CANT_CLOSE;
+
+  return hr;
+}
+
+
+/***********************************************************************
+ *           OleIsCurrentClipboard32 [OLE32.110]
+ */
+HRESULT WIN32API OleIsCurrentClipboard (  IDataObject *pDataObject) 
+{
+    dprintf(("OLE32: OleIsCurrentClipboard"));
+  /*
+   * Make sure we have a clipboard object
+   */
+  OLEClipbrd_Initialize();
+
+  if (!theOleClipboard)
+    return E_OUTOFMEMORY;
+
+  return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE;
+}
+
+
+/*---------------------------------------------------------------------*
+ *           Internal implementation methods for the OLE clipboard 
+ *---------------------------------------------------------------------*/
+
+/***********************************************************************
+ * OLEClipbrd_Initialize()
+ * Initializes the OLE clipboard. 
+ */
+void OLEClipbrd_Initialize()
+{
+    dprintf(("OLE32: OLEClipbrd_Initialize"));
+  /*
+   * Create the clipboard if necesary 
+   */
+  if ( !theOleClipboard )
+  {
+    theOleClipboard = OLEClipbrd_Construct();
+  }
+}
+
+
+/***********************************************************************
+ * OLEClipbrd_UnInitialize()
+ * Un-Initializes the OLE clipboard 
+ */
+void OLEClipbrd_UnInitialize()
+{
+    dprintf(("OLE32: OLEClipbrd_UnInitialize"));
+
+  /*
+   * Destroy the clipboard if no one holds a reference to us.
+   * Note that the clipboard was created with a reference count of 1.
+   */
+  if ( theOleClipboard && (theOleClipboard->ref <= 1) )
+  {
+    OLEClipbrd_Destroy( theOleClipboard );
+  }
+  else
+  {
+    dprintf(( "OLE32: Warning : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n"));
+  }
+}
+
+
+/*********************************************************
+ * Construct the OLEClipbrd class.
+ */
+static OLEClipbrd* OLEClipbrd_Construct()
+{
+    dprintf(("OLE32: OLEClipbrd_Construct"));
+
+  OLEClipbrd* newObject = NULL;
+  HGLOBAL hNewObject = 0;
+  
+  /*
+   * Allocate space for the object. We use GlobalAlloc since we need
+   * an HGLOBAL to expose our DataObject as a registered clipboard type.
+   */
+  hNewObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT,
+                           sizeof(OLEClipbrd));
+  if (hNewObject==0)
+    return NULL;
+
+  /*
+   * Lock the handle for the entire lifetime of the clipboard.
+   */
+  newObject = (OLEClipbrd *)GlobalLock(hNewObject);
+  
+  /*
+   * Initialize the virtual function table.
+   */
+  newObject->lpvtbl1 = &OLEClipbrd_IDataObject_VTable;
+
+  /*
+   * Start with one reference count. The caller of this function 
+   * must release the interface pointer when it is done.
+   */
+  newObject->ref = 1;
+
+  newObject->hSelf = hNewObject;
+  
+  /*
+   * The Ole clipboard is a singleton - save the global handle and pointer
+   */
+  theOleClipboard = newObject;
+  hTheOleClipboard = hNewObject;
+
+  return theOleClipboard;
+}
+
+static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy)
+{
+    dprintf(("OLE32: OLEClipbrd_Destroy"));
+    
+  if ( !ptrToDestroy )
+    return;
+
+  /*
+   * Destroy the Ole clipboard window 
+   */
+  if ( ptrToDestroy->hWndClipboard )
+    OLEClipbrd_DestroyWindow(ptrToDestroy->hWndClipboard);
+
+  /*
+   * Free the actual OLE Clipboard structure.
+   */
+    dprintf(("OLE32: Destroying clipboard data object."));
+  GlobalUnlock(ptrToDestroy->hSelf);
+  GlobalFree(ptrToDestroy->hSelf);
+
+  /*
+   * The Ole clipboard is a singleton (ptrToDestroy == theOleClipboard)
+   */
+  theOleClipboard = NULL;
+  hTheOleClipboard = 0;
+}
+
+
+/***********************************************************************
+ * OLEClipbrd_CreateWindow()
+ * Create the clipboard window 
+ */
+static HWND OLEClipbrd_CreateWindow()
+{
+    dprintf(("OLE32: OLEClipbrd_CreateWindow"));
+
+  HWND hwnd = 0;
+  WNDCLASSEXA wcex;
+  ATOM atom;
+
+  /* 
+   * Register the clipboard window class if necessary 
+   */
+
+//  if ( !( atom = GlobalFindAtomA(OLEClipbrd_WNDCLASS) ) || !( CLASS_FindClassByAtom(atom, 0) ) )
+//  if ( !( atom = GlobalFindAtomA(OLEClipbrd_WNDCLASS) ) )
+//  {
+    ZeroMemory( &wcex, sizeof(WNDCLASSEXA));
+
+    wcex.cbSize         = sizeof(WNDCLASSEXA);
+    /* Windows creates this class with a style mask of 0
+     * We dont bother doing this since the FindClassByAtom code
+     * would have to be changed to deal with this idiosyncracy. */
+    wcex.style          = CS_GLOBALCLASS;
+    wcex.lpfnWndProc    = (WNDPROC)OLEClipbrd_WndProc;
+    wcex.hInstance      = 0;
+    wcex.lpszClassName  = OLEClipbrd_WNDCLASS;
+
+    RegisterClassExA(&wcex);
+//  }
+
+  /*
+   * Create a hidden window to receive OLE clipboard messages 
+   */
+
+/*
+ *  If we need to store state info we can store it here.
+ *  For now we dont need this functionality.
+ *   ClipboardWindowInfo clipboardInfo;
+ *   ZeroMemory( &trackerInfo, sizeof(ClipboardWindowInfo));
+ */
+
+  hwnd = CreateWindowA(OLEClipbrd_WNDCLASS, 
+				    "ClipboardWindow",
+				    WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED,
+				    CW_USEDEFAULT, CW_USEDEFAULT,
+				    CW_USEDEFAULT, CW_USEDEFAULT,
+				    0,
+				    0,
+				    0,
+				    0 /*(LPVOID)&clipboardInfo */);
+
+  return hwnd;
+}
+
+/***********************************************************************
+ * OLEClipbrd_DestroyWindow(HWND)
+ * Destroy the clipboard window and unregister its class
+ */
+static void OLEClipbrd_DestroyWindow(HWND hwnd)
+{
+    dprintf(("OLE32: OLEClipbrd_DestroyWindow"));
+  /* 
+   * Destroy clipboard window and unregister its WNDCLASS 
+   */
+  DestroyWindow(hwnd);
+  UnregisterClassA( OLEClipbrd_WNDCLASS, 0 );
+}
+
+/***********************************************************************
+ * OLEClipbrd_WndProc(HWND, unsigned, WORD, LONG)
+ * Processes messages sent to the OLE clipboard window. 
+ * Note that we will intercept messages in our WndProc only when data 
+ * has been placed in the clipboard via OleSetClipboard(). 
+ * i.e. Only when OLE owns the windows clipboard.
+ */
+LRESULT CALLBACK OLEClipbrd_WndProc
+  (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+  switch (message) 
+  {
+    /*
+     * WM_RENDERFORMAT 
+     * We receive this message to allow us to handle delayed rendering of
+     * a specific clipboard format when an application requests data in 
+     * that format by calling GetClipboardData.
+     * (Recall that in OleSetClipboard, we used SetClipboardData to 
+     * make all HGLOBAL formats supported by the source IDataObject
+     * available using delayed rendering)
+     * On receiving this mesage we must actually render the data in the 
+     * specified format and place it on the clipboard by calling the 
+     * SetClipboardData function. 
+     */
+    case WM_RENDERFORMAT:
+    {
+      FORMATETC rgelt;
+        
+      ZeroMemory( &rgelt, sizeof(FORMATETC));
+
+      /*
+       * Initialize FORMATETC to a Windows clipboard friendly format
+       */
+      rgelt.cfFormat = (UINT) wParam;
+      rgelt.dwAspect = DVASPECT_CONTENT;
+      rgelt.lindex = -1;
+      rgelt.tymed = TYMED_HGLOBAL;
+
+      dprintf(("OLE32: OLEClipbrd_WndProc - WM_RENDERFORMAT(cfFormat=%d)\n", rgelt.cfFormat));
+      
+      /*
+       * Render the clipboard data.
+       * (We must have a source data object or we wouldn't be in this WndProc)
+       */
+      OLEClipbrd_RenderFormat( &rgelt );
+
+      break;
+    }
+
+    /*
+     * WM_RENDERALLFORMATS
+     * Sent before the clipboard owner window is destroyed.
+     * We should receive this message only when OleUninitialize is called
+     * while we have an IDataObject in the clipboard.
+     * For the content of the clipboard to remain available to other
+     * applications, we must render data in all the formats the source IDataObject
+     * is capable of generating, and place the data on the clipboard by calling
+     * SetClipboardData.
+     */
+    case WM_RENDERALLFORMATS:
+    {
+      IEnumFORMATETC* penumFormatetc = NULL;
+      FORMATETC rgelt;
+      
+      dprintf(("OLE32: OLEClipbrd_WndProc - WM_RENDERALLFORMATS\n"));
+      
+      /*
+       * Render all HGLOBAL formats supported by the source into
+       * the windows clipboard.
+       */
+      if ( FAILED( IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl1),
+                                 DATADIR_GET, &penumFormatetc) ) )
+      {
+        dprintf(("OLE32: Warning: WM_RENDERALLFORMATS failed to retrieve EnumFormatEtc!\n"));
+        return 0;
+      }
+      
+      while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) )
+      {
+        if ( rgelt.tymed == TYMED_HGLOBAL )
+        {
+          /*
+           * Render the clipboard data. 
+           */
+          if ( FAILED(OLEClipbrd_RenderFormat( &rgelt )) )
+            continue;
+        
+          dprintf(("OLE32: OLEClipbrd_WndProc - WM_RENDERALLFORMATS(cfFormat=%d)\n", rgelt.cfFormat));
+        }
+      }
+      
+      IEnumFORMATETC_Release(penumFormatetc);
+
+      break;
+    }
+
+    /*
+     * WM_DESTROYCLIPBOARD
+     * This is sent by EmptyClipboard before the clipboard is emptied.
+     * We should release any IDataObject we are holding onto when we receive
+     * this message, since it indicates that the OLE clipboard should be empty
+     * from this point on.
+     */
+    case WM_DESTROYCLIPBOARD:
+    {
+      dprintf(("OLE32: OLEClipbrd_WndProc - WM_DESTROYCLIPBOARD\n"));
+      /*
+       * Release the data object we are holding on to
+       */
+      if ( theOleClipboard->pIDataObjectSrc )
+      {
+        IDataObject_Release(theOleClipboard->pIDataObjectSrc);
+        theOleClipboard->pIDataObjectSrc = NULL;
+      }
+      break;
+    }
+
+/*
+    case WM_ASKCBFORMATNAME:
+    case WM_CHANGECBCHAIN:
+    case WM_DRAWCLIPBOARD:
+    case WM_SIZECLIPBOARD:
+    case WM_HSCROLLCLIPBOARD:
+    case WM_VSCROLLCLIPBOARD:
+    case WM_PAINTCLIPBOARD:
+*/
+    default:
+      return DefWindowProcA(hWnd, message, wParam, lParam);
+  }
+
+  return 0;
+}
+
+
+/***********************************************************************
+ * OLEClipbrd_RenderFormat(LPFORMATETC)
+ * Render the clipboard data. Note that this call will delegate to the
+ * source data object.
+ * Note: This function assumes it is passed an HGLOBAL format to render.
+ */
+static HRESULT OLEClipbrd_RenderFormat(LPFORMATETC pFormatetc)
+{
+  STGMEDIUM medium;
+  HGLOBAL hDup;
+  HRESULT hr = S_OK;
+  
+  if ( FAILED(hr = IDataObject_GetData((IDataObject*)&(theOleClipboard->lpvtbl1),
+                                       pFormatetc, &medium)) )
+  {
+    dprintf(("OLE32: Warning : IDataObject_GetData failed to render clipboard data! (%lx)\n", hr));
+    return hr;
+  }
+
+  /*
+   *  Put a copy of the rendered data back on the clipboard
+   */
+  
+  if ( !(hDup = OLEClipbrd_GlobalDupMem(medium.u.hGlobal)) )
+    HANDLE_ERROR( E_OUTOFMEMORY );
+       
+  if ( !SetClipboardData( pFormatetc->cfFormat, hDup ) )
+  {
+    GlobalFree(hDup);
+    dprintf(("OLE32: Warning : Failed to set rendered clipboard data into clipboard!\n"));
+  }
+
+CLEANUP:
+  
+  ReleaseStgMedium(&medium);
+  
+  return hr;
+}
+
+
+/***********************************************************************
+ * OLEClipbrd_GlobalDupMem( HGLOBAL )
+ * Helper method to duplicate an HGLOBAL chunk of memory
+ */
+static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc )
+{
+    HGLOBAL hGlobalDest;
+    PVOID pGlobalSrc, pGlobalDest;
+    DWORD cBytes;
+    
+    if ( !hGlobalSrc )
+      return 0;
+
+    cBytes = GlobalSize(hGlobalSrc);
+    if ( 0 == cBytes )
+      return 0;
+        
+    hGlobalDest = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE,
+                               cBytes );
+    if ( !hGlobalDest )
+      return 0;
+    
+    pGlobalSrc = GlobalLock(hGlobalSrc);
+    pGlobalDest = GlobalLock(hGlobalDest);
+    if ( !pGlobalSrc || !pGlobalDest )
+      return 0;
+
+    memcpy(pGlobalDest, pGlobalSrc, cBytes);
+        
+    GlobalUnlock(hGlobalSrc);
+    GlobalUnlock(hGlobalDest);
+
+    return hGlobalDest;
+}
+
+
+/*---------------------------------------------------------------------*
+ *  Implementation of the internal IDataObject interface exposed by 
+ *  the OLE clipboard.
+ *---------------------------------------------------------------------*/
+
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IDataObject_QueryInterface(
+            IDataObject*     iface,
+            REFIID           riid,
+            void**           ppvObject)
+{
+  /* 
+   * Declare "This" pointer 
+   */
+  ICOM_THIS(OLEClipbrd, iface);
+  char    xriid[50];
+
+  WINE_StringFromCLSID((LPCLSID)riid,xriid);
+  dprintf(("OLE32: OLEClipbrd_IDataObject_QueryInterface(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObject));
+  
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppvObject==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = iface;
+  }
+  else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) 
+  {
+    *ppvObject = (IDataObject*)&(This->lpvtbl1);
+  }
+  else  /* We only support IUnknown and IDataObject */
+  {
+    char clsid[50];
+
+    WINE_StringFromCLSID((LPCLSID)riid,clsid);
+    dprintf(( "OLE32: Warning : asking for unsupported interface %s\n", clsid));
+
+    return E_NOINTERFACE;
+  }
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful. 
+   */
+  IUnknown_AddRef((IUnknown*)*ppvObject);
+
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WIN32API OLEClipbrd_IDataObject_AddRef( 
+            IDataObject*     iface)
+{
+  /* 
+   * Declare "This" pointer 
+   */
+  ICOM_THIS(OLEClipbrd, iface);
+
+  dprintf(("OLE32: OLEClipbrd_IDataObject_AddRef(%p)->(count=%lu)\n",This, This->ref));
+
+  This->ref++;
+
+  return This->ref;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WIN32API OLEClipbrd_IDataObject_Release( 
+            IDataObject*     iface)
+{
+  /* 
+   * Declare "This" pointer 
+   */
+  ICOM_THIS(OLEClipbrd, iface);
+
+  dprintf(("OLE32: OLEClipbrd_IDataObject_Release(%p)->(count=%lu)\n",This, This->ref));
+  
+  /*
+   * Decrease the reference count on this object.
+   */
+  This->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (This->ref==0)
+  {
+    OLEClipbrd_Destroy(This);
+  }
+  
+  return This->ref;
+}
+
+ 
+/************************************************************************
+ * OLEClipbrd_IDataObject_GetData (IDataObject)
+ *
+ * The OLE Clipboard's implementation of this method delegates to 
+ * a data source if there is one or wraps around the windows clipboard
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IDataObject_GetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetcIn, 
+	    STGMEDIUM*       pmedium)
+{
+  HANDLE      hData = 0;
+  /*
+   * Declare "This" pointer 
+   */
+  ICOM_THIS(OLEClipbrd, iface);
+
+  if ( !pformatetcIn || !pformatetcIn || !pmedium )
+    return E_INVALIDARG;
+
+  dprintf(("OLE32: OLEClipbrd_IDataObject_GetData(%p, %p)\n", iface, pformatetcIn));
+
+  /*
+   * If we have a data source placed on the clipboard (via OleSetClipboard)
+   * simply delegate to the source object's QueryGetData
+   * NOTE: This code assumes that the IDataObject is in the same address space!
+   * We will need to add marshalling support when Wine handles multiple processes.
+   */
+  if ( This->pIDataObjectSrc )
+  {
+    return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium);
+  }
+
+  if ( pformatetcIn->lindex != -1 )
+    return DV_E_LINDEX;
+  if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL )
+    return DV_E_TYMED;
+/*
+   if ( pformatetcIn->dwAspect != DVASPECT_CONTENT )
+     return DV_E_DVASPECT;
+*/
+
+  /* 
+   * Otherwise, delegate to the Windows clipboard function GetClipboardData
+   */
+  hData = GetClipboardData(pformatetcIn->cfFormat);
+
+  /* 
+   * Return the clipboard data in the storage medium structure
+   */
+  pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL;
+  pmedium->u.hGlobal = (HGLOBAL)hData;
+  pmedium->pUnkForRelease = NULL;
+  
+  return (hData == 0) ? DV_E_FORMATETC : S_OK;
+}
+
+static HRESULT WIN32API OLEClipbrd_IDataObject_GetDataHere(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatetc,
+	    STGMEDIUM*       pmedium)
+{
+  dprintf(("OLE32: OLEClipbrd_IDataObject_GetDataHere - stub"));
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_QueryGetData (IDataObject)
+ *
+ * The OLE Clipboard's implementation of this method delegates to 
+ * a data source if there is one or wraps around the windows clipboard
+ * function IsClipboardFormatAvailable() otherwise.
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IDataObject_QueryGetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc)
+{
+  /* 
+   * Declare "This" pointer 
+   */
+  ICOM_THIS(OLEClipbrd, iface);
+
+  dprintf(("OLE32: OLEClipbrd_IDataObject_QueryGetData(%p, %p)\n", iface, pformatetc));
+
+  /*
+   * If we have a data source placed on the clipboard (via OleSetClipboard)
+   * simply delegate to the source object's QueryGetData
+   */
+  if ( This->pIDataObjectSrc )
+  {
+    return IDataObject_QueryGetData(This->pIDataObjectSrc, pformatetc);
+  }
+
+  if (!pformatetc)
+    return E_INVALIDARG;
+/*
+   if ( pformatetc->dwAspect != DVASPECT_CONTENT )
+     return DV_E_DVASPECT;
+*/
+  if ( pformatetc->lindex != -1 )
+    return DV_E_LINDEX;
+
+  /* TODO: Handle TYMED_IStorage media which were put on the clipboard
+   * by copying the storage into global memory. We must convert this
+   * TYMED_HGLOBAL back to TYMED_IStorage.
+   */
+  if ( pformatetc->tymed != TYMED_HGLOBAL )
+    return DV_E_TYMED;
+          
+  /*
+   * Delegate to the Windows clipboard function IsClipboardFormatAvailable
+   */
+  return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_FORMATETC;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject)
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IDataObject_GetCanonicalFormatEtc(
+	    IDataObject*     iface, 
+	    LPFORMATETC      pformatectIn, 
+	    LPFORMATETC      pformatetcOut)
+{
+  dprintf(("OLE32: OLEClipbrd_IDataObject_GetCanonicalFormatEtc(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut));
+
+  if ( !pformatectIn || !pformatetcOut )
+    return E_INVALIDARG;
+
+  memcpy(pformatetcOut, pformatectIn, sizeof(FORMATETC));
+  return DATA_S_SAMEFORMATETC;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_SetData (IDataObject)
+ *
+ * The OLE Clipboard's does not implement this method 
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IDataObject_SetData(
+	    IDataObject*     iface,
+	    LPFORMATETC      pformatetc, 
+	    STGMEDIUM*       pmedium, 
+	    BOOL             fRelease)
+{
+  dprintf(("OLE32: OLEClipbrd_IDataObject_SetData - stub"));
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject)
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IDataObject_EnumFormatEtc(
+	    IDataObject*     iface,
+	    DWORD            dwDirection,
+	    IEnumFORMATETC** ppenumFormatEtc)
+{
+  HRESULT hr = S_OK;
+  FORMATETC *afmt = NULL;
+  int cfmt, i;
+  UINT format;
+  BOOL bClipboardOpen;
+  
+  /* 
+   * Declare "This" pointer 
+   */
+  ICOM_THIS(OLEClipbrd, iface);
+
+  dprintf(("OLE32: OLEClipbrd_IDataObject_EnumFormatEtc(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc));
+
+  /*
+   * If we have a data source placed on the clipboard (via OleSetClipboard)
+   * simply delegate to the source object's EnumFormatEtc
+   */
+  if ( This->pIDataObjectSrc )
+  {
+    return IDataObject_EnumFormatEtc(This->pIDataObjectSrc,
+                                     dwDirection, ppenumFormatEtc);
+  }
+
+  /*
+   * Otherwise we must provide our own enumerator which wraps around the
+   * Windows clipboard function EnumClipboardFormats
+   */
+  if ( !ppenumFormatEtc )
+    return E_INVALIDARG;
+
+  if ( dwDirection != DATADIR_GET ) /* IDataObject_SetData not implemented */
+    return E_NOTIMPL;
+
+  /*
+   * Store all current clipboard formats in an array of FORMATETC's,
+   * and create an IEnumFORMATETC enumerator from this list.
+   */
+  cfmt = CountClipboardFormats();
+  afmt = (FORMATETC *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                sizeof(FORMATETC) * cfmt);
+  /*
+   * Open the Windows clipboard, associating it with our hidden window
+   */
+  if ( !(bClipboardOpen = OpenClipboard(This->hWndClipboard)) )
+    HANDLE_ERROR( CLIPBRD_E_CANT_OPEN );
+
+  /*
+   * Store all current clipboard formats in an array of FORMATETC's
+   * TODO: Handle TYMED_IStorage media which were put on the clipboard
+   * by copying the storage into global memory. We must convert this
+   * TYMED_HGLOBAL back to TYMED_IStorage.
+   */
+  for (i = 0, format = 0; i < cfmt; i++)
+  {
+    format = EnumClipboardFormats(format);
+    if (!format)  /* Failed! */
+    {
+      dprintf(("OLE32: Error: EnumClipboardFormats failed to return format!"));
+      HANDLE_ERROR( E_FAIL );
+    }
+    
+    /* Init the FORMATETC struct */
+    afmt[i].cfFormat = format;
+    afmt[i].ptd = NULL;
+    afmt[i].dwAspect = DVASPECT_CONTENT;
+    afmt[i].lindex = -1;
+    afmt[i].tymed = TYMED_HGLOBAL;
+  }
+
+  /*
+   * Create an EnumFORMATETC enumerator and return an
+   * EnumFORMATETC after bumping up its ref count
+   */
+  *ppenumFormatEtc = OLEClipbrd_IEnumFORMATETC_Construct( cfmt, afmt, (LPUNKNOWN)iface);
+  if (!(*ppenumFormatEtc))
+    HANDLE_ERROR( E_OUTOFMEMORY );
+
+  if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenumFormatEtc)))
+    HANDLE_ERROR( hr );
+      
+  hr = S_OK;
+  
+CLEANUP:
+  /*
+   * Free the array of FORMATETC's
+   */
+  if (afmt)
+    HeapFree(GetProcessHeap(), 0, afmt);
+  
+  /*
+   * Close Windows clipboard
+   */
+  if ( bClipboardOpen && !CloseClipboard() )
+    hr = CLIPBRD_E_CANT_CLOSE;
+
+  return hr;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_DAdvise (IDataObject)
+ *
+ * The OLE Clipboard's does not implement this method 
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IDataObject_DAdvise(
+	    IDataObject*     iface, 
+	    FORMATETC*       pformatetc, 
+	    DWORD            advf, 
+	    IAdviseSink*     pAdvSink, 
+	    DWORD*           pdwConnection)
+{
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_DUnadvise (IDataObject)
+ *
+ * The OLE Clipboard's does not implement this method 
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IDataObject_DUnadvise(
+	    IDataObject*     iface,
+	    DWORD            dwConnection)
+{
+  return E_NOTIMPL;
+}
+
+/************************************************************************
+ * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject)
+ *
+ * The OLE Clipboard does not implement this method
+ *
+ * See Windows documentation for more details on IDataObject methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IDataObject_EnumDAdvise(
+	    IDataObject*     iface,
+	    IEnumSTATDATA**  ppenumAdvise)
+{
+  return E_NOTIMPL;
+}
+
+
+/*---------------------------------------------------------------------*
+ *  Implementation of the internal IEnumFORMATETC interface returned by
+ *  the OLE clipboard's IDataObject.
+ *---------------------------------------------------------------------*/
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Construct (UINT, const FORMATETC, LPUNKNOWN)
+ *
+ * Creates an IEnumFORMATETC enumerator from an array of FORMATETC
+ * Structures. pUnkOuter is the outer unknown for reference counting only.
+ * NOTE: this does not AddRef the interface.
+ */
+
+LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[],
+                                                    LPUNKNOWN pUnkDataObj)
+{
+  IEnumFORMATETCImpl* ef;
+  DWORD size=cfmt * sizeof(FORMATETC);
+  LPMALLOC pIMalloc;
+  
+  ef = (IEnumFORMATETCImpl*)HeapAlloc(GetProcessHeap(),
+                                      HEAP_ZERO_MEMORY,
+                                      sizeof(IEnumFORMATETCImpl));
+  if (!ef)
+    return NULL;
+  
+  ef->ref = 0;
+  ef->lpvtbl = &efvt;
+  ef->pUnkDataObj = pUnkDataObj;
+  
+  ef->posFmt = 0;
+  ef->countFmt = cfmt;
+  if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
+    return NULL;
+  ef->pFmt = (LPFORMATETC)IMalloc_Alloc(pIMalloc, size);
+  IMalloc_Release(pIMalloc);
+  
+  if (ef->pFmt)
+    memcpy(ef->pFmt, afmt, size);
+  
+  dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_Construct(%p)->()\n",ef));
+  return (LPENUMFORMATETC)ef;
+}
+
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WIN32API OLEClipbrd_IEnumFORMATETC_QueryInterface
+  (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj)
+{
+  ICOM_THIS(IEnumFORMATETCImpl,iface);
+  char    xriid[50];
+
+  WINE_StringFromCLSID((LPCLSID)riid,xriid);
+  dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_QueryInterface(%p)->(\n\tIID:\t%s,%p)\n",This,xriid,ppvObj));
+
+  /*
+   * Since enumerators are seperate objects from the parent data object
+   * we only need to support the IUnknown and IEnumFORMATETC interfaces
+   */
+  
+  *ppvObj = NULL;
+  
+  if(IsEqualIID(riid, &IID_IUnknown))
+  {
+    *ppvObj = This;
+  }
+  else if(IsEqualIID(riid, &IID_IEnumFORMATETC))
+  {
+    *ppvObj = (IDataObject*)This;
+  }   
+  
+  if(*ppvObj)
+  {
+    IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj);
+    dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_QueryInterface - Interface: (%p)->(%p)\n",ppvObj,*ppvObj));
+    return S_OK;
+  }
+  
+  dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_QueryInterface - Interface: E_NOINTERFACE\n"));
+  return E_NOINTERFACE;
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown)
+ *
+ * Since enumerating formats only makes sense when our data object is around,
+ * we insure that it stays as long as we stay by calling our parents IUnknown
+ * for AddRef and Release. But since we are not controlled by the lifetime of
+ * the outer object, we still keep our own reference count in order to
+ * free ourselves.
+ */
+static ULONG WIN32API OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface)
+{
+  ICOM_THIS(IEnumFORMATETCImpl,iface);
+  dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_AddRef(%p)->(count=%lu)\n",This, This->ref));
+
+  if (This->pUnkDataObj)
+    IUnknown_AddRef(This->pUnkDataObj);
+  
+  return ++(This->ref);
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WIN32API OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface)
+{
+  ICOM_THIS(IEnumFORMATETCImpl,iface);
+  LPMALLOC pIMalloc;
+
+  dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_Release(%p)->(count=%lu)\n",This, This->ref));
+
+  if (This->pUnkDataObj)
+    IUnknown_Release(This->pUnkDataObj);  /* Release parent data object */
+  
+  if (!--(This->ref)) 
+  {
+    dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_Release() - destroying IEnumFORMATETC(%p)\n",This));
+    if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc)))
+    {
+      IMalloc_Free(pIMalloc, This->pFmt);
+      IMalloc_Release(pIMalloc);
+    }
+      
+    HeapFree(GetProcessHeap(),0,This);
+    return 0;
+  }
+
+  return This->ref;
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC)
+ *
+ * Standard enumerator members for IEnumFORMATETC
+ */
+static HRESULT WIN32API OLEClipbrd_IEnumFORMATETC_Next
+  (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed)
+{
+  ICOM_THIS(IEnumFORMATETCImpl,iface);
+  UINT cfetch;
+  HRESULT hres = S_FALSE;
+  
+  dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_Next(%p)->(pos=%u)\n", This, This->posFmt));
+  
+  if (This->posFmt < This->countFmt)
+  {
+    cfetch = This->countFmt - This->posFmt;
+    if (cfetch >= celt)
+    {
+      cfetch = celt;
+      hres = S_OK;
+    }
+    
+    memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC));
+    This->posFmt += cfetch;
+  }
+  else
+  {
+    cfetch = 0;
+  }
+  
+  if (pceltFethed)
+  {
+    *pceltFethed = cfetch;
+  }
+  
+  return hres;
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC)
+ *
+ * Standard enumerator members for IEnumFORMATETC
+ */
+static HRESULT WIN32API OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt)
+{
+  ICOM_THIS(IEnumFORMATETCImpl,iface);
+  dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_Skip(%p)->(num=%lu)\n", This, celt));
+  
+  This->posFmt += celt;
+  if (This->posFmt > This->countFmt)
+  {
+    This->posFmt = This->countFmt;
+    return S_FALSE;
+  }
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC)
+ *
+ * Standard enumerator members for IEnumFORMATETC
+ */
+static HRESULT WIN32API OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface)
+{
+  ICOM_THIS(IEnumFORMATETCImpl,iface);
+  dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_Reset(%p)->()\n", This));
+  
+  This->posFmt = 0;
+  return S_OK;
+}
+
+/************************************************************************
+ * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC)
+ *
+ * Standard enumerator members for IEnumFORMATETC
+ */
+static HRESULT WIN32API OLEClipbrd_IEnumFORMATETC_Clone
+  (LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum)
+{
+  ICOM_THIS(IEnumFORMATETCImpl,iface);
+  HRESULT hr = S_OK;
+  
+  dprintf(("OLE32: OLEClipbrd_IEnumFORMATETC_Clone(%p)->(ppenum=%p)\n", This, ppenum));
+
+  if ( !ppenum )
+    return E_INVALIDARG;
+
+  *ppenum = OLEClipbrd_IEnumFORMATETC_Construct(This->countFmt,
+                                                This->pFmt,
+                                                This->pUnkDataObj);
+
+  if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenum)))
+    return ( hr );
+  
+  return (*ppenum) ? S_OK : E_OUTOFMEMORY;
+}
+
Index: trunk/src/ole32/new/oleDrag.cpp
===================================================================
--- trunk/src/ole32/new/oleDrag.cpp	(revision 3456)
+++ trunk/src/ole32/new/oleDrag.cpp	(revision 3456)
@@ -0,0 +1,781 @@
+/* $Id: oleDrag.cpp,v 1.1 2000-04-27 22:18:28 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * OLE Drag Drop functions.
+ * 
+ * 5/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ *
+ * Some portions from Wine Implementation (2/9/99)
+ *   Copyright 1995  Martin von Loewis
+ *   Copyright 1999  Francis Beaudet
+ *   Copyright 1999  Noel Borthwick 
+ */
+
+#include "ole32.h"
+#include "commctrl.h"
+#include "oString.h"
+#include <assert.h>
+
+// ======================================================================
+// Local Data
+// ======================================================================
+
+typedef struct tagDropTargetNode
+{
+    HWND			hwndTarget;
+    IDropTarget *		dropTarget;
+    struct tagDropTargetNode *	prevDropTarget;
+    struct tagDropTargetNode *	nextDropTarget;
+} DropTargetNode;
+
+typedef struct tagTrackerWindowInfo
+{
+    IDataObject *		dataObject;
+    IDropSource *		dropSource;
+    DWORD       		dwOKEffect;
+    DWORD*      		pdwEffect;
+    BOOL      			trackingDone;
+    HRESULT     		returnValue;
+
+    BOOL      			escPressed;
+    HWND      			curDragTargetHWND;
+    IDropTarget *		curDragTarget;
+} TrackerWindowInfo;
+
+/*
+ * Name of our registered window class.
+ */
+static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32";
+
+/*
+ * This is the head of the Drop target container.
+ */
+static DropTargetNode * targetListHead = NULL;
+
+// ======================================================================
+// Prototypes.
+// ======================================================================
+
+extern void            OLEDD_Initialize();
+extern void            OLEDD_UnInitialize();
+static void            OLEDD_InsertDropTarget(
+			 DropTargetNode* nodeToAdd);
+static DropTargetNode* OLEDD_ExtractDropTarget(
+                         HWND hwndOfTarget);
+static DropTargetNode* OLEDD_FindDropTarget(
+                         HWND hwndOfTarget);
+static LRESULT WIN32API  OLEDD_DragTrackerWindowProc(
+			 HWND   hwnd, 
+			 UINT   uMsg,
+			 WPARAM wParam, 
+			 LPARAM   lParam);
+static void OLEDD_TrackMouseMove(
+                         TrackerWindowInfo* trackerInfo,
+			 POINT            mousePos,
+			 DWORD              keyState);
+static void OLEDD_TrackStateChange(
+                         TrackerWindowInfo* trackerInfo,
+			 POINT            mousePos,
+			 DWORD              keyState);
+static DWORD OLEDD_GetButtonState();
+
+// ======================================================================
+// Public API's
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// RegisterDragDrop()
+// ----------------------------------------------------------------------
+HRESULT WIN32API RegisterDragDrop
+   (HWND		hwnd,
+    LPDROPTARGET	pDropTarget)
+{
+    dprintf(("OLE32: RegisterDragDrop"));
+
+    DropTargetNode *	dropTargetInfo;
+
+    // First, check if the window is already registered.
+    dropTargetInfo = OLEDD_FindDropTarget(hwnd);
+    if (dropTargetInfo != NULL)
+	return DRAGDROP_E_ALREADYREGISTERED;
+
+    // If it's not there, we can add it. We first create a node for it.
+    dropTargetInfo = (DropTargetNode *)HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode));
+
+    if (dropTargetInfo == NULL)
+	return E_OUTOFMEMORY;
+
+    dropTargetInfo->hwndTarget     = hwnd;
+    dropTargetInfo->prevDropTarget = NULL;
+    dropTargetInfo->nextDropTarget = NULL;
+
+    // Don't forget that this is an interface pointer, need to nail it down since
+    // we keep a copy of it.
+    dropTargetInfo->dropTarget  = pDropTarget;
+    IDropTarget_AddRef(dropTargetInfo->dropTarget);
+
+    OLEDD_InsertDropTarget(dropTargetInfo);
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// RevokeDragDrop()
+// ----------------------------------------------------------------------
+HRESULT WIN32API RevokeDragDrop
+    (HWND		hwnd)
+{
+    dprintf(("OLE32: RevokeDragDrop"));
+
+    DropTargetNode *	dropTargetInfo;
+
+    // First, check if the window is already registered.
+    dropTargetInfo = OLEDD_ExtractDropTarget(hwnd);
+    if (dropTargetInfo == NULL)
+	return DRAGDROP_E_NOTREGISTERED;
+
+    // If it's in there, clean-up it's used memory and references
+    IDropTarget_Release(dropTargetInfo->dropTarget);
+    HeapFree(GetProcessHeap(), 0, dropTargetInfo);  
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// DoDragDrop()
+// ----------------------------------------------------------------------
+HRESULT WIN32API DoDragDrop
+   (IDataObject *	pDataObject,  // ptr to the data obj
+    IDropSource *	pDropSource,  // ptr to the source obj
+    DWORD       	dwOKEffect,   // effects allowed by the source
+    DWORD *		pdwEffect)    // ptr to effects of the source
+{
+    dprintf(("OLE32: DoDragDrop"));
+
+    TrackerWindowInfo 	trackerInfo;
+    HWND            	hwndTrackWindow;
+    MSG             	msg;
+
+    // Setup the drag n drop tracking window.
+    trackerInfo.dataObject        = pDataObject;
+    trackerInfo.dropSource        = pDropSource;
+    trackerInfo.dwOKEffect        = dwOKEffect;
+    trackerInfo.pdwEffect         = pdwEffect;
+    trackerInfo.trackingDone      = FALSE;
+    trackerInfo.escPressed        = FALSE;
+    trackerInfo.curDragTargetHWND = 0;
+    trackerInfo.curDragTarget     = 0;
+
+    hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS,
+				    "TrackerWindow",
+				    WS_POPUP,
+				    CW_USEDEFAULT, CW_USEDEFAULT,
+				    CW_USEDEFAULT, CW_USEDEFAULT,
+				    0,
+				    0,
+				    0,
+				    (LPVOID)&trackerInfo);
+
+    if (hwndTrackWindow != 0)
+    {
+	// Capture the mouse input
+	SetCapture(hwndTrackWindow);
+
+	// Pump messages. All mouse input should go the the capture window.
+	while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) )
+	{
+	    if ( (msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYFIRST) )
+	    {
+		// When keyboard messages are sent to windows on this thread, we
+		// want to ignore notify the drop source that the state changed.
+		// in the case of the Escape key, we also notify the drop source
+		// we give it a special meaning.
+		if ( (msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE) )
+		    trackerInfo.escPressed = TRUE;
+
+		// Notify the drop source.
+		OLEDD_TrackStateChange(&trackerInfo, msg.pt, OLEDD_GetButtonState());
+	    }
+	    else
+	    {
+		// Dispatch the messages only when it's not a keyboard message.
+		DispatchMessageA(&msg);
+	    }
+	}
+
+	// Destroy the temporary window.
+	DestroyWindow(hwndTrackWindow);
+
+	return trackerInfo.returnValue;
+    }
+
+    return E_FAIL;
+}
+
+// ----------------------------------------------------------------------
+// OLEDD_Initialize()
+// ----------------------------------------------------------------------
+extern void OLEDD_Initialize()
+{
+    dprintf(("OLE32: OLEDD_Initialize"));
+
+    WNDCLASSA wndClass;
+
+    ZeroMemory (&wndClass, sizeof(WNDCLASSA));
+    wndClass.style         = CS_GLOBALCLASS;
+    wndClass.lpfnWndProc   = (WNDPROC)OLEDD_DragTrackerWindowProc;
+    wndClass.cbClsExtra    = 0;
+    wndClass.cbWndExtra    = sizeof(TrackerWindowInfo*);
+    wndClass.hCursor       = 0;
+    wndClass.hbrBackground = 0;
+    wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS;
+ 
+    RegisterClassA (&wndClass);
+}
+
+// ----------------------------------------------------------------------
+// OLEDD_UnInitialize()
+// ----------------------------------------------------------------------
+extern void OLEDD_UnInitialize()
+{
+    dprintf(("OLE32: OLEDD_UnInitialize"));
+
+    // Simply empty the list.
+    while (targetListHead!=NULL)
+    {
+	RevokeDragDrop(targetListHead->hwndTarget);
+    }
+}
+
+// ======================================================================
+// Private functions.
+// ======================================================================
+
+/***
+ * OLEDD_InsertDropTarget()
+ *
+ * Insert the target node in the tree.
+ */
+static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd)
+{
+  DropTargetNode*  curNode;
+  DropTargetNode** parentNodeLink;
+
+  /*
+   * Iterate the tree to find the insertion point.
+   */
+  curNode        = targetListHead;
+  parentNodeLink = &targetListHead;
+
+  while (curNode!=NULL)
+  {
+    if (nodeToAdd->hwndTarget<curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a smaller HWND, go left
+       */
+      parentNodeLink = &curNode->prevDropTarget;
+      curNode        =  curNode->prevDropTarget;
+    }
+    else if (nodeToAdd->hwndTarget>curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a larger HWND, go right
+       */
+      parentNodeLink = &curNode->nextDropTarget;
+      curNode        =  curNode->nextDropTarget;
+    }
+    else
+    {
+      /*
+       * The item was found in the list. It shouldn't have been there
+       */
+      assert(FALSE);
+      return;
+    }
+  }
+
+  /*
+   * If we get here, we have found a spot for our item. The parentNodeLink
+   * pointer points to the pointer that we have to modify. 
+   * The curNode should be NULL. We just have to establish the link and Voila!
+   */
+  assert(curNode==NULL);
+  assert(parentNodeLink!=NULL);
+  assert(*parentNodeLink==NULL);
+
+  *parentNodeLink=nodeToAdd;
+}
+
+/***
+ * OLEDD_ExtractDropTarget()
+ *
+ * Removes the target node from the tree.
+ */
+static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget)
+{
+  DropTargetNode*  curNode;
+  DropTargetNode** parentNodeLink;
+
+  /*
+   * Iterate the tree to find the insertion point.
+   */
+  curNode        = targetListHead;
+  parentNodeLink = &targetListHead;
+
+  while (curNode!=NULL)
+  {
+    if (hwndOfTarget<curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a smaller HWND, go left
+       */
+      parentNodeLink = &curNode->prevDropTarget;
+      curNode        =  curNode->prevDropTarget;
+    }
+    else if (hwndOfTarget>curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a larger HWND, go right
+       */
+      parentNodeLink = &curNode->nextDropTarget;
+      curNode        =  curNode->nextDropTarget;
+    }
+    else
+    {
+      /*
+       * The item was found in the list. Detach it from it's parent and 
+       * re-insert it's kids in the tree.
+       */
+      assert(parentNodeLink!=NULL);
+      assert(*parentNodeLink==curNode);
+
+      /*
+       * We arbitrately re-attach the left sub-tree to the parent.
+       */
+      *parentNodeLink = curNode->prevDropTarget;
+
+      /*
+       * And we re-insert the right subtree
+       */
+      if (curNode->nextDropTarget!=NULL)
+      {
+	OLEDD_InsertDropTarget(curNode->nextDropTarget);
+      }
+
+      /*
+       * The node we found is still a valid node once we complete
+       * the unlinking of the kids.
+       */
+      curNode->nextDropTarget=NULL;
+      curNode->prevDropTarget=NULL;
+
+      return curNode;
+    }
+  }
+
+  /*
+   * If we get here, the node is not in the tree
+   */
+  return NULL;
+}
+
+/***
+ * OLEDD_FindDropTarget()
+ *
+ * Finds information about the drop target.
+ */
+static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget)
+{
+  DropTargetNode*  curNode;
+
+  /*
+   * Iterate the tree to find the HWND value.
+   */
+  curNode        = targetListHead;
+
+  while (curNode!=NULL)
+  {
+    if (hwndOfTarget<curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a smaller HWND, go left
+       */
+      curNode =  curNode->prevDropTarget;
+    }
+    else if (hwndOfTarget>curNode->hwndTarget)
+    {
+      /*
+       * If the node we want to add has a larger HWND, go right
+       */
+      curNode =  curNode->nextDropTarget;
+    }
+    else
+    {
+      /*
+       * The item was found in the list.
+       */
+      return curNode;
+    }
+  }
+
+  /*
+   * If we get here, the item is not in the list
+   */
+  return NULL;
+}
+
+/***
+ * OLEDD_DragTrackerWindowProc()
+ *
+ * This method is the WindowProcedure of the drag n drop tracking
+ * window. During a drag n Drop operation, an invisible window is created
+ * to receive the user input and act upon it. This procedure is in charge
+ * of this behavior.
+ */
+static LRESULT WIN32API OLEDD_DragTrackerWindowProc(
+			 HWND   hwnd, 
+			 UINT   uMsg,
+			 WPARAM wParam, 
+			 LPARAM   lParam)
+{
+  switch (uMsg)
+  {
+    case WM_CREATE:
+    {
+      LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam;
+
+      SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams); 
+
+      
+      break;
+    }
+    case WM_MOUSEMOVE:
+    {
+      TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
+      POINT            mousePos;
+
+      /*
+       * Get the current mouse position in screen coordinates.
+       */
+      mousePos.x = LOWORD(lParam);
+      mousePos.y = HIWORD(lParam);
+      ClientToScreen(hwnd, &mousePos);
+
+      /*
+       * Track the movement of the mouse.
+       */
+      OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam);
+
+      break;
+    }
+    case WM_LBUTTONUP:
+    case WM_MBUTTONUP:
+    case WM_RBUTTONUP:
+    case WM_LBUTTONDOWN:
+    case WM_MBUTTONDOWN:
+    case WM_RBUTTONDOWN:
+    {
+      TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0);
+      POINT            mousePos;
+
+      /*
+       * Get the current mouse position in screen coordinates.
+       */
+      mousePos.x = LOWORD(lParam);
+      mousePos.y = HIWORD(lParam);
+      ClientToScreen(hwnd, &mousePos);
+
+      /*
+       * Notify everyone that the button state changed
+       * TODO: Check if the "escape" key was pressed.
+       */
+      OLEDD_TrackStateChange(trackerInfo, mousePos, wParam);
+
+      break;
+    }
+  }
+
+  /*
+   * This is a window proc after all. Let's call the default.
+   */
+  return DefWindowProcA (hwnd, uMsg, wParam, lParam);
+}
+
+/***
+ * OLEDD_TrackMouseMove()
+ *
+ * This method is invoked while a drag and drop operation is in effect.
+ * it will generate the appropriate callbacks in the drop source
+ * and drop target. It will also provide the expected feedback to
+ * the user.
+ *
+ * params:
+ *    trackerInfo - Pointer to the structure identifying the
+ *                  drag & drop operation that is currently
+ *                  active.
+ *    mousePos    - Current position of the mouse in screen
+ *                  coordinates.
+ *    keyState    - Contains the state of the shift keys and the
+ *                  mouse buttons (MK_LBUTTON and the like)
+ */
+static void OLEDD_TrackMouseMove(
+  TrackerWindowInfo* trackerInfo,
+  POINT            mousePos,
+  DWORD              keyState)
+{
+  HWND   hwndNewTarget = 0;
+  HRESULT  hr = S_OK;
+
+  /*
+   * Get the handle of the window under the mouse
+   */
+  hwndNewTarget = WindowFromPoint(mousePos);
+
+  /*
+   * Every time, we re-initialize the effects passed to the
+   * IDropTarget to the effects allowed by the source.
+   */
+  *trackerInfo->pdwEffect = trackerInfo->dwOKEffect;
+
+  /*
+   * If we are hovering over the same target as before, send the
+   * DragOver notification
+   */
+  if ( (trackerInfo->curDragTarget != 0) && 
+       (trackerInfo->curDragTargetHWND==hwndNewTarget) )
+  {
+    POINTL  mousePosParam;
+    
+    /*
+     * The documentation tells me that the coordinate should be in the target
+     * window's coordinate space. However, the tests I made tell me the
+     * coordinates should be in screen coordinates.
+     */
+    mousePosParam.x = mousePos.x;
+    mousePosParam.y = mousePos.y;
+    
+    IDropTarget_DragOver(trackerInfo->curDragTarget,
+			 keyState,
+			 mousePosParam,
+			 trackerInfo->pdwEffect);
+  }
+  else
+  {
+    DropTargetNode* newDropTargetNode = 0;
+    
+    /*
+     * If we changed window, we have to notify our old target and check for
+     * the new one.
+     */
+    if (trackerInfo->curDragTarget!=0)
+    {
+      IDropTarget_DragLeave(trackerInfo->curDragTarget);
+    }
+    
+    /*
+     * Make sure we're hovering over a window.
+     */
+    if (hwndNewTarget!=0)
+    {
+      /*
+       * Find-out if there is a drag target under the mouse
+       */
+      newDropTargetNode = OLEDD_FindDropTarget(hwndNewTarget);
+      
+      trackerInfo->curDragTargetHWND = hwndNewTarget;
+      trackerInfo->curDragTarget     = newDropTargetNode ? newDropTargetNode->dropTarget : 0;
+      
+      /*
+       * If there is, notify it that we just dragged-in
+       */
+      if (trackerInfo->curDragTarget!=0)
+      {
+	POINTL  mousePosParam;
+	
+	/*
+	 * The documentation tells me that the coordinate should be in the target
+	 * window's coordinate space. However, the tests I made tell me the
+	 * coordinates should be in screen coordinates.
+	 */
+	mousePosParam.x = mousePos.x;
+	mousePosParam.y = mousePos.y;
+	
+	IDropTarget_DragEnter(trackerInfo->curDragTarget,
+			      trackerInfo->dataObject,
+			      keyState,
+			      mousePosParam,
+			      trackerInfo->pdwEffect);
+      }
+    }
+    else
+    {
+      /*
+       * The mouse is not over a window so we don't track anything.
+       */
+      trackerInfo->curDragTargetHWND = 0;
+      trackerInfo->curDragTarget     = 0;
+    }
+  }
+
+  /*
+   * Now that we have done that, we have to tell the source to give 
+   * us feedback on the work being done by the target.  If we don't 
+   * have a target, simulate no effect.
+   */
+  if (trackerInfo->curDragTarget==0)
+  {
+    *trackerInfo->pdwEffect = DROPEFFECT_NONE;
+  }
+
+  hr = IDropSource_GiveFeedback(trackerInfo->dropSource,
+  				*trackerInfo->pdwEffect);
+
+  /*
+   * When we ask for feedback from the drop source, sometimes it will
+   * do all the necessary work and sometimes it will not handle it
+   * when that's the case, we must display the standard drag and drop
+   * cursors.
+   */
+  if (hr==DRAGDROP_S_USEDEFAULTCURSORS)
+  {
+    if ( (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) ||
+	 (*trackerInfo->pdwEffect & DROPEFFECT_COPY) ||
+	 (*trackerInfo->pdwEffect & DROPEFFECT_LINK) )
+    {
+      SetCursor(LoadCursorA(0, IDC_SIZEALLA));
+    }
+    else
+    {
+      SetCursor(LoadCursorA(0, IDC_NOA));
+    }
+  }  
+}
+
+/***
+ * OLEDD_TrackStateChange()
+ *
+ * This method is invoked while a drag and drop operation is in effect.
+ * It is used to notify the drop target/drop source callbacks when
+ * the state of the keyboard or mouse button change.
+ *
+ * params:
+ *    trackerInfo - Pointer to the structure identifying the
+ *                  drag & drop operation that is currently
+ *                  active.
+ *    mousePos    - Current position of the mouse in screen
+ *                  coordinates.
+ *    keyState    - Contains the state of the shift keys and the
+ *                  mouse buttons (MK_LBUTTON and the like)
+ */
+static void OLEDD_TrackStateChange(
+  TrackerWindowInfo* trackerInfo,
+  POINT            mousePos,
+  DWORD              keyState)
+{
+  /*
+   * Ask the drop source what to do with the operation.
+   */
+  trackerInfo->returnValue = IDropSource_QueryContinueDrag(
+			       trackerInfo->dropSource,
+			       trackerInfo->escPressed, 
+			       keyState);
+  
+  /*
+   * All the return valued will stop the operation except the S_OK
+   * return value.
+   */
+  if (trackerInfo->returnValue!=S_OK)
+  {
+    /*
+     * Make sure the message loop in DoDragDrop stops
+     */
+    trackerInfo->trackingDone = TRUE;
+
+    /*
+     * Release the mouse in case the drop target decides to show a popup 
+     * or a menu or something.
+     */
+    ReleaseCapture();
+    
+    /*
+     * If we end-up over a target, drop the object in the target or 
+     * inform the target that the operation was cancelled.
+     */
+    if (trackerInfo->curDragTarget!=0)
+    {
+      switch (trackerInfo->returnValue)
+      {
+	/*
+	 * If the source wants us to complete the operation, we tell 
+	 * the drop target that we just dropped the object in it.
+	 */
+        case DRAGDROP_S_DROP:
+	{
+	  POINTL  mousePosParam;
+	
+	  /*
+	   * The documentation tells me that the coordinate should be 
+	   * in the target window's coordinate space. However, the tests
+	   * I made tell me the coordinates should be in screen coordinates.
+	   */
+	  mousePosParam.x = mousePos.x;
+	  mousePosParam.y = mousePos.y;
+	  
+	  IDropTarget_Drop(trackerInfo->curDragTarget,
+			   trackerInfo->dataObject,
+			   keyState,
+			   mousePosParam,
+			   trackerInfo->pdwEffect);
+	  break;
+	}
+	/*
+	 * If the source told us that we should cancel, fool the drop 
+	 * target by telling it that the mouse left it's window.
+	 */
+        case DRAGDROP_S_CANCEL:
+	  IDropTarget_DragLeave(trackerInfo->curDragTarget);
+	  break;
+      }
+    }
+  }
+}
+
+/***
+ * OLEDD_GetButtonState()
+ *
+ * This method will use the current state of the keyboard to build
+ * a button state mask equivalent to the one passed in the
+ * WM_MOUSEMOVE wParam.
+ */
+static DWORD OLEDD_GetButtonState()
+{
+  BYTE  keyboardState[256];
+  DWORD keyMask = 0;
+
+  GetKeyboardState(keyboardState);
+
+  if ( (keyboardState[VK_SHIFT] & 0x80) !=0)
+    keyMask |= MK_SHIFT;
+
+  if ( (keyboardState[VK_CONTROL] & 0x80) !=0)
+    keyMask |= MK_CONTROL;
+
+  if ( (keyboardState[VK_LBUTTON] & 0x80) !=0)
+    keyMask |= MK_LBUTTON;
+
+  if ( (keyboardState[VK_RBUTTON] & 0x80) !=0)
+    keyMask |= MK_RBUTTON;
+
+  if ( (keyboardState[VK_MBUTTON] & 0x80) !=0)
+    keyMask |= MK_MBUTTON;
+
+  return keyMask;
+}
+
Index: trunk/src/ole32/new/oleMenu.cpp
===================================================================
--- trunk/src/ole32/new/oleMenu.cpp	(revision 3456)
+++ trunk/src/ole32/new/oleMenu.cpp	(revision 3456)
@@ -0,0 +1,650 @@
+/* $Id: oleMenu.cpp,v 1.1 2000-04-27 22:18:28 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * OLEMENU functions.
+ * 
+ * 4/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ *
+ * Some portions from Wine Implementation (2/9/99)
+ *   Copyright 1995  Martin von Loewis
+ *   Copyright 1999  Francis Beaudet
+ *   Copyright 1999  Noel Borthwick 
+ */
+
+#include "ole32.h"
+#include "commctrl.h"
+#include "oString.h"
+#include <assert.h>
+
+// ======================================================================
+// Local Data
+// ======================================================================
+
+typedef struct tagOleMenuDescriptor  /* OleMenuDescriptor */
+{
+    HWND              		hwndFrame;         /* The containers frame window */
+    HWND              		hwndActiveObject;  /* The active objects window */
+    OLEMENUGROUPWIDTHS		mgw;               /* OLE menu group widths for the shared menu */
+    HMENU             		hmenuCombined;     /* The combined menu */
+    BOOL              		bIsServerItem;     /* True if the currently open popup belongs to the server */
+} OleMenuDescriptor;
+
+typedef struct tagOleMenuHookItem   /* OleMenu hook item in per thread hook list */
+{
+    DWORD			tid;                /* Thread Id  */
+    HANDLE			hHeap;             /* Heap this is allocated from */
+    HHOOK			GetMsg_hHook;       /* message hook for WH_GETMESSAGE */
+    HHOOK			CallWndProc_hHook;  /* message hook for WH_CALLWNDPROC */
+} OleMenuHookItem;
+
+/*
+ * Dynamic pointer array of per thread message hooks (maintained by OleSetMenuDescriptor)
+ */
+static HDPA OLEMenu_MsgHookDPA = NULL;
+
+
+// ======================================================================
+// Prototypes.
+// ======================================================================
+static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue);
+
+// These are the prototypes of the utility methods used to manage a shared menu
+extern void OLEMenu_Initialize();
+extern void OLEMenu_UnInitialize();
+
+BOOL OLEMenu_InstallHooks( DWORD tid );
+BOOL OLEMenu_UnInstallHooks( DWORD tid );
+OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid, INT *pixHook );
+static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos );
+BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor );
+LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam);
+
+// ======================================================================
+// Public API's
+// ======================================================================
+
+/*
+ * OleCreateMenuDescriptor [OLE32.97]
+ * Creates an OLE menu descriptor for OLE to use when dispatching
+ * menu messages and commands.
+ *
+ * PARAMS:
+ *    hmenuCombined  -  Handle to the objects combined menu
+ *    lpMenuWidths   -  Pointer to array of 6 LONG's indicating menus per group
+ *
+ */
+HOLEMENU WIN32API OleCreateMenuDescriptor(
+  HMENU                hmenuCombined,
+  LPOLEMENUGROUPWIDTHS lpMenuWidths)
+{
+  HOLEMENU hOleMenu;
+  OleMenuDescriptor *pOleMenuDescriptor;
+  int i;
+
+  if ( !hmenuCombined || !lpMenuWidths )
+    return 0;
+
+  /* Create an OLE menu descriptor */
+  if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
+                                sizeof(OleMenuDescriptor) ) ) )
+  return 0;
+
+  pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
+  if ( !pOleMenuDescriptor )
+    return 0;
+
+  /* Initialize menu group widths and hmenu */
+  for ( i = 0; i < 6; i++ )
+    pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i];
+  
+  pOleMenuDescriptor->hmenuCombined = hmenuCombined;
+  pOleMenuDescriptor->bIsServerItem = FALSE;
+  GlobalUnlock( hOleMenu );
+      
+  return hOleMenu;
+}
+
+/*
+ * OleDestroyMenuDescriptor [OLE32.99]
+ * Destroy the shared menu descriptor
+ */
+HRESULT WIN32API OleDestroyMenuDescriptor(
+  HOLEMENU hmenuDescriptor)
+{
+  if ( hmenuDescriptor )
+    GlobalFree( hmenuDescriptor );
+	return S_OK;
+}
+
+/*
+ * OleSetMenuDescriptor [OLE32.129]
+ * Installs or removes OLE dispatching code for the containers frame window
+ * FIXME: The lpFrame and lpActiveObject parameters are currently ignored
+ * OLE should install context sensitive help F1 filtering for the app when
+ * these are non null.
+ * 
+ * PARAMS:
+ *     hOleMenu         Handle to composite menu descriptor
+ *     hwndFrame        Handle to containers frame window
+ *     hwndActiveObject Handle to objects in-place activation window
+ *     lpFrame          Pointer to IOleInPlaceFrame on containers window
+ *     lpActiveObject   Pointer to IOleInPlaceActiveObject on active in-place object
+ *
+ * RETURNS:
+ *      S_OK                               - menu installed correctly
+ *      E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure
+ */
+HRESULT WIN32API OleSetMenuDescriptor(
+  HOLEMENU               hOleMenu,
+  HWND                   hwndFrame,
+  HWND                   hwndActiveObject,
+  LPOLEINPLACEFRAME        lpFrame,
+  LPOLEINPLACEACTIVEOBJECT lpActiveObject)
+{
+  OleMenuDescriptor *pOleMenuDescriptor = NULL;
+
+  /* Check args */
+  if ( !hwndFrame || (hOleMenu && !hwndActiveObject) )
+    return E_INVALIDARG;
+
+  if ( lpFrame || lpActiveObject )
+  {
+     dprintf(("OLE32: OleSetMenuDescriptor(%x, %x, %x, %p, %p), Context sensitive help filtering not implemented!\n",
+	(unsigned int)hOleMenu,
+	hwndFrame,
+	hwndActiveObject,
+	lpFrame,
+	lpActiveObject));
+  }
+
+  /* Set up a message hook to intercept the containers frame window messages.
+   * The message filter is responsible for dispatching menu messages from the
+   * shared menu which are intended for the object.
+   */
+
+  if ( hOleMenu )  /* Want to install dispatching code */
+  {
+    /* If OLEMenu hooks are already installed for this thread, fail
+     * Note: This effectively means that OleSetMenuDescriptor cannot
+     * be called twice in succession on the same frame window
+     * without first calling it with a null hOleMenu to uninstall */
+    if ( OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) )
+  return E_FAIL;
+        
+    /* Get the menu descriptor */
+    pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
+    if ( !pOleMenuDescriptor )
+      return E_UNEXPECTED;
+
+    /* Update the menu descriptor */
+    pOleMenuDescriptor->hwndFrame = hwndFrame;
+    pOleMenuDescriptor->hwndActiveObject = hwndActiveObject;
+
+    GlobalUnlock( hOleMenu );
+    pOleMenuDescriptor = NULL;
+    
+    /* Add a menu descriptor windows property to the frame window */
+    SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu );
+
+    /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */
+    if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) )
+      return E_FAIL;
+  }
+  else  /* Want to uninstall dispatching code */
+  {
+    /* Uninstall the hooks */
+    if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) )
+      return E_FAIL;
+    
+    /* Remove the menu descriptor property from the frame window */
+    RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" );
+  }
+      
+  return S_OK;
+}
+
+/*
+ * OLEMenu_Initialize()
+ *
+ * Initializes the OLEMENU data structures.
+ */
+extern void OLEMenu_Initialize()
+{
+    dprintf(("OLE32: OLEMenu_Initialize"));
+
+    /* Create a dynamic pointer array to store the hook handles */
+    if ( !OLEMenu_MsgHookDPA )
+	OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() );
+}
+
+/*
+ * OLEMenu_UnInitialize()
+ *
+ * Releases the OLEMENU data structures.
+ */
+extern void OLEMenu_UnInitialize()
+{
+    dprintf(("OLE32: OLEMenu_UnInitialize"));
+
+  /* Release the hook table */
+    if ( OLEMenu_MsgHookDPA )
+	DPA_Destroy( OLEMenu_MsgHookDPA );
+
+    OLEMenu_MsgHookDPA = NULL;
+}
+
+// ======================================================================
+// Private functions.
+// ======================================================================
+
+/*
+ * Internal methods to manage the shared OLE menu in response to the
+ * OLE***MenuDescriptor API
+ */
+
+/*
+ * OLEMenu_InstallHooks
+ * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
+ *
+ * RETURNS: TRUE if message hooks were succesfully installed
+ *          FALSE on failure
+ */
+BOOL OLEMenu_InstallHooks( DWORD tid )
+{
+  OleMenuHookItem *pHookItem = NULL;
+
+  if ( !OLEMenu_MsgHookDPA ) /* No hook table? Create one */
+  {
+    /* Create a dynamic pointer array to store the hook handles */
+    if ( !(OLEMenu_MsgHookDPA = DPA_CreateEx( 2, GetProcessHeap() )) ) 
+      return FALSE;
+  }
+
+  /* Create an entry for the hook table */
+  if ( !(pHookItem = (OleMenuHookItem *)HeapAlloc(GetProcessHeap(), 0,
+                               sizeof(OleMenuHookItem)) ) )
+    return FALSE;
+
+  pHookItem->tid = tid;
+  pHookItem->hHeap = GetProcessHeap();
+  
+  /* Install a thread scope message hook for WH_GETMESSAGE */
+  pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc,
+                                               0, GetCurrentThreadId() );
+  if ( !pHookItem->GetMsg_hHook )
+    goto CLEANUP;
+
+  /* Install a thread scope message hook for WH_CALLWNDPROC */
+  pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc,
+                                                    0, GetCurrentThreadId() );
+  if ( !pHookItem->CallWndProc_hHook )
+    goto CLEANUP;
+
+  /* Insert the hook table entry */
+  if ( -1 == DPA_InsertPtr( OLEMenu_MsgHookDPA, 0, pHookItem ) )
+    goto CLEANUP;
+  
+  return TRUE;
+  
+CLEANUP:
+  /* Unhook any hooks */
+  if ( pHookItem->GetMsg_hHook )
+    UnhookWindowsHookEx( pHookItem->GetMsg_hHook );
+  if ( pHookItem->CallWndProc_hHook )
+    UnhookWindowsHookEx( pHookItem->CallWndProc_hHook );
+  /* Release the hook table entry */
+  HeapFree(pHookItem->hHeap, 0, pHookItem );
+  
+  return FALSE;
+}
+
+/*
+ * OLEMenu_UnInstallHooks
+ * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC
+ *
+ * RETURNS: TRUE if message hooks were succesfully installed
+ *          FALSE on failure
+ */
+BOOL OLEMenu_UnInstallHooks( DWORD tid )
+{
+  INT ixHook;
+  OleMenuHookItem *pHookItem = NULL;
+
+  if ( !OLEMenu_MsgHookDPA )  /* No hooks set */
+    return TRUE;
+
+  /* Lookup the hHook index for this tid */
+  if ( !OLEMenu_IsHookInstalled( tid , &ixHook ) )
+    return TRUE;
+
+  /* Remove the hook entry from the table(the pointer itself is not deleted) */
+  if ( !( pHookItem = (OleMenuHookItem *)DPA_DeletePtr(OLEMenu_MsgHookDPA, ixHook) ) )
+    return FALSE;
+
+  /* Uninstall the hooks installed for this thread */
+  if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) )
+    goto CLEANUP;
+  if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) )
+    goto CLEANUP;
+
+  /* Release the hook table entry */
+  HeapFree(pHookItem->hHeap, 0, pHookItem );
+
+  return TRUE;
+
+CLEANUP:
+  /* Release the hook table entry */
+  if (pHookItem)
+    HeapFree(pHookItem->hHeap, 0, pHookItem );
+
+  return FALSE;
+}
+
+/*
+ * OLEMenu_IsHookInstalled
+ * Tests if OLEMenu hooks have been installed for a thread
+ *
+ * RETURNS: The pointer and index of the hook table entry for the tid
+ *          NULL and -1 for the index if no hooks were installed for this thread
+ */
+OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid, INT *pixHook )
+{
+  INT ixHook;
+  OleMenuHookItem *pHookItem = NULL;
+
+  if ( pixHook )
+    *pixHook = -1;
+  
+  if ( !OLEMenu_MsgHookDPA )  /* No hooks set */
+    return NULL;
+
+  /* Do a simple linear search for an entry whose tid matches ours.
+   * We really need a map but efficiency is not a concern here. */
+  for( ixHook = 0; ; ixHook++ )
+  {
+    /* Retrieve the hook entry */
+    if ( !( pHookItem = (OleMenuHookItem *)DPA_GetPtr(OLEMenu_MsgHookDPA, ixHook) ) )
+      return NULL;
+
+    if ( tid == pHookItem->tid )
+    {
+      if ( pixHook )
+        *pixHook = ixHook;
+      return pHookItem;
+    }
+  }
+  
+  return NULL;
+}
+
+/*
+ *           OLEMenu_FindMainMenuIndex
+ *
+ * Used by OLEMenu API to find the top level group a menu item belongs to.
+ * On success pnPos contains the index of the item in the top level menu group
+ *
+ * RETURNS: TRUE if the ID was found, FALSE on failure
+ */
+static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
+{
+  UINT i, nItems;
+
+  nItems = GetMenuItemCount( hMainMenu );
+
+  for (i = 0; i < nItems; i++)
+  {
+    HMENU hsubmenu;
+      
+    /*  Is the current item a submenu? */
+    if ( (hsubmenu = GetSubMenu(hMainMenu, i)) != NULL)
+    {
+      /* If the handle is the same we're done */
+      if ( hsubmenu == hPopupMenu )
+      {
+        if (pnPos)
+          *pnPos = i;
+        return TRUE;
+      }
+      /* Recursively search without updating pnPos */
+      else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) )
+      {
+        if (pnPos)
+          *pnPos = i;
+        return TRUE;
+      }
+    }
+  }
+
+  return FALSE;
+}
+
+/*
+ *           OLEMenu_SetIsServerMenu
+ *
+ * Checks whether a popup menu belongs to a shared menu group which is
+ * owned by the server, and sets the menu descriptor state accordingly.
+ * All menu messages from these groups should be routed to the server.
+ *
+ * RETURNS: TRUE if the popup menu is part of a server owned group
+ *          FASE if the popup menu is part of a container owned group
+ */
+BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor )
+{
+  UINT nPos = 0, nWidth, i;
+
+  pOleMenuDescriptor->bIsServerItem = FALSE;
+
+  /* Don't bother searching if the popup is the combined menu itself */
+  if ( hmenu == pOleMenuDescriptor->hmenuCombined )
+    return FALSE;
+
+  /* Find the menu item index in the shared OLE menu that this item belongs to */
+  if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu,  &nPos ) )
+    return FALSE;
+  
+  /* The group widths array has counts for the number of elements
+   * in the groups File, Edit, Container, Object, Window, Help.
+   * The Edit, Object & Help groups belong to the server object
+   * and the other three belong to the container.
+   * Loop thru the group widths and locate the group we are a member of.
+   */
+  for ( i = 0, nWidth = 0; i < 6; i++ )
+  {
+    nWidth += pOleMenuDescriptor->mgw.width[i];
+    if ( nPos < nWidth )
+    {
+      /* Odd elements are server menu widths */
+      pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE;
+      break;
+    }
+  }
+
+  return pOleMenuDescriptor->bIsServerItem;
+}
+
+/*
+ * OLEMenu_CallWndProc
+ * Thread scope WH_CALLWNDPROC hook proc filter function (callback)
+ * This is invoked from a message hook installed in OleSetMenuDescriptor.
+ */
+LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam)
+{
+  LPCWPSTRUCT pMsg = NULL;
+  HOLEMENU hOleMenu = 0;
+  OleMenuDescriptor *pOleMenuDescriptor = NULL;
+  OleMenuHookItem *pHookItem = NULL;
+  WORD fuFlags;
+
+    dprintf(("OLE32: OLEMenu_CallWndProc %i, %04x, %08x", code, wParam, (unsigned)lParam));
+
+  /* Check if we're being asked to process the message */
+  if ( HC_ACTION != code )
+    goto NEXTHOOK;
+      
+  /* Retrieve the current message being dispatched from lParam */
+  pMsg = (LPCWPSTRUCT)lParam;
+
+  /* Check if the message is destined for a window we are interested in:
+   * If the window has an OLEMenu property we may need to dispatch
+   * the menu message to its active objects window instead. */
+
+  hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
+  if ( !hOleMenu )
+    goto NEXTHOOK;
+
+  /* Get the menu descriptor */
+  pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
+  if ( !pOleMenuDescriptor ) /* Bad descriptor! */
+    goto NEXTHOOK;
+
+  /* Process menu messages */
+  switch( pMsg->message )
+  {
+    case WM_INITMENU:
+    {
+      /* Reset the menu descriptor state */
+      pOleMenuDescriptor->bIsServerItem = FALSE;
+
+      /* Send this message to the server as well */
+      SendMessageA( pOleMenuDescriptor->hwndActiveObject,
+                  pMsg->message, pMsg->wParam, pMsg->lParam );
+      goto NEXTHOOK;
+    }
+    
+    case WM_INITMENUPOPUP:
+    {
+      /* Save the state for whether this is a server owned menu */
+      OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor );
+      break;
+    }
+    
+    case WM_MENUSELECT:
+    {
+      fuFlags = HIWORD(pMsg->wParam);  /* Get flags */
+      if ( fuFlags & MF_SYSMENU )
+         goto NEXTHOOK;
+
+      /* Save the state for whether this is a server owned popup menu */
+      else if ( fuFlags & MF_POPUP )
+        OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor );
+
+      break;
+    }
+    
+    case WM_DRAWITEM:
+    {
+      LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam;
+      if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU )
+        goto NEXTHOOK;  /* Not a menu message */
+
+      break;
+    }
+
+    default:
+      goto NEXTHOOK;
+  }
+
+  /* If the message was for the server dispatch it accordingly */
+  if ( pOleMenuDescriptor->bIsServerItem )
+  {
+    SendMessageA( pOleMenuDescriptor->hwndActiveObject,
+                  pMsg->message, pMsg->wParam, pMsg->lParam );
+  }
+    
+NEXTHOOK:
+  if ( pOleMenuDescriptor )
+    GlobalUnlock( hOleMenu );
+  
+  /* Lookup the hook item for the current thread */
+  if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
+  {
+    /* This should never fail!! */
+    dprintf(("Warning: Could not retrieve hHook for current thread!"));
+    return 0;
+  }
+  
+  /* Pass on the message to the next hooker */
+  return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam );
+}
+
+/*
+ * OLEMenu_GetMsgProc
+ * Thread scope WH_GETMESSAGE hook proc filter function (callback)
+ * This is invoked from a message hook installed in OleSetMenuDescriptor.
+ */
+LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam)
+{
+  LPMSG pMsg = NULL;
+  HOLEMENU hOleMenu = 0;
+  OleMenuDescriptor *pOleMenuDescriptor = NULL;
+  OleMenuHookItem *pHookItem = NULL;
+  WORD wCode;
+  
+    dprintf(("OLE32: OLEMenu_GetMsgProc %i, %04x, %08x", code, wParam, (unsigned)lParam ));
+
+  /* Check if we're being asked to process a  messages */
+  if ( HC_ACTION != code )
+    goto NEXTHOOK;
+      
+  /* Retrieve the current message being dispatched from lParam */
+  pMsg = (LPMSG)lParam;
+
+  /* Check if the message is destined for a window we are interested in:
+   * If the window has an OLEMenu property we may need to dispatch
+   * the menu message to its active objects window instead. */
+
+  hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" );
+  if ( !hOleMenu )
+    goto NEXTHOOK;
+
+  /* Process menu messages */
+  switch( pMsg->message )
+  {
+    case WM_COMMAND:
+    {
+      wCode = HIWORD(pMsg->wParam);  /* Get notification code */
+      if ( wCode )
+        goto NEXTHOOK;  /* Not a menu message */
+      break;
+    }
+    default:
+      goto NEXTHOOK;
+  }
+
+  /* Get the menu descriptor */
+  pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu );
+  if ( !pOleMenuDescriptor ) /* Bad descriptor! */
+    goto NEXTHOOK;
+
+  /* If the message was for the server dispatch it accordingly */
+  if ( pOleMenuDescriptor->bIsServerItem )
+  {
+    /* Change the hWnd in the message to the active objects hWnd.
+     * The message loop which reads this message will automatically
+     * dispatch it to the embedded objects window. */
+    pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject;
+  }
+    
+NEXTHOOK:
+  if ( pOleMenuDescriptor )
+    GlobalUnlock( hOleMenu );
+  
+  /* Lookup the hook item for the current thread */
+  if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId(), NULL ) ) )
+  {
+    /* This should never fail!! */
+    dprintf(("Warning: Could not retrieve hHook for current thread!\n" ));
+    return FALSE;
+  }
+  
+  /* Pass on the message to the next hooker */
+  return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam );
+}
+
Index: trunk/src/ole32/new/oleobj.cpp
===================================================================
--- trunk/src/ole32/new/oleobj.cpp	(revision 3456)
+++ trunk/src/ole32/new/oleobj.cpp	(revision 3456)
@@ -0,0 +1,607 @@
+/* $Id: oleobj.cpp,v 1.1 2000-04-27 22:18:28 davidr Exp $ */
+/* 
+ * OLE2 COM objects
+ * 
+ * 21/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *
+ *	Copyright 1998 Eric Kohl
+ *      Copyright 1999 Francis Beaudet
+ */
+
+#include "ole32.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(ole)
+
+
+/**************************************************************************
+ *  OleAdviseHolderImpl Implementation
+ */
+typedef struct OleAdviseHolderImpl
+{
+  ICOM_VFIELD(IOleAdviseHolder);
+
+  DWORD ref;
+
+  DWORD         maxSinks;
+  IAdviseSink** arrayOfSinks;
+
+} OleAdviseHolderImpl;
+
+static LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor();
+static void              OleAdviseHolderImpl_Destructor(OleAdviseHolderImpl* ptrToDestroy);
+static HRESULT WINAPI    OleAdviseHolderImpl_QueryInterface(LPOLEADVISEHOLDER,REFIID,LPVOID*);
+static ULONG WINAPI      OleAdviseHolderImpl_AddRef(LPOLEADVISEHOLDER);
+static ULONG WINAPI      OleAdviseHolderImpl_Release(LPOLEADVISEHOLDER);
+static HRESULT WINAPI    OleAdviseHolderImpl_Advise(LPOLEADVISEHOLDER, IAdviseSink*, DWORD*);
+static HRESULT WINAPI    OleAdviseHolderImpl_Unadvise (LPOLEADVISEHOLDER, DWORD);
+static HRESULT WINAPI    OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER, IEnumSTATDATA **);
+static HRESULT WINAPI    OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER, IMoniker *);
+static HRESULT WINAPI    OleAdviseHolderImpl_SendOnSave (LPOLEADVISEHOLDER);
+static HRESULT WINAPI    OleAdviseHolderImpl_SendOnClose (LPOLEADVISEHOLDER);
+
+
+/**************************************************************************
+ *  OleAdviseHolderImpl_VTable
+ */
+static struct ICOM_VTABLE(IOleAdviseHolder) oahvt =
+{
+    OleAdviseHolderImpl_QueryInterface,
+    OleAdviseHolderImpl_AddRef,
+    OleAdviseHolderImpl_Release,
+    OleAdviseHolderImpl_Advise,
+    OleAdviseHolderImpl_Unadvise,
+    OleAdviseHolderImpl_EnumAdvise,
+    OleAdviseHolderImpl_SendOnRename,
+    OleAdviseHolderImpl_SendOnSave,
+    OleAdviseHolderImpl_SendOnClose
+};
+
+/**************************************************************************
+ *  OleAdviseHolderImpl_Constructor
+ */
+
+static LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor()
+{
+  OleAdviseHolderImpl* lpoah;
+  DWORD                index;
+
+  lpoah= (OleAdviseHolderImpl*)HeapAlloc(GetProcessHeap(),
+					 0,
+					 sizeof(OleAdviseHolderImpl));
+  
+  ICOM_VTBL(lpoah) = &oahvt;
+  lpoah->ref = 1;
+  lpoah->maxSinks = 10;
+  lpoah->arrayOfSinks = (IAdviseSink**)HeapAlloc(GetProcessHeap(),
+				  0,
+				  lpoah->maxSinks * sizeof(IAdviseSink*));
+
+  for (index = 0; index < lpoah->maxSinks; index++)
+    lpoah->arrayOfSinks[index]=0;
+
+  return (LPOLEADVISEHOLDER)lpoah;
+}
+
+/**************************************************************************
+ *  OleAdviseHolderImpl_Destructor
+ */
+static void OleAdviseHolderImpl_Destructor(
+  OleAdviseHolderImpl* ptrToDestroy)
+{
+  DWORD index;
+
+  for (index = 0; index < ptrToDestroy->maxSinks; index++)
+  {
+    if (ptrToDestroy->arrayOfSinks[index]!=0)
+    {
+      IAdviseSink_Release(ptrToDestroy->arrayOfSinks[index]);
+      ptrToDestroy->arrayOfSinks[index] = NULL;
+    }
+  }
+  
+  HeapFree(GetProcessHeap(),
+	   0,
+	   ptrToDestroy->arrayOfSinks);
+  
+
+  HeapFree(GetProcessHeap(),
+	   0,
+	   ptrToDestroy);
+}
+
+/**************************************************************************
+ *  OleAdviseHolderImpl_QueryInterface
+ */
+static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface(
+  LPOLEADVISEHOLDER iface,
+  REFIID            riid, 
+  LPVOID*           ppvObj)
+{
+  ICOM_THIS(OleAdviseHolderImpl, iface); 
+
+  /*
+   * Sanity check
+   */
+  if (ppvObj==NULL)
+    return E_POINTER;
+
+  *ppvObj = NULL;
+
+  if (IsEqualIID(riid, &IID_IUnknown)) 
+  {
+    /* IUnknown */
+    *ppvObj = This; 
+  }
+  else if(IsEqualIID(riid, &IID_IOleAdviseHolder)) 
+  {
+    /* IOleAdviseHolder */
+    *ppvObj = (IOleAdviseHolder*) This;
+  }
+
+  if(*ppvObj == NULL)
+    return E_NOINTERFACE;
+  
+  /*
+   * A successful QI always increments the reference count.
+   */
+  IUnknown_AddRef((IUnknown*)*ppvObj);
+
+  return S_OK;
+}
+
+/******************************************************************************
+ * OleAdviseHolderImpl_AddRef
+ */
+static ULONG WINAPI OleAdviseHolderImpl_AddRef(
+  LPOLEADVISEHOLDER iface)
+{
+  ICOM_THIS(OleAdviseHolderImpl, iface); 
+  
+  return ++(This->ref);
+}
+
+/******************************************************************************
+ * OleAdviseHolderImpl_Release
+ */
+static ULONG WINAPI OleAdviseHolderImpl_Release(
+  LPOLEADVISEHOLDER iface)
+{
+  ICOM_THIS(OleAdviseHolderImpl, iface); 
+
+  This->ref--;
+
+  if (This->ref == 0)
+  {
+    OleAdviseHolderImpl_Destructor(This);
+
+    return 0;
+  }
+
+  return This->ref;
+}
+
+/******************************************************************************
+ * OleAdviseHolderImpl_Advise
+ */
+static HRESULT WINAPI OleAdviseHolderImpl_Advise(
+  LPOLEADVISEHOLDER iface,
+  IAdviseSink*      pAdvise,
+  DWORD*            pdwConnection)
+{
+  DWORD index;
+  
+  ICOM_THIS(OleAdviseHolderImpl, iface); 
+
+  TRACE("(%p, %p, %p)\n", This, pAdvise, pdwConnection);
+
+  /*
+   * Sanity check
+   */
+  if (pdwConnection==NULL)
+    return E_POINTER;
+  
+  *pdwConnection = 0;
+
+  /*
+   * Find a free spot in the array.
+   */
+  for (index = 0; index < This->maxSinks; index++)
+  {
+    if (This->arrayOfSinks[index]==NULL)
+      break;
+  }
+
+  /*
+   * If the array is full, we need to grow it.
+   */
+  if (index == This->maxSinks)
+  {
+    DWORD i;
+
+    This->maxSinks+=10;
+
+    This->arrayOfSinks = (IAdviseSink**)HeapReAlloc(GetProcessHeap(), 
+				     0,
+				     This->arrayOfSinks,
+				     This->maxSinks*sizeof(IAdviseSink*));
+
+    for (i=index;i < This->maxSinks; i++)
+      This->arrayOfSinks[i]=0;      
+  }
+
+  /*
+   * Store the new sink
+   */
+  This->arrayOfSinks[index] = pAdvise;
+
+  if (This->arrayOfSinks[index]!=NULL)
+    IAdviseSink_AddRef(This->arrayOfSinks[index]);
+
+  /*
+   * Return the index as the cookie.
+   * Since 0 is not a valid cookie, we will increment by
+   * 1 the index in the table.
+   */
+  *pdwConnection = index+1;
+
+  return S_OK;
+}
+
+/******************************************************************************
+ * OleAdviseHolderImpl_Unadvise
+ */
+static HRESULT WINAPI OleAdviseHolderImpl_Unadvise(
+  LPOLEADVISEHOLDER iface, 
+  DWORD             dwConnection)
+{
+  ICOM_THIS(OleAdviseHolderImpl, iface); 
+
+  TRACE("(%p, %lu)\n", This, dwConnection);
+
+  /*
+   * So we don't return 0 as a cookie, the index was 
+   * incremented by 1 in OleAdviseHolderImpl_Advise
+   * we have to compensate.
+   */
+  dwConnection--;
+  
+  /*
+   * Check for invalid cookies.
+   */
+  if ( (dwConnection < 0) || 
+       (dwConnection >= This->maxSinks) )
+    return OLE_E_NOCONNECTION;
+
+  if (This->arrayOfSinks[dwConnection] == NULL)
+    return OLE_E_NOCONNECTION;
+
+  /*
+   * Release the sink and mark the spot in the list as free.
+   */
+  IAdviseSink_Release(This->arrayOfSinks[dwConnection]);
+  This->arrayOfSinks[dwConnection] = NULL;
+
+  return S_OK;
+}
+
+/******************************************************************************
+ * OleAdviseHolderImpl_EnumAdvise
+ */
+static HRESULT WINAPI
+OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER iface, IEnumSTATDATA **ppenumAdvise)
+{
+		ICOM_THIS(OleAdviseHolderImpl, iface); 
+    FIXME("(%p)->(%p)\n", This, ppenumAdvise);
+
+    *ppenumAdvise = NULL;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ * OleAdviseHolderImpl_SendOnRename
+ */
+static HRESULT WINAPI
+OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER iface, IMoniker *pmk)
+{
+		ICOM_THIS(OleAdviseHolderImpl, iface); 
+    FIXME("(%p)->(%p)\n", This, pmk);
+
+
+    return S_OK;
+}
+
+/******************************************************************************
+ * OleAdviseHolderImpl_SendOnSave
+ */
+static HRESULT WINAPI
+OleAdviseHolderImpl_SendOnSave (LPOLEADVISEHOLDER iface)
+{
+		ICOM_THIS(OleAdviseHolderImpl, iface); 
+    FIXME("(%p)\n", This);
+
+
+    return S_OK;
+}
+
+/******************************************************************************
+ * OleAdviseHolderImpl_SendOnClose
+ */
+static HRESULT WINAPI
+OleAdviseHolderImpl_SendOnClose (LPOLEADVISEHOLDER iface)
+{
+  ICOM_THIS(OleAdviseHolderImpl, iface); 
+    FIXME("(%p)\n", This);
+
+
+    return S_OK;
+}
+
+/**************************************************************************
+ *  DataAdviseHolder Implementation
+ */
+typedef struct DataAdviseHolder
+{
+  ICOM_VFIELD(IDataAdviseHolder);
+
+  DWORD ref;
+} DataAdviseHolder;
+
+/**************************************************************************
+ *  DataAdviseHolder method prototypes
+ */
+static IDataAdviseHolder* DataAdviseHolder_Constructor();
+static void               DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy);
+static HRESULT WINAPI     DataAdviseHolder_QueryInterface(
+			    IDataAdviseHolder*      iface,
+			    REFIID                  riid,
+			    void**                  ppvObject);
+static ULONG WINAPI       DataAdviseHolder_AddRef( 
+                            IDataAdviseHolder*      iface);
+static ULONG WINAPI       DataAdviseHolder_Release( 
+                            IDataAdviseHolder*      iface);
+static HRESULT WINAPI     DataAdviseHolder_Advise( 
+                            IDataAdviseHolder*      iface,
+			    IDataObject*            pDataObject, 
+			    FORMATETC*              pFetc, 
+			    DWORD                   advf, 
+			    IAdviseSink*            pAdvise, 
+			    DWORD*                  pdwConnection);
+static HRESULT WINAPI     DataAdviseHolder_Unadvise( 
+                            IDataAdviseHolder*      iface,
+			    DWORD                   dwConnection);
+static HRESULT WINAPI     DataAdviseHolder_EnumAdvise( 
+                            IDataAdviseHolder*      iface,       
+			    IEnumSTATDATA**         ppenumAdvise);
+static HRESULT WINAPI     DataAdviseHolder_SendOnDataChange( 
+                            IDataAdviseHolder*      iface, 
+			    IDataObject*            pDataObject, 
+			    DWORD                   dwReserved, 
+			    DWORD                   advf);
+
+/**************************************************************************
+ *  DataAdviseHolderImpl_VTable
+ */
+static struct ICOM_VTABLE(IDataAdviseHolder) DataAdviseHolderImpl_VTable =
+{
+  ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+  DataAdviseHolder_QueryInterface,
+  DataAdviseHolder_AddRef,
+  DataAdviseHolder_Release,
+  DataAdviseHolder_Advise,
+  DataAdviseHolder_Unadvise,
+  DataAdviseHolder_EnumAdvise,
+  DataAdviseHolder_SendOnDataChange
+};
+
+/******************************************************************************
+ * DataAdviseHolder_Constructor
+ */
+static IDataAdviseHolder* DataAdviseHolder_Constructor()
+{
+  DataAdviseHolder* newHolder;
+
+  newHolder = (DataAdviseHolder*)HeapAlloc(GetProcessHeap(),
+					   0,
+					   sizeof(DataAdviseHolder));
+  
+  ICOM_VTBL(newHolder) = &DataAdviseHolderImpl_VTable;
+  newHolder->ref = 1;
+
+  return (IDataAdviseHolder*)newHolder;
+}
+
+/******************************************************************************
+ * DataAdviseHolder_Destructor
+ */
+static void DataAdviseHolder_Destructor(
+  DataAdviseHolder* ptrToDestroy)
+{
+  HeapFree(GetProcessHeap(),
+	   0,
+	   ptrToDestroy);
+}
+
+/************************************************************************
+ * DataAdviseHolder_QueryInterface (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static HRESULT WINAPI DataAdviseHolder_QueryInterface(
+  IDataAdviseHolder*      iface,
+  REFIID                  riid,
+  void**                  ppvObject)
+{
+  ICOM_THIS(DataAdviseHolder, iface); 
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppvObject==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if ( (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) ||
+       (memcmp(&IID_IDataAdviseHolder, riid, sizeof(IID_IDataAdviseHolder)) == 0)  )
+  {
+    *ppvObject = iface;
+  }
+  
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+  {
+    return E_NOINTERFACE;
+  }
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful. 
+   */
+  IUnknown_AddRef((IUnknown*)*ppvObject);
+
+  return S_OK;;  
+}
+
+/************************************************************************
+ * DataAdviseHolder_AddRef (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI       DataAdviseHolder_AddRef(                             
+  IDataAdviseHolder*      iface)
+{
+  ICOM_THIS(DataAdviseHolder, iface); 
+
+  This->ref++;
+
+  return This->ref;
+}
+
+/************************************************************************
+ * DataAdviseHolder_Release (IUnknown)
+ *
+ * See Windows documentation for more details on IUnknown methods.
+ */
+static ULONG WINAPI DataAdviseHolder_Release( 
+  IDataAdviseHolder*      iface)
+{
+  ICOM_THIS(DataAdviseHolder, iface); 
+
+  /*
+   * Decrease the reference count on this object.
+   */
+  This->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (This->ref==0)
+  {
+    DataAdviseHolder_Destructor(This);
+
+    return 0;
+  }
+  
+  return This->ref;
+}
+
+static HRESULT WINAPI DataAdviseHolder_Advise(
+  IDataAdviseHolder*      iface,
+  IDataObject*            pDataObject, 
+  FORMATETC*              pFetc, 
+  DWORD                   advf, 
+  IAdviseSink*            pAdvise, 
+  DWORD*                  pdwConnection)
+{
+  FIXME("(): stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI     DataAdviseHolder_Unadvise( 
+  IDataAdviseHolder*      iface,
+  DWORD                   dwConnection)
+{
+  FIXME("(): stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI     DataAdviseHolder_EnumAdvise( 
+  IDataAdviseHolder*      iface,       
+  IEnumSTATDATA**         ppenumAdvise)
+{
+  FIXME("(): stub\n");
+  return E_NOTIMPL;
+}
+
+static HRESULT WINAPI     DataAdviseHolder_SendOnDataChange( 
+  IDataAdviseHolder*      iface, 
+  IDataObject*            pDataObject, 
+  DWORD                   dwReserved, 
+  DWORD                   advf)
+{
+  FIXME("(): stub\n");
+  return E_NOTIMPL;
+}
+
+/***********************************************************************
+ * API functions
+ */
+
+/***********************************************************************
+ * CreateOleAdviseHolder [OLE32.59]
+ */
+HRESULT WINAPI CreateOleAdviseHolder(
+  LPOLEADVISEHOLDER *ppOAHolder)
+{
+  TRACE("(%p)\n", ppOAHolder);
+
+  /*
+   * Sanity check,
+   */
+  if (ppOAHolder==NULL)
+    return E_POINTER;
+
+  *ppOAHolder = OleAdviseHolderImpl_Constructor ();
+
+  if (*ppOAHolder != NULL)
+    return S_OK;
+
+  return E_OUTOFMEMORY;
+}
+
+/******************************************************************************
+ *              CreateDataAdviseHolder        [OLE32.53]
+ */
+HRESULT WINAPI CreateDataAdviseHolder(
+  LPDATAADVISEHOLDER* ppDAHolder)
+{
+  TRACE("(%p)\n", ppDAHolder);
+
+  /*
+   * Sanity check,
+   */
+  if (ppDAHolder==NULL)
+    return E_POINTER;
+
+  *ppDAHolder = DataAdviseHolder_Constructor();
+
+  if (*ppDAHolder != NULL)
+    return S_OK;
+
+  return E_OUTOFMEMORY;
+}
+
Index: trunk/src/ole32/new/regsvr32.cpp
===================================================================
--- trunk/src/ole32/new/regsvr32.cpp	(revision 3456)
+++ trunk/src/ole32/new/regsvr32.cpp	(revision 3456)
@@ -0,0 +1,307 @@
+/* $Id: regsvr32.cpp,v 1.1 2000-04-27 22:18:29 davidr Exp $ */
+/* 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+/* 
+ * RegSvr32 for OS/2
+ * 
+ * 1/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ */
+
+#include <windows.h>
+#include <odinlx.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+
+// ======================================================================
+// Local Data
+// ======================================================================
+static	int	fRegister = 1;
+static	int	fSilent = 0;
+static  char	szFile[1024];
+static	HANDLE	hdlObject;
+
+// ======================================================================
+// Prototypes.
+// ======================================================================
+extern HRESULT WIN32API OleInitialize(LPVOID reserved);
+extern HRESULT WIN32API OleUninitialize(void);
+
+static	HRESULT	parse_command(int argc, char * argv[]);
+static	HRESULT	load_object(void);
+static	HRESULT	register_object(void);
+static	HRESULT	deregister_object(void);
+static	HRESULT	unload_object(void);
+static	HRESULT	sign_on(void);
+static	HRESULT	sign_off(void);
+static	HRESULT	report_msg(char * fmt, ...);
+static	HRESULT	report_err(HRESULT hr, char * fmt, ...);
+static	HRESULT	usage(char * fmt, ...);
+static int WIN32API EntryPoint(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+		    LPSTR lpCmdLine, int nCmdShow);
+
+// ======================================================================
+// Public API's
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// main
+// ----------------------------------------------------------------------
+int main(int argc, char *argv[])
+{
+    RegisterLxExe(EntryPoint, NULL);
+
+    HRESULT	hr;
+
+    if((hr = sign_on()) != S_OK)
+	return hr;
+
+    if((hr = parse_command(argc, argv)) != S_OK)
+	return hr;
+
+    if((hr = load_object()) != S_OK)
+	return hr;
+
+    if (fRegister)
+	hr = register_object();
+    else
+	hr = deregister_object();
+
+    if (hr != S_OK)
+	return hr;
+
+    if((hr = unload_object()) != S_OK)
+	return hr;
+
+    return sign_off();
+}
+
+// ======================================================================
+// Private functions.
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// EntryPoint
+// ----------------------------------------------------------------------
+static int WIN32API EntryPoint
+   (HINSTANCE	hInstance,
+    HINSTANCE	hPrevInstance,
+    LPSTR	lpCmdLine,
+    int		nCmdShow)
+{
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// sign_on
+// ----------------------------------------------------------------------
+static	HRESULT	sign_on(void)
+{
+    HRESULT	hr;
+
+    hr = OleInitialize(NULL);
+    if (hr != S_OK)
+	return report_err(hr, "Error initialising OLE");
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// sign_off
+// ----------------------------------------------------------------------
+static	HRESULT	sign_off(void)
+{
+    OleUninitialize();
+    return report_msg("%s initialised OK", szFile);
+}
+
+// ----------------------------------------------------------------------
+// parse_command
+// ----------------------------------------------------------------------
+static	HRESULT	parse_command(int argc, char * argv[])
+{
+    int		ii;
+    char *	pArg;
+
+    // Initial conditions.
+    fRegister = 1;
+    fSilent = 0;
+    szFile[0] = 0;
+
+    // Loop through args...
+    for (ii = 1; ii < argc; ii++)
+    {
+	pArg = argv[ii];
+
+	if ((pArg[0] == '-') || (pArg[0] == '/'))
+	{
+	    switch(toupper(pArg[1]))
+	    {
+		case 'S':
+		{
+		    fSilent = 1;
+		    break;
+		}
+
+		case 'U':
+		{
+		    fRegister = 0;
+		    break;
+		}
+
+		default:
+		{
+		    return usage("Unknown switch '%c'", pArg[1] );
+		}
+	    }
+	}
+	else if (strlen(szFile) == 0) 
+	{
+	    strcpy(szFile, pArg);
+	}
+	else
+	{
+	    return usage("Too many files specified");
+	}
+    }
+    if (strlen(szFile) == 0) 
+	return usage("No file specified");
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// load_object
+// ----------------------------------------------------------------------
+static	HRESULT	load_object(void)
+{
+    hdlObject = CoLoadLibrary(szFile, 1);
+    if (hdlObject == 0)
+	return report_err(S_FALSE, "Failed to load '%s'", szFile);
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// register_object
+// ----------------------------------------------------------------------
+static	HRESULT	register_object(void)
+{
+    typedef HRESULT(*LPFNREGISTER)(void);
+
+    LPFNREGISTER	pfnRegister;
+    HRESULT		hr;
+
+    pfnRegister = (LPFNREGISTER)GetProcAddress(hdlObject, "DllRegisterServer");
+
+    if (pfnRegister == NULL)
+	return report_err(S_FALSE, "Unable to locate registration entry point in '%s'", szFile);
+
+    hr = pfnRegister();
+    if (hr != S_OK)
+	return report_err(hr, "Registration for '%s' returned error 0x%08lx", szFile, hr);
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// deregister_object
+// ----------------------------------------------------------------------
+static	HRESULT	deregister_object(void)
+{
+    typedef HRESULT(*LPFNUNREGISTER)(void);
+
+    LPFNUNREGISTER	pfnUnregister;
+    HRESULT		hr;
+
+    pfnUnregister = (LPFNUNREGISTER)GetProcAddress(hdlObject, "DllUnregisterServer");
+
+    if (pfnUnregister == NULL)
+	return report_err(S_FALSE, "Unable to locate unregistration entry point in '%s'", szFile);
+
+    hr = pfnUnregister();
+    if (hr != S_OK)
+	return report_err(hr, "Unregistration for '%s' returned error 0x%08lx", szFile, hr);
+
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// unload_object
+// ----------------------------------------------------------------------
+static	HRESULT	unload_object(void)
+{
+    CoFreeLibrary(hdlObject);
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// report_msg
+// ----------------------------------------------------------------------
+static	HRESULT	report_msg(char * fmt, ...)
+{
+    if (!fSilent)
+    {
+	va_list	va_ptr;
+	HWND	hwnd = GetDesktopWindow();
+	char	text[1024];
+
+	va_start(va_ptr, fmt);
+	vsprintf(text, fmt, va_ptr);
+	va_end(va_ptr);
+
+	MessageBoxA(hwnd, text, "RegSvr32", MB_OK | MB_ICONINFORMATION);
+    }
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// report_err
+// ----------------------------------------------------------------------
+static	HRESULT	report_err(HRESULT hr, char * fmt, ...)
+{
+    va_list	va_ptr;
+    HWND	hwnd = GetDesktopWindow();
+    char	text[1024];
+
+    va_start(va_ptr, fmt);
+    vsprintf(text, fmt, va_ptr);
+    va_end(va_ptr);
+
+    MessageBoxA(hwnd, text, "RegSvr32", MB_OK | MB_ICONERROR);
+
+    return hr;
+}
+
+// ----------------------------------------------------------------------
+// usage
+// ----------------------------------------------------------------------
+static	HRESULT	usage(char * fmt, ...)
+{
+    va_list	va_ptr;
+    HWND	hwnd = GetDesktopWindow();
+    char	text[256];
+    char	msg[1024];
+
+    va_start(va_ptr, fmt);
+    vsprintf(text, fmt, va_ptr);
+    va_end(va_ptr);
+    sprintf(msg, "Error - %s\n\n"
+    		 "Usage:\n"
+    		 "regsvr32 [/s] [/u] filename\n"
+    		 "where\n"
+    		 "/s - silent completion\n"
+    		 "/u - unregister", text);
+
+    MessageBoxA(hwnd, msg, "RegSvr32", MB_OK | MB_ICONWARNING);
+
+    return S_FALSE;
+}
Index: trunk/src/ole32/new/regsvr32.def
===================================================================
--- trunk/src/ole32/new/regsvr32.def	(revision 3456)
+++ trunk/src/ole32/new/regsvr32.def	(revision 3456)
@@ -0,0 +1,2 @@
+NAME "RegSvr32" WINDOWAPI
+
Index: trunk/src/ole32/new/stg_bigblockfile.cpp
===================================================================
--- trunk/src/ole32/new/stg_bigblockfile.cpp	(revision 3456)
+++ trunk/src/ole32/new/stg_bigblockfile.cpp	(revision 3456)
@@ -0,0 +1,838 @@
+/* $Id: stg_bigblockfile.cpp,v 1.1 2000-04-27 22:18:29 davidr Exp $ */
+/* 
+ * BigBlockFile
+ * 
+ * 12/03/00
+ * 
+ * Direct port of Wine Implementation
+ *
+ * This is the implementation of a file that consists of blocks of 
+ * a predetermined size.
+ * This class is used in the Compound File implementation of the 
+ * IStorage and IStream interfaces. It provides the functionality 
+ * to read and write any blocks in the file as well as setting and 
+ * obtaining the size of the file.
+ * The blocks are indexed sequentially from the start of the file
+ * starting with -1.
+ * 
+ * TODO:
+ * - Support for a transacted mode
+ *
+ * Copyright 1999 Thuy Nguyen
+ */
+
+#include "ole32.h"
+#include "heapstring.h"
+#include "debugtools.h"
+#include "storage.h"
+
+#include <assert.h>
+
+#define CHAR_BIT 8	// (From EMX limits.h)
+
+/***********************************************************
+ * Data structures used internally by the BigBlockFile
+ * class.
+ */
+
+/* We map in PAGE_SIZE-sized chunks. Must be a multiple of 4096. */
+#define PAGE_SIZE       131072
+
+#define BLOCKS_PER_PAGE (PAGE_SIZE / BIG_BLOCK_SIZE)
+
+/* We keep a list of recently-discarded pages. This controls the
+ * size of that list. */
+#define MAX_VICTIM_PAGES 16
+
+/* This structure provides one bit for each block in a page.
+ * Use BIGBLOCKFILE_{Test,Set,Clear}Bit to manipulate it. */
+typedef struct
+{
+    unsigned int bits[BLOCKS_PER_PAGE / (CHAR_BIT * sizeof(unsigned int))];
+} BlockBits;
+
+/***
+ * This structure identifies the paged that are mapped
+ * from the file and their position in memory. It is 
+ * also used to hold a reference count to those pages.
+ *
+ * page_index identifies which PAGE_SIZE chunk from the
+ * file this mapping represents. (The mappings are always
+ * PAGE_SIZE-aligned.)
+ */
+struct MappedPage
+{
+    MappedPage *next;
+    MappedPage *prev;
+
+    DWORD  page_index;
+    LPVOID lpBytes;
+    LONG   refcnt;
+
+    BlockBits readable_blocks;
+    BlockBits writable_blocks;
+};
+
+/***********************************************************
+ * Prototypes for private methods
+ */
+static void*     BIGBLOCKFILE_GetMappedView(LPBIGBLOCKFILE This,
+                                            DWORD          page_index);
+static void      BIGBLOCKFILE_ReleaseMappedPage(LPBIGBLOCKFILE This,
+                                                MappedPage *page);
+static void      BIGBLOCKFILE_FreeAllMappedPages(LPBIGBLOCKFILE This);
+static void      BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This);
+static void      BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This);
+static void*     BIGBLOCKFILE_GetBigBlockPointer(LPBIGBLOCKFILE This,
+                                                 ULONG          index,
+                                                 DWORD          desired_access);
+static MappedPage* BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This, 
+						   void*         pBlock);
+static MappedPage* BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This,
+					   ULONG page_index);
+static DWORD     BIGBLOCKFILE_GetProtectMode(DWORD openFlags);
+static BOOL      BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile);
+static BOOL      BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt);
+
+/* Note that this evaluates a and b multiple times, so don't
+ * pass expressions with side effects. */
+#define ROUND_UP(a, b) (!(a) ? 0 : ((a) + (b) - (((a)-1) % (b)) - 1))
+
+/***********************************************************
+ * Blockbits functions.
+ */
+static inline BOOL BIGBLOCKFILE_TestBit(const BlockBits *bb,
+					unsigned int index)
+{
+    unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
+    unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
+
+    return bb->bits[array_index] & (1 << bit_index);
+}
+
+static inline void BIGBLOCKFILE_SetBit(BlockBits *bb, unsigned int index)
+{
+    unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
+    unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
+
+    bb->bits[array_index] |= (1 << bit_index);
+}
+
+static inline void BIGBLOCKFILE_ClearBit(BlockBits *bb, unsigned int index)
+{
+    unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
+    unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
+
+    bb->bits[array_index] &= ~(1 << bit_index);
+}
+
+static inline void BIGBLOCKFILE_Zero(BlockBits *bb)
+{
+    memset(bb->bits, 0, sizeof(bb->bits));
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_Construct
+ *
+ * Construct a big block file. Create the file mapping object. 
+ * Create the read only mapped pages list, the writable mapped page list
+ * and the blocks in use list.
+ */
+BigBlockFile * BIGBLOCKFILE_Construct(
+  HANDLE   hFile,
+  ILockBytes* pLkByt,
+  DWORD    openFlags,
+  ULONG    blocksize,
+  BOOL     fileBased)
+{
+  LPBIGBLOCKFILE This;
+
+  This = (LPBIGBLOCKFILE)HeapAlloc(GetProcessHeap(), 0, sizeof(BigBlockFile));
+
+  if (This == NULL)
+    return NULL;
+
+  This->fileBased = fileBased;
+
+  This->flProtect = BIGBLOCKFILE_GetProtectMode(openFlags);
+
+  This->blocksize = blocksize;
+
+  This->maplist = NULL;
+  This->victimhead = NULL;
+  This->victimtail = NULL;
+  This->num_victim_pages = 0;
+
+  if (This->fileBased)
+  {
+    if (!BIGBLOCKFILE_FileInit(This, hFile))
+    {
+      HeapFree(GetProcessHeap(), 0, This);
+      return NULL;
+    }
+  }
+  else
+  {
+    if (!BIGBLOCKFILE_MemInit(This, pLkByt))
+    {
+      HeapFree(GetProcessHeap(), 0, This);
+      return NULL;
+    }
+  }
+
+  return This;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_FileInit
+ *
+ * Initialize a big block object supported by a file.
+ */
+static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile)
+{
+  This->pLkbyt     = NULL;
+  This->hbytearray = 0;
+  This->pbytearray = NULL;
+
+  This->hfile = hFile;
+
+  if (This->hfile == INVALID_HANDLE_VALUE)
+    return FALSE;
+
+  /* create the file mapping object
+   */
+  This->hfilemap = CreateFileMappingA(This->hfile,
+                                      NULL,
+                                      This->flProtect,
+                                      0, 0,
+                                      NULL);
+
+  if (This->hfilemap == NULL)
+  {
+    CloseHandle(This->hfile);
+    return FALSE;
+  }
+
+  This->filesize.LowPart = GetFileSize(This->hfile,
+					 (LPDWORD)&This->filesize.HighPart);
+
+  This->maplist = NULL;
+
+  TRACE("file len %lu\n", This->filesize.LowPart);
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_MemInit
+ *
+ * Initialize a big block object supported by an ILockBytes on HGLOABL.
+ */
+static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt)
+{
+  This->hfile       = 0;
+  This->hfilemap    = NULL;
+
+  /*
+   * Retrieve the handle to the byte array from the LockByte object.
+   */
+  if (GetHGlobalFromILockBytes(plkbyt, &(This->hbytearray)) != S_OK)
+  {
+    FIXME("May not be an ILockBytes on HGLOBAL\n");
+    return FALSE;
+  }
+
+  This->pLkbyt = plkbyt;
+
+  /*
+   * Increment the reference count of the ILockByte object since
+   * we're keeping a reference to it.
+   */
+  ILockBytes_AddRef(This->pLkbyt);
+
+  This->filesize.LowPart = GlobalSize(This->hbytearray);
+  This->filesize.HighPart = 0;
+
+  This->pbytearray = GlobalLock(This->hbytearray);
+
+  TRACE("mem on %p len %lu\n", This->pbytearray, This->filesize.LowPart);
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_Destructor
+ *
+ * Destructor. Clean up, free memory.
+ */
+void BIGBLOCKFILE_Destructor(
+  LPBIGBLOCKFILE This)
+{
+  BIGBLOCKFILE_FreeAllMappedPages(This);
+
+  if (This->fileBased)
+  {
+    CloseHandle(This->hfilemap);
+    CloseHandle(This->hfile);
+  }
+  else
+  {
+    GlobalUnlock(This->hbytearray);
+    ILockBytes_Release(This->pLkbyt);
+  }
+
+  /* destroy this
+   */
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetROBigBlock
+ *
+ * Returns the specified block in read only mode.
+ * Will return NULL if the block doesn't exists.
+ */
+void* BIGBLOCKFILE_GetROBigBlock(
+  LPBIGBLOCKFILE This,
+  ULONG          index)
+{
+  /*
+   * block index starts at -1
+   * translate to zero based index
+   */
+  if (index == 0xffffffff)
+    index = 0;
+  else
+    index++;
+
+  /*
+   * validate the block index
+   * 
+   */
+  if (This->blocksize * (index + 1)
+      > ROUND_UP(This->filesize.LowPart, This->blocksize))
+  {
+    TRACE("out of range %lu vs %lu\n", This->blocksize * (index + 1),
+	  This->filesize.LowPart);
+    return NULL;
+  }
+
+  return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_READ);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetBigBlock
+ *
+ * Returns the specified block.
+ * Will grow the file if necessary.
+ */
+void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index)
+{
+  /*
+   * block index starts at -1
+   * translate to zero based index
+   */
+  if (index == 0xffffffff)
+    index = 0;
+  else
+    index++;
+
+  /*
+   * make sure that the block physically exists
+   */
+  if ((This->blocksize * (index + 1)) > This->filesize.LowPart)
+  {
+    ULARGE_INTEGER newSize;
+
+    newSize.HighPart = 0;
+    newSize.LowPart = This->blocksize * (index + 1);
+
+    BIGBLOCKFILE_SetSize(This, newSize);
+  }
+
+  return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_WRITE);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_ReleaseBigBlock
+ *
+ * Releases the specified block.
+ */
+void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock)
+{
+    MappedPage *page;
+
+    if (pBlock == NULL)
+	return;
+
+    page = BIGBLOCKFILE_GetPageFromPointer(This, pBlock);
+
+    if (page == NULL)
+	return;
+
+    BIGBLOCKFILE_ReleaseMappedPage(This, page);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_SetSize
+ *
+ * Sets the size of the file.
+ * 
+ */
+void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize)
+{
+  if (This->filesize.LowPart == newSize.LowPart)
+    return;
+
+  TRACE("from %lu to %lu\n", This->filesize.LowPart, newSize.LowPart);
+  /*
+   * unmap all views, must be done before call to SetEndFile
+   */
+  BIGBLOCKFILE_UnmapAllMappedPages(This);
+  
+  if (This->fileBased)
+  {
+    char buf[10];
+
+    /*
+     * close file-mapping object, must be done before call to SetEndFile
+     */
+    CloseHandle(This->hfilemap);
+    This->hfilemap = NULL;
+
+    /*
+     * BEGIN HACK
+     * This fixes a bug when saving through smbfs.
+     * smbmount a Windows shared directory, save a structured storage file
+     * to that dir: crash.
+     *
+     * The problem is that the SetFilePointer-SetEndOfFile combo below
+     * doesn't always succeed. The file is not grown. It seems like the 
+     * operation is cached. By doing the WriteFile, the file is actually
+     * grown on disk.
+     * This hack is only needed when saving to smbfs.
+     */
+    memset(buf, '0', 10);
+    SetFilePointer(This->hfile, newSize.LowPart, NULL, FILE_BEGIN);
+    WriteFile(This->hfile, buf, 10, NULL, NULL);
+    /*
+     * END HACK 
+     */
+  
+    /*
+     * set the new end of file
+     */
+    SetFilePointer(This->hfile, newSize.LowPart, NULL, FILE_BEGIN);
+    SetEndOfFile(This->hfile);
+  
+    /*
+     * re-create the file mapping object
+     */
+    This->hfilemap = CreateFileMappingA(This->hfile,
+                                        NULL,
+                                        This->flProtect,
+                                        0, 0, 
+                                        NULL);
+  }
+  else
+  {
+    GlobalUnlock(This->hbytearray);
+
+    /*
+     * Resize the byte array object.
+     */
+    ILockBytes_SetSize(This->pLkbyt, newSize);
+
+    /*
+     * Re-acquire the handle, it may have changed.
+     */
+    GetHGlobalFromILockBytes(This->pLkbyt, &This->hbytearray);
+    This->pbytearray = GlobalLock(This->hbytearray);
+  }
+
+  This->filesize.LowPart = newSize.LowPart;
+  This->filesize.HighPart = newSize.HighPart;
+
+  BIGBLOCKFILE_RemapAllMappedPages(This);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetSize
+ *
+ * Returns the size of the file.
+ * 
+ */
+ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This)
+{
+  return This->filesize;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_AccessCheck     [PRIVATE]
+ *
+ * block_index is the index within the page.
+ */
+static BOOL BIGBLOCKFILE_AccessCheck(MappedPage *page, ULONG block_index,
+				     DWORD desired_access)
+{
+    assert(block_index < BLOCKS_PER_PAGE);
+
+    if (desired_access == FILE_MAP_READ)
+    {
+	if (BIGBLOCKFILE_TestBit(&page->writable_blocks, block_index))
+	    return FALSE;
+
+	BIGBLOCKFILE_SetBit(&page->readable_blocks, block_index);
+    }
+    else
+    {
+	assert(desired_access == FILE_MAP_WRITE);
+
+	if (BIGBLOCKFILE_TestBit(&page->readable_blocks, block_index))
+	    return FALSE;
+
+	BIGBLOCKFILE_SetBit(&page->writable_blocks, block_index);
+    }
+
+    return TRUE;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetBigBlockPointer     [PRIVATE]
+ *
+ * Returns a pointer to the specified block.
+ */
+static void* BIGBLOCKFILE_GetBigBlockPointer(
+  LPBIGBLOCKFILE This, 
+  ULONG          block_index, 
+  DWORD          desired_access)
+{
+    DWORD page_index = block_index / BLOCKS_PER_PAGE;
+    DWORD block_on_page = block_index % BLOCKS_PER_PAGE;
+
+    MappedPage *page = (MappedPage *)BIGBLOCKFILE_GetMappedView(This, page_index);
+    if (!page || !page->lpBytes) return NULL;
+
+    if (!BIGBLOCKFILE_AccessCheck(page, block_on_page, desired_access))
+    {
+	BIGBLOCKFILE_ReleaseMappedPage(This, page);
+	return NULL;
+    }
+
+    return (LPBYTE)page->lpBytes + (block_on_page * This->blocksize);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetMappedPageFromPointer     [PRIVATE]
+ *
+ * pBlock is a pointer to a block on a page.
+ * The page has to be on the in-use list. (As oppsed to the victim list.)
+ *
+ * Does not increment the usage count.
+ */
+static MappedPage *BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This,
+						   void *pBlock)
+{
+    MappedPage *page;
+
+    for (page = This->maplist; page != NULL; page = page->next)
+    {
+	if ((LPBYTE)pBlock >= (LPBYTE)page->lpBytes
+	    && (LPBYTE)pBlock <= (LPBYTE)page->lpBytes + PAGE_SIZE)
+	    break;
+
+    }
+
+    return page;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_FindPageInList      [PRIVATE]
+ *
+ */
+static MappedPage *BIGBLOCKFILE_FindPageInList(MappedPage *head,
+					       ULONG page_index)
+{
+    for (; head != NULL; head = head->next)
+    {
+	if (head->page_index == page_index)
+	{
+	    InterlockedIncrement(&head->refcnt);
+	    break;
+	}
+    }
+
+    return head;
+
+}
+
+static void BIGBLOCKFILE_UnlinkPage(MappedPage *page)
+{
+    if (page->next) page->next->prev = page->prev;
+    if (page->prev) page->prev->next = page->next;
+}
+
+static void BIGBLOCKFILE_LinkHeadPage(MappedPage **head, MappedPage *page)
+{
+    if (*head) (*head)->prev = page;
+    page->next = *head;
+    page->prev = NULL;
+    *head = page;
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_GetMappedView      [PRIVATE]
+ *
+ * Gets the page requested if it is already mapped.
+ * If it's not already mapped, this method will map it
+ */
+static void * BIGBLOCKFILE_GetMappedView(
+  LPBIGBLOCKFILE This,
+  DWORD          page_index)
+{
+    MappedPage *page;
+
+    page = BIGBLOCKFILE_FindPageInList(This->maplist, page_index);
+    if (!page)
+    {
+	page = BIGBLOCKFILE_FindPageInList(This->victimhead, page_index);
+	if (page)
+	{
+	    This->num_victim_pages--;
+
+	    BIGBLOCKFILE_Zero(&page->readable_blocks);
+	    BIGBLOCKFILE_Zero(&page->writable_blocks);
+	}
+    }
+
+    if (page)
+    {
+	/* If the page is not already at the head of the list, move
+	 * it there. (Also moves pages from victim to main list.) */
+	if (This->maplist != page)
+	{
+	    if (This->victimhead == page) This->victimhead = page->next;
+	    if (This->victimtail == page) This->victimtail = page->prev;
+
+	    BIGBLOCKFILE_UnlinkPage(page);
+
+	    BIGBLOCKFILE_LinkHeadPage(&This->maplist, page);
+	}
+
+	return page;
+    }
+
+    page = BIGBLOCKFILE_CreatePage(This, page_index);
+    if (!page) return NULL;
+
+    BIGBLOCKFILE_LinkHeadPage(&This->maplist, page);
+
+    return page;
+}
+
+static BOOL BIGBLOCKFILE_MapPage(LPBIGBLOCKFILE This, MappedPage *page)
+{
+    DWORD lowoffset = PAGE_SIZE * page->page_index;
+
+    if (This->fileBased)
+    {
+	DWORD numBytesToMap;
+	DWORD desired_access;
+
+	if (lowoffset + PAGE_SIZE > This->filesize.LowPart)
+	    numBytesToMap = This->filesize.LowPart - lowoffset;
+	else
+	    numBytesToMap = PAGE_SIZE;
+
+	if (This->flProtect == PAGE_READONLY)
+	    desired_access = FILE_MAP_READ;
+	else
+	    desired_access = FILE_MAP_WRITE;
+
+	page->lpBytes = MapViewOfFile(This->hfilemap, desired_access, 0,
+				      lowoffset, numBytesToMap);
+    }
+    else
+    {
+	page->lpBytes = (LPBYTE)This->pbytearray + lowoffset;
+    }
+
+    TRACE("mapped page %lu to %p\n", page->page_index, page->lpBytes);
+
+    return page->lpBytes != NULL;
+}
+
+static MappedPage *BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This,
+					   ULONG page_index)
+{
+    MappedPage *page;
+
+    page = (MappedPage *)HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage));
+    if (page == NULL)
+      return NULL;
+
+    page->page_index = page_index;
+    page->refcnt = 1;
+
+    page->next = NULL;
+    page->prev = NULL;
+
+    BIGBLOCKFILE_MapPage(This, page);
+
+    BIGBLOCKFILE_Zero(&page->readable_blocks);
+    BIGBLOCKFILE_Zero(&page->writable_blocks);
+
+    return page;
+}
+
+static void BIGBLOCKFILE_UnmapPage(LPBIGBLOCKFILE This, MappedPage *page)
+{
+    TRACE("%ld at %p\n", page->page_index, page->lpBytes);
+    if (page->refcnt > 0)
+	ERR("unmapping inuse page %p\n", page->lpBytes);
+
+    if (This->fileBased && page->lpBytes)
+	UnmapViewOfFile(page->lpBytes);
+
+    page->lpBytes = NULL;
+}
+
+static void BIGBLOCKFILE_DeletePage(LPBIGBLOCKFILE This, MappedPage *page)
+{
+    BIGBLOCKFILE_UnmapPage(This, page);
+
+    HeapFree(GetProcessHeap(), 0, page);
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_ReleaseMappedPage      [PRIVATE]
+ *
+ * Decrements the reference count of the mapped page.
+ */
+static void BIGBLOCKFILE_ReleaseMappedPage(
+  LPBIGBLOCKFILE This,
+  MappedPage    *page)
+{
+    assert(This != NULL);
+    assert(page != NULL);
+
+    /* If the page is no longer refenced, move it to the victim list.
+     * If the victim list is too long, kick somebody off. */
+    if (!InterlockedDecrement(&page->refcnt))
+    {
+	if (This->maplist == page) This->maplist = page->next;
+
+	BIGBLOCKFILE_UnlinkPage(page);
+
+	if (MAX_VICTIM_PAGES > 0)
+	{
+	    if (This->num_victim_pages >= MAX_VICTIM_PAGES)
+	    {
+		MappedPage *victim = This->victimtail;
+		if (victim)
+		{
+		    This->victimtail = victim->prev;
+		    if (This->victimhead == victim)
+			This->victimhead = victim->next;
+
+		    BIGBLOCKFILE_UnlinkPage(victim);
+		    BIGBLOCKFILE_DeletePage(This, victim);
+		}
+	    }
+	    else This->num_victim_pages++;
+
+	    BIGBLOCKFILE_LinkHeadPage(&This->victimhead, page);
+	    if (This->victimtail == NULL) This->victimtail = page;
+	}
+	else
+	    BIGBLOCKFILE_DeletePage(This, page);
+    }
+}
+
+static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This, MappedPage *list)
+{
+    while (list != NULL)
+    {
+	MappedPage *next = list->next;
+
+	BIGBLOCKFILE_DeletePage(This, list);
+
+	list = next;
+    }
+}
+
+/******************************************************************************
+ *      BIGBLOCKFILE_FreeAllMappedPages     [PRIVATE]
+ *
+ * Unmap all currently mapped pages.
+ * Empty mapped pages list.
+ */
+static void BIGBLOCKFILE_FreeAllMappedPages(
+  LPBIGBLOCKFILE This)
+{
+    BIGBLOCKFILE_DeleteList(This, This->maplist);
+    BIGBLOCKFILE_DeleteList(This, This->victimhead);
+
+    This->maplist = NULL;
+    This->victimhead = NULL;
+    This->victimtail = NULL;
+    This->num_victim_pages = 0;
+}
+
+static void BIGBLOCKFILE_UnmapList(LPBIGBLOCKFILE This, MappedPage *list)
+{
+    for (; list != NULL; list = list->next)
+    {
+	BIGBLOCKFILE_UnmapPage(This, list);
+    }
+}
+
+static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This)
+{
+    BIGBLOCKFILE_UnmapList(This, This->maplist);
+    BIGBLOCKFILE_UnmapList(This, This->victimhead);
+}
+
+static void BIGBLOCKFILE_RemapList(LPBIGBLOCKFILE This, MappedPage *list)
+{
+    while (list != NULL)
+    {
+	MappedPage *next = list->next;
+
+	if (list->page_index * PAGE_SIZE > This->filesize.LowPart)
+	{
+	    TRACE("discarding %lu\n", list->page_index);
+
+	    /* page is entirely outside of the file, delete it */
+	    BIGBLOCKFILE_UnlinkPage(list);
+	    BIGBLOCKFILE_DeletePage(This, list);
+	}
+	else
+	{
+	    /* otherwise, remap it */
+	    BIGBLOCKFILE_MapPage(This, list);
+	}
+
+	list = next;
+    }
+}
+
+static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This)
+{
+    BIGBLOCKFILE_RemapList(This, This->maplist);
+    BIGBLOCKFILE_RemapList(This, This->victimhead);
+}
+
+/****************************************************************************
+ *      BIGBLOCKFILE_GetProtectMode
+ *
+ * This function will return a protection mode flag for a file-mapping object
+ * from the open flags of a file.
+ */
+static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags)
+{
+    if (openFlags & (STGM_WRITE | STGM_READWRITE))
+	return PAGE_READWRITE;
+    else
+	return PAGE_READONLY;
+}
Index: trunk/src/ole32/new/stg_stream.cpp
===================================================================
--- trunk/src/ole32/new/stg_stream.cpp	(revision 3456)
+++ trunk/src/ole32/new/stg_stream.cpp	(revision 3456)
@@ -0,0 +1,885 @@
+/* $Id: stg_stream.cpp,v 1.1 2000-04-27 22:18:29 davidr Exp $ */
+/* 
+ * Compound Storage (32 bit version)
+ * Stream implementation
+ *
+ * 20/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *
+ * This file contains the implementation of the stream interface
+ * for streams contained in a compound storage.
+ * 
+ * TODO:
+ * - Support for a transacted mode
+ *
+ * Copyright 1999 Francis Beaudet
+ * Copyright 1999 Thuy Nguyen
+ */
+
+#include "ole32.h"
+#include "heapstring.h"
+#include "debugtools.h"
+#include "storage.h"
+
+#include <assert.h>
+
+DEFAULT_DEBUG_CHANNEL(storage)
+
+
+/*
+ * Virtual function table for the StgStreamImpl class.
+ */
+static ICOM_VTABLE(IStream) StgStreamImpl_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    StgStreamImpl_QueryInterface,
+    StgStreamImpl_AddRef,
+    StgStreamImpl_Release,
+    StgStreamImpl_Read,
+    StgStreamImpl_Write,
+    StgStreamImpl_Seek,
+    StgStreamImpl_SetSize,
+    StgStreamImpl_CopyTo,
+    StgStreamImpl_Commit,
+    StgStreamImpl_Revert,
+    StgStreamImpl_LockRegion,
+    StgStreamImpl_UnlockRegion,
+    StgStreamImpl_Stat,
+    StgStreamImpl_Clone
+};
+
+/******************************************************************************
+** StgStreamImpl implementation
+*/
+
+/***
+ * This is the constructor for the StgStreamImpl class.
+ *
+ * Params:
+ *    parentStorage - Pointer to the storage that contains the stream to open
+ *    ownerProperty - Index of the property that points to this stream.
+ */
+StgStreamImpl* StgStreamImpl_Construct(
+		StorageBaseImpl* parentStorage,
+		DWORD            grfMode,
+		ULONG              ownerProperty)
+{
+  StgStreamImpl* newStream;
+
+  newStream = (StgStreamImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl));
+  
+  if (newStream!=0)
+  {
+    /*
+     * Set-up the virtual function table and reference count.
+     */
+    ICOM_VTBL(newStream) = &StgStreamImpl_Vtbl;
+    newStream->ref    = 0;
+    
+    /*
+     * We want to nail-down the reference to the storage in case the
+     * stream out-lives the storage in the client application.
+     */
+    newStream->parentStorage = parentStorage;
+    IStorage_AddRef((IStorage*)newStream->parentStorage);
+    
+    newStream->grfMode = grfMode;    
+    newStream->ownerProperty = ownerProperty;
+    
+    /*
+     * Start the stream at the begining.
+     */
+    newStream->currentPosition.HighPart = 0;
+    newStream->currentPosition.LowPart = 0;
+    
+    /*
+     * Initialize the rest of the data.
+     */
+    newStream->streamSize.HighPart = 0;
+    newStream->streamSize.LowPart  = 0;
+    newStream->bigBlockChain       = 0;
+    newStream->smallBlockChain     = 0;
+    
+    /*
+     * Read the size from the property and determine if the blocks forming
+     * this stream are large or small.
+     */
+    StgStreamImpl_OpenBlockChain(newStream);
+  }
+  
+  return newStream;
+}
+
+/***
+ * This is the destructor of the StgStreamImpl class.
+ *
+ * This method will clean-up all the resources used-up by the given StgStreamImpl 
+ * class. The pointer passed-in to this function will be freed and will not
+ * be valid anymore.
+ */
+void StgStreamImpl_Destroy(StgStreamImpl* This)
+{
+  TRACE("(%p)\n", This);
+
+  /*
+   * Release the reference we are holding on the parent storage.
+   */
+  IStorage_Release((IStorage*)This->parentStorage);
+  This->parentStorage = 0;
+
+  /*
+   * Make sure we clean-up the block chain stream objects that we were using.
+   */
+  if (This->bigBlockChain != 0)
+  {
+    BlockChainStream_Destroy(This->bigBlockChain);
+    This->bigBlockChain = 0;
+  }
+
+  if (This->smallBlockChain != 0)
+  {
+    SmallBlockChainStream_Destroy(This->smallBlockChain);
+    This->smallBlockChain = 0;
+  }
+
+  /*
+   * Finally, free the memory used-up by the class.
+   */
+  HeapFree(GetProcessHeap(), 0, This);  
+}
+
+/***
+ * This implements the IUnknown method QueryInterface for this
+ * class
+ */
+HRESULT WINAPI StgStreamImpl_QueryInterface(
+		  IStream*     iface,
+		  REFIID         riid,	      /* [in] */          
+		  void**         ppvObject)   /* [iid_is][out] */ 
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (ppvObject==0)
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+  
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = (IStream*)This;
+  }
+  else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0) 
+  {
+    *ppvObject = (IStream*)This;
+  }
+  
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+    return E_NOINTERFACE;
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  StgStreamImpl_AddRef(iface);
+  
+  return S_OK;;
+}
+
+/***
+ * This implements the IUnknown method AddRef for this
+ * class
+ */
+ULONG WINAPI StgStreamImpl_AddRef(
+		IStream* iface)
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  This->ref++;
+  
+  return This->ref;
+}
+
+/***
+ * This implements the IUnknown method Release for this
+ * class
+ */
+ULONG WINAPI StgStreamImpl_Release(
+		IStream* iface)
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  ULONG newRef;
+  
+  This->ref--;
+  
+  newRef = This->ref;
+  
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (newRef==0)
+  {
+    StgStreamImpl_Destroy(This);
+  }
+  
+  return newRef;
+}
+
+/***
+ * This method will open the block chain pointed by the property
+ * that describes the stream.
+ * If the stream's size is null, no chain is opened.
+ */
+void StgStreamImpl_OpenBlockChain(
+        StgStreamImpl* This)
+{
+  StgProperty    curProperty;
+  BOOL         readSucessful;
+
+  /*
+   * Make sure no old object is staying behind.
+   */
+  if (This->smallBlockChain != 0)
+  {
+    SmallBlockChainStream_Destroy(This->smallBlockChain);
+    This->smallBlockChain = 0;
+  }
+
+  if (This->bigBlockChain != 0)
+  {
+    BlockChainStream_Destroy(This->bigBlockChain);
+    This->bigBlockChain = 0;
+  }
+
+  /*
+   * Read the information from the property.
+   */
+  readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
+					     This->ownerProperty,
+					     &curProperty);
+  
+  if (readSucessful)
+  {
+    This->streamSize = curProperty.size;
+    
+    /*
+     * This code supports only streams that are <32 bits in size.
+     */
+    assert(This->streamSize.HighPart == 0);
+    
+    if(curProperty.startingBlock == BLOCK_END_OF_CHAIN)
+    {
+      assert( (This->streamSize.HighPart == 0) && (This->streamSize.LowPart == 0) );
+    }
+    else
+    {
+      if ( (This->streamSize.HighPart == 0) &&
+	   (This->streamSize.LowPart < LIMIT_TO_USE_SMALL_BLOCK) )
+      {
+	This->smallBlockChain = SmallBlockChainStream_Construct(
+								This->parentStorage->ancestorStorage,	
+								This->ownerProperty);
+      }
+      else
+      {
+	This->bigBlockChain = BlockChainStream_Construct(
+							 This->parentStorage->ancestorStorage,
+							 NULL,
+							 This->ownerProperty);
+      }
+    }
+  }
+}
+
+/***
+ * This method is part of the ISequentialStream interface.
+ *
+ * If reads a block of information from the stream at the current
+ * position. It then moves the current position at the end of the
+ * read block
+ *
+ * See the documentation of ISequentialStream for more info.
+ */
+HRESULT WINAPI StgStreamImpl_Read( 
+		  IStream*     iface,
+		  void*          pv,        /* [length_is][size_is][out] */
+		  ULONG          cb,        /* [in] */                     
+		  ULONG*         pcbRead)   /* [out] */                    
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  ULONG bytesReadBuffer;
+  ULONG bytesToReadFromBuffer;
+
+  TRACE("(%p, %p, %ld, %p)\n",
+	iface, pv, cb, pcbRead);
+
+  /* 
+   * If the caller is not interested in the nubmer of bytes read,
+   * we use another buffer to avoid "if" statements in the code.
+   */
+  if (pcbRead==0)
+    pcbRead = &bytesReadBuffer;
+  
+  /*
+   * Using the known size of the stream, calculate the number of bytes
+   * to read from the block chain
+   */
+  bytesToReadFromBuffer = MIN( This->streamSize.LowPart - This->currentPosition.LowPart, cb);
+  
+  /*
+   * Depending on the type of chain that was opened when the stream was constructed,
+   * we delegate the work to the method that read the block chains.
+   */
+  if (This->smallBlockChain!=0)
+  {
+    SmallBlockChainStream_ReadAt(This->smallBlockChain,
+				 This->currentPosition,
+				 bytesToReadFromBuffer,
+				 pv,
+				 pcbRead);
+    
+  }
+  else if (This->bigBlockChain!=0)
+  {
+    BlockChainStream_ReadAt(This->bigBlockChain,
+			    This->currentPosition,
+			    bytesToReadFromBuffer,
+			    pv,
+			    pcbRead);
+  }
+  else
+  {
+    /*
+     * Small and big block chains are both NULL. This case will happen
+     * when a stream starts with BLOCK_END_OF_CHAIN and has size zero.
+     */
+
+    *pcbRead = 0;
+    return S_OK;
+  }
+
+  /*
+   * We should always be able to read the proper amount of data from the
+   * chain.
+   */
+  assert(bytesToReadFromBuffer == *pcbRead);
+
+  /*
+   * Advance the pointer for the number of positions read.
+   */
+  This->currentPosition.LowPart += *pcbRead;
+  
+  /*
+   * The function returns S_OK if the buffer was filled completely
+   * it returns S_FALSE if the end of the stream is reached before the
+   * buffer is filled
+   */
+  if(*pcbRead == cb)
+    return S_OK;
+  
+  return S_FALSE;
+}
+        
+/***
+ * This method is part of the ISequentialStream interface.
+ *
+ * It writes a block of information to the stream at the current
+ * position. It then moves the current position at the end of the
+ * written block. If the stream is too small to fit the block,
+ * the stream is grown to fit.
+ *
+ * See the documentation of ISequentialStream for more info.
+ */
+HRESULT WINAPI StgStreamImpl_Write(
+	          IStream*     iface,
+		  const void*    pv,          /* [size_is][in] */ 
+		  ULONG          cb,          /* [in] */          
+		  ULONG*         pcbWritten)  /* [out] */         
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  ULARGE_INTEGER newSize;
+  ULONG bytesWritten = 0;
+
+  TRACE("(%p, %p, %ld, %p)\n",
+	iface, pv, cb, pcbWritten);
+  
+  /*
+   * If the caller is not interested in the number of bytes written,
+   * we use another buffer to avoid "if" statements in the code.
+   */
+  if (pcbWritten == 0)
+    pcbWritten = &bytesWritten;
+  
+  /*
+   * Initialize the out parameter
+   */
+  *pcbWritten = 0;
+
+  /*
+   * Do we have permission to write to this stream?
+   */
+  if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
+    return STG_E_ACCESSDENIED;
+
+  if (cb == 0)
+  {
+    return S_OK;
+  }
+  else
+  {
+    newSize.HighPart = 0;
+    newSize.LowPart = This->currentPosition.LowPart + cb;
+  }
+  
+  /*
+   * Verify if we need to grow the stream
+   */
+  if (newSize.LowPart > This->streamSize.LowPart)
+  {
+    /* grow stream */
+    IStream_SetSize(iface, newSize);
+  }
+  
+  /*
+   * Depending on the type of chain that was opened when the stream was constructed,
+   * we delegate the work to the method that readwrites to the block chains.
+   */
+  if (This->smallBlockChain!=0)
+  {
+    SmallBlockChainStream_WriteAt(This->smallBlockChain,
+				  This->currentPosition,
+				  cb,
+				  pv,
+				  pcbWritten);
+    
+  }
+  else if (This->bigBlockChain!=0)
+  {
+    BlockChainStream_WriteAt(This->bigBlockChain,
+			     This->currentPosition,
+			     cb,
+			     pv,
+			     pcbWritten);
+  }
+  else
+    assert(FALSE);
+  
+  /*
+   * Advance the position pointer for the number of positions written.
+   */
+  This->currentPosition.LowPart += *pcbWritten;
+  
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * It will move the current stream pointer according to the parameters
+ * given.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI StgStreamImpl_Seek( 
+		  IStream*      iface,
+		  LARGE_INTEGER   dlibMove,         /* [in] */ 
+		  DWORD           dwOrigin,         /* [in] */ 
+		  ULARGE_INTEGER* plibNewPosition) /* [out] */
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  ULARGE_INTEGER newPosition;
+
+  TRACE("(%p, %ld, %ld, %p)\n",
+	iface, dlibMove.LowPart, dwOrigin, plibNewPosition);
+
+  /* 
+   * The caller is allowed to pass in NULL as the new position return value.
+   * If it happens, we assign it to a dynamic variable to avoid special cases
+   * in the code below.
+   */
+  if (plibNewPosition == 0)
+  {
+    plibNewPosition = &newPosition;
+  }
+
+  /*
+   * The file pointer is moved depending on the given "function"
+   * parameter.
+   */
+  switch (dwOrigin)
+  {
+    case STREAM_SEEK_SET:
+      plibNewPosition->HighPart = 0;
+      plibNewPosition->LowPart  = 0;
+      break;
+    case STREAM_SEEK_CUR:
+      *plibNewPosition = This->currentPosition;
+      break;
+    case STREAM_SEEK_END:
+      *plibNewPosition = This->streamSize;
+      break;
+    default:
+      return STG_E_INVALIDFUNCTION;
+  }
+
+#if SIZEOF_LONG_LONG >= 8
+  plibNewPosition->QuadPart += dlibMove.QuadPart;
+#else
+  /*
+   * do some multiword arithmetic:
+   *    treat HighPart as a signed value
+   *    treat LowPart as unsigned
+   *  NOTE: this stuff is two's complement specific!
+   */
+  if (dlibMove.HighPart < 0) { /* dlibMove is < 0 */
+      /* calculate the absolute value of dlibMove ... */
+      dlibMove.HighPart = -dlibMove.HighPart;
+      dlibMove.LowPart ^= -1;
+      /* ... and subtract with carry */
+      if (dlibMove.LowPart > plibNewPosition->LowPart) {
+	  /* carry needed, This accounts for any underflows at [1]*/
+	  plibNewPosition->HighPart -= 1; 
+      }
+      plibNewPosition->LowPart -= dlibMove.LowPart; /* [1] */
+      plibNewPosition->HighPart -= dlibMove.HighPart; 
+  } else {
+      /* add directly */
+      int initialLowPart = plibNewPosition->LowPart;
+      plibNewPosition->LowPart += dlibMove.LowPart;
+      if((plibNewPosition->LowPart < initialLowPart) ||
+	 (plibNewPosition->LowPart < dlibMove.LowPart)) {
+	  /* LowPart has rolled over => add the carry digit to HighPart */
+	  plibNewPosition->HighPart++;
+      }
+      plibNewPosition->HighPart += dlibMove.HighPart; 
+  }
+  /*
+   * Check if we end-up before the beginning of the file. That should 
+   * trigger an error.
+   */
+  if (plibNewPosition->HighPart < 0) {
+      return STG_E_INVALIDPOINTER;
+  }
+
+    /*
+   * We currently don't support files with offsets of >32 bits.  
+   * Note that we have checked for a negative offset already
+     */
+  assert(plibNewPosition->HighPart <= 0);
+
+#endif
+
+  /*
+   * tell the caller what we calculated
+   */
+  This->currentPosition = *plibNewPosition;
+ 
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * It will change the size of a stream.
+ *
+ * TODO: Switch from small blocks to big blocks and vice versa.
+ *
+ * See the documentation of IStream for more info.
+ */
+HRESULT WINAPI StgStreamImpl_SetSize( 
+				     IStream*      iface,
+				     ULARGE_INTEGER  libNewSize)   /* [in] */ 
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  StgProperty    curProperty;
+  BOOL         Success;
+
+  TRACE("(%p, %ld)\n", iface, libNewSize.LowPart);
+
+  /*
+   * As documented.
+   */
+  if (libNewSize.HighPart != 0)
+    return STG_E_INVALIDFUNCTION;
+  
+  /*
+   * Do we have permission?
+   */
+  if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE)))
+    return STG_E_ACCESSDENIED;
+
+  if (This->streamSize.LowPart == libNewSize.LowPart)
+    return S_OK;
+
+  /*
+   * This will happen if we're creating a stream
+   */
+  if ((This->smallBlockChain == 0) && (This->bigBlockChain == 0))
+  {
+    if (libNewSize.LowPart < LIMIT_TO_USE_SMALL_BLOCK)
+    {
+      This->smallBlockChain = SmallBlockChainStream_Construct(
+                                    This->parentStorage->ancestorStorage,
+                                    This->ownerProperty);
+    }
+    else
+    {
+      This->bigBlockChain = BlockChainStream_Construct(
+                                This->parentStorage->ancestorStorage,
+                                NULL,
+                                This->ownerProperty);
+    }
+  }
+
+  /*
+   * Read this stream's property to see if it's small blocks or big blocks
+   */
+  Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
+                                       This->ownerProperty,
+                                       &curProperty); 
+  /*
+   * Determine if we have to switch from small to big blocks or vice versa
+   */  
+  if ( (This->smallBlockChain!=0) && 
+       (curProperty.size.LowPart < LIMIT_TO_USE_SMALL_BLOCK) )
+  {
+    if (libNewSize.LowPart >= LIMIT_TO_USE_SMALL_BLOCK)
+    {
+      /*
+       * Transform the small block chain into a big block chain
+       */
+      This->bigBlockChain = Storage32Impl_SmallBlocksToBigBlocks(
+                                This->parentStorage->ancestorStorage,
+                                &This->smallBlockChain);
+    }
+  }
+
+  if (This->smallBlockChain!=0)
+  {
+    Success = SmallBlockChainStream_SetSize(This->smallBlockChain, libNewSize);
+  }
+  else
+  {
+    Success = BlockChainStream_SetSize(This->bigBlockChain, libNewSize);
+  }
+
+  /*
+   * Write to the property the new information about this stream
+   */
+  Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
+                                       This->ownerProperty,
+                                       &curProperty);
+
+  curProperty.size.HighPart = libNewSize.HighPart;
+  curProperty.size.LowPart = libNewSize.LowPart;
+  
+  if (Success)
+  {
+    StorageImpl_WriteProperty(This->parentStorage->ancestorStorage,
+				This->ownerProperty,
+				&curProperty);
+  }
+  
+  This->streamSize = libNewSize;
+  
+  return S_OK;
+}
+        
+/***
+ * This method is part of the IStream interface.
+ *
+ * It will copy the 'cb' Bytes to 'pstm' IStream.
+ *
+ * See the documentation of IStream for more info.
+ */
+HRESULT WINAPI StgStreamImpl_CopyTo( 
+				    IStream*      iface,
+				    IStream*      pstm,         /* [unique][in] */ 
+				    ULARGE_INTEGER  cb,           /* [in] */         
+				    ULARGE_INTEGER* pcbRead,      /* [out] */        
+				    ULARGE_INTEGER* pcbWritten)   /* [out] */        
+{
+  HRESULT        hr = S_OK;
+  BYTE           tmpBuffer[128];
+  ULONG          bytesRead, bytesWritten, copySize;
+  ULARGE_INTEGER totalBytesRead;
+  ULARGE_INTEGER totalBytesWritten;
+
+  TRACE("(%p, %p, %ld, %p, %p)\n", 
+	iface, pstm, cb.LowPart, pcbRead, pcbWritten);
+
+  /*
+   * Sanity check
+   */
+  if ( pstm == 0 )
+    return STG_E_INVALIDPOINTER;
+
+  totalBytesRead.LowPart = totalBytesRead.HighPart = 0;
+  totalBytesWritten.LowPart = totalBytesWritten.HighPart = 0;
+
+  /*
+   * use stack to store data temporarly
+   * there is surely more performant way of doing it, for now this basic
+   * implementation will do the job
+   */
+  while ( cb.LowPart > 0 )
+  {
+    if ( cb.LowPart >= 128 )
+      copySize = 128;
+    else
+      copySize = cb.LowPart;
+    
+    IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
+
+    totalBytesRead.LowPart += bytesRead;
+    
+    IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
+
+    totalBytesWritten.LowPart += bytesWritten;
+
+    /*
+     * Check that read & write operations were succesfull
+     */
+    if (bytesRead != bytesWritten)
+    {
+      hr = STG_E_MEDIUMFULL;
+      break;
+    }
+    
+    if (bytesRead!=copySize)
+      cb.LowPart = 0;
+    else
+      cb.LowPart -= bytesRead;
+  }
+
+  /*
+   * Update number of bytes read and written
+   */
+  if (pcbRead)
+  {
+    pcbRead->LowPart = totalBytesRead.LowPart;
+    pcbRead->HighPart = totalBytesRead.HighPart;
+  }
+
+  if (pcbWritten)
+  {
+    pcbWritten->LowPart = totalBytesWritten.LowPart;
+    pcbWritten->HighPart = totalBytesWritten.HighPart;
+  }
+  return hr;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * For streams contained in structured storages, this method
+ * does nothing. This is what the documentation tells us.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI StgStreamImpl_Commit( 
+		  IStream*      iface,
+		  DWORD           grfCommitFlags)  /* [in] */ 
+{
+  return S_OK;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * For streams contained in structured storages, this method
+ * does nothing. This is what the documentation tells us.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI StgStreamImpl_Revert( 
+		  IStream* iface)
+{
+  return S_OK;
+}
+
+HRESULT WINAPI StgStreamImpl_LockRegion( 
+					IStream*     iface,
+					ULARGE_INTEGER libOffset,   /* [in] */ 
+					ULARGE_INTEGER cb,          /* [in] */ 
+					DWORD          dwLockType)  /* [in] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+HRESULT WINAPI StgStreamImpl_UnlockRegion( 
+					  IStream*     iface,
+					  ULARGE_INTEGER libOffset,   /* [in] */ 
+					  ULARGE_INTEGER cb,          /* [in] */ 
+					  DWORD          dwLockType)  /* [in] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+/***
+ * This method is part of the IStream interface.
+ *
+ * This method returns information about the current
+ * stream.
+ *
+ * See the documentation of IStream for more info.
+ */        
+HRESULT WINAPI StgStreamImpl_Stat( 
+		  IStream*     iface,
+		  STATSTG*       pstatstg,     /* [out] */
+		  DWORD          grfStatFlag)  /* [in] */ 
+{
+  StgStreamImpl* const This=(StgStreamImpl*)iface;
+
+  StgProperty    curProperty;
+  BOOL         readSucessful;
+  
+  /*
+   * Read the information from the property.
+   */
+  readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage,
+					     This->ownerProperty,
+					     &curProperty);
+  
+  if (readSucessful)
+  {
+    StorageUtl_CopyPropertyToSTATSTG(pstatstg, 
+				     &curProperty, 
+				     grfStatFlag);
+    
+    pstatstg->grfMode = This->grfMode;
+
+    return S_OK;
+  }
+  
+  return E_FAIL;
+}
+        
+HRESULT WINAPI StgStreamImpl_Clone( 
+				   IStream*     iface,
+				   IStream**    ppstm) /* [out] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
Index: trunk/src/ole32/new/storage.cpp
===================================================================
--- trunk/src/ole32/new/storage.cpp	(revision 3456)
+++ trunk/src/ole32/new/storage.cpp	(revision 3456)
@@ -0,0 +1,7546 @@
+/* $Id: storage.cpp,v 1.1 2000-04-27 22:18:29 davidr Exp $ */
+/* 
+ * Compound Storage functions.
+ * 
+ * 20/9/99
+ * 
+ * Copyright 1999 David J. Raison
+ * 
+ * Direct port of Wine Implementation
+ *   Copyright 1999 Francis Beaudet
+ *   Copyright 1999 Sylvain St-Germain
+ *   Copyright 1999 Thuy Nguyen
+ *   Copyright 1998 Marcus Meissner
+ *
+ * Implemented using the documentation of the LAOLA project at
+ * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
+ * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
+ *
+ */
+
+#include "ole32.h"
+#include "heapstring.h"
+#include "debugtools.h"
+#include <assert.h>
+
+#include "storage.h"
+
+#include "winnls.h"
+#include "winreg.h"
+#include "wine/wingdi16.h"
+
+DEFAULT_DEBUG_CHANNEL(storage)
+
+#define FILE_BEGIN 0
+
+
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+#define OLESTREAM_ID 0x501
+#define OLESTREAM_MAX_STR_LEN 255
+
+#define OLECONVERT_NUM_OLE10STREAMS 2
+
+#define OLECONVERT_LINK_TYPE              1L
+#define OLECONVERT_EMBEDDED_TYPE          2L
+#define OLECONVERT_PRESENTATION_DATA_TYPE 5L
+
+static const char rootPropertyName[] = "Root Entry";
+
+
+/* OLESTREAM memory structure to use for Get and Put Routines */
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+typedef struct 
+{
+    DWORD dwOleID;
+    DWORD dwObjectTypeID;
+    DWORD dwOleTypeNameLength;
+    CHAR  strOleTypeName[OLESTREAM_MAX_STR_LEN];
+    DWORD dwLinkFileNameLength;
+    BYTE *strLinkFileName;
+    DWORD dwLinkExtraInfoLength;
+    BYTE *pLinkExtraInfo;
+    DWORD dwMetaFileWidth;
+    DWORD dwMetaFileHeight;
+    DWORD dwDataLength;
+    BYTE *pData;
+}OLECONVERT_OLESTREAM_DATA;
+
+/* CompObj Stream structure */
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+typedef struct
+{
+    BYTE byUnknown1[12];
+    CLSID clsid;
+    DWORD dwCLSIDNameLength;
+    CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN];
+    DWORD dwOleTypeNameLength;
+    CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN];
+    DWORD dwProgIDNameLength;
+    CHAR strProgIDName[OLESTREAM_MAX_STR_LEN];
+    BYTE byUnknown2[16];
+}OLECONVERT_ISTORAGE_COMPOBJ;
+
+
+/* Ole Presention Stream structure */
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+typedef struct
+{
+    BYTE byUnknown1[28];
+    DWORD dwExtentX;
+    DWORD dwExtentY;
+    DWORD dwSize;  
+    BYTE *pData;
+}OLECONVERT_ISTORAGE_OLEPRES;
+
+
+/* Ole Stream Structure */
+/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */
+typedef struct
+{
+    DWORD dwOLEHEADER_ID;
+    DWORD dwUnknown1;
+    DWORD dwUnknown2;
+    DWORD dwUnknown3;
+    DWORD dwUnknown4; /*Only used when using a Moniker is present in the /001Ole Stream*/
+    DWORD dwUnknown5; /*Only used when using a Moniker is present in the /001Ole stream*/
+    DWORD dwObjectCLSIDOffset;
+    CLSID clsidMonikerTypeID;
+    /*Save info for clsidMonikerTypeID (eg. FileMoniker, ItemMoniker, or CompositeMoniker) */
+    DWORD dwUnknown6;
+    CLSID clsidObject;
+    BYTE dwUnknown7[32];
+}OLECONVERT_ISTORAGE_OLE;
+
+
+
+
+/***********************************************************************
+ * Forward declaration of internal functions used by the method DestroyElement
+ */
+static HRESULT deleteStorageProperty(
+  StorageImpl *parentStorage,
+  ULONG        foundPropertyIndexToDelete,
+  StgProperty  propertyToDelete);
+
+static HRESULT deleteStreamProperty(
+  StorageImpl *parentStorage,
+  ULONG         foundPropertyIndexToDelete,
+  StgProperty   propertyToDelete);
+
+static HRESULT findPlaceholder(
+  StorageImpl *storage,
+  ULONG         propertyIndexToStore,
+  ULONG         storagePropertyIndex,
+  INT         typeOfRelation);
+
+static HRESULT adjustPropertyChain( 
+  StorageImpl *This,
+  StgProperty   propertyToDelete,
+  StgProperty   parentProperty,
+  ULONG         parentPropertyId,
+  INT         typeOfRelation);
+
+/***********************************************************************
+ * Declaration of the functions used to manipulate StgProperty
+ */
+
+static ULONG getFreeProperty(
+  StorageImpl *storage);
+
+static void updatePropertyChain(
+  StorageImpl *storage,
+  ULONG       newPropertyIndex,
+  StgProperty newProperty);
+
+static LONG propertyNameCmp(
+  OLECHAR *newProperty,
+  OLECHAR *currentProperty);
+
+
+/***********************************************************************
+ * Declaration of miscellaneous functions...
+ */
+static HRESULT validateSTGM(DWORD stgmValue); 
+
+static DWORD GetShareModeFromSTGM(DWORD stgm);
+static DWORD GetAccessModeFromSTGM(DWORD stgm);
+static DWORD GetCreationModeFromSTGM(DWORD stgm);
+
+/*
+ * Virtual function table for the IStorage32Impl class.
+ */
+static ICOM_VTABLE(IStorage) Storage32Impl_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    StorageBaseImpl_QueryInterface,
+    StorageBaseImpl_AddRef,
+    StorageBaseImpl_Release,
+    StorageBaseImpl_CreateStream,
+    StorageBaseImpl_OpenStream,
+    StorageImpl_CreateStorage,
+    StorageBaseImpl_OpenStorage,
+    StorageImpl_CopyTo,
+    StorageImpl_MoveElementTo,
+    StorageImpl_Commit,
+    StorageImpl_Revert,
+    StorageBaseImpl_EnumElements,
+    StorageImpl_DestroyElement,
+    StorageBaseImpl_RenameElement,
+    StorageImpl_SetElementTimes,
+    StorageBaseImpl_SetClass,
+    StorageImpl_SetStateBits,
+    StorageBaseImpl_Stat
+};
+
+/*
+ * Virtual function table for the Storage32InternalImpl class.
+ */
+static ICOM_VTABLE(IStorage) Storage32InternalImpl_Vtbl =
+  {
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    StorageBaseImpl_QueryInterface,
+    StorageBaseImpl_AddRef,
+    StorageBaseImpl_Release,
+    StorageBaseImpl_CreateStream,
+    StorageBaseImpl_OpenStream,
+    StorageImpl_CreateStorage,
+    StorageBaseImpl_OpenStorage,
+    StorageImpl_CopyTo,
+    StorageImpl_MoveElementTo,
+    StorageInternalImpl_Commit,
+    StorageInternalImpl_Revert,
+    StorageBaseImpl_EnumElements,
+    StorageImpl_DestroyElement,
+    StorageBaseImpl_RenameElement,
+    StorageImpl_SetElementTimes,
+    StorageBaseImpl_SetClass,
+    StorageImpl_SetStateBits,
+    StorageBaseImpl_Stat
+};
+
+/*
+ * Virtual function table for the IEnumSTATSTGImpl class.
+ */
+static ICOM_VTABLE(IEnumSTATSTG) IEnumSTATSTGImpl_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    IEnumSTATSTGImpl_QueryInterface,
+    IEnumSTATSTGImpl_AddRef,
+    IEnumSTATSTGImpl_Release,
+    IEnumSTATSTGImpl_Next,
+    IEnumSTATSTGImpl_Skip,
+    IEnumSTATSTGImpl_Reset,
+    IEnumSTATSTGImpl_Clone
+};
+
+
+
+
+
+/************************************************************************
+** Storage32BaseImpl implementatiion
+*/
+
+/************************************************************************
+ * Storage32BaseImpl_QueryInterface (IUnknown)
+ *
+ * This method implements the common QueryInterface for all IStorage32
+ * implementations contained in this file.
+ * 
+ * See Windows documentation for more details on IUnknown methods.
+ */
+HRESULT WINAPI StorageBaseImpl_QueryInterface(
+  IStorage*        iface,
+  REFIID             riid,
+  void**             ppvObject)
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppvObject==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+  
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = (IStorage*)This;
+  }
+  else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0) 
+  {
+    *ppvObject = (IStorage*)This;
+  }
+  
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+    return E_NOINTERFACE;
+  
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  StorageBaseImpl_AddRef(iface);
+
+  return S_OK;
+}
+        
+/************************************************************************
+ * Storage32BaseImpl_AddRef (IUnknown)
+ *
+ * This method implements the common AddRef for all IStorage32
+ * implementations contained in this file.
+ * 
+ * See Windows documentation for more details on IUnknown methods.
+ */
+ULONG WINAPI StorageBaseImpl_AddRef( 
+            IStorage* iface)
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  This->ref++;
+
+  return This->ref;
+}
+        
+/************************************************************************
+ * Storage32BaseImpl_Release (IUnknown)
+ *
+ * This method implements the common Release for all IStorage32
+ * implementations contained in this file.
+ * 
+ * See Windows documentation for more details on IUnknown methods.
+ */
+ULONG WINAPI StorageBaseImpl_Release( 
+      IStorage* iface)
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  /*
+   * Decrease the reference count on this object.
+   */
+  This->ref--;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (This->ref==0)
+  {
+    /*
+     * Since we are using a system of base-classes, we want to call the 
+     * destructor of the appropriate derived class. To do this, we are 
+     * using virtual functions to implement the destructor.
+     */
+    This->v_destructor(This);
+
+    return 0;
+  }
+  
+  return This->ref;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_OpenStream (IStorage)
+ *
+ * This method will open the specified stream object from the current storage.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_OpenStream( 
+  IStorage*        iface,
+  const OLECHAR*   pwcsName,  /* [string][in] */
+  void*            reserved1, /* [unique][in] */
+  DWORD            grfMode,   /* [in]  */        
+  DWORD            reserved2, /* [in]  */        
+  IStream**        ppstm)     /* [out] */       
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  IEnumSTATSTGImpl* propertyEnumeration;
+  StgStreamImpl*    newStream;
+  StgProperty       currentProperty;
+  ULONG             foundPropertyIndex;
+
+  TRACE("(%p, %s, %p, %lx, %ld, %p)\n", 
+	iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (pwcsName==NULL) || (ppstm==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Initialize the out parameter
+   */
+  *ppstm = 0;
+  
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * As documented.
+   */
+  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
+        (grfMode & STGM_DELETEONRELEASE) ||
+        (grfMode & STGM_TRANSACTED) )
+    return STG_E_INVALIDFUNCTION;
+
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(
+    This->ancestorStorage, 
+    This->rootPropertySetIndex);
+  
+  /*
+   * Search the enumeration for the property with the given name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
+    propertyEnumeration,
+    pwcsName,
+    &currentProperty);
+  
+  /*
+   * Delete the property enumeration since we don't need it anymore
+   */
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+  
+  /*
+   * If it was found, construct the stream object and return a pointer to it.
+   */
+  if ( (foundPropertyIndex!=PROPERTY_NULL) && 
+       (currentProperty.propertyType==PROPTYPE_STREAM) )
+  {
+    newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex);
+    
+    if (newStream!=0)
+    {
+      *ppstm = (IStream*)newStream;
+
+      /*
+       * Since we are returning a pointer to the interface, we have to 
+       * nail down the reference.
+       */
+      StgStreamImpl_AddRef(*ppstm);
+      
+      return S_OK;
+    }
+    
+    return E_OUTOFMEMORY;
+  }
+  
+  return STG_E_FILENOTFOUND;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_OpenStorage (IStorage)
+ *
+ * This method will open a new storage object from the current storage.
+ * 
+ * See Windows documentation for more details on IStorage methods.
+ */        
+HRESULT WINAPI StorageBaseImpl_OpenStorage( 
+  IStorage*        iface,
+  const OLECHAR*   pwcsName,      /* [string][unique][in] */ 
+  IStorage*        pstgPriority,  /* [unique][in] */         
+  DWORD            grfMode,       /* [in] */                 
+  SNB              snbExclude,    /* [unique][in] */         
+  DWORD            reserved,      /* [in] */                 
+  IStorage**       ppstg)         /* [out] */                        
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  StorageInternalImpl* newStorage;
+  IEnumSTATSTGImpl*      propertyEnumeration;
+  StgProperty            currentProperty;
+  ULONG                  foundPropertyIndex;
+
+  TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n", 
+	iface, debugstr_w(pwcsName), pstgPriority, 
+	grfMode, snbExclude, reserved, ppstg);
+  
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (pwcsName==NULL) || (ppstg==0) )
+    return E_INVALIDARG;
+  
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * As documented.
+   */
+  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) || 
+        (grfMode & STGM_DELETEONRELEASE) ||
+        (grfMode & STGM_PRIORITY) )
+    return STG_E_INVALIDFUNCTION;
+
+  /*
+   * Initialize the out parameter
+   */
+  *ppstg = 0;
+  
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(
+                          This->ancestorStorage, 
+                          This->rootPropertySetIndex);
+  
+  /*
+   * Search the enumeration for the property with the given name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(
+                         propertyEnumeration,
+                         pwcsName,
+                         &currentProperty);
+  
+  /*
+   * Delete the property enumeration since we don't need it anymore
+   */
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+  
+  /*
+   * If it was found, construct the stream object and return a pointer to it.
+   */
+  if ( (foundPropertyIndex!=PROPERTY_NULL) && 
+       (currentProperty.propertyType==PROPTYPE_STORAGE) )
+  {
+    /*
+     * Construct a new Storage object
+     */
+    newStorage = StorageInternalImpl_Construct(
+                   This->ancestorStorage,
+                   foundPropertyIndex);
+    
+    if (newStorage != 0)
+    {
+      *ppstg = (IStorage*)newStorage;
+
+      /*
+       * Since we are returning a pointer to the interface, 
+       * we have to nail down the reference.
+       */
+      StorageBaseImpl_AddRef(*ppstg);
+      
+      return S_OK;
+    }
+    
+    return STG_E_INSUFFICIENTMEMORY;
+  }
+  
+  return STG_E_FILENOTFOUND;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_EnumElements (IStorage)
+ *
+ * This method will create an enumerator object that can be used to 
+ * retrieve informatino about all the properties in the storage object.
+ * 
+ * See Windows documentation for more details on IStorage methods.
+ */        
+HRESULT WINAPI StorageBaseImpl_EnumElements( 
+  IStorage*       iface,
+  DWORD           reserved1, /* [in] */                  
+  void*           reserved2, /* [size_is][unique][in] */ 
+  DWORD           reserved3, /* [in] */                  
+  IEnumSTATSTG**  ppenum)    /* [out] */                 
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  IEnumSTATSTGImpl* newEnum;
+
+  TRACE("(%p, %ld, %p, %ld, %p)\n", 
+	iface, reserved1, reserved2, reserved3, ppenum);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (ppenum==0))
+    return E_INVALIDARG;
+  
+  /*
+   * Construct the enumerator.
+   */
+  newEnum = IEnumSTATSTGImpl_Construct(
+              This->ancestorStorage,
+              This->rootPropertySetIndex);
+
+  if (newEnum!=0)
+  {
+    *ppenum = (IEnumSTATSTG*)newEnum;
+
+    /*
+     * Don't forget to nail down a reference to the new object before
+     * returning it.
+     */
+    IEnumSTATSTGImpl_AddRef(*ppenum);
+    
+    return S_OK;
+  }
+
+  return E_OUTOFMEMORY;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_Stat (IStorage)
+ *
+ * This method will retrieve information about this storage object.
+ * 
+ * See Windows documentation for more details on IStorage methods.
+ */        
+HRESULT WINAPI StorageBaseImpl_Stat( 
+  IStorage*        iface,
+  STATSTG*         pstatstg,     /* [out] */ 
+  DWORD            grfStatFlag)  /* [in] */  
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  StgProperty    curProperty;
+  BOOL         readSucessful;
+
+  TRACE("(%p, %p, %lx)\n", 
+	iface, pstatstg, grfStatFlag);
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (This==0) || (pstatstg==0))
+    return E_INVALIDARG;
+
+  /*
+   * Read the information from the property.
+   */
+  readSucessful = StorageImpl_ReadProperty(
+                    This->ancestorStorage,
+                    This->rootPropertySetIndex,
+                    &curProperty);
+
+  if (readSucessful)
+  {
+    StorageUtl_CopyPropertyToSTATSTG(
+      pstatstg, 
+      &curProperty, 
+      grfStatFlag);
+    
+    return S_OK;
+  }
+  
+  return E_FAIL;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_RenameElement (IStorage)
+ *
+ * This method will rename the specified element. 
+ *
+ * See Windows documentation for more details on IStorage methods.
+ * 
+ * Implementation notes: The method used to rename consists of creating a clone 
+ *    of the deleted StgProperty object setting it with the new name and to 
+ *    perform a DestroyElement of the old StgProperty.
+ */
+HRESULT WINAPI StorageBaseImpl_RenameElement(
+            IStorage*        iface,
+            const OLECHAR*   pwcsOldName,  /* [in] */
+            const OLECHAR*   pwcsNewName)  /* [in] */
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  IEnumSTATSTGImpl* propertyEnumeration;
+  StgProperty       currentProperty;
+  ULONG             foundPropertyIndex;
+
+  TRACE("(%p, %s, %s)\n", 
+	iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName));
+
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
+                                                   This->rootPropertySetIndex);
+
+  /*
+   * Search the enumeration for the new property name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsNewName,
+                                                     &currentProperty);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    /*
+     * There is already a property with the new name
+     */
+    IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+    return STG_E_FILEALREADYEXISTS;
+  }
+
+  IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)propertyEnumeration);
+
+  /*
+   * Search the enumeration for the old property name
+   */
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsOldName,
+                                                     &currentProperty);
+
+  /*
+   * Delete the property enumeration since we don't need it anymore
+   */
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    StgProperty renamedProperty;
+    ULONG       renamedPropertyIndex;
+
+    /*
+     * Setup a new property for the renamed property
+     */
+    renamedProperty.sizeOfNameString = 
+      ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR);
+  
+    if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+      return STG_E_INVALIDNAME;
+  
+    lstrcpyW(renamedProperty.name, pwcsNewName);
+ 
+    renamedProperty.propertyType  = currentProperty.propertyType;
+    renamedProperty.startingBlock = currentProperty.startingBlock;
+    renamedProperty.size.LowPart  = currentProperty.size.LowPart;
+    renamedProperty.size.HighPart = currentProperty.size.HighPart;
+  
+    renamedProperty.previousProperty = PROPERTY_NULL;
+    renamedProperty.nextProperty     = PROPERTY_NULL;
+  
+    /*
+     * Bring the dirProperty link in case it is a storage and in which
+     * case the renamed storage elements don't require to be reorganized.
+     */
+    renamedProperty.dirProperty = currentProperty.dirProperty;
+  
+    /* call CoFileTime to get the current time 
+    renamedProperty.timeStampS1
+    renamedProperty.timeStampD1
+    renamedProperty.timeStampS2
+    renamedProperty.timeStampD2
+    renamedProperty.propertyUniqueID 
+    */
+  
+    /* 
+     * Obtain a free property in the property chain
+     */
+    renamedPropertyIndex = getFreeProperty(This->ancestorStorage);
+  
+    /*
+     * Save the new property into the new property spot
+     */  
+    StorageImpl_WriteProperty(
+      This->ancestorStorage,
+      renamedPropertyIndex, 
+      &renamedProperty);
+  
+    /* 
+     * Find a spot in the property chain for our newly created property.
+     */
+    updatePropertyChain(
+      (StorageImpl*)This,
+      renamedPropertyIndex, 
+      renamedProperty);
+
+    /*
+     * At this point the renamed property has been inserted in the tree, 
+     * now, before to Destroy the old property we must zeroed it's dirProperty 
+     * otherwise the DestroyProperty below will zap it all and we do not want 
+     * this to happen.
+     * Also, we fake that the old property is a storage so the DestroyProperty
+     * will not do a SetSize(0) on the stream data.
+     * 
+     * This means that we need to tweek the StgProperty if it is a stream or a
+     * non empty storage.
+     */
+    StorageImpl_ReadProperty(This->ancestorStorage,
+                             foundPropertyIndex,
+                             &currentProperty);
+
+    currentProperty.dirProperty  = PROPERTY_NULL;
+    currentProperty.propertyType = PROPTYPE_STORAGE;
+    StorageImpl_WriteProperty(
+      This->ancestorStorage,
+      foundPropertyIndex, 
+      &currentProperty);
+
+    /* 
+     * Invoke Destroy to get rid of the ole property and automatically redo 
+     * the linking of it's previous and next members... 
+     */ 
+    StorageImpl_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName); 
+
+  }
+  else
+  {
+    /*
+     * There is no property with the old name
+     */
+    return STG_E_FILENOTFOUND;
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_CreateStream (IStorage)
+ *
+ * This method will create a stream object within this storage 
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_CreateStream(
+            IStorage*        iface,
+            const OLECHAR*   pwcsName,  /* [string][in] */
+            DWORD            grfMode,   /* [in] */
+            DWORD            reserved1, /* [in] */
+            DWORD            reserved2, /* [in] */
+            IStream**        ppstm)     /* [out] */
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  IEnumSTATSTGImpl* propertyEnumeration;
+  StgStreamImpl*    newStream;
+  StgProperty       currentProperty, newStreamProperty;
+  ULONG             foundPropertyIndex, newPropertyIndex;
+
+  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", 
+	iface, debugstr_w(pwcsName), grfMode, 
+	reserved1, reserved2, ppstm);
+
+  /*
+   * Validate parameters
+   */
+  if (ppstm == 0)
+    return STG_E_INVALIDPOINTER;
+
+  if (pwcsName == 0)
+    return STG_E_INVALIDNAME;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * As documented.
+   */
+  if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ||
+        (grfMode & STGM_DELETEONRELEASE) ||
+        (grfMode & STGM_TRANSACTED) )
+    return STG_E_INVALIDFUNCTION;
+
+  /*
+   * Initialize the out parameter
+   */
+  *ppstm = 0;
+
+  /*
+   * Create a property enumeration to search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage,
+                                                   This->rootPropertySetIndex);
+
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsName,
+                                                     &currentProperty);
+
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    /*
+     * An element with this name already exists 
+     */
+    if (grfMode & STGM_CREATE)
+    {
+      IStorage_DestroyElement(iface, pwcsName); 
+    }
+    else 
+      return STG_E_FILEALREADYEXISTS;
+  }
+
+  /* 
+   * memset the empty property 
+   */
+  memset(&newStreamProperty, 0, sizeof(StgProperty));
+
+  newStreamProperty.sizeOfNameString =
+      ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR);
+
+  if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+    return STG_E_INVALIDNAME;
+
+  lstrcpyW(newStreamProperty.name, pwcsName);
+
+  newStreamProperty.propertyType  = PROPTYPE_STREAM;
+  newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN;
+  newStreamProperty.size.LowPart  = 0;
+  newStreamProperty.size.HighPart = 0;
+
+  newStreamProperty.previousProperty = PROPERTY_NULL;
+  newStreamProperty.nextProperty     = PROPERTY_NULL;
+  newStreamProperty.dirProperty      = PROPERTY_NULL;
+
+  /* call CoFileTime to get the current time 
+  newStreamProperty.timeStampS1
+  newStreamProperty.timeStampD1
+  newStreamProperty.timeStampS2
+  newStreamProperty.timeStampD2
+  */
+
+  /*  newStreamProperty.propertyUniqueID */
+
+  /*
+   * Get a free property or create a new one 
+   */
+  newPropertyIndex = getFreeProperty(This->ancestorStorage);
+
+  /*
+   * Save the new property into the new property spot
+   */  
+  StorageImpl_WriteProperty(
+    This->ancestorStorage,
+    newPropertyIndex, 
+    &newStreamProperty);
+
+  /* 
+   * Find a spot in the property chain for our newly created property.
+   */
+  updatePropertyChain(
+    (StorageImpl*)This,
+    newPropertyIndex, 
+    newStreamProperty);
+
+  /* 
+   * Open the stream to return it.
+   */
+  newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex);
+
+  if (newStream != 0)
+  {
+    *ppstm = (IStream*)newStream;
+
+    /*
+     * Since we are returning a pointer to the interface, we have to nail down
+     * the reference.
+     */
+    StgStreamImpl_AddRef(*ppstm);
+  }
+  else
+  {
+    return STG_E_INSUFFICIENTMEMORY;
+  }
+
+  return S_OK;
+}
+
+/************************************************************************
+ * Storage32BaseImpl_SetClass (IStorage)
+ *
+ * This method will write the specified CLSID in the property of this 
+ * storage.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageBaseImpl_SetClass(
+  IStorage*        iface,
+  REFCLSID         clsid) /* [in] */
+{
+  ICOM_THIS(StorageBaseImpl,iface);
+  HRESULT hRes = E_FAIL;
+  StgProperty curProperty;
+  BOOL success;
+
+  TRACE("(%p, %p)\n", iface, clsid);
+  
+  success = StorageImpl_ReadProperty(This->ancestorStorage,
+                                       This->rootPropertySetIndex,
+                                       &curProperty);
+  if (success)
+  {
+    curProperty.propertyUniqueID = *clsid;
+
+    success =  StorageImpl_WriteProperty(This->ancestorStorage,
+                                           This->rootPropertySetIndex,
+                                           &curProperty);
+    if (success)
+      hRes = S_OK;
+  }
+
+  return hRes;
+}
+
+/************************************************************************
+** Storage32Impl implementation
+*/
+        
+/************************************************************************
+ * Storage32Impl_CreateStorage (IStorage)
+ *
+ * This method will create the storage object within the provided storage.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+HRESULT WINAPI StorageImpl_CreateStorage( 
+  IStorage*      iface,
+  const OLECHAR  *pwcsName, /* [string][in] */ 
+  DWORD            grfMode,   /* [in] */ 
+  DWORD            reserved1, /* [in] */ 
+  DWORD            reserved2, /* [in] */ 
+  IStorage       **ppstg)   /* [out] */ 
+{
+  StorageImpl* const This=(StorageImpl*)iface;
+
+  IEnumSTATSTGImpl *propertyEnumeration;
+  StgProperty      currentProperty;
+  StgProperty      newProperty;
+  ULONG            foundPropertyIndex;
+  ULONG            newPropertyIndex;
+  HRESULT          hr;
+
+  TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", 
+	iface, debugstr_w(pwcsName), grfMode, 
+	reserved1, reserved2, ppstg);
+  
+  /*
+   * Validate parameters
+   */
+  if (ppstg == 0)
+    return STG_E_INVALIDPOINTER;
+
+  if (pwcsName == 0)
+    return STG_E_INVALIDNAME;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ) ||
+       (grfMode & STGM_DELETEONRELEASE) )
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * Initialize the out parameter
+   */
+  *ppstg = 0;
+
+  /*
+   * Create a property enumeration and search the properties
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct( This->ancestorStorage,
+                                                    This->rootPropertySetIndex);
+
+  foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration,
+                                                     pwcsName,
+                                                     &currentProperty);
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if (foundPropertyIndex != PROPERTY_NULL)
+  {
+    /*
+     * An element with this name already exists 
+     */
+    if (grfMode & STGM_CREATE)
+      IStorage_DestroyElement(iface, pwcsName); 
+    else 
+      return STG_E_FILEALREADYEXISTS;
+  }
+
+  /* 
+   * memset the empty property 
+   */
+  memset(&newProperty, 0, sizeof(StgProperty));
+
+  newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR);
+
+  if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN)
+    return STG_E_INVALIDNAME;
+
+  lstrcpyW(newProperty.name, pwcsName);
+
+  newProperty.propertyType  = PROPTYPE_STORAGE;
+  newProperty.startingBlock = BLOCK_END_OF_CHAIN;
+  newProperty.size.LowPart  = 0;
+  newProperty.size.HighPart = 0;
+
+  newProperty.previousProperty = PROPERTY_NULL;
+  newProperty.nextProperty     = PROPERTY_NULL;
+  newProperty.dirProperty      = PROPERTY_NULL;
+
+  /* call CoFileTime to get the current time 
+  newProperty.timeStampS1
+  newProperty.timeStampD1
+  newProperty.timeStampS2
+  newProperty.timeStampD2
+  */
+
+  /*  newStorageProperty.propertyUniqueID */
+
+  /* 
+   * Obtain a free property in the property chain
+   */
+  newPropertyIndex = getFreeProperty(This->ancestorStorage);
+
+  /*
+   * Save the new property into the new property spot
+   */  
+  StorageImpl_WriteProperty(
+    This->ancestorStorage,
+    newPropertyIndex, 
+    &newProperty);
+
+  /* 
+   * Find a spot in the property chain for our newly created property.
+   */
+  updatePropertyChain(
+    This,
+    newPropertyIndex, 
+    newProperty);
+
+  /* 
+   * Open it to get a pointer to return.
+   */
+  hr = IStorage_OpenStorage(
+         iface,
+         (OLECHAR*)pwcsName,
+         0,
+         grfMode,
+         0,
+         0,
+         ppstg);
+
+  if( (hr != S_OK) || (*ppstg == NULL))
+  {
+    return hr;
+  }
+
+  
+  return S_OK;
+}
+
+
+/***************************************************************************
+ *
+ * Internal Method
+ *
+ * Get a free property or create a new one.
+ */
+static ULONG getFreeProperty(
+  StorageImpl *storage)
+{
+  ULONG       currentPropertyIndex = 0;
+  ULONG       newPropertyIndex     = PROPERTY_NULL;
+  BOOL      readSucessful        = TRUE;
+  StgProperty currentProperty;
+
+  do
+  {
+    /*
+     * Start by reading the root property
+     */
+    readSucessful = StorageImpl_ReadProperty(storage->ancestorStorage,
+                                               currentPropertyIndex,
+                                               &currentProperty);
+    if (readSucessful)
+    {
+      if (currentProperty.sizeOfNameString == 0)
+      {
+        /* 
+         * The property existis and is available, we found it.
+         */
+        newPropertyIndex = currentPropertyIndex;
+      }
+    }
+    else
+    {
+      /*
+       * We exhausted the property list, we will create more space below
+       */
+      newPropertyIndex = currentPropertyIndex;
+    }
+    currentPropertyIndex++;
+
+  } while (newPropertyIndex == PROPERTY_NULL);
+
+  /* 
+   * grow the property chain 
+   */
+  if (! readSucessful)
+  {
+    StgProperty    emptyProperty;
+    ULARGE_INTEGER newSize;
+    ULONG          propertyIndex;
+    ULONG          lastProperty  = 0;
+    ULONG          blockCount    = 0;
+
+    /* 
+     * obtain the new count of property blocks 
+     */
+    blockCount = BlockChainStream_GetCount(
+                   storage->ancestorStorage->rootBlockChain)+1;
+
+    /* 
+     * initialize the size used by the property stream 
+     */
+    newSize.HighPart = 0;
+    newSize.LowPart  = storage->bigBlockSize * blockCount;
+
+    /* 
+     * add a property block to the property chain 
+     */
+    BlockChainStream_SetSize(storage->ancestorStorage->rootBlockChain, newSize);
+
+    /* 
+     * memset the empty property in order to initialize the unused newly 
+     * created property
+     */
+    memset(&emptyProperty, 0, sizeof(StgProperty));
+
+    /* 
+     * initialize them
+     */
+    lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount; 
+    
+    for(
+      propertyIndex = newPropertyIndex;
+      propertyIndex < lastProperty;
+      propertyIndex++)
+    {
+      StorageImpl_WriteProperty(
+        storage->ancestorStorage,
+        propertyIndex, 
+        &emptyProperty);
+    }
+  }
+
+  return newPropertyIndex;
+}
+
+/****************************************************************************
+ *
+ * Internal Method
+ *
+ * Case insensitive comparaison of StgProperty.name by first considering 
+ * their size.
+ *
+ * Returns <0 when newPrpoerty < currentProperty
+ *         >0 when newPrpoerty > currentProperty
+ *          0 when newPrpoerty == currentProperty
+ */
+static LONG propertyNameCmp(
+  OLECHAR *newProperty,
+  OLECHAR *currentProperty)
+{
+  LONG diff      = lstrlenW(newProperty) - lstrlenW(currentProperty);
+
+  if (diff == 0) 
+  {
+    /* 
+     * We compare the string themselves only when they are of the same lenght
+     */
+    diff = lstrcmpiW( newProperty, currentProperty);
+  }
+
+  return diff;  
+}
+
+/****************************************************************************
+ *
+ * Internal Method
+ *
+ * Properly link this new element in the property chain.
+ */
+static void updatePropertyChain(
+  StorageImpl *storage,
+  ULONG         newPropertyIndex,
+  StgProperty   newProperty) 
+{
+  StgProperty currentProperty;
+
+  /*
+   * Read the root property
+   */
+  StorageImpl_ReadProperty(storage->ancestorStorage,
+                             storage->rootPropertySetIndex,
+                             &currentProperty);
+
+  if (currentProperty.dirProperty != PROPERTY_NULL)
+  {
+    /* 
+     * The root storage contains some element, therefore, start the research
+     * for the appropriate location.
+     */
+    BOOL found = 0;
+    ULONG  current, next, previous, currentPropertyId;
+
+    /*
+     * Keep the StgProperty sequence number of the storage first property
+     */
+    currentPropertyId = currentProperty.dirProperty;
+
+    /*
+     * Read 
+     */
+    StorageImpl_ReadProperty(storage->ancestorStorage,
+                               currentProperty.dirProperty,
+                               &currentProperty);
+
+    previous = currentProperty.previousProperty;
+    next     = currentProperty.nextProperty;
+    current  = currentPropertyId;
+
+    while (found == 0)
+    {
+      LONG diff = propertyNameCmp( newProperty.name, currentProperty.name);
+  
+      if (diff < 0)
+      {
+        if (previous != PROPERTY_NULL)
+        {
+          StorageImpl_ReadProperty(storage->ancestorStorage,
+                                     previous,
+                                     &currentProperty);
+          current = previous;
+        }
+        else
+        {
+          currentProperty.previousProperty = newPropertyIndex;
+          StorageImpl_WriteProperty(storage->ancestorStorage,
+                                      current,
+                                      &currentProperty);
+          found = 1;
+        }
+      }
+      else if (diff > 0)
+      {
+        if (next != PROPERTY_NULL)
+        {
+          StorageImpl_ReadProperty(storage->ancestorStorage,
+                                     next,
+                                     &currentProperty);
+          current = next;
+        }
+        else
+        {
+          currentProperty.nextProperty = newPropertyIndex;
+          StorageImpl_WriteProperty(storage->ancestorStorage,
+                                      current,
+                                      &currentProperty);
+          found = 1;
+        }
+      }
+      else
+      {
+	/*
+	 * Trying to insert an item with the same name in the
+	 * subtree structure.
+	 */
+	assert(FALSE);
+      }
+
+      previous = currentProperty.previousProperty;
+      next     = currentProperty.nextProperty;
+    }
+  }
+  else
+  {
+    /* 
+     * The root storage is empty, link the new property to it's dir property
+     */
+    currentProperty.dirProperty = newPropertyIndex;
+    StorageImpl_WriteProperty(storage->ancestorStorage,
+                                storage->rootPropertySetIndex,
+                                &currentProperty);
+  }
+}
+
+      
+/*************************************************************************
+ * CopyTo (IStorage)
+ */
+HRESULT WINAPI StorageImpl_CopyTo( 
+  IStorage*   iface,
+  DWORD       ciidExclude,  /* [in] */ 
+  const IID*  rgiidExclude, /* [size_is][unique][in] */ 
+  SNB         snbExclude,   /* [unique][in] */ 
+  IStorage*   pstgDest)     /* [unique][in] */ 
+{
+  IEnumSTATSTG *elements     = 0;
+  STATSTG      curElement, strStat;
+  HRESULT      hr;
+  IStorage     *pstgTmp, *pstgChild;
+  IStream      *pstrTmp, *pstrChild;
+
+  if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL))
+    FIXME("Exclude option not implemented\n");
+
+  TRACE("(%p, %ld, %p, %p, %p)\n", 
+	iface, ciidExclude, rgiidExclude, 
+	snbExclude, pstgDest);
+
+  /*
+   * Perform a sanity check
+   */
+  if ( pstgDest == 0 )
+    return STG_E_INVALIDPOINTER;
+
+  /* 
+   * Enumerate the elements
+   */
+  hr = IStorage_EnumElements( iface, 0, 0, 0, &elements );
+
+  if ( hr != S_OK )
+    return hr;
+
+  /*
+   * set the class ID
+   */
+  IStorage_Stat( iface, &curElement, STATFLAG_NONAME);
+  IStorage_SetClass( pstgDest, &curElement.clsid );
+  
+  do
+  {
+    /*
+     * Obtain the next element
+     */
+    hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL );
+
+    if ( hr == S_FALSE )
+    {
+      hr = S_OK;   /* done, every element has been copied */
+      break;
+    }
+
+    if (curElement.type == STGTY_STORAGE)
+    {
+      /*
+       * open child source storage
+       */
+      hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL,
+				 STGM_READ|STGM_SHARE_EXCLUSIVE,
+				 NULL, 0, &pstgChild );
+
+      if (hr != S_OK)
+        break;
+
+      /*
+       * Check if destination storage is not a child of the source
+       * storage, which will cause an infinite loop
+       */
+      if (pstgChild == pstgDest)
+      {
+	IEnumSTATSTG_Release(elements);
+
+	return STG_E_ACCESSDENIED;
+      }
+            
+      /*
+       * create a new storage in destination storage
+       */
+      hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName,
+                                   STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
+				   0, 0,
+                                   &pstgTmp );
+      /*
+       * if it already exist, don't create a new one use this one
+       */
+      if (hr == STG_E_FILEALREADYEXISTS)
+      {
+        hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL,
+                                   STGM_WRITE|STGM_SHARE_EXCLUSIVE,
+                                   NULL, 0, &pstgTmp );
+      }
+        
+      if (hr != S_OK)
+        break;
+
+        
+      /*
+       * do the copy recursively
+       */
+      hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude,
+                               snbExclude, pstgTmp );
+                                
+      IStorage_Release( pstgTmp );
+      IStorage_Release( pstgChild );
+    }
+    else if (curElement.type == STGTY_STREAM)
+    {
+      /*
+       * create a new stream in destination storage. If the stream already
+       * exist, it will be deleted and a new one will be created.
+       */
+      hr = IStorage_CreateStream( pstgDest, curElement.pwcsName,
+                                  STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE,
+                                  0, 0, &pstrTmp );
+
+      if (hr != S_OK)
+        break;
+
+      /*
+       * open child stream storage
+       */
+      hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL,
+				STGM_READ|STGM_SHARE_EXCLUSIVE,
+				0, &pstrChild );
+
+      if (hr != S_OK)
+        break;
+
+      /*
+       * Get the size of the source stream
+       */
+      IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME );
+
+      /*
+       * Set the size of the destination stream.
+       */
+      IStream_SetSize(pstrTmp, strStat.cbSize);
+      
+      /*
+       * do the copy
+       */
+      hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize,
+                           NULL, NULL );
+                                
+      IStream_Release( pstrTmp );
+      IStream_Release( pstrChild );
+    }
+    else
+    {
+      WARN("unknown element type: %ld\n", curElement.type);
+    }
+
+  } while (hr == S_OK);
+
+  /*
+   * Clean-up
+   */
+  IEnumSTATSTG_Release(elements);
+  
+  return hr;
+}
+        
+/*************************************************************************
+ * MoveElementTo (IStorage)
+ */
+HRESULT WINAPI StorageImpl_MoveElementTo( 
+  IStorage*     iface,
+  const OLECHAR *pwcsName,   /* [string][in] */ 
+  IStorage      *pstgDest,   /* [unique][in] */ 
+  const OLECHAR *pwcsNewName,/* [string][in] */ 
+  DWORD           grfFlags)    /* [in] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+        
+/*************************************************************************
+ * Commit (IStorage)
+ */
+HRESULT WINAPI StorageImpl_Commit( 
+  IStorage*   iface,
+  DWORD         grfCommitFlags)/* [in] */ 
+{
+  FIXME("(%ld): stub!\n", grfCommitFlags);
+  return S_OK;
+}
+        
+/*************************************************************************
+ * Revert (IStorage)
+ */
+HRESULT WINAPI StorageImpl_Revert( 
+  IStorage* iface)
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+/*************************************************************************
+ * DestroyElement (IStorage)
+ *
+ * Stategy: This implementation is build this way for simplicity not for speed. 
+ *          I always delete the top most element of the enumeration and adjust
+ *          the deleted element pointer all the time.  This takes longer to 
+ *          do but allow to reinvoke DestroyElement whenever we encounter a 
+ *          storage object.  The optimisation reside in the usage of another
+ *          enumeration stategy that would give all the leaves of a storage 
+ *          first. (postfix order)
+ */
+HRESULT WINAPI StorageImpl_DestroyElement( 
+  IStorage*     iface,
+  const OLECHAR *pwcsName)/* [string][in] */ 
+{
+  StorageImpl* const This=(StorageImpl*)iface;
+
+  IEnumSTATSTGImpl* propertyEnumeration;
+  HRESULT           hr = S_OK;
+  BOOL            res;
+  StgProperty       propertyToDelete;
+  StgProperty       parentProperty;
+  ULONG             foundPropertyIndexToDelete;
+  ULONG             typeOfRelation;
+  ULONG             parentPropertyId;
+
+  TRACE("(%p, %s)\n", 
+	iface, debugstr_w(pwcsName));
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (pwcsName==NULL) 
+    return STG_E_INVALIDPOINTER;
+  
+  /*
+   * Create a property enumeration to search the property with the given name
+   */
+  propertyEnumeration = IEnumSTATSTGImpl_Construct(
+    This->ancestorStorage, 
+    This->rootPropertySetIndex);
+  
+  foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty(
+    propertyEnumeration,
+    pwcsName,
+    &propertyToDelete);
+
+  IEnumSTATSTGImpl_Destroy(propertyEnumeration);
+
+  if ( foundPropertyIndexToDelete == PROPERTY_NULL )  
+  {
+    return STG_E_FILENOTFOUND;
+  }
+
+  /* 
+   * Find the parent property of the property to delete (the one that 
+   * link to it).  If This->dirProperty == foundPropertyIndexToDelete, 
+   * the parent is This. Otherwise, the parent is one of it's sibling...
+   */
+
+  /* 
+   * First, read This's StgProperty..
+   */
+  res = StorageImpl_ReadProperty( 
+          This->ancestorStorage,
+          This->rootPropertySetIndex,
+          &parentProperty);
+
+  assert(res==TRUE);
+
+  /* 
+   * Second, check to see if by any chance the actual storage (This) is not
+   * the parent of the property to delete... We never know...
+   */
+  if ( parentProperty.dirProperty == foundPropertyIndexToDelete )
+  {
+    /* 
+     * Set data as it would have been done in the else part...
+     */
+    typeOfRelation   = PROPERTY_RELATION_DIR;
+    parentPropertyId = This->rootPropertySetIndex;
+  }
+  else 
+  { 
+    /*
+     * Create a property enumeration to search the parent properties, and 
+     * delete it once done.
+     */
+    IEnumSTATSTGImpl* propertyEnumeration2;
+
+    propertyEnumeration2 = IEnumSTATSTGImpl_Construct(
+      This->ancestorStorage, 
+      This->rootPropertySetIndex);
+  
+    typeOfRelation = IEnumSTATSTGImpl_FindParentProperty(
+      propertyEnumeration2,
+      foundPropertyIndexToDelete,
+      &parentProperty,
+      &parentPropertyId);
+
+    IEnumSTATSTGImpl_Destroy(propertyEnumeration2);
+  }
+
+  if ( propertyToDelete.propertyType == PROPTYPE_STORAGE ) 
+  {
+    hr = deleteStorageProperty(
+           This, 
+           foundPropertyIndexToDelete,
+           propertyToDelete);
+  } 
+  else if ( propertyToDelete.propertyType == PROPTYPE_STREAM )
+  {
+    hr = deleteStreamProperty(
+           This, 
+           foundPropertyIndexToDelete,
+           propertyToDelete);
+  }
+
+  if (hr!=S_OK) 
+    return hr;
+
+  /*
+   * Adjust the property chain
+   */
+  hr = adjustPropertyChain(
+        This,
+        propertyToDelete, 
+        parentProperty,
+        parentPropertyId,
+        typeOfRelation);
+
+  return hr;
+}
+
+
+/*********************************************************************
+ *
+ * Internal Method
+ *
+ * Perform the deletion of a complete storage node
+ *
+ */
+static HRESULT deleteStorageProperty(
+  StorageImpl *parentStorage,
+  ULONG        indexOfPropertyToDelete,
+  StgProperty  propertyToDelete)
+{
+  IEnumSTATSTG *elements     = 0;
+  IStorage   *childStorage = 0;
+  STATSTG      currentElement;
+  HRESULT      hr;
+  HRESULT      destroyHr = S_OK;
+
+  /*
+   * Open the storage and enumerate it
+   */
+  hr = StorageBaseImpl_OpenStorage(
+        (IStorage*)parentStorage,
+        propertyToDelete.name,
+        0,
+        STGM_SHARE_EXCLUSIVE,
+        0,
+        0,
+        &childStorage);
+
+  if (hr != S_OK)
+  {
+    return hr;
+  }
+
+  /* 
+   * Enumerate the elements
+   */
+  IStorage_EnumElements( childStorage, 0, 0, 0, &elements);
+
+  do
+  {
+    /*
+     * Obtain the next element
+     */
+    hr = IEnumSTATSTG_Next(elements, 1, &currentElement, NULL);
+    if (hr==S_OK)
+    {
+      destroyHr = StorageImpl_DestroyElement(
+                    (IStorage*)childStorage, 
+                    (OLECHAR*)currentElement.pwcsName);
+
+      CoTaskMemFree(currentElement.pwcsName);
+    }
+
+    /*
+     * We need to Reset the enumeration every time because we delete elements
+     * and the enumeration could be invalid
+     */
+    IEnumSTATSTG_Reset(elements);
+
+  } while ((hr == S_OK) && (destroyHr == S_OK));
+
+  /*
+   * Invalidate the property by zeroing it's name member.
+   */
+  propertyToDelete.sizeOfNameString = 0;
+
+  StorageImpl_WriteProperty(parentStorage->ancestorStorage,
+                            indexOfPropertyToDelete,
+                            &propertyToDelete);
+
+  IStorage_Release(childStorage);
+  IEnumSTATSTG_Release(elements);
+    
+  return destroyHr;
+}
+
+/*********************************************************************
+ *
+ * Internal Method
+ *
+ * Perform the deletion of a stream node
+ *
+ */
+static HRESULT deleteStreamProperty(
+  StorageImpl *parentStorage,
+  ULONG         indexOfPropertyToDelete,
+  StgProperty   propertyToDelete)
+{
+  IStream      *pis;
+  HRESULT        hr;
+  ULARGE_INTEGER size;
+
+  size.HighPart = 0;
+  size.LowPart = 0;
+
+  hr = StorageBaseImpl_OpenStream(
+         (IStorage*)parentStorage,
+         (OLECHAR*)propertyToDelete.name,
+         NULL,
+         STGM_WRITE | STGM_SHARE_EXCLUSIVE,
+         0,
+         &pis);
+    
+  if (hr!=S_OK)
+  {
+    return(hr);
+  }
+
+  /* 
+   * Zap the stream 
+   */ 
+  hr = IStream_SetSize(pis, size); 
+
+  if(hr != S_OK)
+  {
+    return hr;
+  }
+
+  /*
+   * Release the stream object.
+   */
+  IStream_Release(pis);
+
+  /* 
+   * Invalidate the property by zeroing it's name member.
+   */
+  propertyToDelete.sizeOfNameString = 0;
+
+  /* 
+   * Here we should re-read the property so we get the updated pointer
+   * but since we are here to zap it, I don't do it...
+   */
+  StorageImpl_WriteProperty(
+    parentStorage->ancestorStorage, 
+    indexOfPropertyToDelete,
+    &propertyToDelete);
+
+  return S_OK;
+}
+
+/*********************************************************************
+ *
+ * Internal Method
+ *
+ * Finds a placeholder for the StgProperty within the Storage
+ *
+ */
+static HRESULT findPlaceholder(
+  StorageImpl *storage,
+  ULONG         propertyIndexToStore,
+  ULONG         storePropertyIndex,
+  INT         typeOfRelation)
+{
+  StgProperty storeProperty;
+  HRESULT     hr = S_OK;
+  BOOL      res = TRUE;
+
+  /*
+   * Read the storage property
+   */
+  res = StorageImpl_ReadProperty(
+          storage->ancestorStorage,
+          storePropertyIndex, 
+          &storeProperty);
+
+  if(! res)
+  {
+    return E_FAIL;
+  }
+
+  if (typeOfRelation == PROPERTY_RELATION_PREVIOUS)
+  {
+    if (storeProperty.previousProperty != PROPERTY_NULL)
+    {
+      return findPlaceholder(
+               storage,
+               propertyIndexToStore, 
+               storeProperty.previousProperty,
+               typeOfRelation);
+    }
+    else
+    {
+      storeProperty.previousProperty = propertyIndexToStore;
+    }
+  }
+  else if (typeOfRelation == PROPERTY_RELATION_NEXT)
+  {
+    if (storeProperty.nextProperty != PROPERTY_NULL)
+    {
+      return findPlaceholder(
+               storage,
+               propertyIndexToStore, 
+               storeProperty.nextProperty,
+               typeOfRelation);
+    }
+    else
+    {
+      storeProperty.nextProperty = propertyIndexToStore;
+    }
+  } 
+  else if (typeOfRelation == PROPERTY_RELATION_DIR)
+  {
+    if (storeProperty.dirProperty != PROPERTY_NULL)
+    {
+      return findPlaceholder(
+               storage,
+               propertyIndexToStore, 
+               storeProperty.dirProperty,
+               typeOfRelation);
+    }
+    else
+    {
+      storeProperty.dirProperty = propertyIndexToStore;
+    }
+  }
+
+  hr = StorageImpl_WriteProperty(
+         storage->ancestorStorage,
+         storePropertyIndex, 
+         &storeProperty);
+
+  if(! hr)
+  {
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+/*************************************************************************
+ *
+ * Internal Method
+ *
+ * This method takes the previous and the next property link of a property 
+ * to be deleted and find them a place in the Storage.
+ */
+static HRESULT adjustPropertyChain( 
+  StorageImpl *This,
+  StgProperty   propertyToDelete,
+  StgProperty   parentProperty,
+  ULONG         parentPropertyId,
+  INT         typeOfRelation)
+{
+  ULONG   newLinkProperty        = PROPERTY_NULL;
+  BOOL  needToFindAPlaceholder = FALSE;
+  ULONG   storeNode              = PROPERTY_NULL;
+  ULONG   toStoreNode            = PROPERTY_NULL;
+  INT   relationType           = 0;
+  HRESULT hr                     = S_OK;
+  BOOL  res                    = TRUE;
+  
+  if (typeOfRelation == PROPERTY_RELATION_PREVIOUS) 
+  {
+    if (propertyToDelete.previousProperty != PROPERTY_NULL)  
+    {
+      /* 
+       * Set the parent previous to the property to delete previous
+       */
+      newLinkProperty = propertyToDelete.previousProperty;
+
+      if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+      {
+        /*
+         * We also need to find a storage for the other link, setup variables 
+         * to do this at the end...
+         */      
+        needToFindAPlaceholder = TRUE;
+        storeNode              = propertyToDelete.previousProperty;
+        toStoreNode            = propertyToDelete.nextProperty;
+        relationType           = PROPERTY_RELATION_NEXT;
+      }
+    } 
+    else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+    {
+      /* 
+       * Set the parent previous to the property to delete next
+       */
+      newLinkProperty = propertyToDelete.nextProperty;
+    }
+   
+    /* 
+     * Link it for real...
+     */ 
+    parentProperty.previousProperty = newLinkProperty;
+  
+  } 
+  else if (typeOfRelation == PROPERTY_RELATION_NEXT) 
+  {
+    if (propertyToDelete.previousProperty != PROPERTY_NULL)  
+    {
+      /* 
+       * Set the parent next to the property to delete next previous
+       */
+      newLinkProperty = propertyToDelete.previousProperty;
+      
+      if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+      {
+        /*
+         * We also need to find a storage for the other link, setup variables 
+         * to do this at the end...
+         */      
+        needToFindAPlaceholder = TRUE;
+        storeNode              = propertyToDelete.previousProperty;
+        toStoreNode            = propertyToDelete.nextProperty;
+        relationType           = PROPERTY_RELATION_NEXT;
+      }
+    } 
+    else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+    {
+      /* 
+       * Set the parent next to the property to delete next
+       */
+      newLinkProperty = propertyToDelete.nextProperty;
+    }
+
+    /* 
+     * Link it for real...
+     */ 
+    parentProperty.nextProperty = newLinkProperty;
+  } 
+  else /* (typeOfRelation == PROPERTY_RELATION_DIR) */
+  {
+    if (propertyToDelete.previousProperty != PROPERTY_NULL) 
+    {
+      /* 
+       * Set the parent dir to the property to delete previous
+       */
+      newLinkProperty = propertyToDelete.previousProperty;
+
+      if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+      {
+        /*
+         * We also need to find a storage for the other link, setup variables 
+         * to do this at the end...
+         */      
+        needToFindAPlaceholder = TRUE;
+        storeNode              = propertyToDelete.previousProperty;
+        toStoreNode            = propertyToDelete.nextProperty;
+        relationType           = PROPERTY_RELATION_NEXT;
+      }
+    } 
+    else if (propertyToDelete.nextProperty != PROPERTY_NULL)  
+    {
+      /* 
+       * Set the parent dir to the property to delete next
+       */
+      newLinkProperty = propertyToDelete.nextProperty;
+    }
+
+    /* 
+     * Link it for real...
+     */ 
+    parentProperty.dirProperty = newLinkProperty;
+  }
+
+  /* 
+   * Write back the parent property    
+   */
+  res = StorageImpl_WriteProperty(
+          This->ancestorStorage, 
+          parentPropertyId,
+          &parentProperty);
+  if(! res)
+  {
+    return E_FAIL;
+  }
+
+  /*
+   * If a placeholder is required for the other link, then, find one and 
+   * get out of here...
+   */
+  if (needToFindAPlaceholder) 
+  {
+    hr = findPlaceholder(
+           This, 
+           toStoreNode, 
+           storeNode,
+           relationType);
+  }
+
+  return hr;
+}
+
+
+/******************************************************************************
+ * SetElementTimes (IStorage)
+ */
+HRESULT WINAPI StorageImpl_SetElementTimes( 
+  IStorage*     iface,
+  const OLECHAR *pwcsName,/* [string][in] */ 
+  const FILETIME  *pctime,  /* [in] */ 
+  const FILETIME  *patime,  /* [in] */ 
+  const FILETIME  *pmtime)  /* [in] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+/******************************************************************************
+ * SetStateBits (IStorage)
+ */
+HRESULT WINAPI StorageImpl_SetStateBits( 
+  IStorage*   iface,
+  DWORD         grfStateBits,/* [in] */ 
+  DWORD         grfMask)     /* [in] */ 
+{
+  FIXME("not implemented!\n");
+  return E_NOTIMPL;
+}
+
+HRESULT StorageImpl_Construct(
+  StorageImpl* This,
+  HANDLE       hFile,
+  ILockBytes*  pLkbyt,
+  DWORD        openFlags,
+  BOOL         fileBased,
+  BOOL         fileCreate)
+{
+  HRESULT     hr = S_OK;
+  StgProperty currentProperty;
+  BOOL      readSucessful;
+  ULONG       currentPropertyIndex;
+  
+  if ( FAILED( validateSTGM(openFlags) ))
+    return STG_E_INVALIDFLAG;
+
+  memset(This, 0, sizeof(StorageImpl));
+  
+  /*
+   * Initialize the virtual fgunction table.
+   */
+  ICOM_VTBL(This)    = &Storage32Impl_Vtbl;
+  This->v_destructor = &StorageImpl_Destroy;
+  
+  /*
+   * This is the top-level storage so initialize the ancester pointer
+   * to this.
+   */
+  This->ancestorStorage = This;
+  
+  /*
+   * Initialize the physical support of the storage.
+   */
+  This->hFile = hFile;
+  
+  /*
+   * Initialize the big block cache.
+   */
+  This->bigBlockSize   = DEF_BIG_BLOCK_SIZE;
+  This->smallBlockSize = DEF_SMALL_BLOCK_SIZE;
+  This->bigBlockFile   = BIGBLOCKFILE_Construct(hFile,
+                                                pLkbyt,
+                                                openFlags,
+                                                This->bigBlockSize,
+                                                fileBased);
+
+  if (This->bigBlockFile == 0)
+    return E_FAIL;
+ 
+  if (fileCreate)
+  {
+    ULARGE_INTEGER size;
+    BYTE* bigBlockBuffer;
+
+    /*
+     * Initialize all header variables:
+     * - The big block depot consists of one block and it is at block 0
+     * - The properties start at block 1
+     * - There is no small block depot
+     */
+    memset( This->bigBlockDepotStart,     
+            BLOCK_UNUSED, 
+            sizeof(This->bigBlockDepotStart));
+
+    This->bigBlockDepotCount    = 1;
+    This->bigBlockDepotStart[0] = 0;
+    This->rootStartBlock        = 1;
+    This->smallBlockDepotStart  = BLOCK_END_OF_CHAIN;
+    This->bigBlockSizeBits      = DEF_BIG_BLOCK_SIZE_BITS;
+    This->smallBlockSizeBits    = DEF_SMALL_BLOCK_SIZE_BITS;
+    This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN;
+    This->extBigBlockDepotCount = 0;
+    StorageImpl_SaveFileHeader(This);
+
+    /*
+     * Add one block for the big block depot and one block for the properties
+     */
+    size.HighPart = 0;
+    size.LowPart  = This->bigBlockSize * 3;
+    BIGBLOCKFILE_SetSize(This->bigBlockFile, size);
+
+    /*
+     * Initialize the big block depot
+     */
+    bigBlockBuffer = (BYTE *)StorageImpl_GetBigBlock(This, 0);
+    memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize);
+    StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL);
+    StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN);
+    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+  }
+  else
+  {
+    /*
+     * Load the header for the file.
+     */
+    hr = StorageImpl_LoadFileHeader(This);
+
+    if (FAILED(hr))
+    {
+      BIGBLOCKFILE_Destructor(This->bigBlockFile);
+
+      return hr;
+    }
+  }
+
+  /*
+   * There is no block depot cached yet.
+   */
+  This->indexBlockDepotCached = 0xFFFFFFFF;
+
+  /*
+   * Start searching for free blocks with block 0.
+   */
+  This->prevFreeBlock = 0;
+  
+  /*
+   * Create the block chain abstractions.
+   */
+  This->rootBlockChain = 
+    BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL);
+
+  This->smallBlockDepotChain = BlockChainStream_Construct(
+                                 This, 
+                                 &This->smallBlockDepotStart, 
+                                 PROPERTY_NULL);
+
+  /*
+   * Write the root property 
+   */
+  if (fileCreate)
+  {
+    StgProperty rootProp;
+    /*
+     * Initialize the property chain
+     */
+    memset(&rootProp, 0, sizeof(rootProp));
+    lstrcpyAtoW(rootProp.name, (LPSTR)rootPropertyName);
+
+    rootProp.sizeOfNameString = (lstrlenW(rootProp.name)+1) * sizeof(WCHAR);
+    rootProp.propertyType     = PROPTYPE_ROOT;
+    rootProp.previousProperty = PROPERTY_NULL;
+    rootProp.nextProperty     = PROPERTY_NULL;
+    rootProp.dirProperty      = PROPERTY_NULL;
+    rootProp.startingBlock    = BLOCK_END_OF_CHAIN;
+    rootProp.size.HighPart    = 0;
+    rootProp.size.LowPart     = 0;
+
+    StorageImpl_WriteProperty(This, 0, &rootProp);
+  }
+
+  /*
+   * Find the ID of the root int he property sets.
+   */
+  currentPropertyIndex = 0;
+  
+  do
+  {
+    readSucessful = StorageImpl_ReadProperty(
+                      This, 
+                      currentPropertyIndex, 
+                      &currentProperty);
+    
+    if (readSucessful)
+    {
+      if ( (currentProperty.sizeOfNameString != 0 ) &&
+           (currentProperty.propertyType     == PROPTYPE_ROOT) )
+      {
+        This->rootPropertySetIndex = currentPropertyIndex;
+      }
+    }
+
+    currentPropertyIndex++;
+    
+  } while (readSucessful && (This->rootPropertySetIndex == PROPERTY_NULL) );
+  
+  if (!readSucessful)
+  {
+    /* TODO CLEANUP */
+    return E_FAIL;
+  }
+
+  /*
+   * Create the block chain abstraction for the small block root chain.
+   */
+  This->smallBlockRootChain = BlockChainStream_Construct(
+                                This, 
+                                NULL, 
+                                This->rootPropertySetIndex);
+  
+  return hr;
+}
+
+void StorageImpl_Destroy(
+  StorageImpl* This)
+{
+  TRACE("(%p)\n", This);
+
+  BlockChainStream_Destroy(This->smallBlockRootChain);
+  BlockChainStream_Destroy(This->rootBlockChain);
+  BlockChainStream_Destroy(This->smallBlockDepotChain);
+
+  BIGBLOCKFILE_Destructor(This->bigBlockFile);
+  return;
+}
+
+/******************************************************************************
+ *      Storage32Impl_GetNextFreeBigBlock
+ *
+ * Returns the index of the next free big block.
+ * If the big block depot is filled, this method will enlarge it.
+ *
+ */
+ULONG StorageImpl_GetNextFreeBigBlock(
+  StorageImpl* This)
+{
+  ULONG depotBlockIndexPos;
+  void  *depotBuffer;
+  ULONG depotBlockOffset;
+  ULONG blocksPerDepot    = This->bigBlockSize / sizeof(ULONG);
+  ULONG nextBlockIndex    = BLOCK_SPECIAL;
+  int   depotIndex        = 0;
+  ULONG freeBlock         = BLOCK_UNUSED;
+
+  depotIndex = This->prevFreeBlock / blocksPerDepot;
+  depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG);
+
+  /*
+   * Scan the entire big block depot until we find a block marked free
+   */
+  while (nextBlockIndex != BLOCK_UNUSED)
+  {
+    if (depotIndex < COUNT_BBDEPOTINHEADER)
+    {
+      depotBlockIndexPos = This->bigBlockDepotStart[depotIndex];
+
+      /*
+       * Grow the primary depot.
+       */
+      if (depotBlockIndexPos == BLOCK_UNUSED)
+      {
+        depotBlockIndexPos = depotIndex*blocksPerDepot;
+
+        /*
+         * Add a block depot.
+         */
+        Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
+        This->bigBlockDepotCount++;
+        This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos;
+
+        /*
+         * Flag it as a block depot.
+         */
+        StorageImpl_SetNextBlockInChain(This,
+                                          depotBlockIndexPos,
+                                          BLOCK_SPECIAL);
+
+        /* Save new header information.
+         */
+        StorageImpl_SaveFileHeader(This);
+      }
+    }
+    else
+    {
+      depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex);
+
+      if (depotBlockIndexPos == BLOCK_UNUSED)
+      {
+        /*
+         * Grow the extended depot.
+         */
+        ULONG extIndex       = BLOCK_UNUSED;
+        ULONG numExtBlocks   = depotIndex - COUNT_BBDEPOTINHEADER;
+        ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1);
+
+        if (extBlockOffset == 0)
+        {
+          /* We need an extended block.
+           */
+          extIndex = Storage32Impl_AddExtBlockDepot(This);
+          This->extBigBlockDepotCount++;
+          depotBlockIndexPos = extIndex + 1;
+        }
+        else
+          depotBlockIndexPos = depotIndex * blocksPerDepot;
+
+        /*
+         * Add a block depot and mark it in the extended block.
+         */
+        Storage32Impl_AddBlockDepot(This, depotBlockIndexPos);
+        This->bigBlockDepotCount++;
+        Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos);
+
+        /* Flag the block depot.
+         */
+        StorageImpl_SetNextBlockInChain(This,
+                                          depotBlockIndexPos,
+                                          BLOCK_SPECIAL);
+
+        /* If necessary, flag the extended depot block.
+         */
+        if (extIndex != BLOCK_UNUSED)
+          StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT);
+
+        /* Save header information.
+         */
+        StorageImpl_SaveFileHeader(This);
+      }
+    }
+
+    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+
+    if (depotBuffer != 0)
+    {
+      while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) &&
+              ( nextBlockIndex != BLOCK_UNUSED))
+      {
+        StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
+
+        if (nextBlockIndex == BLOCK_UNUSED)
+        {
+          freeBlock = (depotIndex * blocksPerDepot) +
+                      (depotBlockOffset/sizeof(ULONG));
+        }
+
+        depotBlockOffset += sizeof(ULONG);
+      }
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+
+    depotIndex++;
+    depotBlockOffset = 0;
+  }
+
+  This->prevFreeBlock = freeBlock;
+
+  return freeBlock;
+}
+
+/******************************************************************************
+ *      Storage32Impl_AddBlockDepot
+ *
+ * This will create a depot block, essentially it is a block initialized
+ * to BLOCK_UNUSEDs.
+ */
+void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex)
+{
+  BYTE* blockBuffer;
+
+  blockBuffer = (BYTE *)StorageImpl_GetBigBlock(This, blockIndex);
+
+  /*
+   * Initialize blocks as free
+   */
+  memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize);
+
+  StorageImpl_ReleaseBigBlock(This, blockBuffer);
+}
+
+/******************************************************************************
+ *      Storage32Impl_GetExtDepotBlock
+ *
+ * Returns the index of the block that corresponds to the specified depot
+ * index. This method is only for depot indexes equal or greater than
+ * COUNT_BBDEPOTINHEADER.
+ */
+ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex)
+{
+  ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
+  ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
+  ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
+  ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
+  ULONG blockIndex             = BLOCK_UNUSED;
+  ULONG extBlockIndex          = This->extBigBlockDepotStart;
+
+  assert(depotIndex >= COUNT_BBDEPOTINHEADER);
+
+  if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN)
+    return BLOCK_UNUSED;
+
+  while (extBlockCount > 0)
+  {
+    extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
+    extBlockCount--;
+  }
+
+  if (extBlockIndex != BLOCK_UNUSED)
+  {
+    BYTE* depotBuffer;
+
+    depotBuffer = (BYTE *)StorageImpl_GetROBigBlock(This, extBlockIndex);
+
+    if (depotBuffer != 0)
+    {
+      StorageUtl_ReadDWord(depotBuffer,
+                           extBlockOffset * sizeof(ULONG),
+                           &blockIndex);
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+  }
+
+  return blockIndex;
+}
+
+/******************************************************************************
+ *      Storage32Impl_SetExtDepotBlock
+ *
+ * Associates the specified block index to the specified depot index.
+ * This method is only for depot indexes equal or greater than
+ * COUNT_BBDEPOTINHEADER.
+ */
+void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
+                                    ULONG depotIndex,
+                                    ULONG blockIndex)
+{
+  ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1;
+  ULONG numExtBlocks           = depotIndex - COUNT_BBDEPOTINHEADER;
+  ULONG extBlockCount          = numExtBlocks / depotBlocksPerExtBlock;
+  ULONG extBlockOffset         = numExtBlocks % depotBlocksPerExtBlock;
+  ULONG extBlockIndex          = This->extBigBlockDepotStart;
+
+  assert(depotIndex >= COUNT_BBDEPOTINHEADER);
+
+  while (extBlockCount > 0)
+  {
+    extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex);
+    extBlockCount--;
+  }
+
+  if (extBlockIndex != BLOCK_UNUSED)
+  {
+    BYTE* depotBuffer;
+
+    depotBuffer = (BYTE *)StorageImpl_GetBigBlock(This, extBlockIndex);
+
+    if (depotBuffer != 0)
+    {
+      StorageUtl_WriteDWord(depotBuffer,
+                            extBlockOffset * sizeof(ULONG),
+                            blockIndex);
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+  }
+}
+
+/******************************************************************************
+ *      Storage32Impl_AddExtBlockDepot
+ *
+ * Creates an extended depot block.
+ */
+ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This)
+{
+  ULONG numExtBlocks           = This->extBigBlockDepotCount;
+  ULONG nextExtBlock           = This->extBigBlockDepotStart;
+  BYTE* depotBuffer            = NULL;
+  ULONG index                  = BLOCK_UNUSED;
+  ULONG nextBlockOffset        = This->bigBlockSize - sizeof(ULONG);
+  ULONG blocksPerDepotBlock    = This->bigBlockSize / sizeof(ULONG);
+  ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1;
+
+  index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) *
+          blocksPerDepotBlock;
+
+  if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN))
+  {
+    /*
+     * The first extended block.
+     */
+    This->extBigBlockDepotStart = index;
+  }
+  else
+  {
+    int i;
+    /*
+     * Follow the chain to the last one.
+     */
+    for (i = 0; i < (numExtBlocks - 1); i++)
+    {
+      nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock);
+    }
+
+    /*
+     * Add the new extended block to the chain.
+     */
+    depotBuffer = (BYTE *)StorageImpl_GetBigBlock(This, nextExtBlock);
+    StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index);
+    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  }
+
+  /*
+   * Initialize this block.
+   */
+  depotBuffer = (BYTE *)StorageImpl_GetBigBlock(This, index);
+  memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize);
+  StorageImpl_ReleaseBigBlock(This, depotBuffer);
+
+  return index;
+}
+
+/******************************************************************************
+ *      Storage32Impl_FreeBigBlock
+ *
+ * This method will flag the specified block as free in the big block depot.
+ */
+void  StorageImpl_FreeBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
+
+  if (blockIndex < This->prevFreeBlock)
+    This->prevFreeBlock = blockIndex;
+}
+
+/************************************************************************
+ * Storage32Impl_GetNextBlockInChain
+ *
+ * This method will retrieve the block index of the next big block in
+ * in the chain.
+ *
+ * Params:  This       - Pointer to the Storage object.
+ *          blockIndex - Index of the block to retrieve the chain
+ *                       for.
+ *
+ * Returns: This method returns the index of the next block in the chain.
+ *          It will return the constants:
+ *              BLOCK_SPECIAL - If the block given was not part of a
+ *                              chain.
+ *              BLOCK_END_OF_CHAIN - If the block given was the last in
+ *                                   a chain.
+ *              BLOCK_UNUSED - If the block given was not past of a chain
+ *                             and is available.
+ *              BLOCK_EXTBBDEPOT - This block is part of the extended
+ *                                 big block depot.
+ *
+ * See Windows documentation for more details on IStorage methods.
+ */
+ULONG StorageImpl_GetNextBlockInChain(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
+  ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
+  ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
+  ULONG nextBlockIndex   = BLOCK_SPECIAL;
+  void* depotBuffer;
+  ULONG depotBlockIndexPos;
+
+  assert(depotBlockCount < This->bigBlockDepotCount);
+
+  /*
+   * Cache the currently accessed depot block.
+   */
+  if (depotBlockCount != This->indexBlockDepotCached)
+  {
+    This->indexBlockDepotCached = depotBlockCount;
+
+    if (depotBlockCount < COUNT_BBDEPOTINHEADER)
+    {
+      depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
+    }
+    else
+    {
+      /*
+       * We have to look in the extended depot.
+       */
+      depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
+    }
+
+    depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos);
+
+    if (depotBuffer!=0)
+    {
+      StorageUtl_ReadDWords(depotBuffer, 0, This->blockDepotCached,
+			    NUM_BLOCKS_PER_DEPOT_BLOCK);
+
+      StorageImpl_ReleaseBigBlock(This, depotBuffer);
+    }
+  }
+
+  nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)];
+
+  return nextBlockIndex;
+}
+
+/******************************************************************************
+ *      Storage32Impl_GetNextExtendedBlock
+ *
+ * Given an extended block this method will return the next extended block.
+ *
+ * NOTES:
+ * The last ULONG of an extended block is the block index of the next
+ * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the
+ * depot.
+ *
+ * Return values:
+ *    - The index of the next extended block
+ *    - BLOCK_UNUSED: there is no next extended block.
+ *    - Any other return values denotes failure.
+ */
+ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex)
+{
+  ULONG nextBlockIndex   = BLOCK_SPECIAL;
+  ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG);
+  void* depotBuffer;
+
+  depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
+
+  if (depotBuffer!=0)
+  {
+    StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex);
+
+    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  }
+
+  return nextBlockIndex;
+}
+
+/******************************************************************************
+ *      Storage32Impl_SetNextBlockInChain
+ *
+ * This method will write the index of the specified block's next block
+ * in the big block depot.
+ *
+ * For example: to create the chain 3 -> 1 -> 7 -> End of Chain
+ *              do the following
+ *
+ * Storage32Impl_SetNextBlockInChain(This, 3, 1);
+ * Storage32Impl_SetNextBlockInChain(This, 1, 7);
+ * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN);
+ *
+ */
+void  StorageImpl_SetNextBlockInChain(
+          StorageImpl* This,
+          ULONG          blockIndex,
+          ULONG          nextBlock)
+{
+  ULONG offsetInDepot    = blockIndex * sizeof (ULONG);
+  ULONG depotBlockCount  = offsetInDepot / This->bigBlockSize;
+  ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize;
+  ULONG depotBlockIndexPos;
+  void* depotBuffer;
+
+  assert(depotBlockCount < This->bigBlockDepotCount);
+  assert(blockIndex != nextBlock);
+
+  if (depotBlockCount < COUNT_BBDEPOTINHEADER)
+  {
+    depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount];
+  }
+  else
+  {
+    /*
+     * We have to look in the extended depot.
+     */
+    depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount);
+  }
+
+  depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos);
+
+  if (depotBuffer!=0)
+  {
+    StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock);
+    StorageImpl_ReleaseBigBlock(This, depotBuffer);
+  }
+
+  /*
+   * Update the cached block depot, if necessary.
+   */
+  if (depotBlockCount == This->indexBlockDepotCached)
+  {
+    This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock;
+  }
+}
+
+/******************************************************************************
+ *      Storage32Impl_LoadFileHeader
+ *
+ * This method will read in the file header, i.e. big block index -1.
+ */
+HRESULT StorageImpl_LoadFileHeader(
+          StorageImpl* This)
+{
+  HRESULT hr = STG_E_FILENOTFOUND;
+  void*   headerBigBlock = NULL;
+  int     index;
+
+  /*
+   * Get a pointer to the big block of data containing the header.
+   */
+  headerBigBlock = StorageImpl_GetROBigBlock(This, -1);
+
+  /*
+   * Extract the information from the header.
+   */
+  if (headerBigBlock!=0)
+  {
+    /*
+     * Check for the "magic number" signature and return an error if it is not
+     * found.
+     */
+    if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0)
+    {
+      StorageImpl_ReleaseBigBlock(This, headerBigBlock);
+      return STG_E_OLDFORMAT;
+    }
+
+    if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0)
+    {
+      StorageImpl_ReleaseBigBlock(This, headerBigBlock);
+      return STG_E_INVALIDHEADER;
+    }
+
+    StorageUtl_ReadWord(
+      headerBigBlock, 
+      OFFSET_BIGBLOCKSIZEBITS,   
+      &This->bigBlockSizeBits);
+
+    StorageUtl_ReadWord(
+      headerBigBlock, 
+      OFFSET_SMALLBLOCKSIZEBITS, 
+      &This->smallBlockSizeBits);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock, 
+      OFFSET_BBDEPOTCOUNT,      
+      &This->bigBlockDepotCount);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock, 
+      OFFSET_ROOTSTARTBLOCK,    
+      &This->rootStartBlock);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock, 
+      OFFSET_SBDEPOTSTART,      
+      &This->smallBlockDepotStart);
+
+    StorageUtl_ReadDWord( 
+      headerBigBlock, 
+      OFFSET_EXTBBDEPOTSTART,   
+      &This->extBigBlockDepotStart);
+
+    StorageUtl_ReadDWord(
+      headerBigBlock, 
+      OFFSET_EXTBBDEPOTCOUNT,   
+      &This->extBigBlockDepotCount);
+    
+    for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
+    {
+      StorageUtl_ReadDWord(
+        headerBigBlock, 
+        OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
+        &(This->bigBlockDepotStart[index]));
+    }
+    
+    /*
+     * Make the bitwise arithmetic to get the size of the blocks in bytes.
+     */
+    if ((1 << 2) == 4)
+    {
+      This->bigBlockSize   = 0x000000001 << (DWORD)This->bigBlockSizeBits;
+      This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits;
+    }
+    else
+    {
+      This->bigBlockSize   = 0x000000001 >> (DWORD)This->bigBlockSizeBits;
+      This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits;
+    }
+    
+    /*
+     * Right now, the code is making some assumptions about the size of the 
+     * blocks, just make sure they are what we're expecting.
+     */
+    assert( (This->bigBlockSize==DEF_BIG_BLOCK_SIZE) && 
+            (This->smallBlockSize==DEF_SMALL_BLOCK_SIZE));
+    
+    /*
+     * Release the block.
+     */
+    StorageImpl_ReleaseBigBlock(This, headerBigBlock);
+
+    hr = S_OK;
+  }
+  
+  return hr;
+}
+
+/******************************************************************************
+ *      Storage32Impl_SaveFileHeader
+ *
+ * This method will save to the file the header, i.e. big block -1.
+ */
+void StorageImpl_SaveFileHeader(
+          StorageImpl* This)
+{
+  BYTE   headerBigBlock[BIG_BLOCK_SIZE];
+  int    index;
+  BOOL success;
+
+  /*
+   * Get a pointer to the big block of data containing the header.
+   */
+  success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock);
+  
+  /*
+   * If the block read failed, the file is probably new.
+   */
+  if (!success)
+  {
+    /*
+     * Initialize for all unknown fields.
+     */
+    memset(headerBigBlock, 0, BIG_BLOCK_SIZE);
+    
+    /*
+     * Initialize the magic number.
+     */
+    memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic));
+    
+    /*
+     * And a bunch of things we don't know what they mean
+     */
+    StorageUtl_WriteWord(headerBigBlock,  0x18, 0x3b);
+    StorageUtl_WriteWord(headerBigBlock,  0x1a, 0x3);
+    StorageUtl_WriteWord(headerBigBlock,  0x1c, (WORD)-2);
+    StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000);
+    StorageUtl_WriteDWord(headerBigBlock, 0x40, (DWORD)0x0001);
+  }
+  
+  /*
+   * Write the information to the header.
+   */
+  if (headerBigBlock!=0)
+  {
+    StorageUtl_WriteWord(
+      headerBigBlock, 
+      OFFSET_BIGBLOCKSIZEBITS,   
+      This->bigBlockSizeBits);
+
+    StorageUtl_WriteWord(
+      headerBigBlock, 
+      OFFSET_SMALLBLOCKSIZEBITS, 
+      This->smallBlockSizeBits);
+
+    StorageUtl_WriteDWord(
+      headerBigBlock, 
+      OFFSET_BBDEPOTCOUNT,      
+      This->bigBlockDepotCount);
+
+    StorageUtl_WriteDWord(
+      headerBigBlock, 
+      OFFSET_ROOTSTARTBLOCK,    
+      This->rootStartBlock);
+
+    StorageUtl_WriteDWord(
+      headerBigBlock, 
+      OFFSET_SBDEPOTSTART,      
+      This->smallBlockDepotStart);
+
+    StorageUtl_WriteDWord(
+      headerBigBlock, 
+      OFFSET_EXTBBDEPOTSTART,   
+      This->extBigBlockDepotStart);
+
+    StorageUtl_WriteDWord(
+      headerBigBlock, 
+      OFFSET_EXTBBDEPOTCOUNT,   
+      This->extBigBlockDepotCount);
+
+    for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++)
+    {
+      StorageUtl_WriteDWord(
+        headerBigBlock, 
+        OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index),
+        (This->bigBlockDepotStart[index]));
+    }
+  }
+  
+  /*
+   * Write the big block back to the file.
+   */
+  StorageImpl_WriteBigBlock(This, -1, headerBigBlock);
+}
+
+/******************************************************************************
+ *      Storage32Impl_ReadProperty
+ *
+ * This method will read the specified property from the property chain.
+ */
+BOOL StorageImpl_ReadProperty(
+  StorageImpl* This,
+  ULONG          index,
+  StgProperty*   buffer)
+{
+  BYTE           currentProperty[PROPSET_BLOCK_SIZE];
+  ULARGE_INTEGER offsetInPropSet;
+  BOOL         readSucessful;
+  ULONG          bytesRead;
+
+  offsetInPropSet.HighPart = 0;
+  offsetInPropSet.LowPart  = index * PROPSET_BLOCK_SIZE;
+  
+  readSucessful = BlockChainStream_ReadAt(
+                    This->rootBlockChain,
+                    offsetInPropSet,
+                    PROPSET_BLOCK_SIZE,
+                    currentProperty,
+                    &bytesRead);
+  
+  if (readSucessful)
+  {
+    memset(buffer->name, 0, sizeof(buffer->name));
+    memcpy(
+      buffer->name, 
+      currentProperty+OFFSET_PS_NAME, 
+      PROPERTY_NAME_BUFFER_LEN );
+
+    memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1);
+    
+    StorageUtl_ReadWord(
+      currentProperty,  
+      OFFSET_PS_NAMELENGTH,  
+      &buffer->sizeOfNameString);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_PREVIOUSPROP, 
+      &buffer->previousProperty);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_NEXTPROP,     
+      &buffer->nextProperty);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_DIRPROP,      
+      &buffer->dirProperty);
+
+    StorageUtl_ReadGUID(
+      currentProperty,  
+      OFFSET_PS_GUID,        
+      &buffer->propertyUniqueID);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_TSS1,         
+      &buffer->timeStampS1);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_TSD1,         
+      &buffer->timeStampD1);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_TSS2,         
+      &buffer->timeStampS2);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_TSD2,         
+      &buffer->timeStampD2);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_STARTBLOCK,   
+      &buffer->startingBlock);
+
+    StorageUtl_ReadDWord(
+      currentProperty, 
+      OFFSET_PS_SIZE,         
+      &buffer->size.LowPart);
+
+    buffer->size.HighPart = 0;
+  }
+
+  return readSucessful;
+}
+
+/*********************************************************************
+ * Write the specified property into the property chain
+ */
+BOOL StorageImpl_WriteProperty(
+  StorageImpl* This,
+  ULONG          index,
+  StgProperty*   buffer)
+{
+  BYTE           currentProperty[PROPSET_BLOCK_SIZE];
+  ULARGE_INTEGER offsetInPropSet;
+  BOOL         writeSucessful;
+  ULONG          bytesWritten;
+
+  offsetInPropSet.HighPart = 0;
+  offsetInPropSet.LowPart  = index * PROPSET_BLOCK_SIZE;
+
+  memset(currentProperty, 0, PROPSET_BLOCK_SIZE);
+
+  memcpy(
+    currentProperty + OFFSET_PS_NAME, 
+    buffer->name, 
+    PROPERTY_NAME_BUFFER_LEN );
+
+  memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1);
+
+  StorageUtl_WriteWord(
+    currentProperty,  
+      OFFSET_PS_NAMELENGTH,   
+      buffer->sizeOfNameString);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_PREVIOUSPROP, 
+      buffer->previousProperty);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_NEXTPROP,     
+      buffer->nextProperty);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_DIRPROP,      
+      buffer->dirProperty);
+
+  StorageUtl_WriteGUID(
+    currentProperty,  
+      OFFSET_PS_GUID,        
+      &buffer->propertyUniqueID);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_TSS1,         
+      buffer->timeStampS1);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_TSD1,         
+      buffer->timeStampD1);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_TSS2,         
+      buffer->timeStampS2);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_TSD2,         
+      buffer->timeStampD2);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_STARTBLOCK,   
+      buffer->startingBlock);
+
+  StorageUtl_WriteDWord(
+    currentProperty, 
+      OFFSET_PS_SIZE,         
+      buffer->size.LowPart);
+
+  writeSucessful = BlockChainStream_WriteAt(This->rootBlockChain,
+                                            offsetInPropSet,
+                                            PROPSET_BLOCK_SIZE,
+                                            currentProperty,
+                                            &bytesWritten);
+  return writeSucessful;
+}
+
+BOOL StorageImpl_ReadBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex,
+  void*          buffer)
+{
+  void* bigBlockBuffer;
+
+  bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex);
+
+  if (bigBlockBuffer!=0)
+  {
+    memcpy(buffer, bigBlockBuffer, This->bigBlockSize);
+
+    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+BOOL StorageImpl_WriteBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex,
+  void*          buffer)
+{
+  void* bigBlockBuffer;
+
+  bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex);
+
+  if (bigBlockBuffer!=0)
+  {
+    memcpy(bigBlockBuffer, buffer, This->bigBlockSize);
+
+    StorageImpl_ReleaseBigBlock(This, bigBlockBuffer);
+    
+    return TRUE;
+  }
+  
+  return FALSE;
+}
+
+void* StorageImpl_GetROBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex);
+}
+
+void* StorageImpl_GetBigBlock(
+  StorageImpl* This,
+  ULONG          blockIndex)
+{
+  return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex);
+}
+
+void StorageImpl_ReleaseBigBlock(
+  StorageImpl* This,
+  void*          pBigBlock)
+{
+  BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock);
+}
+
+/******************************************************************************
+ *              Storage32Impl_SmallBlocksToBigBlocks
+ *
+ * This method will convert a small block chain to a big block chain.
+ * The small block chain will be destroyed.
+ */
+BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
+                      StorageImpl* This,
+                      SmallBlockChainStream** ppsbChain)
+{
+  ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN;
+  ULARGE_INTEGER size, offset;
+  ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten;
+  ULONG propertyIndex;
+  BOOL successRead, successWrite;
+  StgProperty chainProperty;
+  BYTE *buffer;
+  BlockChainStream *bbTempChain = NULL;
+  BlockChainStream *bigBlockChain = NULL;
+
+  /*
+   * Create a temporary big block chain that doesn't have
+   * an associated property. This temporary chain will be
+   * used to copy data from small blocks to big blocks.
+   */
+  bbTempChain = BlockChainStream_Construct(This,
+                                           &bbHeadOfChain,
+                                           PROPERTY_NULL);
+
+  /*
+   * Grow the big block chain.
+   */
+  size = SmallBlockChainStream_GetSize(*ppsbChain);
+  BlockChainStream_SetSize(bbTempChain, size);
+
+  /*
+   * Copy the contents of the small block chain to the big block chain
+   * by small block size increments.
+   */
+  offset.LowPart = 0;
+  offset.HighPart = 0;
+  cbTotalRead = 0;
+  cbTotalWritten = 0;
+
+  buffer = (BYTE *) malloc(DEF_SMALL_BLOCK_SIZE);
+  do
+  {
+    successRead = SmallBlockChainStream_ReadAt(*ppsbChain,
+                                               offset,
+                                               DEF_SMALL_BLOCK_SIZE,
+                                               buffer,
+                                               &cbRead);
+    cbTotalRead += cbRead;
+
+    successWrite = BlockChainStream_WriteAt(bbTempChain,
+                                            offset,
+                                            cbRead,
+                                            buffer,
+                                            &cbWritten);
+    cbTotalWritten += cbWritten;
+
+    offset.LowPart += This->smallBlockSize;
+
+  } while (successRead && successWrite);
+  free(buffer);
+
+  assert(cbTotalRead == cbTotalWritten);
+
+  /*
+   * Destroy the small block chain.
+   */
+  propertyIndex = (*ppsbChain)->ownerPropertyIndex;
+  size.HighPart = 0;
+  size.LowPart  = 0;
+  SmallBlockChainStream_SetSize(*ppsbChain, size);
+  SmallBlockChainStream_Destroy(*ppsbChain);
+  *ppsbChain = 0;
+
+  /*
+   * Change the property information. This chain is now a big block chain
+   * and it doesn't reside in the small blocks chain anymore.
+   */
+  StorageImpl_ReadProperty(This, propertyIndex, &chainProperty);
+
+  chainProperty.startingBlock = bbHeadOfChain;
+
+  StorageImpl_WriteProperty(This, propertyIndex, &chainProperty);
+
+  /*
+   * Destroy the temporary propertyless big block chain.
+   * Create a new big block chain associated with this property.
+   */
+  BlockChainStream_Destroy(bbTempChain);
+  bigBlockChain = BlockChainStream_Construct(This,
+                                             NULL,
+                                             propertyIndex);
+
+  return bigBlockChain;
+}
+
+/******************************************************************************
+** Storage32InternalImpl implementation
+*/
+
+StorageInternalImpl* StorageInternalImpl_Construct(
+  StorageImpl* ancestorStorage,  
+  ULONG          rootPropertyIndex)
+{
+  StorageInternalImpl* newStorage;
+
+  /*
+   * Allocate space for the new storage object
+   */
+  newStorage = (StorageInternalImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl));
+
+  if (newStorage!=0)
+  {
+    memset(newStorage, 0, sizeof(StorageInternalImpl));
+
+    /*
+     * Initialize the virtual function table.
+     */
+    ICOM_VTBL(newStorage)    = &Storage32InternalImpl_Vtbl;
+    newStorage->v_destructor = &StorageInternalImpl_Destroy;
+
+    /*
+     * Keep the ancestor storage pointer and nail a reference to it.
+     */
+    newStorage->ancestorStorage = ancestorStorage;
+    StorageBaseImpl_AddRef((IStorage*)(newStorage->ancestorStorage));
+
+    /*
+     * Keep the index of the root property set for this storage,
+     */
+    newStorage->rootPropertySetIndex = rootPropertyIndex;
+
+    return newStorage;
+  }
+
+  return 0;
+}
+
+void StorageInternalImpl_Destroy(
+  StorageInternalImpl* This)
+{
+  StorageBaseImpl_Release((IStorage*)This->ancestorStorage);
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+**
+** Storage32InternalImpl_Commit
+**
+** The non-root storages cannot be opened in transacted mode thus this function
+** does nothing.
+*/
+HRESULT WINAPI StorageInternalImpl_Commit( 
+  IStorage*            iface,
+  DWORD                  grfCommitFlags)  /* [in] */ 
+{
+  return S_OK;
+}
+        
+/******************************************************************************
+**
+** Storage32InternalImpl_Revert
+**
+** The non-root storages cannot be opened in transacted mode thus this function
+** does nothing.
+*/
+HRESULT WINAPI StorageInternalImpl_Revert( 
+  IStorage*            iface)
+{
+  return S_OK;
+}
+
+/******************************************************************************
+** IEnumSTATSTGImpl implementation
+*/
+
+IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
+  StorageImpl* parentStorage,
+  ULONG          firstPropertyNode)
+{
+  IEnumSTATSTGImpl* newEnumeration;
+
+  newEnumeration = (IEnumSTATSTGImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl));
+  
+  if (newEnumeration!=0)
+  {
+    /*
+     * Set-up the virtual function table and reference count.
+     */
+    ICOM_VTBL(newEnumeration) = &IEnumSTATSTGImpl_Vtbl;
+    newEnumeration->ref    = 0;
+    
+    /*
+     * We want to nail-down the reference to the storage in case the
+     * enumeration out-lives the storage in the client application.
+     */
+    newEnumeration->parentStorage = parentStorage;
+    IStorage_AddRef((IStorage*)newEnumeration->parentStorage);
+    
+    newEnumeration->firstPropertyNode   = firstPropertyNode;
+    
+    /*
+     * Initialize the search stack
+     */
+    newEnumeration->stackSize    = 0;
+    newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT;
+    newEnumeration->stackToVisit = 
+      (ULONG *)HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT);
+    
+    /*
+     * Make sure the current node of the iterator is the first one.
+     */
+    IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration);
+  }
+  
+  return newEnumeration;
+}
+
+void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This)
+{
+  IStorage_Release((IStorage*)This->parentStorage);
+  HeapFree(GetProcessHeap(), 0, This->stackToVisit);
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
+  IEnumSTATSTG*     iface,
+  REFIID            riid,
+  void**            ppvObject)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (ppvObject==0)
+    return E_INVALIDARG;
+
+  /*
+   * Initialize the return parameter.
+   */
+  *ppvObject = 0;
+
+  /*
+   * Compare the riid with the interface IDs implemented by this object.
+   */
+  if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) 
+  {
+    *ppvObject = (IEnumSTATSTG*)This;
+  }
+  else if (memcmp(&IID_IStorage, riid, sizeof(IID_IEnumSTATSTG)) == 0) 
+  {
+    *ppvObject = (IEnumSTATSTG*)This;
+  }
+
+  /*
+   * Check that we obtained an interface.
+   */
+  if ((*ppvObject)==0)
+    return E_NOINTERFACE;
+
+  /*
+   * Query Interface always increases the reference count by one when it is
+   * successful
+   */
+  IEnumSTATSTGImpl_AddRef((IEnumSTATSTG*)This);
+
+  return S_OK;
+}
+        
+ULONG   WINAPI IEnumSTATSTGImpl_AddRef(
+  IEnumSTATSTG* iface)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  This->ref++;
+  return This->ref;
+}
+        
+ULONG   WINAPI IEnumSTATSTGImpl_Release(
+  IEnumSTATSTG* iface)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  ULONG newRef;
+
+  This->ref--;
+  newRef = This->ref;
+
+  /*
+   * If the reference count goes down to 0, perform suicide.
+   */
+  if (newRef==0)
+  {
+    IEnumSTATSTGImpl_Destroy(This);
+  }
+
+  return newRef;;
+}
+
+HRESULT WINAPI IEnumSTATSTGImpl_Next(
+  IEnumSTATSTG* iface,
+  ULONG             celt,
+  STATSTG*          rgelt,
+  ULONG*            pceltFetched)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  StgProperty currentProperty;
+  STATSTG*    currentReturnStruct = rgelt;
+  ULONG       objectFetched       = 0;
+  ULONG      currentSearchNode;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) )
+    return E_INVALIDARG;  
+  
+  /*
+   * To avoid the special case, get another pointer to a ULONG value if
+   * the caller didn't supply one.
+   */
+  if (pceltFetched==0)
+    pceltFetched = &objectFetched;
+  
+  /*
+   * Start the iteration, we will iterate until we hit the end of the
+   * linked list or until we hit the number of items to iterate through
+   */
+  *pceltFetched = 0;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+
+  while ( ( *pceltFetched < celt) && 
+          ( currentSearchNode!=PROPERTY_NULL) )
+  {
+    /* 
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(This->parentStorage,
+      currentSearchNode, 
+      &currentProperty);
+
+    /*
+     * Copy the information to the return buffer.
+     */
+    StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct,
+      &currentProperty,
+      STATFLAG_DEFAULT);
+        
+    /*
+     * Step to the next item in the iteration
+     */
+    (*pceltFetched)++;
+    currentReturnStruct++;
+
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  if (*pceltFetched == celt)
+    return S_OK;
+
+  return S_FALSE;
+}
+
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Skip(
+  IEnumSTATSTG* iface,
+  ULONG             celt)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  StgProperty currentProperty;
+  ULONG       objectFetched       = 0;
+  ULONG       currentSearchNode;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+
+  while ( (objectFetched < celt) && 
+          (currentSearchNode!=PROPERTY_NULL) )
+  {
+    /* 
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(This->parentStorage,
+      currentSearchNode, 
+      &currentProperty);
+    
+    /*
+     * Step to the next item in the iteration
+     */
+    objectFetched++;
+
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  if (objectFetched == celt)
+    return S_OK;
+
+  return S_FALSE;
+}
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Reset(
+  IEnumSTATSTG* iface)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  StgProperty rootProperty;
+  BOOL      readSucessful;
+
+  /*
+   * Re-initialize the search stack to an empty stack
+   */
+  This->stackSize = 0;
+
+  /*
+   * Read the root property from the storage.
+   */
+  readSucessful = StorageImpl_ReadProperty(
+                    This->parentStorage,
+                    This->firstPropertyNode, 
+                    &rootProperty);
+
+  if (readSucessful)
+  {
+    assert(rootProperty.sizeOfNameString!=0);
+
+    /*
+     * Push the search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty);
+  }
+
+  return S_OK;
+}
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Clone(
+  IEnumSTATSTG* iface,
+  IEnumSTATSTG**    ppenum)
+{
+  IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface;
+
+  IEnumSTATSTGImpl* newClone;
+
+  /*
+   * Perform a sanity check on the parameters.
+   */
+  if (ppenum==0)
+    return E_INVALIDARG;
+  
+  newClone = IEnumSTATSTGImpl_Construct(This->parentStorage,
+               This->firstPropertyNode);
+
+  
+  /*
+   * The new clone enumeration must point to the same current node as
+   * the ole one.
+   */
+  newClone->stackSize    = This->stackSize    ;
+  newClone->stackMaxSize = This->stackMaxSize ;
+  newClone->stackToVisit = 
+    (ULONG *)HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize);
+
+  memcpy(
+    newClone->stackToVisit, 
+    This->stackToVisit, 
+    sizeof(ULONG) * newClone->stackSize);
+
+  *ppenum = (IEnumSTATSTG*)newClone;
+
+  /*
+   * Don't forget to nail down a reference to the clone before
+   * returning it.
+   */
+  IEnumSTATSTGImpl_AddRef(*ppenum);
+
+  return S_OK;
+}
+
+INT IEnumSTATSTGImpl_FindParentProperty(
+  IEnumSTATSTGImpl *This,
+  ULONG             childProperty, 
+  StgProperty      *currentProperty,
+  ULONG            *thisNodeId)
+{
+  ULONG currentSearchNode;
+  ULONG foundNode;
+
+  /*
+   * To avoid the special case, get another pointer to a ULONG value if
+   * the caller didn't supply one.
+   */
+  if (thisNodeId==0)
+    thisNodeId = &foundNode;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  
+
+  while (currentSearchNode!=PROPERTY_NULL)
+  {
+    /*
+     * Store the current node in the returned parameters
+     */
+    *thisNodeId = currentSearchNode;
+
+    /* 
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(
+      This->parentStorage,
+      currentSearchNode, 
+      currentProperty);
+      
+    if (currentProperty->previousProperty == childProperty)
+      return PROPERTY_RELATION_PREVIOUS;
+
+    else if (currentProperty->nextProperty == childProperty)  
+      return PROPERTY_RELATION_NEXT;
+  
+    else if (currentProperty->dirProperty == childProperty)
+      return PROPERTY_RELATION_DIR;
+       
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  return PROPERTY_NULL;
+}
+
+ULONG IEnumSTATSTGImpl_FindProperty(
+  IEnumSTATSTGImpl* This,
+  const OLECHAR*  lpszPropName,
+  StgProperty*      currentProperty)
+{
+  ULONG currentSearchNode;
+
+  /*
+   * Start with the node at the top of the stack.
+   */
+  currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+
+  while (currentSearchNode!=PROPERTY_NULL)
+  {
+    /* 
+     * Remove the top node from the stack
+     */
+    IEnumSTATSTGImpl_PopSearchNode(This, TRUE);
+
+    /*
+     * Read the property from the storage.
+     */
+    StorageImpl_ReadProperty(This->parentStorage,
+      currentSearchNode, 
+      currentProperty);
+
+    if ( propertyNameCmp(
+          (OLECHAR*)currentProperty->name, 
+          (OLECHAR*)lpszPropName) == 0)
+      return currentSearchNode;
+
+    /*
+     * Push the next search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty);
+
+    /*
+     * continue the iteration.
+     */
+    currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE);
+  }
+
+  return PROPERTY_NULL;
+}
+
+void IEnumSTATSTGImpl_PushSearchNode(
+  IEnumSTATSTGImpl* This,
+  ULONG             nodeToPush)
+{
+  StgProperty rootProperty;
+  BOOL      readSucessful;
+
+  /*
+   * First, make sure we're not trying to push an unexisting node.
+   */
+  if (nodeToPush==PROPERTY_NULL)
+    return;
+
+  /*
+   * First push the node to the stack
+   */
+  if (This->stackSize == This->stackMaxSize)
+  {
+    This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT;
+
+    This->stackToVisit = (ULONG *)HeapReAlloc(
+                           GetProcessHeap(), 
+                           0,
+                           This->stackToVisit,
+                           sizeof(ULONG) * This->stackMaxSize);
+  }
+
+  This->stackToVisit[This->stackSize] = nodeToPush;
+  This->stackSize++;
+
+  /*
+   * Read the root property from the storage.
+   */
+  readSucessful = StorageImpl_ReadProperty(
+                    This->parentStorage,
+                    nodeToPush, 
+                    &rootProperty);
+
+  if (readSucessful)
+  {
+    assert(rootProperty.sizeOfNameString!=0);
+
+    /*
+     * Push the previous search node in the search stack.
+     */
+    IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty);
+  }
+}
+
+ULONG IEnumSTATSTGImpl_PopSearchNode(
+  IEnumSTATSTGImpl* This,
+  BOOL            remove)
+{
+  ULONG topNode;
+
+  if (This->stackSize == 0)
+    return PROPERTY_NULL;
+
+  topNode = This->stackToVisit[This->stackSize-1];
+
+  if (remove)
+    This->stackSize--;
+
+  return topNode;
+}
+
+/******************************************************************************
+** StorageUtl implementation
+*/
+
+void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value)
+{
+  memcpy(value, (BYTE*)buffer+offset, sizeof(WORD));
+}
+
+void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value)
+{
+  memcpy((BYTE*)buffer+offset, &value, sizeof(WORD));
+}
+
+void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value)
+{
+  memcpy(value, (BYTE*)buffer+offset, sizeof(DWORD));
+}
+
+void StorageUtl_ReadDWords(void *buffer, ULONG offset, DWORD *values,
+			   ULONG len)
+{
+  memcpy(values, (BYTE*)buffer+offset, sizeof(DWORD)*len);
+}
+
+void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value)
+{
+  memcpy((BYTE*)buffer+offset, &value, sizeof(DWORD));
+}
+
+void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value)
+{
+  StorageUtl_ReadDWord(buffer, offset,   &(value->Data1));
+  StorageUtl_ReadWord(buffer,  offset+4, &(value->Data2));
+  StorageUtl_ReadWord(buffer,  offset+6, &(value->Data3));
+
+  memcpy(value->Data4, (BYTE*)buffer+offset+8, sizeof(value->Data4));
+}
+
+void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value)
+{
+  StorageUtl_WriteDWord(buffer, offset,   value->Data1);
+  StorageUtl_WriteWord(buffer,  offset+4, value->Data2);
+  StorageUtl_WriteWord(buffer,  offset+6, value->Data3);
+
+  memcpy((BYTE*)buffer+offset+8, value->Data4, sizeof(value->Data4));
+}
+
+void StorageUtl_CopyPropertyToSTATSTG(
+  STATSTG*     destination,
+  StgProperty* source,
+  int          statFlags)
+{
+  /*
+   * The copy of the string occurs only when the flag is not set
+   */
+  if ((statFlags & STATFLAG_NONAME) != 0)
+  {
+    destination->pwcsName = 0;
+  }
+  else
+  {
+    destination->pwcsName = 
+      (WCHAR *)CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR));
+
+    lstrcpyW((LPWSTR)destination->pwcsName, source->name);
+  }
+  
+  switch (source->propertyType)
+  {
+    case PROPTYPE_STORAGE:
+    case PROPTYPE_ROOT:
+      destination->type = STGTY_STORAGE;
+      break;
+    case PROPTYPE_STREAM:
+      destination->type = STGTY_STREAM;
+      break;
+    default:
+      destination->type = STGTY_STREAM;
+      break;        
+  }
+
+  destination->cbSize            = source->size;
+/*    
+  currentReturnStruct->mtime     = {0}; TODO
+  currentReturnStruct->ctime     = {0};
+  currentReturnStruct->atime     = {0}; 
+*/
+  destination->grfMode           = 0;
+  destination->grfLocksSupported = 0; 
+  destination->clsid             = source->propertyUniqueID;
+  destination->grfStateBits      = 0; 
+  destination->reserved          = 0; 
+}
+
+/******************************************************************************
+** BlockChainStream implementation
+*/
+
+BlockChainStream* BlockChainStream_Construct(
+  StorageImpl* parentStorage,  
+  ULONG*         headOfStreamPlaceHolder,
+  ULONG          propertyIndex)
+{
+  BlockChainStream* newStream;
+
+  newStream = (BlockChainStream *)HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream));
+
+  newStream->parentStorage           = parentStorage;
+  newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder;
+  newStream->ownerPropertyIndex      = propertyIndex;
+  newStream->lastBlockNoInSequence   = 0xFFFFFFFF;
+  newStream->lazyInitComplete        = FALSE;
+  newStream->tailIndex               = BLOCK_END_OF_CHAIN;
+  newStream->numBlocks               = 0;
+
+  return newStream;
+}
+
+static void BlockChainStream_LazyInit(BlockChainStream *This)
+{
+    ULONG numBlocks = 0;
+    ULONG tailIndex = BLOCK_END_OF_CHAIN;
+    StorageImpl *parentStorage = This->parentStorage;
+
+    ULONG blockIndex = BlockChainStream_GetHeadOfChain(This);
+
+    while (blockIndex != BLOCK_END_OF_CHAIN)
+    {
+	numBlocks++;
+	tailIndex = blockIndex;
+
+	blockIndex = StorageImpl_GetNextBlockInChain(parentStorage,
+						     blockIndex);
+    }
+
+    This->numBlocks = numBlocks;
+    This->tailIndex = tailIndex;
+}
+
+static inline ULONG BlockChainStream_TailIndex(BlockChainStream *This)
+{
+    if (!This->lazyInitComplete)
+	BlockChainStream_LazyInit(This);
+    return This->tailIndex;
+}
+
+static inline ULONG BlockChainStream_NumBlocks(BlockChainStream *This)
+{
+    if (!This->lazyInitComplete)
+	BlockChainStream_LazyInit(This);
+    return This->numBlocks;
+}
+
+void BlockChainStream_Destroy(BlockChainStream* This)
+{
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ *      BlockChainStream_GetHeadOfChain
+ *
+ * Returns the head of this stream chain.
+ * Some special chains don't have properties, their heads are kept in
+ * This->headOfStreamPlaceHolder.
+ *
+ */
+ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This)
+{
+  StgProperty chainProperty;
+  BOOL      readSucessful;
+
+  if (This->headOfStreamPlaceHolder != 0)
+    return *(This->headOfStreamPlaceHolder);
+
+  if (This->ownerPropertyIndex != PROPERTY_NULL)
+  {
+    readSucessful = StorageImpl_ReadProperty(
+                      This->parentStorage,
+                      This->ownerPropertyIndex,
+                      &chainProperty);
+
+    if (readSucessful)
+    {
+      return chainProperty.startingBlock;
+    }
+  }
+
+  return BLOCK_END_OF_CHAIN;
+}
+
+/******************************************************************************
+ *       BlockChainStream_GetCount
+ *
+ * Returns the number of blocks that comprises this chain.
+ * This is not the size of the stream as the last block may not be full!
+ * 
+ */
+ULONG BlockChainStream_GetCount(BlockChainStream* This)
+{
+  ULONG blockIndex;
+  ULONG count = 0;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(This);
+
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    count++;
+
+    blockIndex = StorageImpl_GetNextBlockInChain(
+                   This->parentStorage, 
+                   blockIndex);
+  }
+
+  return count;
+}
+
+/******************************************************************************
+ *      BlockChainStream_ReadAt 
+ *
+ * Reads a specified number of bytes from this chain at the specified offset.
+ * bytesRead may be NULL.
+ * Failure will be returned if the specified number of bytes has not been read.
+ */
+BOOL BlockChainStream_ReadAt(BlockChainStream* This,
+  ULARGE_INTEGER offset,
+  ULONG          size,
+  void*          buffer,
+  ULONG*         bytesRead)
+{
+  ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
+  ULONG offsetInBlock     = offset.LowPart % This->parentStorage->bigBlockSize;
+  ULONG bytesToReadInBuffer;
+  ULONG blockIndex;
+  BYTE* bufferWalker;
+  BYTE* bigBlockBuffer;
+
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
+       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
+       (blockNoInSequence < This->lastBlockNoInSequence) )
+  {
+    blockIndex = BlockChainStream_GetHeadOfChain(This);
+    This->lastBlockNoInSequence = blockNoInSequence;
+  }
+  else
+  {
+    ULONG temp = blockNoInSequence;
+
+    blockIndex = This->lastBlockNoInSequenceIndex;
+    blockNoInSequence -= This->lastBlockNoInSequence;
+    This->lastBlockNoInSequence = temp;
+  }
+
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    blockIndex = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+    
+    blockNoInSequence--;
+  }
+
+  This->lastBlockNoInSequenceIndex = blockIndex;
+
+  /*
+   * Start reading the buffer.
+   */
+  *bytesRead   = 0;
+  bufferWalker = (BYTE *)buffer;
+  
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy from this big block.
+     */
+    bytesToReadInBuffer = 
+      MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
+    
+    /*
+     * Copy those bytes to the buffer
+     */
+    bigBlockBuffer = 
+      (BYTE *)StorageImpl_GetROBigBlock(This->parentStorage, blockIndex);
+    
+    memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer);
+    
+    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+    
+    /*
+     * Step to the next big block.
+     */
+    blockIndex    = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+
+    bufferWalker += bytesToReadInBuffer;
+    size         -= bytesToReadInBuffer;
+    *bytesRead   += bytesToReadInBuffer;
+    offsetInBlock = 0;  /* There is no offset on the next block */
+
+  }
+  
+  return (size == 0);
+}
+
+/******************************************************************************
+ *      BlockChainStream_WriteAt
+ *
+ * Writes the specified number of bytes to this chain at the specified offset.
+ * bytesWritten may be NULL.
+ * Will fail if not all specified number of bytes have been written.
+ */
+BOOL BlockChainStream_WriteAt(BlockChainStream* This,
+  ULARGE_INTEGER    offset,
+  ULONG             size,
+  const void*       buffer,
+  ULONG*            bytesWritten)
+{
+  ULONG blockNoInSequence = offset.LowPart / This->parentStorage->bigBlockSize;
+  ULONG offsetInBlock     = offset.LowPart % This->parentStorage->bigBlockSize;
+  ULONG bytesToWrite;
+  ULONG blockIndex;
+  BYTE* bufferWalker;
+  BYTE* bigBlockBuffer;
+
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) ||
+       (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) ||
+       (blockNoInSequence < This->lastBlockNoInSequence) )
+  {
+    blockIndex = BlockChainStream_GetHeadOfChain(This);
+    This->lastBlockNoInSequence = blockNoInSequence;
+  }
+  else
+  {
+    ULONG temp = blockNoInSequence;
+
+    blockIndex = This->lastBlockNoInSequenceIndex;
+    blockNoInSequence -= This->lastBlockNoInSequence;
+    This->lastBlockNoInSequence = temp;
+  }
+
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    blockIndex = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+    
+    blockNoInSequence--;
+  }
+
+  This->lastBlockNoInSequenceIndex = blockIndex;
+
+  /*
+   * Here, I'm casting away the constness on the buffer variable
+   * This is OK since we don't intend to modify that buffer.
+   */
+  *bytesWritten   = 0;
+  bufferWalker = (BYTE*)buffer;
+
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy from this big block.
+     */
+    bytesToWrite = 
+      MIN(This->parentStorage->bigBlockSize - offsetInBlock, size);
+    
+    /*
+     * Copy those bytes to the buffer
+     */
+    bigBlockBuffer = (BYTE *)StorageImpl_GetBigBlock(This->parentStorage, blockIndex);
+    
+    memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite);
+    
+    StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer);
+    
+    /*
+     * Step to the next big block.
+     */
+    blockIndex    = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+
+    bufferWalker  += bytesToWrite;
+    size          -= bytesToWrite;
+    *bytesWritten += bytesToWrite;
+    offsetInBlock  = 0;      /* There is no offset on the next block */
+  }
+  
+  return (size == 0);
+}
+
+/******************************************************************************
+ *      BlockChainStream_Shrink
+ *
+ * Shrinks this chain in the big block depot.
+ */
+BOOL BlockChainStream_Shrink(BlockChainStream* This,
+                               ULARGE_INTEGER    newSize)
+{
+  ULONG blockIndex, extraBlock;
+  ULONG numBlocks;
+  ULONG count = 1;
+
+  /*
+   * Reset the last accessed block cache.
+   */
+  This->lastBlockNoInSequence = 0xFFFFFFFF;
+  This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN;
+
+  /*
+   * Figure out how many blocks are needed to contain the new size
+   */
+  numBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
+
+  if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
+    numBlocks++;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Go to the new end of chain
+   */
+  while (count < numBlocks)
+  {
+    blockIndex = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+
+    count++;
+  }
+
+  /* Get the next block before marking the new end */
+  extraBlock = 
+    StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex);
+
+  /* Mark the new end of chain */
+  StorageImpl_SetNextBlockInChain(
+    This->parentStorage, 
+    blockIndex, 
+    BLOCK_END_OF_CHAIN);
+
+  This->tailIndex = blockIndex;
+  This->numBlocks = numBlocks;
+
+  /*
+   * Mark the extra blocks as free
+   */
+  while (extraBlock != BLOCK_END_OF_CHAIN)
+  {
+    blockIndex = 
+      StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock);
+
+    StorageImpl_FreeBigBlock(This->parentStorage, extraBlock);
+    extraBlock = blockIndex;
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BlockChainStream_Enlarge
+ *
+ * Grows this chain in the big block depot.
+ */
+BOOL BlockChainStream_Enlarge(BlockChainStream* This,
+                                ULARGE_INTEGER    newSize)
+{
+  ULONG blockIndex, currentBlock;
+  ULONG newNumBlocks;
+  ULONG oldNumBlocks = 0;
+
+  blockIndex = BlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Empty chain. Create the head.
+   */
+  if (blockIndex == BLOCK_END_OF_CHAIN)
+  {
+    blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+    StorageImpl_SetNextBlockInChain(This->parentStorage,
+                                      blockIndex,
+                                      BLOCK_END_OF_CHAIN);
+
+    if (This->headOfStreamPlaceHolder != 0)
+    {
+      *(This->headOfStreamPlaceHolder) = blockIndex;
+    }
+    else
+    {
+      StgProperty chainProp;
+      assert(This->ownerPropertyIndex != PROPERTY_NULL);
+
+      StorageImpl_ReadProperty(
+        This->parentStorage, 
+        This->ownerPropertyIndex,
+        &chainProp);
+
+      chainProp.startingBlock = blockIndex; 
+
+      StorageImpl_WriteProperty(
+        This->parentStorage, 
+        This->ownerPropertyIndex,
+        &chainProp);
+    }
+
+    This->tailIndex = blockIndex;
+    This->numBlocks = 1;
+  }
+
+  /*
+   * Figure out how many blocks are needed to contain this stream
+   */
+  newNumBlocks = newSize.LowPart / This->parentStorage->bigBlockSize;
+
+  if ((newSize.LowPart % This->parentStorage->bigBlockSize) != 0)
+    newNumBlocks++;
+
+  /*
+   * Go to the current end of chain
+   */
+  currentBlock = BlockChainStream_TailIndex(This);
+  oldNumBlocks = BlockChainStream_NumBlocks(This);
+
+  /*
+   * Add new blocks to the chain
+   */
+  if (oldNumBlocks < newNumBlocks)
+  {
+    while (oldNumBlocks < newNumBlocks)
+    {
+      blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+
+      StorageImpl_SetNextBlockInChain(
+	This->parentStorage, 
+	currentBlock, 
+	blockIndex);
+
+      StorageImpl_SetNextBlockInChain(
+        This->parentStorage, 
+	blockIndex, 
+	BLOCK_END_OF_CHAIN);
+
+      currentBlock = blockIndex;
+      oldNumBlocks++;
+    }
+
+    This->tailIndex = blockIndex;
+    This->numBlocks = newNumBlocks;
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BlockChainStream_SetSize
+ *
+ * Sets the size of this stream. The big block depot will be updated.
+ * The file will grow if we grow the chain.
+ *
+ * TODO: Free the actual blocks in the file when we shrink the chain.
+ *       Currently, the blocks are still in the file. So the file size
+ *       doesn't shrink even if we shrink streams. 
+ */
+BOOL BlockChainStream_SetSize(
+  BlockChainStream* This,
+  ULARGE_INTEGER    newSize)
+{
+  ULARGE_INTEGER size = BlockChainStream_GetSize(This);
+
+  if (newSize.LowPart == size.LowPart)
+    return TRUE;
+
+  if (newSize.LowPart < size.LowPart)
+  {
+    BlockChainStream_Shrink(This, newSize);
+  }
+  else
+  {
+    ULARGE_INTEGER fileSize = 
+      BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile);
+
+    ULONG diff = newSize.LowPart - size.LowPart;
+
+    /*
+     * Make sure the file stays a multiple of blocksize
+     */
+    if ((diff % This->parentStorage->bigBlockSize) != 0)
+      diff += (This->parentStorage->bigBlockSize - 
+                (diff % This->parentStorage->bigBlockSize) );
+
+    fileSize.LowPart += diff;
+    BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize);
+
+    BlockChainStream_Enlarge(This, newSize);
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      BlockChainStream_GetSize
+ *
+ * Returns the size of this chain.
+ * Will return the block count if this chain doesn't have a property.
+ */
+ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This)
+{
+  StgProperty chainProperty;
+
+  if(This->headOfStreamPlaceHolder == NULL)
+  {
+    /* 
+     * This chain is a data stream read the property and return 
+     * the appropriate size
+     */
+    StorageImpl_ReadProperty(
+      This->parentStorage,
+      This->ownerPropertyIndex,
+      &chainProperty);
+
+    return chainProperty.size;
+  }
+  else
+  {
+    /*
+     * this chain is a chain that does not have a property, figure out the 
+     * size by making the product number of used blocks times the 
+     * size of them
+     */
+    ULARGE_INTEGER result;
+    result.HighPart = 0;
+
+    result.LowPart  = 
+      BlockChainStream_GetCount(This) * 
+      This->parentStorage->bigBlockSize;
+
+    return result;
+  }
+}
+
+/******************************************************************************
+** SmallBlockChainStream implementation
+*/
+
+SmallBlockChainStream* SmallBlockChainStream_Construct(
+  StorageImpl* parentStorage,  
+  ULONG          propertyIndex)
+{
+  SmallBlockChainStream* newStream;
+
+  newStream =
+      (SmallBlockChainStream *)HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream));
+
+  newStream->parentStorage      = parentStorage;
+  newStream->ownerPropertyIndex = propertyIndex;
+
+  return newStream;
+}
+
+void SmallBlockChainStream_Destroy(
+  SmallBlockChainStream* This)
+{
+  HeapFree(GetProcessHeap(), 0, This);
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetHeadOfChain
+ *
+ * Returns the head of this chain of small blocks.
+ */
+ULONG SmallBlockChainStream_GetHeadOfChain(
+  SmallBlockChainStream* This)
+{
+  StgProperty chainProperty;
+  BOOL      readSucessful;
+
+  if (This->ownerPropertyIndex)
+  {
+    readSucessful = StorageImpl_ReadProperty(
+                      This->parentStorage,
+                      This->ownerPropertyIndex,
+                      &chainProperty);
+
+    if (readSucessful)
+    {
+      return chainProperty.startingBlock;
+    }
+
+  }
+
+  return BLOCK_END_OF_CHAIN;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetNextBlockInChain
+ *
+ * Returns the index of the next small block in this chain.
+ * 
+ * Return Values:
+ *    - BLOCK_END_OF_CHAIN: end of this chain
+ *    - BLOCK_UNUSED: small block 'blockIndex' is free
+ */
+ULONG SmallBlockChainStream_GetNextBlockInChain(
+  SmallBlockChainStream* This,
+  ULONG                  blockIndex)
+{
+  ULARGE_INTEGER offsetOfBlockInDepot;
+  DWORD  buffer;
+  ULONG  nextBlockInChain = BLOCK_END_OF_CHAIN;
+  ULONG  bytesRead;
+  BOOL success;
+
+  offsetOfBlockInDepot.HighPart = 0;
+  offsetOfBlockInDepot.LowPart  = blockIndex * sizeof(ULONG);
+
+  /*
+   * Read those bytes in the buffer from the small block file.
+   */
+  success = BlockChainStream_ReadAt(
+              This->parentStorage->smallBlockDepotChain,
+              offsetOfBlockInDepot,
+              sizeof(DWORD),
+              &buffer,
+              &bytesRead);
+
+  if (success)
+  {
+    StorageUtl_ReadDWord(&buffer, 0, &nextBlockInChain);
+  }
+
+  return nextBlockInChain;
+}
+
+/******************************************************************************
+ *       SmallBlockChainStream_SetNextBlockInChain
+ *
+ * Writes the index of the next block of the specified block in the small
+ * block depot.
+ * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock.
+ * To flag a block as free use BLOCK_UNUSED as nextBlock.
+ */
+void SmallBlockChainStream_SetNextBlockInChain(
+  SmallBlockChainStream* This,
+  ULONG                  blockIndex,
+  ULONG                  nextBlock)
+{
+  ULARGE_INTEGER offsetOfBlockInDepot;
+  DWORD  buffer;
+  ULONG  bytesWritten;
+
+  offsetOfBlockInDepot.HighPart = 0;
+  offsetOfBlockInDepot.LowPart  = blockIndex * sizeof(ULONG);
+
+  StorageUtl_WriteDWord(&buffer, 0, nextBlock);
+
+  /*
+   * Read those bytes in the buffer from the small block file.
+   */
+  BlockChainStream_WriteAt(
+    This->parentStorage->smallBlockDepotChain,
+    offsetOfBlockInDepot,
+    sizeof(DWORD),
+    &buffer,
+    &bytesWritten);
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_FreeBlock
+ *
+ * Flag small block 'blockIndex' as free in the small block depot.
+ */
+void SmallBlockChainStream_FreeBlock(
+  SmallBlockChainStream* This,
+  ULONG                  blockIndex)
+{
+  SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED);
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetNextFreeBlock
+ *
+ * Returns the index of a free small block. The small block depot will be
+ * enlarged if necessary. The small block chain will also be enlarged if
+ * necessary.
+ */
+ULONG SmallBlockChainStream_GetNextFreeBlock(
+  SmallBlockChainStream* This)
+{
+  ULARGE_INTEGER offsetOfBlockInDepot;
+  DWORD buffer;
+  ULONG bytesRead;
+  ULONG blockIndex = 0;
+  ULONG nextBlockIndex = BLOCK_END_OF_CHAIN;
+  BOOL success = TRUE;
+  ULONG smallBlocksPerBigBlock;
+
+  offsetOfBlockInDepot.HighPart = 0;
+
+  /*
+   * Scan the small block depot for a free block
+   */
+  while (nextBlockIndex != BLOCK_UNUSED)
+  {
+    offsetOfBlockInDepot.LowPart = blockIndex * sizeof(ULONG);
+
+    success = BlockChainStream_ReadAt(
+                This->parentStorage->smallBlockDepotChain,
+                offsetOfBlockInDepot,
+                sizeof(DWORD),
+                &buffer,
+                &bytesRead);
+
+    /*
+     * If we run out of space for the small block depot, enlarge it
+     */
+    if (success)
+    {
+      StorageUtl_ReadDWord(&buffer, 0, &nextBlockIndex);
+
+      if (nextBlockIndex != BLOCK_UNUSED)
+        blockIndex++;
+    }
+    else
+    {
+      ULONG count = 
+        BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain);
+
+      ULONG sbdIndex = This->parentStorage->smallBlockDepotStart;
+      ULONG nextBlock, newsbdIndex;
+      BYTE* smallBlockDepot;
+
+      nextBlock = sbdIndex;
+      while (nextBlock != BLOCK_END_OF_CHAIN)
+      {
+        sbdIndex = nextBlock;
+        nextBlock = 
+          StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex);
+      }
+
+      newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+      if (sbdIndex != BLOCK_END_OF_CHAIN)
+        StorageImpl_SetNextBlockInChain(
+          This->parentStorage, 
+          sbdIndex, 
+          newsbdIndex);
+
+      StorageImpl_SetNextBlockInChain(
+        This->parentStorage, 
+        newsbdIndex, 
+        BLOCK_END_OF_CHAIN);
+
+      /*
+       * Initialize all the small blocks to free
+       */
+      smallBlockDepot = 
+        (BYTE *)StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex);
+
+      memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize);
+      StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot);
+
+      if (count == 0)
+      {
+        /*
+         * We have just created the small block depot.
+         */
+        StgProperty rootProp;
+        ULONG sbStartIndex; 
+
+        /*
+         * Save it in the header
+         */
+        This->parentStorage->smallBlockDepotStart = newsbdIndex;
+        StorageImpl_SaveFileHeader(This->parentStorage);
+
+        /*
+         * And allocate the first big block that will contain small blocks 
+         */
+        sbStartIndex = 
+          StorageImpl_GetNextFreeBigBlock(This->parentStorage);
+
+        StorageImpl_SetNextBlockInChain(
+          This->parentStorage, 
+          sbStartIndex, 
+          BLOCK_END_OF_CHAIN);
+
+        StorageImpl_ReadProperty(
+          This->parentStorage, 
+          This->parentStorage->rootPropertySetIndex, 
+          &rootProp);
+
+        rootProp.startingBlock = sbStartIndex;
+        rootProp.size.HighPart = 0;
+        rootProp.size.LowPart  = This->parentStorage->bigBlockSize;
+
+        StorageImpl_WriteProperty(
+          This->parentStorage, 
+          This->parentStorage->rootPropertySetIndex, 
+          &rootProp);
+      }
+    }
+  }
+
+  smallBlocksPerBigBlock = 
+    This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize;
+
+  /*
+   * Verify if we have to allocate big blocks to contain small blocks
+   */
+  if (blockIndex % smallBlocksPerBigBlock == 0)
+  {
+    StgProperty rootProp;
+    ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1;
+
+    StorageImpl_ReadProperty(
+      This->parentStorage, 
+      This->parentStorage->rootPropertySetIndex, 
+      &rootProp);
+
+    if (rootProp.size.LowPart < 
+       (blocksRequired * This->parentStorage->bigBlockSize))
+    {
+      rootProp.size.LowPart += This->parentStorage->bigBlockSize;
+
+      BlockChainStream_SetSize(
+        This->parentStorage->smallBlockRootChain, 
+        rootProp.size);
+
+      StorageImpl_WriteProperty(
+        This->parentStorage, 
+        This->parentStorage->rootPropertySetIndex, 
+        &rootProp);
+    }
+  }
+
+  return blockIndex;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_ReadAt
+ *
+ * Reads a specified number of bytes from this chain at the specified offset.
+ * bytesRead may be NULL.
+ * Failure will be returned if the specified number of bytes has not been read. 
+ */
+BOOL SmallBlockChainStream_ReadAt(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER         offset,
+  ULONG                  size,
+  void*                  buffer,
+  ULONG*                 bytesRead)
+{
+  ULARGE_INTEGER offsetInBigBlockFile;
+  ULONG blockNoInSequence = 
+    offset.LowPart / This->parentStorage->smallBlockSize;
+
+  ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
+  ULONG bytesToReadInBuffer;
+  ULONG blockIndex;
+  ULONG bytesReadFromBigBlockFile;
+  BYTE* bufferWalker;
+
+  /*
+   * This should never happen on a small block file.
+   */
+  assert(offset.HighPart==0);
+
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+
+    blockNoInSequence--;
+  }
+
+  /*
+   * Start reading the buffer.
+   */
+  *bytesRead   = 0;
+  bufferWalker = (BYTE *)buffer;
+
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy from this small block.
+     */
+    bytesToReadInBuffer = 
+      MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
+
+    /*
+     * Calculate the offset of the small block in the small block file.
+     */
+    offsetInBigBlockFile.HighPart  = 0;
+    offsetInBigBlockFile.LowPart   = 
+      blockIndex * This->parentStorage->smallBlockSize;
+
+    offsetInBigBlockFile.LowPart  += offsetInBlock;
+
+    /*
+     * Read those bytes in the buffer from the small block file.
+     */
+    BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain,
+      offsetInBigBlockFile,
+      bytesToReadInBuffer,
+      bufferWalker,
+      &bytesReadFromBigBlockFile);
+
+    assert(bytesReadFromBigBlockFile == bytesToReadInBuffer);
+
+    /*
+     * Step to the next big block.
+     */
+    blockIndex    = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+    bufferWalker += bytesToReadInBuffer;
+    size         -= bytesToReadInBuffer;
+    *bytesRead   += bytesToReadInBuffer;
+    offsetInBlock = 0;  /* There is no offset on the next block */
+  }
+
+  return (size == 0);
+}
+
+/******************************************************************************
+ *       SmallBlockChainStream_WriteAt
+ *
+ * Writes the specified number of bytes to this chain at the specified offset.
+ * bytesWritten may be NULL.
+ * Will fail if not all specified number of bytes have been written.
+ */
+BOOL SmallBlockChainStream_WriteAt(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER offset,
+  ULONG          size,
+  const void*    buffer,
+  ULONG*         bytesWritten)
+{
+  ULARGE_INTEGER offsetInBigBlockFile;
+  ULONG blockNoInSequence = 
+    offset.LowPart / This->parentStorage->smallBlockSize;
+
+  ULONG offsetInBlock = offset.LowPart % This->parentStorage->smallBlockSize;
+  ULONG bytesToWriteInBuffer;
+  ULONG blockIndex;
+  ULONG bytesWrittenFromBigBlockFile;
+  BYTE* bufferWalker;
+  
+  /*
+   * This should never happen on a small block file.
+   */
+  assert(offset.HighPart==0);
+  
+  /*
+   * Find the first block in the stream that contains part of the buffer.
+   */
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+  
+  while ( (blockNoInSequence > 0) &&  (blockIndex != BLOCK_END_OF_CHAIN))
+  {
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+    
+    blockNoInSequence--;
+  }
+  
+  /*
+   * Start writing the buffer.
+   *
+   * Here, I'm casting away the constness on the buffer variable
+   * This is OK since we don't intend to modify that buffer.
+   */
+  *bytesWritten   = 0;
+  bufferWalker = (BYTE*)buffer;
+  while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) )
+  {
+    /*
+     * Calculate how many bytes we can copy to this small block.
+     */
+    bytesToWriteInBuffer = 
+      MIN(This->parentStorage->smallBlockSize - offsetInBlock, size);
+    
+    /*
+     * Calculate the offset of the small block in the small block file.
+     */
+    offsetInBigBlockFile.HighPart  = 0;
+    offsetInBigBlockFile.LowPart   = 
+      blockIndex * This->parentStorage->smallBlockSize;
+
+    offsetInBigBlockFile.LowPart  += offsetInBlock;
+    
+    /*
+     * Write those bytes in the buffer to the small block file.
+     */
+    BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain,
+      offsetInBigBlockFile,
+      bytesToWriteInBuffer,
+      bufferWalker,
+      &bytesWrittenFromBigBlockFile);
+    
+    assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer);
+    
+    /*
+     * Step to the next big block.
+     */
+    blockIndex    = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+    bufferWalker  += bytesToWriteInBuffer;
+    size          -= bytesToWriteInBuffer;
+    *bytesWritten += bytesToWriteInBuffer;
+    offsetInBlock  = 0;     /* There is no offset on the next block */
+  }
+  
+  return (size == 0);
+}
+
+/******************************************************************************
+ *       SmallBlockChainStream_Shrink
+ *
+ * Shrinks this chain in the small block depot. 
+ */
+BOOL SmallBlockChainStream_Shrink(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER newSize)
+{
+  ULONG blockIndex, extraBlock;
+  ULONG numBlocks;
+  ULONG count = 0;
+
+  numBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
+
+  if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
+    numBlocks++;
+
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Go to the new end of chain
+   */
+  while (count < numBlocks)
+  {
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+    count++;
+  }
+
+  /*
+   * If the count is 0, we have a special case, the head of the chain was
+   * just freed. 
+   */
+  if (count == 0)
+  {
+    StgProperty chainProp;
+
+    StorageImpl_ReadProperty(This->parentStorage, 
+			     This->ownerPropertyIndex,
+			     &chainProp);
+
+    chainProp.startingBlock = BLOCK_END_OF_CHAIN;
+
+    StorageImpl_WriteProperty(This->parentStorage,
+			      This->ownerPropertyIndex,
+			      &chainProp);
+
+    /*
+     * We start freeing the chain at the head block.
+     */
+    extraBlock = blockIndex;
+  }
+  else
+  {
+    /* Get the next block before marking the new end */
+    extraBlock = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+
+    /* Mark the new end of chain */
+    SmallBlockChainStream_SetNextBlockInChain(
+      This, 
+      blockIndex, 
+      BLOCK_END_OF_CHAIN);
+  }
+
+  /*
+   * Mark the extra blocks as free
+   */
+  while (extraBlock != BLOCK_END_OF_CHAIN)
+  {
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, extraBlock);
+    SmallBlockChainStream_FreeBlock(This, extraBlock);
+    extraBlock = blockIndex;
+  }
+
+  return TRUE;  
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_Enlarge
+ *
+ * Grows this chain in the small block depot.
+ */
+BOOL SmallBlockChainStream_Enlarge(
+  SmallBlockChainStream* This,
+  ULARGE_INTEGER newSize)
+{
+  ULONG blockIndex, currentBlock;
+  ULONG newNumBlocks;
+  ULONG oldNumBlocks = 0;
+
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  /*
+   * Empty chain
+   */
+  if (blockIndex == BLOCK_END_OF_CHAIN)
+  {
+
+    StgProperty chainProp;
+
+    StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex,
+                               &chainProp);
+
+    chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This);
+
+    StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex,
+                                &chainProp);
+
+    blockIndex = chainProp.startingBlock;
+    SmallBlockChainStream_SetNextBlockInChain(
+      This, 
+      blockIndex, 
+      BLOCK_END_OF_CHAIN);
+  }
+
+  currentBlock = blockIndex;
+
+  /*
+   * Figure out how many blocks are needed to contain this stream
+   */
+  newNumBlocks = newSize.LowPart / This->parentStorage->smallBlockSize;
+
+  if ((newSize.LowPart % This->parentStorage->smallBlockSize) != 0)
+    newNumBlocks++;
+
+  /*
+   * Go to the current end of chain
+   */
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    oldNumBlocks++;
+    currentBlock = blockIndex;
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, currentBlock);
+  }
+
+  /*
+   * Add new blocks to the chain
+   */
+  while (oldNumBlocks < newNumBlocks)
+  {
+    blockIndex = SmallBlockChainStream_GetNextFreeBlock(This);
+    SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex);
+
+    SmallBlockChainStream_SetNextBlockInChain(
+      This, 
+      blockIndex, 
+      BLOCK_END_OF_CHAIN);
+
+    currentBlock = blockIndex;
+    oldNumBlocks++;
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetCount
+ *
+ * Returns the number of blocks that comprises this chain.
+ * This is not the size of this chain as the last block may not be full!
+ */
+ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This)
+{
+  ULONG blockIndex;
+  ULONG count = 0;
+
+  blockIndex = SmallBlockChainStream_GetHeadOfChain(This);
+
+  while (blockIndex != BLOCK_END_OF_CHAIN)
+  {
+    count++;
+
+    blockIndex = SmallBlockChainStream_GetNextBlockInChain(This, blockIndex);
+  }
+
+  return count;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_SetSize
+ *
+ * Sets the size of this stream.
+ * The file will grow if we grow the chain.
+ *
+ * TODO: Free the actual blocks in the file when we shrink the chain.
+ *       Currently, the blocks are still in the file. So the file size
+ *       doesn't shrink even if we shrink streams. 
+ */
+BOOL SmallBlockChainStream_SetSize(
+                SmallBlockChainStream* This,
+                ULARGE_INTEGER    newSize)
+{
+  ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This);
+
+  if (newSize.LowPart == size.LowPart)
+    return TRUE;
+
+  if (newSize.LowPart < size.LowPart)
+  {
+    SmallBlockChainStream_Shrink(This, newSize);
+  }
+  else
+  {
+    SmallBlockChainStream_Enlarge(This, newSize);
+  }
+
+  return TRUE;
+}
+
+/******************************************************************************
+ *      SmallBlockChainStream_GetSize
+ *
+ * Returns the size of this chain.
+ */
+ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This)
+{
+  StgProperty chainProperty;
+
+  StorageImpl_ReadProperty(
+    This->parentStorage,
+    This->ownerPropertyIndex,
+    &chainProperty);
+
+  return chainProperty.size;
+}
+
+/******************************************************************************
+ *    StgCreateDocfile32  [OLE32.144]
+ */
+HRESULT WINAPI StgCreateDocfile(
+  LPCOLESTR pwcsName,
+  DWORD       grfMode,
+  DWORD       reserved,
+  IStorage  **ppstgOpen)
+{
+  StorageImpl* newStorage = 0;
+  HANDLE       hFile      = INVALID_HANDLE_VALUE;
+  HRESULT        hr         = S_OK;
+  DWORD          shareMode;
+  DWORD          accessMode;
+  DWORD          creationMode;
+  DWORD          fileAttributes;
+  WCHAR          tempFileName[MAX_PATH];
+  BOOL           switchRemoteToLocalFile = TRUE;
+
+  TRACE("(%s, %lx, %ld, %p)\n", 
+	debugstr_w(pwcsName), grfMode, 
+	reserved, ppstgOpen);
+
+  /*
+   * Validate the parameters
+   */
+  if (ppstgOpen == 0)
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * Generate a unique name.
+   */
+  if (pwcsName == 0)
+  {
+    WCHAR tempPath[MAX_PATH];
+    WCHAR prefix[] = { 'S', 'T', 'O', 0 };
+
+    switchRemoteToLocalFile = FALSE;
+
+    memset(tempPath, 0, sizeof(tempPath));
+    memset(tempFileName, 0, sizeof(tempFileName));
+
+    if ((GetTempPathW(MAX_PATH, tempPath)) == 0 )
+      tempPath[0] = '.';
+
+    if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0)
+      pwcsName = tempFileName;
+    else
+      return STG_E_INSUFFICIENTMEMORY;
+  }
+
+  /*
+   * Interpret the STGM value grfMode 
+   */
+  shareMode    = GetShareModeFromSTGM(grfMode);
+  accessMode   = GetAccessModeFromSTGM(grfMode);
+  creationMode = GetCreationModeFromSTGM(grfMode);
+
+  if (grfMode & STGM_DELETEONRELEASE)
+    fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE;
+  else
+    fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS;
+
+  if (grfMode & STGM_TRANSACTED)
+    FIXME("Transacted mode not implemented.\n");
+
+  /*
+   * Initialize the "out" parameter.
+   */
+  *ppstgOpen = 0;
+
+  hFile = CreateFileW(pwcsName,
+                        accessMode,
+                        shareMode,
+            NULL,
+                        creationMode,
+                        fileAttributes,
+            0);
+ 
+  if (hFile == INVALID_HANDLE_VALUE)
+  {
+    return E_FAIL;
+  }
+
+  /*
+   * Allocate and initialize the new IStorage32object.
+   */
+  newStorage = (StorageImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+ 
+  if (newStorage == 0)
+    return STG_E_INSUFFICIENTMEMORY;
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         hFile,
+         NULL,
+         grfMode,
+         TRUE,
+         TRUE);
+ 
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    return hr;
+  }
+
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+
+  return hr;
+}
+
+/******************************************************************************
+ *              StgOpenStorage32        [OLE32.148]
+ */
+HRESULT WINAPI StgOpenStorage(
+  const OLECHAR *pwcsName,
+  IStorage      *pstgPriority,
+  DWORD           grfMode,
+  SNB           snbExclude,
+  DWORD           reserved, 
+  IStorage      **ppstgOpen)
+{
+  StorageImpl* newStorage = 0;
+  HRESULT        hr = S_OK;
+  HANDLE       hFile = 0;
+  DWORD          shareMode;
+  DWORD          accessMode;
+
+  TRACE("(%s, %p, %lx, %p, %ld, %p)\n", 
+	debugstr_w(pwcsName), pstgPriority, grfMode,
+	snbExclude, reserved, ppstgOpen);
+
+  /*
+   * Perform a sanity check
+   */
+  if (( pwcsName == 0) || (ppstgOpen == 0) )
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * Interpret the STGM value grfMode
+   */
+  shareMode    = GetShareModeFromSTGM(grfMode);
+  accessMode   = GetAccessModeFromSTGM(grfMode);
+
+  /*
+   * Initialize the "out" parameter.
+   */
+  *ppstgOpen = 0;
+  
+  hFile = CreateFileW( pwcsName, 
+                       accessMode,
+                       shareMode,
+                       NULL,
+                       OPEN_EXISTING,
+                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+                       0);
+  
+  
+  if (hFile==INVALID_HANDLE_VALUE)
+  {
+    HRESULT hr = E_FAIL;
+    DWORD last_error = GetLastError();
+
+    switch (last_error)
+    {
+      case ERROR_FILE_NOT_FOUND:
+        hr = STG_E_FILENOTFOUND;
+        break;
+
+      case ERROR_PATH_NOT_FOUND:
+        hr = STG_E_PATHNOTFOUND;
+        break;
+
+      case ERROR_ACCESS_DENIED:
+      case ERROR_WRITE_PROTECT:
+        hr = STG_E_ACCESSDENIED;
+        break;
+
+      case ERROR_SHARING_VIOLATION:
+        hr = STG_E_SHAREVIOLATION;
+        break;
+
+      default:
+        hr = E_FAIL;
+    }
+
+    return hr;
+  }
+
+  /*
+   * Allocate and initialize the new IStorage32object.
+   */
+  newStorage = (StorageImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+  
+  if (newStorage == 0)
+    return STG_E_INSUFFICIENTMEMORY;
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         hFile,
+         NULL,
+         grfMode,
+         TRUE,
+         FALSE);
+  
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    return hr;
+  }
+  
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+  
+  return hr;
+}
+
+/******************************************************************************
+ *    StgCreateDocfileOnILockBytes    [OLE32.145]
+ */
+HRESULT WINAPI StgCreateDocfileOnILockBytes(
+      ILockBytes *plkbyt,
+      DWORD grfMode,
+      DWORD reserved,
+      IStorage** ppstgOpen)
+{
+  StorageImpl*   newStorage = 0;
+  HRESULT        hr         = S_OK;
+
+  /*
+   * Validate the parameters
+   */
+  if ((ppstgOpen == 0) || (plkbyt == 0))
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Allocate and initialize the new IStorage object.
+   */
+  newStorage = (StorageImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+
+  if (newStorage == 0)
+    return STG_E_INSUFFICIENTMEMORY;
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         0,
+         plkbyt,
+         grfMode,
+         FALSE,
+         TRUE);
+
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    return hr;
+  }
+
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+
+  return hr;  
+}
+
+/******************************************************************************
+ *    StgOpenStorageOnILockBytes    [OLE32.149]
+ */
+HRESULT WINAPI StgOpenStorageOnILockBytes(
+      ILockBytes *plkbyt,
+      IStorage *pstgPriority,
+      DWORD grfMode,
+      SNB snbExclude,
+      DWORD reserved,
+      IStorage **ppstgOpen)
+{
+  StorageImpl* newStorage = 0;
+  HRESULT        hr = S_OK;
+
+  /*
+   * Perform a sanity check
+   */
+  if ((plkbyt == 0) || (ppstgOpen == 0))
+    return STG_E_INVALIDPOINTER;
+
+  /*
+   * Validate the STGM flags
+   */
+  if ( FAILED( validateSTGM(grfMode) ))
+    return STG_E_INVALIDFLAG;
+
+  /*
+   * Initialize the "out" parameter.
+   */
+  *ppstgOpen = 0;
+
+  /*
+   * Allocate and initialize the new IStorage object.
+   */
+  newStorage = (StorageImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl));
+ 
+  if (newStorage == 0)
+    return STG_E_INSUFFICIENTMEMORY;
+
+  hr = StorageImpl_Construct(
+         newStorage,
+         0,
+         plkbyt,
+         grfMode,
+         FALSE,
+         FALSE);
+
+  if (FAILED(hr))
+  {
+    HeapFree(GetProcessHeap(), 0, newStorage);
+    return hr;
+  }
+
+  /*
+   * Get an "out" pointer for the caller.
+   */
+  hr = StorageBaseImpl_QueryInterface(
+         (IStorage*)newStorage,
+         (REFIID)&IID_IStorage,
+         (void**)ppstgOpen);
+
+  return hr;
+}
+
+/******************************************************************************
+ *              StgIsStorageILockBytes        [OLE32.147]
+ *
+ * Determines if the ILockBytes contains a storage object.
+ */
+HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt)
+{
+  BYTE sig[8];
+  ULARGE_INTEGER offset;
+
+  offset.HighPart = 0;
+  offset.LowPart  = 0;
+
+  ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL);
+
+  if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0)
+    return S_OK;
+
+  return S_FALSE;
+}
+
+/******************************************************************************
+ *              WriteClassStg32        [OLE32.158]
+ *
+ * This method will store the specified CLSID in the specified storage object
+ */
+HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid)
+{
+  HRESULT hRes;
+
+  assert(pStg != 0);
+
+  hRes = IStorage_SetClass(pStg, rclsid);
+
+  return hRes;
+}
+
+/*******************************************************************************************
+ *    ReadClassStg
+ *
+ * This method reads the CLSID previously written to a storage object with the WriteClassStg.
+ */
+HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){
+
+    STATSTG pstatstg;
+    HRESULT hRes;
+    
+    TRACE("()\n");
+
+    if(pclsid==NULL)
+        return E_POINTER;
+   /*
+    * read a STATSTG structure (contains the clsid) from the storage
+    */
+    hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT);
+
+    if(SUCCEEDED(hRes))
+        *pclsid=pstatstg.clsid;
+
+    return hRes;
+}
+
+/*************************************************************************************
+ *    OleLoadFromStream
+ *
+ * This function loads an object from stream
+ */
+HRESULT  WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj)
+{
+    CLSID clsid;
+    HRESULT res;
+
+/* For this function to work.  All registry keys related to Interface must be in            */
+/* Installed in the wine registry (eg. Search for IFileMoniker in the windows registry,     */
+/* copy the missing CLSID keys (and all contents) to wine registry). Implement              */
+/* the OLE32_DllGetClassObject (a big switch for all interface in OLE32.dll to allocate the */
+/* actual interface )                                                                       */
+    FIXME("(),stub!\n");
+
+    res=ReadClassStm(pStm,&clsid);
+
+    if (SUCCEEDED(res)){
+        /* For this to work properly iidInterface should be IUnknown, need to Query */
+        /* for IPersitStream, if successful, query for iidInterface */
+
+        res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
+
+        if (SUCCEEDED(res))
+
+            res=IPersistStream_Load((IPersistStream*)ppvObj,pStm);
+    }
+
+    return res;
+}
+
+/************************************************************************************************
+ *    OleSaveToStream
+ *
+ * This function saves an object with the IPersistStream interface on it to the specified stream
+ */
+HRESULT  WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm)
+{
+
+    CLSID clsid;
+    HRESULT res;
+    
+    TRACE("(%p,%p)\n",pPStm,pStm);
+
+    res=IPersistStream_GetClassID(pPStm,&clsid);
+
+    if (SUCCEEDED(res)){
+        
+        res=WriteClassStm(pStm,&clsid);
+
+        if (SUCCEEDED(res))
+
+            res=IPersistStream_Save(pPStm,pStm,TRUE);
+    }
+
+    TRACE("Finished Save\n");
+    return res;
+}
+
+/****************************************************************************
+ * This method validate a STGM parameter that can contain the values below
+ *
+ * STGM_DIRECT               0x00000000
+ * STGM_TRANSACTED           0x00010000
+ * STGM_SIMPLE               0x08000000
+ * 
+ * STGM_READ                 0x00000000
+ * STGM_WRITE                0x00000001
+ * STGM_READWRITE            0x00000002
+ * 
+ * STGM_SHARE_DENY_NONE      0x00000040
+ * STGM_SHARE_DENY_READ      0x00000030
+ * STGM_SHARE_DENY_WRITE     0x00000020
+ * STGM_SHARE_EXCLUSIVE      0x00000010
+ * 
+ * STGM_PRIORITY             0x00040000
+ * STGM_DELETEONRELEASE      0x04000000
+ *
+ * STGM_CREATE               0x00001000
+ * STGM_CONVERT              0x00020000
+ * STGM_FAILIFTHERE          0x00000000
+ *
+ * STGM_NOSCRATCH            0x00100000
+ * STGM_NOSNAPSHOT           0x00200000
+ */
+static HRESULT validateSTGM(DWORD stgm)
+{
+  BOOL bSTGM_TRANSACTED       = ((stgm & STGM_TRANSACTED) == STGM_TRANSACTED);
+  BOOL bSTGM_SIMPLE           = ((stgm & STGM_SIMPLE) == STGM_SIMPLE);
+  BOOL bSTGM_DIRECT           = ! (bSTGM_TRANSACTED || bSTGM_SIMPLE);
+   
+  BOOL bSTGM_WRITE            = ((stgm & STGM_WRITE) == STGM_WRITE);
+  BOOL bSTGM_READWRITE        = ((stgm & STGM_READWRITE) == STGM_READWRITE);
+  BOOL bSTGM_READ             = ! (bSTGM_WRITE || bSTGM_READWRITE);
+   
+  BOOL bSTGM_SHARE_DENY_NONE  =
+                     ((stgm & STGM_SHARE_DENY_NONE)  == STGM_SHARE_DENY_NONE);
+
+  BOOL bSTGM_SHARE_DENY_READ  =
+                     ((stgm & STGM_SHARE_DENY_READ)  == STGM_SHARE_DENY_READ);
+
+  BOOL bSTGM_SHARE_DENY_WRITE =
+                     ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
+
+  BOOL bSTGM_SHARE_EXCLUSIVE  =
+                     ((stgm & STGM_SHARE_EXCLUSIVE)  == STGM_SHARE_EXCLUSIVE);
+
+  BOOL bSTGM_CREATE           = ((stgm & STGM_CREATE) == STGM_CREATE);
+  BOOL bSTGM_CONVERT          = ((stgm & STGM_CONVERT) == STGM_CONVERT);
+   
+  BOOL bSTGM_NOSCRATCH        = ((stgm & STGM_NOSCRATCH) == STGM_NOSCRATCH);
+  BOOL bSTGM_NOSNAPSHOT       = ((stgm & STGM_NOSNAPSHOT) == STGM_NOSNAPSHOT);
+
+  /* 
+   * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE
+   */
+  if ( ! bSTGM_DIRECT )
+    if( bSTGM_TRANSACTED && bSTGM_SIMPLE )
+      return E_FAIL;
+
+  /* 
+   * STGM_WRITE |  STGM_READWRITE | STGM_READ
+   */
+  if ( ! bSTGM_READ )
+    if( bSTGM_WRITE && bSTGM_READWRITE )
+      return E_FAIL;
+
+  /*
+   * STGM_SHARE_DENY_NONE | others 
+   * (I assume here that DENY_READ implies DENY_WRITE)
+   */
+  if ( bSTGM_SHARE_DENY_NONE )
+    if ( bSTGM_SHARE_DENY_READ ||
+         bSTGM_SHARE_DENY_WRITE || 
+         bSTGM_SHARE_EXCLUSIVE) 
+      return E_FAIL;
+
+  /*
+   * STGM_CREATE | STGM_CONVERT
+   * if both are false, STGM_FAILIFTHERE is set to TRUE
+   */
+  if ( bSTGM_CREATE && bSTGM_CONVERT )
+    return E_FAIL;
+
+  /*
+   * STGM_NOSCRATCH requires STGM_TRANSACTED
+   */
+  if ( bSTGM_NOSCRATCH && ! bSTGM_TRANSACTED )
+    return E_FAIL;
+  
+  /*
+   * STGM_NOSNAPSHOT requires STGM_TRANSACTED and 
+   * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE`
+   */
+  if (bSTGM_NOSNAPSHOT)
+  {
+    if ( ! ( bSTGM_TRANSACTED && 
+           !(bSTGM_SHARE_EXCLUSIVE || bSTGM_SHARE_DENY_WRITE)) )
+    return E_FAIL;
+  }
+
+  return S_OK;
+}
+
+/****************************************************************************
+ *      GetShareModeFromSTGM
+ *
+ * This method will return a share mode flag from a STGM value.
+ * The STGM value is assumed valid. 
+ */
+static DWORD GetShareModeFromSTGM(DWORD stgm)
+{
+  DWORD dwShareMode = 0;
+  BOOL bSTGM_SHARE_DENY_NONE  =
+                     ((stgm & STGM_SHARE_DENY_NONE)  == STGM_SHARE_DENY_NONE);
+
+  BOOL bSTGM_SHARE_DENY_READ  =
+                     ((stgm & STGM_SHARE_DENY_READ)  == STGM_SHARE_DENY_READ);
+
+  BOOL bSTGM_SHARE_DENY_WRITE =
+                     ((stgm & STGM_SHARE_DENY_WRITE) == STGM_SHARE_DENY_WRITE);
+
+  BOOL bSTGM_SHARE_EXCLUSIVE  =
+                     ((stgm & STGM_SHARE_EXCLUSIVE)  == STGM_SHARE_EXCLUSIVE);
+
+  if ((bSTGM_SHARE_EXCLUSIVE) || (bSTGM_SHARE_DENY_READ))
+    dwShareMode = 0;
+
+  if (bSTGM_SHARE_DENY_NONE)
+    dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+  if (bSTGM_SHARE_DENY_WRITE)
+    dwShareMode = FILE_SHARE_READ;
+
+  return dwShareMode;
+}
+
+/****************************************************************************
+ *      GetAccessModeFromSTGM
+ *
+ * This method will return an access mode flag from a STGM value.
+ * The STGM value is assumed valid.
+ */
+static DWORD GetAccessModeFromSTGM(DWORD stgm)
+{
+  DWORD dwDesiredAccess = GENERIC_READ;
+  BOOL bSTGM_WRITE     = ((stgm & STGM_WRITE) == STGM_WRITE);
+  BOOL bSTGM_READWRITE = ((stgm & STGM_READWRITE) == STGM_READWRITE);
+  BOOL bSTGM_READ      = ! (bSTGM_WRITE || bSTGM_READWRITE);
+
+  if (bSTGM_READ)
+    dwDesiredAccess = GENERIC_READ;
+
+  if (bSTGM_WRITE)
+    dwDesiredAccess |= GENERIC_WRITE;
+
+  if (bSTGM_READWRITE)
+    dwDesiredAccess = GENERIC_READ | GENERIC_WRITE;
+
+  return dwDesiredAccess;
+}
+
+/****************************************************************************
+ *      GetCreationModeFromSTGM
+ *
+ * This method will return a creation mode flag from a STGM value.
+ * The STGM value is assumed valid.
+ */
+static DWORD GetCreationModeFromSTGM(DWORD stgm)
+{
+  if ( stgm & STGM_CREATE)
+    return CREATE_ALWAYS;
+  if (stgm & STGM_CONVERT) {
+    FIXME("STGM_CONVERT not implemented!\n");
+    return CREATE_NEW;
+  }
+  /* All other cases */
+  if (stgm & ~ (STGM_CREATE|STGM_CONVERT))
+  	FIXME("unhandled storage mode : 0x%08lx\n",stgm & ~ (STGM_CREATE|STGM_CONVERT));
+  return CREATE_NEW;
+}
+
+BOOL OLECONVERT_IsStorageLink(LPSTORAGE pStorage)
+{
+    STATSTG stat;
+
+    IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
+    
+    return IsEqualCLSID(&IID_StdOleLink, &stat.clsid);
+}
+
+/*************************************************************************
+ * OLECONVERT_LoadOLE10 [Internal] 
+ *
+ * Loads the OLE10 STREAM to memory 
+ *
+ * PARAMS
+ *     pOleStream   [I] The OLESTREAM
+ *     pData        [I] Data Structure for the OLESTREAM Data
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  CONVERT10_E_OLESTREAM_GET for invalid Get
+ *               CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *     
+ *     Memory allocated for pData must be freed by the caller
+ */
+HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData)
+{
+    DWORD dwSize;
+    pData->pData = NULL;
+    pData->pLinkExtraInfo = NULL;
+    pData->strLinkFileName = NULL;
+
+    /* Get the OleID */
+    dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)&(pData->dwOleID), sizeof(pData->dwOleID));
+    if(dwSize != sizeof(pData->dwOleID))
+    {
+         return CONVERT10_E_OLESTREAM_GET;
+    }
+    else if(pData->dwOleID != OLESTREAM_ID)
+    {
+        return CONVERT10_E_OLESTREAM_FMT;
+    }
+
+    /* Get the TypeID...more info needed for this field */
+    dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)&(pData->dwObjectTypeID), sizeof(pData->dwObjectTypeID));
+
+    if(dwSize != sizeof(pData->dwObjectTypeID))
+    {
+        return CONVERT10_E_OLESTREAM_GET;
+    }
+    if(pData->dwObjectTypeID != 0)
+    {
+        if(pData->dwObjectTypeID != OLECONVERT_LINK_TYPE 
+            && pData->dwObjectTypeID != OLECONVERT_EMBEDDED_TYPE
+            && pData->dwObjectTypeID != OLECONVERT_PRESENTATION_DATA_TYPE)
+        {
+            FIXME("Unknown ObjectTypeID: %lx\n", pData->dwObjectTypeID);
+        }
+
+        /* Get the lenght of the OleTypeName */
+        dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
+        if(dwSize != sizeof(pData->dwOleTypeNameLength))
+        {
+            return CONVERT10_E_OLESTREAM_GET;
+        }
+        if(pData->dwOleTypeNameLength > 0)
+        {
+            /* Get the OleTypeName */
+            dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)pData->strOleTypeName, pData->dwOleTypeNameLength);
+            if(dwSize != pData->dwOleTypeNameLength)
+            {
+                return CONVERT10_E_OLESTREAM_GET;
+            }
+        }
+        if(pData->dwObjectTypeID == OLECONVERT_LINK_TYPE)
+        {
+            dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR) &(pData->dwLinkFileNameLength), sizeof(pData->dwLinkFileNameLength));
+            if(dwSize != sizeof(pData->dwLinkFileNameLength))
+            {
+                return CONVERT10_E_OLESTREAM_GET;
+            }
+
+            if(pData->dwLinkFileNameLength > 0)
+            {
+                pData->strLinkFileName = (BYTE *)malloc(pData->dwLinkFileNameLength);
+                if(pData->strLinkFileName == NULL)
+                {
+                    return E_OUTOFMEMORY;
+                }
+                dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR) pData->strLinkFileName, pData->dwLinkFileNameLength);
+                if(dwSize != pData->dwLinkFileNameLength)
+                {
+                    return CONVERT10_E_OLESTREAM_GET;
+                }
+            }
+            dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR) &(pData->dwLinkExtraInfoLength), sizeof(pData->dwLinkExtraInfoLength));
+            if(dwSize != sizeof(pData->dwLinkExtraInfoLength))
+            {
+                return CONVERT10_E_OLESTREAM_GET;
+            }
+          
+            if(pData->dwLinkExtraInfoLength > 0)
+            {
+                pData->pLinkExtraInfo = (BYTE *)malloc(pData->dwLinkExtraInfoLength);
+                if(pData->pLinkExtraInfo == NULL)
+                {
+                    return E_OUTOFMEMORY;
+                }
+                dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR) pData->pLinkExtraInfo, pData->dwLinkExtraInfoLength);
+                if(dwSize != pData->dwLinkExtraInfoLength)
+                {
+                    return CONVERT10_E_OLESTREAM_GET;
+                }
+            }
+        }
+
+        /* Get the Width of the Metafile */
+        dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
+        if(dwSize != sizeof(pData->dwMetaFileWidth))
+        {
+            return CONVERT10_E_OLESTREAM_GET;
+        }
+
+        /* Get the Height of the Metafile */
+        dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
+        if(dwSize != sizeof(pData->dwMetaFileHeight))
+        {
+            return CONVERT10_E_OLESTREAM_GET;
+        }
+
+        /* Get the Length of the Data */
+        dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)&(pData->dwDataLength), sizeof(pData->dwDataLength));
+        if(dwSize != sizeof(pData->dwDataLength))
+        {
+            return CONVERT10_E_OLESTREAM_GET;
+        }
+        if(pData->dwDataLength > 0)
+        {
+            pData->pData = (BYTE *)malloc(pData->dwDataLength);
+            if(pData->pData == NULL)
+            {
+                return E_OUTOFMEMORY;
+            }
+            /* Get Data (ex. IStorage, Metafile, or BMP) */
+            dwSize = pOleStream->lpstbl->Get(pOleStream, (LPSTR)pData->pData, pData->dwDataLength);
+            if(dwSize != pData->dwDataLength)
+            {
+                return CONVERT10_E_OLESTREAM_GET;
+            }
+        }
+    }
+    return S_OK;
+}
+
+
+/*************************************************************************
+ * OLECONVERT_SaveOLE10 [Internal] 
+ *
+ * Saves the OLE10 STREAM From memory 
+ *
+ * PARAMS
+ *     pData        [I] Data Structure for the OLESTREAM Data
+ *     pOleStream   [I] The OLESTREAM to save
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *     
+ */
+HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream)
+{
+    DWORD dwSize;
+    HRESULT hRes = S_OK;
+
+
+   /* Set the OleID */
+    dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwOleID), sizeof(pData->dwOleID));
+    if(dwSize != sizeof(pData->dwOleID))
+    {
+        return CONVERT10_E_OLESTREAM_PUT;
+    }
+
+    /* Set the TypeID */
+    dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwObjectTypeID), sizeof(pData->dwObjectTypeID));
+    if(dwSize != sizeof(pData->dwObjectTypeID))
+    {
+        return CONVERT10_E_OLESTREAM_PUT;
+    }
+
+    if(pData->dwOleID == OLESTREAM_ID && pData->dwObjectTypeID != 0 && hRes == S_OK)
+    {
+        /* Set the Length of the OleTypeName */
+        dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength));
+        if(dwSize != sizeof(pData->dwOleTypeNameLength))
+        {
+            return CONVERT10_E_OLESTREAM_PUT;
+        }
+
+        if(pData->dwOleTypeNameLength > 0)
+        {
+            /* Set the OleTypeName */
+            dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)  pData->strOleTypeName, pData->dwOleTypeNameLength);
+            if(dwSize != pData->dwOleTypeNameLength)
+            {
+                return CONVERT10_E_OLESTREAM_PUT;
+            }
+        }
+
+        if(pData->dwObjectTypeID == OLECONVERT_LINK_TYPE)
+        {
+            dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR) &(pData->dwLinkFileNameLength), sizeof(pData->dwLinkFileNameLength));
+            if(dwSize != sizeof(pData->dwLinkFileNameLength))
+            {
+                return CONVERT10_E_OLESTREAM_GET;
+            }
+
+            if(pData->dwLinkFileNameLength > 0)
+            {
+                dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR) pData->strLinkFileName, pData->dwLinkFileNameLength);
+                if(dwSize != pData->dwLinkFileNameLength)
+                {
+                    return CONVERT10_E_OLESTREAM_GET;
+                }
+            }
+
+            dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR) &(pData->dwLinkExtraInfoLength), sizeof(pData->dwLinkExtraInfoLength));
+            if(dwSize != sizeof(pData->dwLinkExtraInfoLength))
+            {
+                return CONVERT10_E_OLESTREAM_GET;
+            }
+          
+            if(pData->dwLinkExtraInfoLength > 0)
+            {
+                dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR) pData->pLinkExtraInfo, pData->dwLinkExtraInfoLength);
+                if(dwSize != pData->dwLinkExtraInfoLength)
+                {
+                    return CONVERT10_E_OLESTREAM_GET;
+                }
+            }
+        }
+
+        /* Set the width of the Metafile */
+        dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth));
+        if(dwSize != sizeof(pData->dwMetaFileWidth))
+        {
+            return CONVERT10_E_OLESTREAM_PUT;
+        }
+
+        /* Set the height of the Metafile */
+        dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight));
+        if(dwSize != sizeof(pData->dwMetaFileHeight))
+        {
+            return CONVERT10_E_OLESTREAM_PUT;
+        }
+
+        /* Set the lenght of the Data */
+        dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)&(pData->dwDataLength), sizeof(pData->dwDataLength));
+        if(dwSize != sizeof(pData->dwDataLength))
+        {
+            return CONVERT10_E_OLESTREAM_PUT;
+        }
+
+        if(pData->dwDataLength > 0)
+        {
+            /* Set the Data (eg. IStorage, Metafile, Bitmap) */
+            dwSize = pOleStream->lpstbl->Put(pOleStream, (LPSTR)  pData->pData, pData->dwDataLength);
+            if(dwSize != pData->dwDataLength)
+            {
+                return CONVERT10_E_OLESTREAM_PUT;
+            }
+        }
+    }
+    return S_OK;
+}
+
+/*************************************************************************
+ * OLECONVERT_GetOLE20FromOLE10[Internal] 
+ *
+ * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk,
+ * opens it, and copies the content to the dest IStorage for 
+ * OleConvertOLESTREAMToIStorage
+ * 
+ *
+ * PARAMS
+ *     pDestStorage  [I] The IStorage to copy the data to
+ *     pBuffer       [I] Buffer that contains the IStorage from the OLESTREAM
+ *     nBufferLength [I] The size of the buffer
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     
+ *     
+ */
+void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength)
+{
+    HRESULT hRes;
+    HANDLE hFile;
+    IStorage *pTempStorage;
+    DWORD dwNumOfBytesWritten;
+    WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
+    WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
+
+    /* Create a temp File */
+    GetTempPathW(MAX_PATH, wstrTempDir);
+    GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
+    hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+    if(hFile != INVALID_HANDLE_VALUE)
+    {
+        /* Write IStorage Data to File */
+        WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL);
+        CloseHandle(hFile);
+
+        /* Open and copy temp storage to the Dest Storage */
+        hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage);
+        if(hRes == S_OK)
+        {
+            hRes = StorageImpl_CopyTo(pTempStorage, NULL,NULL,NULL, pDestStorage);
+            StorageBaseImpl_Release(pTempStorage);
+        }
+        DeleteFileW(wstrTempFile);
+    }
+}
+
+
+/*************************************************************************
+ * OLECONVERT_WriteOLE20ToBuffer [Internal] 
+ *
+ * Saves the OLE10 STREAM From memory 
+ *
+ * PARAMS
+ *     pStorage  [I] The Src IStorage to copy
+ *     pData     [I] The Dest Memory to write to.
+ *
+ * RETURNS
+ *     The size in bytes allocated for pData
+ *
+ * NOTES
+ *     Memory allocated for pData must be freed by the caller
+ *
+ *     Used by OleConvertIStorageToOLESTREAM only.
+ *     
+ */
+DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData)
+{
+    HANDLE hFile;
+    HRESULT hRes;
+    DWORD nDataLength = 0;
+    IStorage *pTempStorage;
+    WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH];
+    WCHAR wstrPrefix[] = {'s', 'i', 's', 0};
+
+    *pData = NULL;
+    
+    /* Create temp Storage */
+    GetTempPathW(MAX_PATH, wstrTempDir);
+    GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile);
+    hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, NULL, &pTempStorage);
+
+    if(hRes == S_OK)
+    {
+        /* Copy Src Storage to the Temp Storage */
+        StorageImpl_CopyTo(pStorage, NULL,NULL,NULL, pTempStorage);
+        StorageBaseImpl_Release(pTempStorage);
+
+        /* Open Temp Storage as a file and copy to memory */
+        hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+        if(hFile != INVALID_HANDLE_VALUE)
+        {
+            nDataLength = GetFileSize(hFile, NULL);
+            *pData = (BYTE *) malloc(nDataLength);
+            ReadFile(hFile, *pData, nDataLength, &nDataLength, 0);
+            CloseHandle(hFile);
+        }
+        DeleteFileW(wstrTempFile);
+    }
+    return nDataLength;
+}
+
+/*************************************************************************
+ * OLECONVERT_CreateEmbeddedOleStream [Internal] 
+ *
+ * Creates the "\001OLE" stream in the IStorage if neccessary.
+ *
+ * PARAMS
+ *     pStorage     [I] Dest storage to create the stream in
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     This stream is still unknown, MS Word seems to have extra data
+ *     but since the data is stored in the OLESTREAM there should be
+ *     no need to recreate the stream.  If the stream is manually 
+ *     deleted it will create it with this default data.
+ *     
+ */
+void OLECONVERT_CreateEmbeddedOleStream(LPSTORAGE pStorage)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
+    BYTE pOleStreamHeader [] = 
+    {
+        0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+        0x00, 0x00, 0x00, 0x00 
+    };
+    
+    /* Create stream if not present */
+    hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
+        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+
+    if(hRes == S_OK)
+    {
+        /* Write default Data */
+        hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL);
+        IStream_Release(pStream);
+    }
+}
+
+/*************************************************************************
+ * OLECONVERT_CreateLinkOleStream [Internal] 
+ *
+ * Creates the "\001OLE" stream in the IStorage if neccessary.
+ *
+ * PARAMS
+ *     pStorage     [I] Dest storage to create the stream in
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     This stream is still unknown, MS Word seems to have extra data
+ *     but since the data is stored in the OLESTREAM there should be
+ *     no need to recreate the stream.  If the stream is manually 
+ *     deleted it will create it with this default data.
+ *     
+ */
+HRESULT OLECONVERT_CreateLinkOleStream(LPSTORAGE pStorage, LPCSTR strProgID, LPCSTR strFileName, BYTE *pItemData, DWORD dwItemDataLength)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
+    OLECONVERT_ISTORAGE_OLE OleStreamHeader;
+    LPMONIKER pFileMoniker=NULL;
+    LPMONIKER pItemMoniker=NULL;
+    LPMONIKER pCompMoniker=NULL;
+    LPMONIKER pDestMoniker=NULL;
+
+
+    BYTE pUnknown7 [] = 
+    {
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+        0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
+    };
+
+    OleStreamHeader.dwOLEHEADER_ID = 0x02000001;
+    OleStreamHeader.dwUnknown1 = 0x01;
+    OleStreamHeader.dwUnknown2 = 0x01;
+    OleStreamHeader.dwUnknown3 = 0x00;
+    OleStreamHeader.dwUnknown4 = 0x00;
+    OleStreamHeader.dwUnknown5 = 0x00;
+    OleStreamHeader.dwUnknown6 = 0xFFFF;
+    hRes = CLSIDFromProgID16(strProgID, &(OleStreamHeader.clsidObject));
+    memcpy(OleStreamHeader.dwUnknown7, pUnknown7, sizeof(pUnknown7));
+
+    if(hRes != S_OK)
+    {
+        return REGDB_E_CLASSNOTREG;
+    }
+
+    if(strFileName != NULL)
+    {
+        WCHAR wstrFileName[MAX_PATH];
+        MultiByteToWideChar(CP_ACP, 0, strFileName, -1, wstrFileName, MAX_PATH); 
+        hRes = CreateFileMoniker(wstrFileName, &pFileMoniker);
+    }
+    if(pItemData != NULL)
+    {
+
+        WCHAR wstrDelim[] = {'!', 0};
+        WCHAR *wstrItem;
+
+        wstrItem = (LPWSTR) malloc(dwItemDataLength * sizeof(WCHAR));
+
+        MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pItemData, -1, wstrItem, dwItemDataLength); 
+        hRes = CreateItemMoniker(wstrDelim, wstrItem, &pItemMoniker);
+
+        free(wstrItem);
+    }
+
+    if(pItemMoniker != NULL && pFileMoniker != NULL)
+    {
+        hRes = CreateGenericComposite(pFileMoniker, pItemMoniker, &pCompMoniker);
+    }
+
+    if(hRes == S_OK)
+    {
+
+        if(pCompMoniker != NULL)
+        {
+            pDestMoniker = pCompMoniker;
+        }
+        else if(pFileMoniker != NULL)
+        {
+            pDestMoniker = pFileMoniker;
+        }
+        else if(pItemMoniker != NULL)
+        {
+            pDestMoniker = pItemMoniker;
+        }
+
+
+        if(pDestMoniker != NULL)
+        {
+            ULARGE_INTEGER liFileMonikerSize;
+            IMoniker_GetClassID(pDestMoniker, &(OleStreamHeader.clsidMonikerTypeID));
+            IMoniker_GetSizeMax(pDestMoniker, &liFileMonikerSize);
+            OleStreamHeader.dwObjectCLSIDOffset = liFileMonikerSize.LowPart + sizeof(OleStreamHeader.dwUnknown6) + sizeof(OleStreamHeader.clsidMonikerTypeID);
+        }
+        
+
+        /* Create stream  (shouldn't be present)*/
+        hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
+            STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+
+        if(hRes == S_OK)
+        {
+            /* Write default Data */
+            IStream_Write(pStream, &(OleStreamHeader.dwOLEHEADER_ID), sizeof(OleStreamHeader.dwOLEHEADER_ID), NULL);
+            IStream_Write(pStream, &(OleStreamHeader.dwUnknown1), sizeof(OleStreamHeader.dwUnknown1), NULL);
+            IStream_Write(pStream, &(OleStreamHeader.dwUnknown2), sizeof(OleStreamHeader.dwUnknown2), NULL);
+            IStream_Write(pStream, &(OleStreamHeader.dwUnknown3), sizeof(OleStreamHeader.dwUnknown3), NULL);
+            IStream_Write(pStream, &(OleStreamHeader.dwUnknown4), sizeof(OleStreamHeader.dwUnknown4), NULL);
+            IStream_Write(pStream, &(OleStreamHeader.dwUnknown5), sizeof(OleStreamHeader.dwUnknown5), NULL);
+            IStream_Write(pStream, &(OleStreamHeader.dwObjectCLSIDOffset), sizeof(OleStreamHeader.dwObjectCLSIDOffset), NULL);
+            /* Should call OleSaveToStream */
+            WriteClassStm(pStream, &(OleStreamHeader.clsidMonikerTypeID));
+            if(pDestMoniker != NULL)
+            {
+                IMoniker_Save(pDestMoniker, pStream, FALSE);
+            }
+            IStream_Write(pStream, &(OleStreamHeader.dwUnknown6), sizeof(OleStreamHeader.dwUnknown6), NULL);
+            WriteClassStm(pStream, &(OleStreamHeader.clsidObject));
+            IStream_Write(pStream, OleStreamHeader.dwUnknown7, sizeof(OleStreamHeader.dwUnknown7), NULL);
+            IStream_Release(pStream);
+        }
+    }
+    if(pFileMoniker != NULL)
+    {
+        IMoniker_Release(pFileMoniker);
+    }
+    if(pItemMoniker != NULL)
+    {
+        IMoniker_Release(pItemMoniker);
+    }
+    if(pCompMoniker != NULL)
+    {
+        IMoniker_Release(pCompMoniker);
+    }
+    return S_OK;
+}
+
+/*************************************************************************
+ * OLECONVERT_CreateCompObjStream [Internal] 
+ *
+ * Creates a "\001CompObj" is the destination IStorage if necessary.
+ *
+ * PARAMS
+ *     pStorage       [I] The dest IStorage to create the CompObj Stream 
+ *                        if necessary.
+ *     strOleTypeName [I] The ProgID
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     The stream data is stored in the OLESTREAM and there should be
+ *     no need to recreate the stream.  If the stream is manually 
+ *     deleted it will attempt to create it by querying the registry.
+ *
+ *     
+ */
+HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName)
+{
+    IStream *pStream;
+    HRESULT hStorageRes, hRes = S_OK;
+    OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj;
+    WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
+
+    BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
+    BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71};
+
+    /* Initialize the CompObj structure */
+    memset(&IStorageCompObj, 0, sizeof(IStorageCompObj));
+    memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1));
+    memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2));
+
+
+    /*  Create a CompObj stream if it doesn't exist */
+    hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName, 
+        STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+    if(hStorageRes == S_OK)
+    {
+        /* copy the OleTypeName to the compobj struct */
+        IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1;
+        strcpy(IStorageCompObj.strOleTypeName, strOleTypeName);
+
+        /* copy the OleTypeName to the compobj struct */
+        /* Note: in the test made, these where Identical      */
+        IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1;
+        strcpy(IStorageCompObj.strProgIDName, strOleTypeName);
+
+        /* Get the CLSID */
+        hRes = CLSIDFromProgID16(IStorageCompObj.strProgIDName, &(IStorageCompObj.clsid));
+
+        if(hRes != S_OK)
+        {
+            hRes = REGDB_E_CLASSNOTREG;
+        }
+        else
+        {
+            HKEY hKey;
+            LONG hErr;
+            /* Get the CLSID Default Name from the Registry */
+            hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey); 
+            if(hErr == ERROR_SUCCESS)
+            {
+                char strTemp[OLESTREAM_MAX_STR_LEN];
+                IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN;
+                hErr = RegQueryValueA(hKey, NULL, strTemp, (LPLONG)&(IStorageCompObj.dwCLSIDNameLength));
+                if(hErr == ERROR_SUCCESS)
+                {
+                    strcpy(IStorageCompObj.strCLSIDName, strTemp);
+                }
+                RegCloseKey(hKey);
+            }
+            if(hErr != ERROR_SUCCESS)
+            {
+                hRes = REGDB_E_CLASSNOTREG;
+            }
+        }
+
+        if(hRes == S_OK )
+        {
+            /* Write CompObj Structure to stream */
+            hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL);
+            WriteClassStm(pStream,&(IStorageCompObj.clsid));
+            hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL);
+            if(IStorageCompObj.dwCLSIDNameLength > 0)
+            {
+                hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL);
+            }
+            hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL);
+            if(IStorageCompObj.dwOleTypeNameLength > 0)
+            {
+                hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL);
+            }
+            hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL);
+            if(IStorageCompObj.dwProgIDNameLength > 0)
+            {
+                hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL);
+            }
+            hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL);
+        }
+        IStream_Release(pStream);
+    }
+    return hRes;
+}
+
+
+/*************************************************************************
+ * OLECONVERT_CreateOlePresStream[Internal] 
+ *
+ * Creates the "\002OlePres000" Stream with the Metafile data
+ *
+ * PARAMS
+ *     pStorage     [I] The dest IStorage to create \002OLEPres000 stream in.
+ *     dwExtentX    [I] Width of the Metafile
+ *     dwExtentY    [I] Height of the Metafile 
+ *     pData        [I] Metafile data
+ *     dwDataLength [I] Size of the Metafile data
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  CONVERT10_E_OLESTREAM_PUT for invalid Put
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *     
+ */
+void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwObjectType, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
+    BYTE pOlePresStreamEmbeddedHeader [] = 
+    {
+        0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 
+        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00
+    };
+
+    BYTE pOlePresStreamLinkHeader [] = 
+    {
+        0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 
+        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+        0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00
+    };
+
+    BYTE pOlePresStreamHeaderEmpty [] = 
+    {
+        0x00, 0x00, 0x00, 0x00, 
+        0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00
+    };
+     
+    /* Create the OlePres000 Stream */
+    hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
+        STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+
+    if(hRes == S_OK)
+    {
+        DWORD nHeaderSize;
+        OLECONVERT_ISTORAGE_OLEPRES OlePres;
+
+        memset(&OlePres, 0, sizeof(OlePres));
+        /* Do we have any metafile data to save */
+        if(dwDataLength > 0)
+        {
+            if(dwObjectType == OLECONVERT_LINK_TYPE)
+            {
+                memcpy(OlePres.byUnknown1, pOlePresStreamLinkHeader, sizeof(pOlePresStreamLinkHeader));
+                nHeaderSize = sizeof(pOlePresStreamLinkHeader);
+            }
+            else
+            {
+                memcpy(OlePres.byUnknown1, pOlePresStreamEmbeddedHeader, sizeof(pOlePresStreamEmbeddedHeader));
+                nHeaderSize = sizeof(pOlePresStreamEmbeddedHeader);
+            }
+        }
+        else
+        {
+            memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty));
+            nHeaderSize = sizeof(pOlePresStreamHeaderEmpty);
+        }
+        /* Set width and height of the metafile */
+        OlePres.dwExtentX = dwExtentX;
+        OlePres.dwExtentY = -dwExtentY;
+
+        /* Set Data and Length */
+        if(dwDataLength > sizeof(METAFILEPICT16))
+        {
+            OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16);
+            OlePres.pData = &(pData[8]);
+        }
+        /* Save OlePres000 Data to Stream */
+        hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL);
+        hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL);
+        hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL);
+        hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL);
+        if(OlePres.dwSize > 0)
+        {
+            hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL);
+        }
+        IStream_Release(pStream);
+    }
+}
+
+/*************************************************************************
+ * OLECONVERT_CreateOle10NativeStream [Internal] 
+ *
+ * Creates the "\001Ole10Native" Stream (should contain a BMP)
+ *
+ * PARAMS
+ *     pStorage     [I] Dest storage to create the stream in
+ *     pData        [I] Ole10 Native Data (ex. bmp)
+ *     dwDataLength [I] Size of the Ole10 Native Data
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertOLESTREAMToIStorage only.
+ *
+ *     Might need to verify the data and return appropriate error message
+ *     
+ */
+void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
+    
+    /* Create the Ole10Native Stream */
+    hRes = IStorage_CreateStream(pStorage, wstrStreamName, 
+        STGM_CREATE | STGM_WRITE  | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream );
+
+    if(hRes == S_OK)
+    {
+        /* Write info to stream */
+        hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL);
+        hRes = IStream_Write(pStream, pData, dwDataLength, NULL);
+        IStream_Release(pStream);
+    }
+
+}
+
+/*************************************************************************
+ * OLECONVERT_GetProgIDFromStorage [Internal] 
+ *
+ * Finds the ProgID (or OleTypeID) from the IStorage
+ *
+ * PARAMS
+ *     pStorage        [I] The Src IStorage to get the ProgID
+ *     strProgID       [I] the ProgID string to get
+ *     dwSize          [I] the size of the string
+ *
+ * RETURNS
+ *     Success:  S_OK
+ *     Failure:  REGDB_E_CLASSNOTREG if cannot reconstruct the stream
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *
+ *     
+ */
+HRESULT OLECONVERT_GetProgIDFromStorage(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    LARGE_INTEGER iSeekPos;
+
+    strProgID[0] = NULL;
+    
+    if(strProgID == NULL || dwSize == NULL)
+    {
+        return E_INVALIDARG;
+    }
+
+    if(OLECONVERT_IsStorageLink(pStorage))
+    {
+        LPOLESTR wstrProgID;
+        WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
+
+        /* Open the CompObj Stream */
+        hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
+            STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+        if(hRes == S_OK)
+        {
+            OLECONVERT_ISTORAGE_OLE OleStreamHeader;
+
+            /* Get the CLSID Offset */
+            iSeekPos.LowPart = sizeof(OleStreamHeader.dwOLEHEADER_ID) + sizeof(OleStreamHeader.dwUnknown1)
+                                + sizeof(OleStreamHeader.dwUnknown2) + sizeof(OleStreamHeader.dwUnknown3) 
+                                + sizeof(OleStreamHeader.dwUnknown4) + sizeof(OleStreamHeader.dwUnknown5);
+            iSeekPos.HighPart = 0;
+            hRes = IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
+            if(hRes == S_OK)
+            {
+                hRes = IStream_Read(pStream, &OleStreamHeader.dwObjectCLSIDOffset, sizeof(OleStreamHeader.dwObjectCLSIDOffset), NULL);
+            }
+            if(hRes == S_OK)
+            {
+                iSeekPos.LowPart = OleStreamHeader.dwObjectCLSIDOffset;
+                hRes = IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR, NULL);
+            }
+            /* Read the CLSID */
+            hRes = ReadClassStm(pStream, &OleStreamHeader.clsidObject);
+            if(hRes == S_OK)
+            {
+                hRes = ProgIDFromCLSID(&(OleStreamHeader.clsidObject), &wstrProgID);
+                if(hRes == S_OK)
+                {
+                    *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
+                }
+            }
+            IStream_Release(pStream);
+        }
+    }
+    else
+    {
+        
+        STATSTG stat;
+        OLECONVERT_ISTORAGE_COMPOBJ CompObj;
+        WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0};
+        /* Open the CompObj Stream */
+        hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
+            STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+
+        if(hRes == S_OK)
+        {
+
+            /*Get the OleType from the CompObj Stream */
+            iSeekPos.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid);
+            iSeekPos.HighPart = 0;
+
+            hRes = IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
+            if(hRes == S_OK)
+            {
+                hRes = IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL);
+            }
+
+            if(hRes == S_OK)
+            {
+                iSeekPos.LowPart = CompObj.dwCLSIDNameLength;
+                hRes = IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
+            }
+            if(hRes == S_OK)
+            {
+                hRes = IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL);
+            }
+            if(hRes == S_OK)
+            {
+                iSeekPos.LowPart = CompObj.dwOleTypeNameLength;
+                hRes = IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL);
+            }
+
+            if(hRes == S_OK)
+            {
+                hRes = IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL);
+                if(*dwSize > 0)
+                {
+                    if(hRes == S_OK)
+                    {
+                        hRes = IStream_Read(pStream, strProgID, *dwSize, NULL);
+                    }
+                }
+            }
+            IStream_Release(pStream);
+        }
+
+        /* If the CompObject is not present, or there was an error reading the CompObject */
+        /* Get the CLSID from the storage stat */
+        if(hRes != S_OK)
+        {
+            LPOLESTR wstrProgID;
+
+            /* Get the OleType from the registry */
+            IStorage_Stat(pStorage, &stat, STATFLAG_NONAME);
+            hRes = ProgIDFromCLSID(&(stat.clsid), &wstrProgID);
+            if(hRes == S_OK)
+            {
+                *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE);
+            }
+        }
+    }
+    if(strProgID[0] == NULL)
+    {
+        *dwSize = 0;
+    }
+    return hRes;
+}
+
+/*************************************************************************
+ * OLECONVERT_GetOle20PresData[Internal] 
+ *
+ * Converts IStorage "/002OlePres000" stream to a OLE10 Stream
+ *
+ * PARAMS
+ *     pStorage         [I] Src IStroage
+ *     pOleStreamData   [I] Dest OleStream Mem Struct
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *     
+ *     Memory allocated for pData must be freed by the caller
+ */
+void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    OLECONVERT_ISTORAGE_OLEPRES olePress;
+    WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0};
+
+ 
+
+    /* Open OlePress000 stream */
+    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
+        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+    if(hRes == S_OK)
+    {
+        LARGE_INTEGER iSeekPos;
+        METAFILEPICT16 MetaFilePict;
+        char strMetafilePictName[] = "METAFILEPICT";
+
+        /* Set the TypeID for a Metafile */
+        pOleStreamData[1].dwObjectTypeID = OLECONVERT_PRESENTATION_DATA_TYPE;
+
+        /* Set the OleTypeName to Metafile */
+        pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1;
+        strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName);
+
+        iSeekPos.HighPart = 0;
+        iSeekPos.LowPart = sizeof(olePress.byUnknown1);
+
+        /* Get Presentation Data */
+        IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL);
+        IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL);
+        IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL);
+        IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL);
+
+        /*Set width and Height */
+        pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX;
+        pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY;
+        if(olePress.dwSize > 0)
+        {
+            /* Set Length */
+            pOleStreamData[1].dwDataLength  = olePress.dwSize + sizeof(METAFILEPICT16);
+
+            /* Set MetaFilePict struct */
+            MetaFilePict.mm = 8;
+            MetaFilePict.xExt = olePress.dwExtentX;
+            MetaFilePict.yExt = olePress.dwExtentY;
+            MetaFilePict.hMF = 0;
+
+            /* Get Metafile Data */
+            pOleStreamData[1].pData = (BYTE *) malloc(pOleStreamData[1].dwDataLength);
+            memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict));
+            IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL);
+        }
+        IStream_Release(pStream);
+    }
+}
+
+LPMONIKER OLECONVERT_LoadMonikers(CLSID *pclsid, IStream *pStream )
+{
+
+    LPMONIKER pDestMoniker=NULL;
+    HRESULT hRes;
+    if(IsEqualCLSID(&CLSID_FileMoniker, pclsid))
+    {
+        WCHAR temp=0;
+        hRes = CreateFileMoniker(&temp, &pDestMoniker);
+        IMoniker_Load(pDestMoniker, pStream);
+    }
+    else if(IsEqualCLSID(&CLSID_ItemMoniker, pclsid))
+    {
+        WCHAR temp1=0;
+        WCHAR temp2=0;
+        hRes = CreateItemMoniker(&temp1, &temp2, &pDestMoniker);
+        IMoniker_Load(pDestMoniker, pStream);
+    }
+    else if(IsEqualCLSID(&CLSID_CompositeMoniker, pclsid))
+    {
+        /* Problem with Saving CompositeMoniker */
+        /* TODO: Rechange remove code, create an empty CompositeMoniker */
+        WCHAR temp1=0;
+        WCHAR temp2=0;
+        LPMONIKER pItemMoniker, pFileMoniker;
+        hRes = CreateItemMoniker(&temp1, &temp2, &pItemMoniker);
+        hRes = CreateFileMoniker(&temp1, &pFileMoniker);
+        hRes = CreateGenericComposite(pFileMoniker, pItemMoniker, &pDestMoniker);
+        IMoniker_Load(pDestMoniker, pStream);
+    }
+    else
+    {
+        FIXME("Unsupported moniker in IStorage, /001Ole stream\n");
+    }
+    return pDestMoniker;
+}
+
+HRESULT OLECONVERT_GetMonikerFromStorage(LPSTORAGE pStorage, 
+    BYTE **pLinkFileName, DWORD* dwLinkFileNameLength, 
+    BYTE **pLinkExtraInfo,  DWORD* dwLinkExtraInfoLength)
+{
+    HRESULT hRes;
+    IStream *pStream;
+    WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0};
+    OLECONVERT_ISTORAGE_OLE OleStreamHeader;
+    LPMONIKER pDestMoniker=NULL;
+
+    *pLinkFileName = NULL;
+    *pLinkExtraInfo = NULL;
+    *dwLinkFileNameLength = 0;
+    *dwLinkExtraInfoLength = 0;
+
+    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
+        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+
+    if(hRes == S_OK)
+    {   
+        /* Write default Data */
+        IStream_Read(pStream, &(OleStreamHeader.dwOLEHEADER_ID), sizeof(OleStreamHeader.dwOLEHEADER_ID), NULL);
+        IStream_Read(pStream, &(OleStreamHeader.dwUnknown1), sizeof(OleStreamHeader.dwUnknown1), NULL);
+        IStream_Read(pStream, &(OleStreamHeader.dwUnknown2), sizeof(OleStreamHeader.dwUnknown2), NULL);
+        IStream_Read(pStream, &(OleStreamHeader.dwUnknown3), sizeof(OleStreamHeader.dwUnknown3), NULL);
+        IStream_Read(pStream, &(OleStreamHeader.dwUnknown4), sizeof(OleStreamHeader.dwUnknown4), NULL);
+        IStream_Read(pStream, &(OleStreamHeader.dwUnknown5), sizeof(OleStreamHeader.dwUnknown5), NULL);
+        IStream_Read(pStream, &(OleStreamHeader.dwObjectCLSIDOffset), sizeof(OleStreamHeader.dwObjectCLSIDOffset), NULL);
+
+        /* Should call OleLoadFromStream, but implementeation incomplete */
+        ReadClassStm(pStream, &(OleStreamHeader.clsidMonikerTypeID));
+        /* Load the moniker */
+        pDestMoniker = OLECONVERT_LoadMonikers(&(OleStreamHeader.clsidMonikerTypeID), pStream);
+
+        /* Retreive the neccesary data */
+        if(IsEqualCLSID(&CLSID_FileMoniker, &(OleStreamHeader.clsidMonikerTypeID)))
+        {
+            
+            LPOLESTR ppszDisplayName;
+            IMoniker_GetDisplayName(pDestMoniker, NULL, NULL, &ppszDisplayName);
+            *dwLinkFileNameLength = WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
+                                        NULL, 0, NULL, FALSE);
+            *pLinkFileName = (BYTE *) malloc(*dwLinkFileNameLength);
+            WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
+                (LPSTR)*pLinkFileName, *dwLinkFileNameLength, NULL, FALSE);
+            CoTaskMemFree(ppszDisplayName);
+        }
+        else if(IsEqualCLSID(&CLSID_ItemMoniker, &(OleStreamHeader.clsidMonikerTypeID)))
+        {
+            LPOLESTR ppszDisplayName;
+            IMoniker_GetDisplayName(pDestMoniker, NULL, NULL, &ppszDisplayName);
+            *dwLinkExtraInfoLength = WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
+                                        NULL, 0, NULL, FALSE);
+            *pLinkExtraInfo = (BYTE *) malloc(*dwLinkExtraInfoLength);
+            WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
+                (LPSTR)*pLinkExtraInfo, *dwLinkExtraInfoLength, NULL, FALSE);
+            CoTaskMemFree(ppszDisplayName);
+            
+        }
+        else if(IsEqualCLSID(&CLSID_CompositeMoniker, &(OleStreamHeader.clsidMonikerTypeID)))
+        {
+            LPOLESTR ppszDisplayName;
+            IMoniker *pmk;
+            IEnumMoniker *enumMk;
+
+            IMoniker_Enum(pDestMoniker,TRUE,&enumMk);
+            IEnumMoniker_Next(enumMk,1,&pmk,NULL);
+            
+
+            IMoniker_GetDisplayName(pDestMoniker, NULL, NULL, &ppszDisplayName);
+            *dwLinkFileNameLength = WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
+                                        NULL, 0, NULL, FALSE);
+            *pLinkFileName = (BYTE *) malloc(*dwLinkFileNameLength);
+            WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
+                (LPSTR)*pLinkFileName, *dwLinkFileNameLength, NULL, FALSE);
+            CoTaskMemFree(ppszDisplayName);
+            IMoniker_Release(pmk);
+
+            IEnumMoniker_Next(enumMk,1,&pmk,NULL);
+
+            IMoniker_GetDisplayName(pDestMoniker, NULL, NULL, &ppszDisplayName);
+            *dwLinkExtraInfoLength = WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
+                                        NULL, 0, NULL, FALSE);
+            *pLinkExtraInfo = (BYTE *) malloc(*dwLinkExtraInfoLength);
+            WideCharToMultiByte(CP_ACP, 0, ppszDisplayName, -1, 
+                (LPSTR)*pLinkExtraInfo, *dwLinkExtraInfoLength, NULL, FALSE);
+            CoTaskMemFree(ppszDisplayName);
+            IMoniker_Release(pmk);
+            IEnumMoniker_Release(enumMk);
+        }
+        IStream_Read(pStream, &(OleStreamHeader.dwUnknown6), sizeof(OleStreamHeader.dwUnknown6), NULL);
+
+        ReadClassStm(pStream, &(OleStreamHeader.clsidObject));
+        IStream_Read(pStream, OleStreamHeader.dwUnknown7, sizeof(OleStreamHeader.dwUnknown7), NULL);
+        IStream_Release(pStream);
+    }
+    if(pDestMoniker != NULL)
+    {
+        IMoniker_Release(pDestMoniker);
+    }
+    return S_OK;
+
+
+}
+/*************************************************************************
+ * OLECONVERT_SetEmbeddedOle10OLESTREAMData [Internal] 
+ *
+ * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream
+ *
+ * PARAMS
+ *     pStorage     [I] Src IStroage
+ *     pOleStream   [I] Dest OleStream Mem Struct
+ *
+ * RETURNS
+ *     Nothing
+ *
+ * NOTES
+ *     This function is used by OleConvertIStorageToOLESTREAM only.
+ *
+ *     Memory allocated for pData must be freed by the caller
+ *      
+ *     
+ */
+HRESULT OLECONVERT_SetEmbeddedOle10OLESTREAMData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+{
+
+    HRESULT hRes;
+    IStream *pStream;
+    WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
+
+    /* Initialize Default data for OLESTREAM */
+    memset(pOleStreamData,0, sizeof(OLECONVERT_OLESTREAM_DATA) * OLECONVERT_NUM_OLE10STREAMS);
+    /* Get the ProgID */
+    pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
+    hRes = OLECONVERT_GetProgIDFromStorage(pStorage, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
+
+    if(hRes != S_OK)
+    {
+        /* Cannot find the CLSID in the registry. Abort! */
+        return hRes;
+    }
+
+    pOleStreamData[0].dwOleID = OLESTREAM_ID;
+    pOleStreamData[0].dwObjectTypeID = OLECONVERT_EMBEDDED_TYPE;
+
+    /* Open Ole10Native Stream */
+    hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL,  
+        STGM_READ  | STGM_SHARE_EXCLUSIVE, 0, &pStream );
+    if(hRes == S_OK)
+    {
+
+        /* Read Size and Data */
+        IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL);
+        if(pOleStreamData->dwDataLength > 0)
+        {
+            pOleStreamData->pData = (BYTE *) malloc(pOleStreamData->dwDataLength);
+            IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL);
+        }
+        IStream_Release(pStream);
+    }
+
+    if(hRes == S_OK)
+    {
+        /* Stream doens't exist for all cases: no stream for pbrush but package does! */
+        /* Cannot check for return value because the stream might not exist (normal behavior)*/
+        pOleStreamData[1].dwOleID = OLESTREAM_ID;
+        OLECONVERT_GetOle20PresData(pStorage, pOleStreamData);
+    }
+
+    return hRes;
+
+}
+
+HRESULT OLECONVERT_SetEmbeddedOle20OLESTREAMData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+{
+
+    HRESULT hRes=S_OK;
+   /* Initialize Default data for OLESTREAM */
+    memset(pOleStreamData,0, sizeof(OLECONVERT_OLESTREAM_DATA) * OLECONVERT_NUM_OLE10STREAMS);
+
+    /* Get the ProgID */
+    pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
+    hRes = OLECONVERT_GetProgIDFromStorage(pStorage, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
+
+    if(hRes != S_OK)
+    {
+        /* Cannot find the CLSID in the registry. Abort! */
+        return hRes;
+    }
+
+    pOleStreamData[0].dwOleID = OLESTREAM_ID;
+    pOleStreamData[0].dwObjectTypeID = OLECONVERT_EMBEDDED_TYPE;
+    pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, 
+                                        &(pOleStreamData[0].pData));
+    pOleStreamData[1].dwOleID = OLESTREAM_ID;
+    OLECONVERT_GetOle20PresData(pStorage, pOleStreamData);
+
+    return hRes;
+}
+
+
+HRESULT OLECONVERT_SetLinkOLESTREAMData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+{
+
+    HRESULT hRes = S_OK;
+   /* Initialize Default data for OLESTREAM */
+    memset(pOleStreamData,0, sizeof(OLECONVERT_OLESTREAM_DATA) * OLECONVERT_NUM_OLE10STREAMS);
+
+    /* Get the ProgID */
+    pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN;
+    hRes = OLECONVERT_GetProgIDFromStorage(pStorage, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength));
+
+    if(hRes != S_OK)
+    {
+        /* Cannot find the CLSID in the registry. Abort! */
+        return hRes;
+    }
+    pOleStreamData[0].dwOleID = OLESTREAM_ID;
+    pOleStreamData[0].dwObjectTypeID = OLECONVERT_LINK_TYPE;
+    /* TODO: Write the Link data */
+    OLECONVERT_GetMonikerFromStorage(pStorage, 
+        &(pOleStreamData[0].strLinkFileName), &(pOleStreamData[0].dwLinkFileNameLength), 
+        &(pOleStreamData[0].pLinkExtraInfo),  &(pOleStreamData[0].dwLinkExtraInfoLength));
+
+/*    pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData)); */
+    pOleStreamData[1].dwOleID = OLESTREAM_ID;
+    OLECONVERT_GetOle20PresData(pStorage, pOleStreamData);
+    return hRes;
+}
+
+
+HRESULT OLECONVERT_CreateEmbeddedIStorage(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+{
+    HRESULT hRes = S_OK;
+    BOOL bCreateOle10Native = TRUE;
+    if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic))
+    {
+        /* Do we have the IStorage Data in the OLESTREAM */
+        if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0)
+        {
+            OLECONVERT_GetOLE20FromOLE10(pStorage, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
+            
+            OLECONVERT_CreateOlePresStream(pStorage, OLECONVERT_EMBEDDED_TYPE,
+                pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, 
+                pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
+            bCreateOle10Native = FALSE;
+        }
+    }
+
+    if(bCreateOle10Native)
+    {
+        /* It must be an original OLE 1.0 source */
+        OLECONVERT_CreateOle10NativeStream(pStorage, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength);
+
+        if(pOleStreamData[1].dwObjectTypeID == OLECONVERT_PRESENTATION_DATA_TYPE)
+        {
+            OLECONVERT_CreateOlePresStream(pStorage, OLECONVERT_EMBEDDED_TYPE, 
+                pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, 
+                pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
+        }
+    }
+
+    /*Create the Ole Stream if necessary */
+    OLECONVERT_CreateEmbeddedOleStream(pStorage);
+    /* Create CompObj Stream if necessary */
+    hRes = OLECONVERT_CreateCompObjStream(pStorage, pOleStreamData[0].strOleTypeName);
+    if(hRes == S_OK)
+    {
+        CLSID clsid;
+        
+        CLSIDFromProgID16(pOleStreamData[0].strOleTypeName, &clsid);
+        IStorage_SetClass(pStorage, &clsid);
+    }
+    return hRes;
+}
+
+HRESULT OLECONVERT_CreateLinkIStorage(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData)
+{
+    HRESULT hRes;
+    hRes = OLECONVERT_CreateLinkOleStream(pStorage, 
+        pOleStreamData[0].strOleTypeName, (LPCSTR)pOleStreamData[0].strLinkFileName, 
+        pOleStreamData[0].pLinkExtraInfo, pOleStreamData[0].dwLinkExtraInfoLength);
+    if(hRes == S_OK)
+    {
+        OLECONVERT_CreateOlePresStream(pStorage, OLECONVERT_LINK_TYPE,
+            pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, 
+            pOleStreamData[1].pData, pOleStreamData[1].dwDataLength);
+    }
+    if(hRes == S_OK)
+    {
+        IStorage_SetClass(pStorage, &IID_StdOleLink);
+    }
+    return hRes;
+}
+
+
+
+/*************************************************************************
+ * OleConvertOLESTREAMToIStorage [OLE32.87] 
+ *
+ * Read info on MSDN
+ *
+ * TODO
+ *      DVTARGETDEVICE paramenter is not handled
+ *      Still unsure of some mem fields for OLE 10 Stream
+ *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
+ *      and "\001OLE" streams
+ *     
+ */
+HRESULT WINAPI OleConvertOLESTREAMToIStorage (
+    LPOLESTREAM pOleStream, 
+    LPSTORAGE pstg, 
+    const DVTARGETDEVICE* ptd)
+{
+    int i;
+    HRESULT hRes=S_OK;
+    OLECONVERT_OLESTREAM_DATA pOleStreamData[OLECONVERT_NUM_OLE10STREAMS];
+
+    memset(pOleStreamData, 0, sizeof(pOleStreamData));
+
+    if(ptd != NULL)
+    {
+        FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n");
+    }
+
+    if(pstg == NULL || pOleStream == NULL)
+    {
+        hRes = E_INVALIDARG;
+    }
+
+    if(hRes == S_OK)
+    {
+        /* Load the OLESTREAM to Memory */
+        hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0]);
+    }
+
+    if(hRes == S_OK)
+    {
+        /* Load the OLESTREAM to Memory (part 2)*/
+        hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1]);
+    }
+
+    if(hRes == S_OK)
+    {
+        /* Is olestream an embedded object */
+        if(pOleStreamData[0].dwObjectTypeID != OLECONVERT_LINK_TYPE)
+        {
+            hRes = OLECONVERT_CreateEmbeddedIStorage(pstg, pOleStreamData);
+        }
+        else
+        {
+            hRes = OLECONVERT_CreateLinkIStorage(pstg, pOleStreamData);
+        }
+    }
+    /* Free allocated memory */
+    for(i=0; i < OLECONVERT_NUM_OLE10STREAMS; i++)
+    {
+        if(pOleStreamData[i].pData != NULL)
+        {
+            free(pOleStreamData[i].pData);
+        }
+
+        if(pOleStreamData[i].pLinkExtraInfo != NULL)
+        {
+            free(pOleStreamData[i].pLinkExtraInfo);
+        }
+        if(pOleStreamData[i].strLinkFileName != NULL)
+        {
+            free(pOleStreamData[i].strLinkFileName);
+        }
+    }
+    return hRes;
+}
+
+/*************************************************************************
+ * OleConvertIStorageToOLESTREAM [OLE32.85]
+ *
+ * Read info on MSDN
+ *
+ * Read info on MSDN
+ *
+ * TODO
+ *      Still unsure of some mem fields for OLE 10 Stream
+ *      Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj",
+ *      and "\001OLE" streams.
+ *     
+ */
+HRESULT WINAPI OleConvertIStorageToOLESTREAM (
+    LPSTORAGE pstg, 
+    LPOLESTREAM pOleStream)
+{
+    int i;
+    HRESULT hRes = S_OK;
+    IStream *pStream;
+    OLECONVERT_OLESTREAM_DATA pOleStreamData[OLECONVERT_NUM_OLE10STREAMS];
+    WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0};
+
+
+    memset(pOleStreamData, 0, sizeof(pOleStreamData));
+
+    if(pstg == NULL || pOleStream == NULL)
+    {
+        hRes = E_INVALIDARG;
+    }
+    if(hRes == S_OK)
+    {
+        if(!OLECONVERT_IsStorageLink(pstg))
+        {
+            /*Was it originaly Ole10 */
+            hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream);    
+            if(hRes == S_OK)
+            {
+                IStream_Release(pStream);
+                /*Get Presentation Data for Ole10Native */
+                hRes = OLECONVERT_SetEmbeddedOle10OLESTREAMData(pstg, pOleStreamData);
+            }
+            else
+            {
+                /*Get Presentation Data (OLE20)*/
+                hRes = OLECONVERT_SetEmbeddedOle20OLESTREAMData(pstg, pOleStreamData);
+            }
+        }
+        else
+        {
+            hRes = OLECONVERT_SetLinkOLESTREAMData(pstg, pOleStreamData);
+        }
+
+        if(hRes == S_OK)
+        {
+            /* Save OLESTREAM */
+            hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream);
+            if(hRes == S_OK)
+            {
+                hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream);
+            }
+        }
+    }
+
+    /* Free allocated memory */
+    for(i=0; i < OLECONVERT_NUM_OLE10STREAMS; i++)
+    {
+        if(pOleStreamData[i].pData != NULL)
+        {
+            free(pOleStreamData[i].pData);
+        }
+
+        if(pOleStreamData[i].pLinkExtraInfo != NULL)
+        {
+            free(pOleStreamData[i].pLinkExtraInfo);
+        }
+
+        if(pOleStreamData[i].strLinkFileName != NULL)
+        {
+            free(pOleStreamData[i].strLinkFileName);
+        }
+    }
+
+    return hRes;
+}
+
+/******************************************************************************
+ * StgIsStorageFile16 [STORAGE.5]
+ */
+HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) {
+static const BYTE STORAGE_notmagic[8]={0x0e,0x11,0xfc,0x0d,0xd0,0xcf,0x11,0xe0};
+        HFILE           hf;
+        OFSTRUCT        ofs;
+        BYTE            magic[24];
+
+        TRACE_(ole)("(\'%s\')\n",fn);
+        hf = OpenFile(fn,&ofs,OF_SHARE_DENY_NONE);
+        if (hf==HFILE_ERROR)
+                return STG_E_FILENOTFOUND;
+        if (24!=_lread(hf,magic,24)) {
+                WARN_(ole)(" too short\n");
+                _lclose(hf);
+                return S_FALSE;
+        }
+        if (!memcmp(magic,STORAGE_magic,8)) {
+                WARN_(ole)(" -> YES\n");
+                _lclose(hf);
+                return S_OK;
+        }
+        if (!memcmp(magic,STORAGE_notmagic,8)) {
+                WARN_(ole)(" -> NO\n");
+                _lclose(hf);
+                return S_FALSE;
+        }
+        if (!memcmp(magic,STORAGE_oldmagic,8)) {
+                WARN_(ole)(" -> old format\n");
+                _lclose(hf);
+                return STG_E_OLDFORMAT;
+        }
+        WARN_(ole)(" -> Invalid header.\n");
+        _lclose(hf);
+        return STG_E_INVALIDHEADER;
+}
+
+HRESULT WINAPI
+StgIsStorageFile(LPCOLESTR fn)
+{
+        LPOLESTR16      xfn = HEAP_strdupWtoA(GetProcessHeap(),0,fn);
+        HRESULT       ret = StgIsStorageFile16(xfn);
+
+        HeapFree(GetProcessHeap(),0,xfn);
+        return ret;
+}
+
Index: trunk/src/ole32/new/storage.h
===================================================================
--- trunk/src/ole32/new/storage.h	(revision 3456)
+++ trunk/src/ole32/new/storage.h	(revision 3456)
@@ -0,0 +1,871 @@
+/* $Id: storage.h,v 1.1 2000-04-27 22:21:36 davidr Exp $ */
+/*
+ * Compound Storage (32 bit version)
+ *
+ * Implemented using the documentation of the LAOLA project at
+ * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html>
+ * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>)
+ *
+ * This include file contains definitions of types and function
+ * prototypes that are used in the many files implementing the 
+ * storage functionality
+ *
+ * Copyright 1998,1999 Francis Beaudet
+ * Copyright 1998,1999 Thuy Nguyen
+ */
+#ifndef __STORAGE32_H__
+#define __STORAGE32_H__
+
+#include "wtypes.h"
+#include "winnt.h"
+#include "wine/obj_storage.h"
+
+/*
+ * Definitions for the file format offsets.
+ */
+static const ULONG OFFSET_BIGBLOCKSIZEBITS   = 0x0000001e;
+static const ULONG OFFSET_SMALLBLOCKSIZEBITS = 0x00000020;
+static const ULONG OFFSET_BBDEPOTCOUNT	     = 0x0000002C;
+static const ULONG OFFSET_ROOTSTARTBLOCK     = 0x00000030;
+static const ULONG OFFSET_SBDEPOTSTART	     = 0x0000003C;
+static const ULONG OFFSET_EXTBBDEPOTSTART    = 0x00000044;
+static const ULONG OFFSET_EXTBBDEPOTCOUNT    = 0x00000048;
+static const ULONG OFFSET_BBDEPOTSTART	     = 0x0000004C;
+static const ULONG OFFSET_PS_NAME            = 0x00000000;
+static const ULONG OFFSET_PS_NAMELENGTH	     = 0x00000040;
+static const ULONG OFFSET_PS_PROPERTYTYPE    = 0x00000042;
+static const ULONG OFFSET_PS_PREVIOUSPROP    = 0x00000044;
+static const ULONG OFFSET_PS_NEXTPROP        = 0x00000048;   
+static const ULONG OFFSET_PS_DIRPROP	     = 0x0000004C;
+static const ULONG OFFSET_PS_GUID            = 0x00000050;
+static const ULONG OFFSET_PS_TSS1	     = 0x00000064;
+static const ULONG OFFSET_PS_TSD1            = 0x00000068;
+static const ULONG OFFSET_PS_TSS2            = 0x0000006C;
+static const ULONG OFFSET_PS_TSD2            = 0x00000070;
+static const ULONG OFFSET_PS_STARTBLOCK	     = 0x00000074; 
+static const ULONG OFFSET_PS_SIZE	     = 0x00000078; 
+static const WORD  DEF_BIG_BLOCK_SIZE_BITS   = 0x0009;
+static const WORD  DEF_SMALL_BLOCK_SIZE_BITS = 0x0006;
+static const WORD  DEF_BIG_BLOCK_SIZE        = 0x0200;
+static const WORD  DEF_SMALL_BLOCK_SIZE      = 0x0040;
+static const ULONG BLOCK_EXTBBDEPOT          = 0xFFFFFFFC;
+static const ULONG BLOCK_SPECIAL             = 0xFFFFFFFD;
+static const ULONG BLOCK_END_OF_CHAIN        = 0xFFFFFFFE;
+static const ULONG BLOCK_UNUSED              = 0xFFFFFFFF;
+static const ULONG PROPERTY_NULL             = 0xFFFFFFFF;
+
+#define PROPERTY_NAME_MAX_LEN    0x20
+#define PROPERTY_NAME_BUFFER_LEN 0x40             
+
+#define PROPSET_BLOCK_SIZE 0x00000080
+
+/*
+ * Property type of relation
+ */
+#define PROPERTY_RELATION_PREVIOUS 0
+#define PROPERTY_RELATION_NEXT     1
+#define PROPERTY_RELATION_DIR      2
+
+/*
+ * Property type constants
+ */
+#define PROPTYPE_STORAGE 0x01
+#define PROPTYPE_STREAM  0x02
+#define PROPTYPE_ROOT    0x05
+
+/*
+ * These defines assume a hardcoded blocksize. The code will assert
+ * if the blocksize is different. Some changes will have to be done if it
+ * becomes the case.
+ */
+#define BIG_BLOCK_SIZE           0x200
+#define COUNT_BBDEPOTINHEADER    109
+#define LIMIT_TO_USE_SMALL_BLOCK 0x1000
+#define NUM_BLOCKS_PER_DEPOT_BLOCK 128
+
+/*
+ * These are signatures to detect the type of Document file.
+ */
+static const BYTE STORAGE_magic[8]    ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1};
+static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d};
+
+/*
+ * Forward declarations of all the structures used by the storage
+ * module.
+ */
+typedef struct StorageBaseImpl     StorageBaseImpl;
+typedef struct StorageImpl         StorageImpl;
+typedef struct StorageInternalImpl StorageInternalImpl;
+typedef struct BlockChainStream      BlockChainStream;
+typedef struct SmallBlockChainStream SmallBlockChainStream;
+typedef struct IEnumSTATSTGImpl      IEnumSTATSTGImpl;
+typedef struct StgProperty           StgProperty;
+typedef struct StgStreamImpl         StgStreamImpl;
+
+/*
+ * This utility structure is used to read/write the information in a storage
+ * property.
+ */
+struct StgProperty
+{
+  WCHAR	         name[PROPERTY_NAME_MAX_LEN];
+  WORD	         sizeOfNameString;
+  BYTE	         propertyType;
+  ULONG	         previousProperty;
+  ULONG	         nextProperty;
+  ULONG          dirProperty;
+  GUID           propertyUniqueID;
+  ULONG          timeStampS1;
+  ULONG          timeStampD1;
+  ULONG          timeStampS2;
+  ULONG          timeStampD2;
+  ULONG          startingBlock;
+  ULARGE_INTEGER size;
+};
+
+/*************************************************************************
+ * Big Block File support
+ *
+ * The big block file is an abstraction of a flat file separated in
+ * same sized blocks. The implementation for the methods described in 
+ * this section appear in stg_bigblockfile.c
+ */
+
+/*
+ * Declaration of the data structures
+ */
+typedef struct BigBlockFile BigBlockFile,*LPBIGBLOCKFILE;
+typedef struct MappedPage   MappedPage,*LPMAPPEDPAGE;
+
+struct BigBlockFile
+{
+  BOOL fileBased;
+  ULARGE_INTEGER filesize;
+  ULONG blocksize;
+  HANDLE hfile;
+  HANDLE hfilemap;
+  DWORD flProtect;
+  MappedPage *maplist;
+  MappedPage *victimhead, *victimtail;
+  ULONG num_victim_pages;
+  ILockBytes *pLkbyt;
+  HGLOBAL hbytearray;
+  LPVOID pbytearray;
+};
+
+/*
+ * Declaration of the functions used to manipulate the BigBlockFile
+ * data structure.
+ */
+BigBlockFile*  BIGBLOCKFILE_Construct(HANDLE hFile,
+                                      ILockBytes* pLkByt,
+                                      DWORD openFlags,
+                                      ULONG blocksize,
+                                      BOOL fileBased);
+void           BIGBLOCKFILE_Destructor(LPBIGBLOCKFILE This);
+void*          BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index);
+void*          BIGBLOCKFILE_GetROBigBlock(LPBIGBLOCKFILE This, ULONG index);
+void           BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock);
+void           BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize);
+ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This);
+
+/****************************************************************************
+ * Storage32BaseImpl definitions.
+ *
+ * This stucture defines the base information contained in all implementations
+ * of IStorage32 contained in this filee storage implementation.
+ *
+ * In OOP terms, this is the base class for all the IStorage32 implementations
+ * contained in this file.
+ */
+struct StorageBaseImpl
+{
+  ICOM_VFIELD(IStorage);   /* Needs to be the first item in the stuct
+			    * since we want to cast this in a Storage32 pointer */
+
+  /*
+   * Reference count of this object
+   */
+  ULONG ref;
+  
+  /* 
+   * Ancestor storage (top level) 
+   */
+  StorageImpl* ancestorStorage;		 
+  
+  /*
+   * Index of the property for the root of
+   * this storage
+   */
+  ULONG rootPropertySetIndex;
+  
+  /* 
+   * virtual Destructor method.
+   */
+  void (*v_destructor)(StorageBaseImpl*);
+};
+
+
+/*
+ * Prototypes for the methods of the Storage32BaseImpl class.
+ */
+HRESULT WINAPI StorageBaseImpl_QueryInterface(
+            IStorage*        iface,
+            REFIID             riid,
+            void**             ppvObject);
+        
+ULONG WINAPI StorageBaseImpl_AddRef( 
+            IStorage*        iface);
+        
+ULONG WINAPI StorageBaseImpl_Release( 
+            IStorage*        iface);
+        
+HRESULT WINAPI StorageBaseImpl_OpenStream( 
+            IStorage*        iface,
+            const OLECHAR*   pwcsName,  /* [string][in] */
+            void*              reserved1, /* [unique][in] */
+            DWORD              grfMode,   /* [in] */        
+            DWORD              reserved2, /* [in] */        
+            IStream**        ppstm);    /* [out] */   
+    
+HRESULT WINAPI StorageBaseImpl_OpenStorage( 
+            IStorage*        iface,
+            const OLECHAR*   pwcsName,      /* [string][unique][in] */ 
+            IStorage*        pstgPriority,  /* [unique][in] */         
+            DWORD              grfMode,       /* [in] */                 
+            SNB              snbExclude,    /* [unique][in] */         
+            DWORD              reserved,      /* [in] */                 
+            IStorage**       ppstg);        /* [out] */                
+          
+HRESULT WINAPI StorageBaseImpl_EnumElements( 
+            IStorage*        iface,
+            DWORD              reserved1, /* [in] */                  
+            void*              reserved2, /* [size_is][unique][in] */ 
+            DWORD              reserved3, /* [in] */                  
+            IEnumSTATSTG**     ppenum);   /* [out] */   
+
+HRESULT WINAPI StorageBaseImpl_Stat( 
+            IStorage*        iface,
+            STATSTG*           pstatstg,     /* [out] */ 
+            DWORD              grfStatFlag); /* [in] */  
+
+HRESULT WINAPI StorageBaseImpl_RenameElement(
+            IStorage*        iface,
+            const OLECHAR*   pwcsOldName,  /* [string][in] */
+            const OLECHAR*   pwcsNewName); /* [string][in] */
+
+HRESULT WINAPI StorageBaseImpl_CreateStream(
+            IStorage*        iface,
+            const OLECHAR*   pwcsName,  /* [string][in] */
+            DWORD              grfMode,   /* [in] */
+            DWORD              reserved1, /* [in] */
+            DWORD              reserved2, /* [in] */
+            IStream**        ppstm);    /* [out] */
+
+HRESULT WINAPI StorageBaseImpl_SetClass(
+            IStorage*        iface,
+            REFCLSID           clsid);  /* [in] */
+
+/****************************************************************************
+ * Storage32Impl definitions.
+ *
+ * This implementation of the IStorage32 interface represents a root
+ * storage. Basically, a document file.
+ */
+struct StorageImpl
+{
+  ICOM_VFIELD(IStorage);   /* Needs to be the first item in the stuct
+				      * since we want to cast this in a Storage32 pointer */
+
+  /*
+   * Declare the member of the Storage32BaseImpl class to allow
+   * casting as a Storage32BaseImpl
+   */
+  ULONG		        ref;
+  struct StorageImpl* ancestorStorage;		 
+  ULONG                 rootPropertySetIndex;
+  void (*v_destructor)(struct StorageImpl*);
+  
+  /*
+   * The following data members are specific to the Storage32Impl
+   * class
+   */
+  HANDLE           hFile;      /* Physical support for the Docfile */
+  
+  /*
+   * File header
+   */
+  WORD  bigBlockSizeBits;
+  WORD  smallBlockSizeBits;
+  ULONG bigBlockSize;
+  ULONG smallBlockSize;
+  ULONG bigBlockDepotCount;
+  ULONG rootStartBlock;
+  ULONG smallBlockDepotStart;
+  ULONG extBigBlockDepotStart;
+  ULONG extBigBlockDepotCount;
+  ULONG bigBlockDepotStart[COUNT_BBDEPOTINHEADER];
+
+  ULONG blockDepotCached[NUM_BLOCKS_PER_DEPOT_BLOCK];
+  ULONG indexBlockDepotCached;
+  ULONG prevFreeBlock;
+
+  /*
+   * Abstraction of the big block chains for the chains of the header.
+   */
+  BlockChainStream* rootBlockChain;
+  BlockChainStream* smallBlockDepotChain;
+  BlockChainStream* smallBlockRootChain;  
+
+  /*
+   * Pointer to the big block file abstraction
+   */
+  BigBlockFile* bigBlockFile; 
+
+  /*****************************************************************************************/
+  /* warning: this is a temp fix for bugs related to save file to mounted network drive    */
+  /* TBD: these lines should be removed when we will get the final fix                     */
+  /*****************************************************************************************/
+  WCHAR* srcDestFiles[2];
+  /*****************************************************************************************/
+};
+
+/*
+ * Method declaration for the Storage32Impl class
+ */        
+
+HRESULT WINAPI StorageImpl_CreateStorage( 
+            IStorage*      iface,
+            const OLECHAR* pwcsName,  /* [string][in] */ 
+            DWORD            grfMode,   /* [in] */ 
+            DWORD            dwStgFmt,  /* [in] */ 
+            DWORD            reserved2, /* [in] */ 
+            IStorage**     ppstg);    /* [out] */ 
+        
+HRESULT WINAPI StorageImpl_CopyTo( 
+            IStorage*      iface,
+            DWORD          ciidExclude,  /* [in] */ 
+            const IID*     rgiidExclude, /* [size_is][unique][in] */ 
+            SNB            snbExclude, /* [unique][in] */ 
+            IStorage*    pstgDest);    /* [unique][in] */ 
+        
+HRESULT WINAPI StorageImpl_MoveElementTo( 
+            IStorage*      iface,
+            const OLECHAR* pwcsName,    /* [string][in] */ 
+            IStorage*      pstgDest,    /* [unique][in] */ 
+            const OLECHAR* pwcsNewName, /* [string][in] */ 
+            DWORD            grfFlags);   /* [in] */ 
+        
+HRESULT WINAPI StorageImpl_Commit( 
+            IStorage*      iface,
+            DWORD          grfCommitFlags); /* [in] */ 
+        
+HRESULT WINAPI StorageImpl_Revert( 
+            IStorage*      iface);
+        
+HRESULT WINAPI StorageImpl_DestroyElement( 
+            IStorage*      iface,
+            const OLECHAR* pwcsName); /* [string][in] */ 
+        
+HRESULT WINAPI StorageImpl_SetElementTimes( 
+            IStorage*      iface,
+            const OLECHAR* pwcsName, /* [string][in] */ 
+            const FILETIME*  pctime,   /* [in] */ 
+            const FILETIME*  patime,   /* [in] */ 
+            const FILETIME*  pmtime);  /* [in] */ 
+
+HRESULT WINAPI StorageImpl_SetStateBits( 
+            IStorage*      iface,
+            DWORD          grfStateBits, /* [in] */ 
+            DWORD          grfMask);     /* [in] */ 
+        
+void StorageImpl_Destroy(
+	    StorageImpl* This);
+
+HRESULT StorageImpl_Construct(
+            StorageImpl* This,
+            HANDLE       hFile,
+            ILockBytes*  pLkbyt,
+            DWORD        openFlags,
+            BOOL         fileBased,
+            BOOL         fileCreate);
+
+BOOL StorageImpl_ReadBigBlock(
+            StorageImpl* This,
+	    ULONG          blockIndex,
+	    void*          buffer);
+
+BOOL StorageImpl_WriteBigBlock(
+            StorageImpl* This,
+	    ULONG          blockIndex,
+	    void*          buffer);
+
+void* StorageImpl_GetROBigBlock(
+            StorageImpl* This,
+	    ULONG          blockIndex);
+
+void* StorageImpl_GetBigBlock(
+	    StorageImpl* This,
+	    ULONG          blockIndex);
+
+void StorageImpl_ReleaseBigBlock(
+            StorageImpl* This,
+            void*          pBigBlock);
+
+ULONG StorageImpl_GetNextFreeBigBlock(
+            StorageImpl* This);
+
+void StorageImpl_FreeBigBlock(
+            StorageImpl* This,
+	    ULONG blockIndex);
+
+ULONG StorageImpl_GetNextBlockInChain(
+            StorageImpl* This,
+	    ULONG blockIndex);
+
+void StorageImpl_SetNextBlockInChain(
+            StorageImpl* This,
+	    ULONG blockIndex,
+      ULONG nextBlock);
+
+HRESULT StorageImpl_LoadFileHeader(
+	    StorageImpl* This);
+
+void StorageImpl_SaveFileHeader(
+            StorageImpl* This);
+
+BOOL StorageImpl_ReadProperty(
+            StorageImpl* This,
+	    ULONG          index,
+	    StgProperty*    buffer);
+
+BOOL StorageImpl_WriteProperty(
+            StorageImpl* This,
+	    ULONG          index,
+	    StgProperty*   buffer);
+
+BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks(
+                      StorageImpl* This,
+                      SmallBlockChainStream** ppsbChain);
+
+ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This,
+                                         ULONG blockIndex);
+
+void Storage32Impl_AddBlockDepot(StorageImpl* This,
+                                 ULONG blockIndex);
+
+ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This);
+
+ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This,
+                                     ULONG depotIndex);
+
+void Storage32Impl_SetExtDepotBlock(StorageImpl* This,
+                                    ULONG depotIndex,
+                                    ULONG blockIndex);
+/****************************************************************************
+ * Storage32InternalImpl definitions.
+ *
+ * Definition of the implementation structure for the IStorage32 interface.
+ * This one implements the IStorage32 interface for storage that are
+ * inside another storage.
+ */
+struct StorageInternalImpl
+{
+  ICOM_VFIELD(IStorage);	/* Needs to be the first item in the stuct
+				 * since we want to cast this in a Storage32 pointer */
+
+  /*
+   * Declare the member of the Storage32BaseImpl class to allow
+   * casting as a Storage32BaseImpl
+   */
+  ULONG		             ref;
+  struct StorageImpl* ancestorStorage;		 
+  ULONG                    rootPropertySetIndex;
+  void (*v_destructor)(struct StorageInternalImpl*);
+
+  /*
+   * There is no specific data for this class.
+   */
+};
+
+/*
+ * Method definitions for the Storage32InternalImpl class.
+ */
+StorageInternalImpl* StorageInternalImpl_Construct(
+	    StorageImpl* ancestorStorage,	
+	    ULONG          rootTropertyIndex);
+
+void StorageInternalImpl_Destroy(
+       	    StorageInternalImpl* This);
+
+HRESULT WINAPI StorageInternalImpl_Commit( 
+	    IStorage*            iface,
+	    DWORD                  grfCommitFlags); /* [in] */ 
+
+HRESULT WINAPI StorageInternalImpl_Revert( 
+     	    IStorage*            iface);
+
+
+/****************************************************************************
+ * IEnumSTATSTGImpl definitions.
+ *
+ * Definition of the implementation structure for the IEnumSTATSTGImpl interface.
+ * This class allows iterating through the content of a storage and to find
+ * specific items inside it.
+ */
+struct IEnumSTATSTGImpl
+{
+  ICOM_VFIELD(IEnumSTATSTG);    /* Needs to be the first item in the stuct
+					 * since we want to cast this in a IEnumSTATSTG pointer */
+  
+  ULONG		 ref;		        /* Reference count */
+  StorageImpl* parentStorage;         /* Reference to the parent storage */
+  ULONG          firstPropertyNode;     /* Index of the root of the storage to enumerate */
+
+  /*
+   * The current implementation of the IEnumSTATSTGImpl class uses a stack
+   * to walk the property sets to get the content of a storage. This stack
+   * is implemented by the following 3 data members
+   */
+  ULONG          stackSize;
+  ULONG          stackMaxSize;
+  ULONG*         stackToVisit;
+
+#define ENUMSTATSGT_SIZE_INCREMENT 10
+};
+
+/*
+ * Method definitions for the IEnumSTATSTGImpl class.
+ */
+HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface(
+	    IEnumSTATSTG*     iface,
+	    REFIID            riid,
+	    void**            ppvObject);
+        
+ULONG WINAPI IEnumSTATSTGImpl_AddRef(
+            IEnumSTATSTG*     iface); 
+        
+ULONG WINAPI IEnumSTATSTGImpl_Release(
+            IEnumSTATSTG*     iface);
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Next(
+            IEnumSTATSTG*     iface,
+	    ULONG             celt,
+	    STATSTG*          rgelt,
+	    ULONG*            pceltFetched);
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Skip(
+            IEnumSTATSTG*     iface,
+	    ULONG             celt);
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Reset(
+            IEnumSTATSTG* iface);
+        
+HRESULT WINAPI IEnumSTATSTGImpl_Clone(
+            IEnumSTATSTG*     iface,
+	    IEnumSTATSTG**    ppenum);
+
+IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct(
+            StorageImpl* This,
+	    ULONG          firstPropertyNode);
+
+void IEnumSTATSTGImpl_Destroy(
+            IEnumSTATSTGImpl* This);
+
+void IEnumSTATSTGImpl_PushSearchNode(
+	    IEnumSTATSTGImpl* This,
+	    ULONG             nodeToPush);
+
+ULONG IEnumSTATSTGImpl_PopSearchNode(
+            IEnumSTATSTGImpl* This,
+	    BOOL            remove);
+
+ULONG IEnumSTATSTGImpl_FindProperty(
+            IEnumSTATSTGImpl* This,
+	    const OLECHAR*  lpszPropName,
+	    StgProperty*      buffer);
+
+INT IEnumSTATSTGImpl_FindParentProperty(
+  IEnumSTATSTGImpl *This,
+  ULONG             childProperty,
+  StgProperty      *currentProperty,
+  ULONG            *propertyId);
+
+
+/****************************************************************************
+ * StgStreamImpl definitions.
+ *
+ * This class imlements the IStream32 inteface and represents a stream
+ * located inside a storage object.
+ */
+struct StgStreamImpl
+{
+  ICOM_VFIELD(IStream);  /* Needs to be the first item in the stuct
+				    * since we want to cast this in a IStream pointer */
+  
+  /*
+   * Reference count
+   */
+  ULONG		     ref;
+
+  /*
+   * Storage that is the parent(owner) of the stream
+   */
+  StorageBaseImpl* parentStorage;
+
+  /*
+   * Access mode of this stream.
+   */
+  DWORD grfMode;
+
+  /*
+   * Index of the property that owns (points to) this stream.
+   */
+  ULONG              ownerProperty;
+
+  /*
+   * Helper variable that contains the size of the stream
+   */
+  ULARGE_INTEGER     streamSize;
+
+  /*
+   * This is the current position of the cursor in the stream
+   */
+  ULARGE_INTEGER     currentPosition;
+  
+  /*
+   * The information in the stream is represented by a chain of small blocks
+   * or a chain of large blocks. Depending on the case, one of the two
+   * following variabled points to that information.
+   */
+  BlockChainStream*      bigBlockChain;
+  SmallBlockChainStream* smallBlockChain;
+  
+};
+
+/*
+ * Method definition for the StgStreamImpl class.
+ */
+StgStreamImpl* StgStreamImpl_Construct(
+		StorageBaseImpl* parentStorage,
+    DWORD            grfMode,
+    ULONG            ownerProperty);
+
+void StgStreamImpl_Destroy(
+                StgStreamImpl* This);
+
+void StgStreamImpl_OpenBlockChain(
+                StgStreamImpl* This);
+
+HRESULT WINAPI StgStreamImpl_QueryInterface(
+		IStream*      iface,
+		REFIID         riid,		/* [in] */          
+		void**         ppvObject);  /* [iid_is][out] */ 
+        
+ULONG WINAPI StgStreamImpl_AddRef(
+		IStream*      iface);
+        
+ULONG WINAPI StgStreamImpl_Release(
+		IStream*      iface);
+        
+HRESULT WINAPI StgStreamImpl_Read( 
+	        IStream*      iface,
+		void*          pv,        /* [length_is][size_is][out] */
+		ULONG          cb,        /* [in] */                     
+		ULONG*         pcbRead);  /* [out] */                    
+        
+HRESULT WINAPI StgStreamImpl_Write(
+		IStream*      iface,
+		const void*    pv,          /* [size_is][in] */ 
+		ULONG          cb,          /* [in] */          
+		ULONG*         pcbWritten); /* [out] */         
+        
+HRESULT WINAPI StgStreamImpl_Seek( 
+		IStream*      iface,
+		LARGE_INTEGER   dlibMove,         /* [in] */ 
+		DWORD           dwOrigin,         /* [in] */ 
+		ULARGE_INTEGER* plibNewPosition); /* [out] */
+        
+HRESULT WINAPI StgStreamImpl_SetSize( 
+	        IStream*      iface,
+		ULARGE_INTEGER  libNewSize);  /* [in] */ 
+        
+HRESULT WINAPI StgStreamImpl_CopyTo( 
+		IStream*      iface,
+		IStream*      pstm,         /* [unique][in] */ 
+		ULARGE_INTEGER  cb,           /* [in] */         
+		ULARGE_INTEGER* pcbRead,      /* [out] */        
+		ULARGE_INTEGER* pcbWritten);  /* [out] */        
+
+HRESULT WINAPI StgStreamImpl_Commit( 
+	    	IStream*      iface,
+		DWORD           grfCommitFlags); /* [in] */ 
+        
+HRESULT WINAPI StgStreamImpl_Revert( 
+		IStream*  iface);
+        
+HRESULT WINAPI StgStreamImpl_LockRegion( 
+		IStream*     iface,
+		ULARGE_INTEGER libOffset,   /* [in] */ 
+		ULARGE_INTEGER cb,          /* [in] */ 
+		DWORD          dwLockType); /* [in] */ 
+        
+HRESULT WINAPI StgStreamImpl_UnlockRegion( 
+		IStream*     iface,
+		ULARGE_INTEGER libOffset,   /* [in] */ 
+	        ULARGE_INTEGER cb,          /* [in] */ 
+		DWORD          dwLockType); /* [in] */ 
+        
+HRESULT WINAPI StgStreamImpl_Stat( 
+		IStream*     iface,
+	        STATSTG*       pstatstg,     /* [out] */
+	        DWORD          grfStatFlag); /* [in] */ 
+        
+HRESULT WINAPI StgStreamImpl_Clone( 
+		IStream*     iface,
+		IStream**    ppstm);       /* [out] */ 
+
+
+/********************************************************************************
+ * The StorageUtl_ functions are miscelaneous utility functions. Most of which are
+ * abstractions used to read values from file buffers without having to worry 
+ * about bit order
+ */
+void StorageUtl_ReadWord(void* buffer, ULONG offset, WORD* value);
+void StorageUtl_WriteWord(void* buffer, ULONG offset, WORD value);
+void StorageUtl_ReadDWord(void* buffer, ULONG offset, DWORD* value);
+void StorageUtl_WriteDWord(void* buffer, ULONG offset, DWORD value);
+void StorageUtl_ReadDWords(void *buffer, ULONG offset, DWORD *values,
+			   ULONG len);
+void StorageUtl_ReadGUID(void* buffer, ULONG offset, GUID* value);
+void StorageUtl_WriteGUID(void* buffer, ULONG offset, GUID* value);
+void StorageUtl_CopyPropertyToSTATSTG(STATSTG*     destination,
+					     StgProperty* source,
+					     int          statFlags);
+
+/****************************************************************************
+ * BlockChainStream definitions.
+ *
+ * The BlockChainStream class is a utility class that is used to create an
+ * abstraction of the big block chains in the storage file.
+ */
+struct BlockChainStream
+{
+  StorageImpl* parentStorage;
+  ULONG*       headOfStreamPlaceHolder;
+  ULONG        ownerPropertyIndex;
+  ULONG        lastBlockNoInSequence;
+  ULONG        lastBlockNoInSequenceIndex;
+  ULONG        tailIndex;
+  ULONG        numBlocks;
+  BOOL         lazyInitComplete;
+};
+
+/*
+ * Methods for the BlockChainStream class.
+ */
+BlockChainStream* BlockChainStream_Construct(
+		StorageImpl* parentStorage,	
+		ULONG*         headOfStreamPlaceHolder,
+		ULONG          propertyIndex);
+
+void BlockChainStream_Destroy(
+		BlockChainStream* This);
+
+ULONG BlockChainStream_GetHeadOfChain(
+		BlockChainStream* This);
+
+BOOL BlockChainStream_ReadAt(
+		BlockChainStream* This,
+		ULARGE_INTEGER offset,
+		ULONG          size,
+		void*          buffer,
+		ULONG*         bytesRead);
+
+BOOL BlockChainStream_WriteAt(
+		BlockChainStream* This,
+		ULARGE_INTEGER offset,
+		ULONG          size,
+		const void*    buffer,
+		ULONG*         bytesWritten);
+
+BOOL BlockChainStream_SetSize(
+		BlockChainStream* This,
+		ULARGE_INTEGER    newSize);
+
+ULARGE_INTEGER BlockChainStream_GetSize(
+    BlockChainStream* This);
+
+ULONG BlockChainStream_GetCount(
+    BlockChainStream* This);
+
+/****************************************************************************
+ * SmallBlockChainStream definitions.
+ *
+ * The SmallBlockChainStream class is a utility class that is used to create an
+ * abstraction of the small block chains in the storage file.
+ */
+struct SmallBlockChainStream
+{
+  StorageImpl* parentStorage;
+  ULONG          ownerPropertyIndex;
+};
+
+/*
+ * Methods of the SmallBlockChainStream class.
+ */
+SmallBlockChainStream* SmallBlockChainStream_Construct(
+	       StorageImpl* parentStorage,	
+	       ULONG          propertyIndex);
+
+void SmallBlockChainStream_Destroy(
+	       SmallBlockChainStream* This);
+
+ULONG SmallBlockChainStream_GetHeadOfChain(
+	       SmallBlockChainStream* This);
+
+ULONG SmallBlockChainStream_GetNextBlockInChain(
+	       SmallBlockChainStream* This,
+	       ULONG                  blockIndex);
+
+void SmallBlockChainStream_SetNextBlockInChain(
+         SmallBlockChainStream* This,
+         ULONG                  blockIndex,
+         ULONG                  nextBlock);
+
+void SmallBlockChainStream_FreeBlock(
+         SmallBlockChainStream* This,
+         ULONG                  blockIndex);
+
+ULONG SmallBlockChainStream_GetNextFreeBlock(
+         SmallBlockChainStream* This);
+
+BOOL SmallBlockChainStream_ReadAt(
+	       SmallBlockChainStream* This,
+	       ULARGE_INTEGER offset,
+	       ULONG          size,
+	       void*          buffer,
+	       ULONG*         bytesRead);
+
+BOOL SmallBlockChainStream_WriteAt(
+	       SmallBlockChainStream* This,
+	       ULARGE_INTEGER offset,
+	       ULONG          size,
+	       const void*    buffer,
+	       ULONG*         bytesWritten);
+
+BOOL SmallBlockChainStream_SetSize(
+	       SmallBlockChainStream* This,
+	       ULARGE_INTEGER          newSize);
+
+ULARGE_INTEGER SmallBlockChainStream_GetSize(
+         SmallBlockChainStream* This);
+
+ULONG SmallBlockChainStream_GetCount(
+         SmallBlockChainStream* This);
+
+
+#endif /* __STORAGE32_H__ */
+
+
+
Index: trunk/src/ole32/new/stubs.cpp
===================================================================
--- trunk/src/ole32/new/stubs.cpp	(revision 3456)
+++ trunk/src/ole32/new/stubs.cpp	(revision 3456)
@@ -0,0 +1,667 @@
+/* $Id: stubs.cpp,v 1.1 2000-04-27 22:18:30 davidr Exp $ */
+/* 
+ * Win32 COM/OLE stubs for OS/2
+ * 
+ * 1/7/99
+ * 
+ * Copyright 1999 David J. Raison
+ * Copyright 1998 Sander van Leeuwen
+ * 
+ * 
+ * Project Odin Software License can be found in LICENSE.TXT
+ * 
+ */
+
+#include "ole32.h"
+
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API DllDebugObjectRPCHook()
+{
+    dprintf(("OLE32: DllDebugObjectRPCHook, UNKNOWN API - stub"));
+    return 0;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
+{
+    dprintf(("OLE32: DllGetClassObject - stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API DllGetClassObjectWOW()
+{
+    dprintf(("OLE32: DllGetClassObjectWOW, UNKNOWN API - stub"));
+    return 0;
+}
+//*****************************************************************************
+//*****************************************************************************
+HRESULT WIN32API CoCreateFreeThreadedMarshaler(LPUNKNOWN punkOuter,
+                                                  LPUNKNOWN *ppunkMarshaler)
+{
+    dprintf(("OLE32: CoCreateFreeThreadedMarshaler- stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoDisconnectObject(IUnknown *pUnk, DWORD dwReserved)
+{
+    dprintf(("OLE32: CoDisconnectObject - stub"));
+    return S_OK;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoGetCallerTID()
+{
+    dprintf(("OLE32: CoGetCallerTID, UNKNOWN API - stub"));
+    return 0;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoGetCurrentLogicalThreadId()
+{
+    dprintf(("OLE32: CoGetCurrentLogicalThreadId, UNKNOWN API - stub"));
+    return 0;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid,
+                                                   LPVOID *ppv)
+{
+    dprintf(("OLE32: CoGetInterfaceAndReleaseStream - stub"));
+    return E_INVALIDARG;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk,
+                                        DWORD dwDestContext, LPVOID pvDestContext,
+                                        DWORD mshlflags)
+{
+    dprintf(("OLE32: CoGetMarshalSizeMax - stub"));
+    return CO_E_NOTINITIALIZED;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoGetPSClsid(REFIID riid, CLSID *pclsid)
+{
+    dprintf(("OLE32: CoGetPSClsid - stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoGetStandardMarshal(REFIID riid, IUnknown *pUnk, DWORD dwDestContext,
+                                         LPVOID pvDestContext, DWORD mshlflags,
+                                         LPMARSHAL *ppMarshal)
+{
+    dprintf(("OLE32: CoGetStandardMarshal - stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoGetState()
+{
+    dprintf(("OLE32: CoGetState, UNKNOWN API - stub"));
+    return 0;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID pclsidNew)
+{
+    dprintf(("OLE32: CoGetTreatAsClass - stub"));
+    return S_FALSE;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoInitializeWOW()
+{
+    dprintf(("OLE32: CoInitializeWOW, UNKNOWN API - stub"));
+    return 0;
+}
+//*******************************************************************************
+//*******************************************************************************
+BOOL WIN32API CoIsHandlerConnected(LPUNKNOWN pUnk)
+{
+    dprintf(("OLE32: CoIsHandlerConnected - stub"));
+    return FALSE;
+}
+//*******************************************************************************
+//*******************************************************************************
+BOOL WIN32API CoIsOle1Class(REFCLSID rclsid)
+{
+    dprintf(("OLE32: CoIsOle1Class - stub"));
+    return S_FALSE;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoMarshalHresult(IStream *pStm, HRESULT hresult)
+{
+    dprintf(("OLE32: CoMarshalHresult - stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoMarshalInterThreadInterfaceInStream(REFIID riid,
+                                                          LPUNKNOWN pUnk,
+                                                          LPSTREAM *ppStm)
+{
+    dprintf(("OLE32: CoMarshalInterThreadInterfaceInStream - stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoMarshalInterface(IStream *pStm, REFIID riid, IUnknown *pUnk,
+                                       DWORD dwDestContext, void *pvDestContext,
+                                       DWORD mshlflags)
+{
+    dprintf(("OLE32: CoMarshalInterface - stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoQueryReleaseObject()
+{
+    dprintf(("OLE32: CoQueryReleaseObject, UNKNOWN API - stub"));
+    return 0;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
+{
+    dprintf(("OLE32: CoRegisterMallocSpy - stub"));
+    return CO_E_OBJISREG;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoReleaseMarshalData(IStream *pStm)
+{
+    dprintf(("OLE32: CoReleaseMarshalData - stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoRevokeMallocSpy()
+{
+    dprintf(("OLE32: CoRevokeMallocSpy - stub"));
+    return E_ACCESSDENIED;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoSetState(LPDWORD state)
+{
+    dprintf(("OLE32: CoSetState (%p),stub!\n", state));
+    if (state) *state = 0;
+    return S_OK;
+}
+
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew)
+{
+    dprintf(("OLE32: CoTreatAsClass - stub"));
+    return E_INVALIDARG;
+}
+//*******************************************************************************
+//*******************************************************************************
+void WIN32API CoUnloadingWOW()
+{
+    dprintf(("OLE32: CoUnloadingWOW, UNKNOWN API - stub"));
+    return ;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoUnmarshalHresult(LPSTREAM pStm, HRESULT *phresult)
+{
+    dprintf(("OLE32: CoUnmarshalHresult - stub"));
+    return S_OK;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoUnmarshalInterface(IStream *pSTm, REFIID riid, void **ppv)
+{
+    dprintf(("OLE32: CoUnmarshalInterface - stub"));
+    return S_OK;
+}
+
+//******************************************************************************
+//******************************************************************************
+HRESULT WIN32API BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID iidResult,
+                                LPVOID *ppvResult)
+{
+    dprintf(("OLE32: BindMoniker- stub"));
+    return MK_E_NOOBJECT;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CreatePointerMoniker(LPUNKNOWN punk, LPMONIKER *ppmk)
+{
+    dprintf(("OLE32: CreatePointerMoniker - stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API EnableHookObject()
+{
+    dprintf(("OLE32: EnableHookObject, UNKNOWN API - stub"));
+    return 0;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API GetConvertStg(IStorage *pStg)
+{
+    dprintf(("OLE32: GetConvertStg - stub"));
+    return STG_E_ACCESSDENIED;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API GetDocumentBitStg()
+{
+    dprintf(("OLE32: GetDocumentBitStg, UNKNOWN API - stub"));
+    return 0;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API GetHookInterface()
+{
+    dprintf(("OLE32: GetHookInterface, UNKNOWN API - stub"));
+    return 0;
+}
+//*******************************************************************************
+//*******************************************************************************
+BOOL WIN32API IsAccelerator(HACCEL hAccel, int cAccelEntries, struct tagMSG* lpMsg, WORD* lpwCmd)
+{
+    dprintf(("OLE32: IsAccelerator - stub"));
+    return FALSE;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API IsValidIid(DWORD Iid)
+{
+    dprintf(("OLE32: IsValidIid, obsolete - stub"));
+    return E_INVALIDARG;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API IsValidPtrIn(DWORD ptrIn)
+{
+    dprintf(("OLE32: IsValidPtrIn, obsolete - stub"));
+    return E_INVALIDARG;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API IsValidPtrOut(DWORD ptrOut)
+{
+    dprintf(("OLE32: IsValidPtrOut, obsolete - stub"));
+    return E_INVALIDARG;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API MkParseDisplayName(LPBC pbc, LPSTR szUserName, ULONG *lpchEaten,
+                                        LPMONIKER *ppmk)
+{
+    dprintf(("OLE32: MkParseDisplayName - stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API MonikerRelativePathTo(LPMONIKER pmkSrc, LPMONIKER pmkDest,
+                                          LPMONIKER *ppmkRelPath, BOOL dwReserved )
+{
+    dprintf(("OLE32: MonikerRelativePathTo - stub"));
+    return E_OUTOFMEMORY;
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleConvertIStorageToOLESTREAMEx(LPSTORAGE	pStg,
+						 CLIPFORMAT	ctFormat,
+						 LONG		lWidth,
+						 LONG		lHeight,
+						 DWORD		dwSize,
+						 LPSTGMEDIUM	pmedium,
+						 LPOLESTREAM	lpolestream)
+{
+    dprintf(("OLE32: OleConvertIStorageToOLESTREAMEx - stub"));
+    return(E_INVALIDARG);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleConvertOLESTREAMToIStorageEx(LPOLESTREAM	lpolestream,
+                                                 LPSTORAGE	pstg,
+                                                 CLIPFORMAT *	ctFormat,
+                                                 LONG *		plWidth,
+                                                 LONG *		plHeight,
+                                                 DWORD *	pdwSize,
+                                                 LPSTGMEDIUM	pmedium)
+{
+    dprintf(("OLE32: OleConvertOLESTREAMToIStorageEx - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleCreate(REFCLSID rclsid, REFIID riid, DWORD renderopt,
+                              FORMATETC *pFormatEtc, IOleClientSite *pClientSite,
+                              IStorage *pStg, void **ppvObject)
+{
+    dprintf(("OLE32: OleCreate - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleCreateEmbeddingHelper(REFCLSID clsid, LPUNKNOWN pUnkOuter,
+                                             DWORD flags, LPCLASSFACTORY pCF,
+                                             REFIID riid, LPVOID *ppvObj)
+{
+    dprintf(("OLE32: OleCreateEmbeddingHelper - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleCreateFromFile(REFCLSID rclsid, LPCOLESTR lpszFileName,
+                                      REFIID riid,
+                                      DWORD renderopt, LPFORMATETC pFormatEtc,
+                                      LPOLECLIENTSITE pClientSite, LPSTORAGE pStg,
+                                      LPVOID *ppvObj)
+{
+    dprintf(("OLE32: OleCreateFromFile - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleCreateLink(LPMONIKER lpmkLinkSrc, REFIID riid,
+                                  DWORD renderopt, LPFORMATETC pFormatEtc,
+                                  LPOLECLIENTSITE lpClientSite, LPSTORAGE pStg,
+                                  LPVOID *ppvObj)
+{
+    dprintf(("OLE32: OleCreateLink - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleCreateLinkFromData(LPDATAOBJECT pSrcDataObj, REFIID riid,
+                                          DWORD renderopt, LPFORMATETC pFormatEtc,
+                                          LPOLECLIENTSITE pClientSite, LPSTORAGE pStg,
+                                          LPVOID *ppvObj)
+{
+    dprintf(("OLE32: OleCreateLinkFromData - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleCreateLinkToFile(LPCOLESTR lpszFileName, REFIID riid, DWORD renderopt,
+                                        LPFORMATETC pFormatEtc, IOleClientSite *pClientSite,
+                                        IStorage *pStg, void **ppvObj)
+{
+    dprintf(("OLE32: OleCreateLinkToFile - stub"));
+    return(STG_E_FILENOTFOUND);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleCreateStaticFromData(LPDATAOBJECT pSrcDataObj, REFIID riid,
+                                            DWORD renderopt, LPFORMATETC pFormatEtc,
+                                            LPOLECLIENTSITE pClientSite, LPSTORAGE pStg,
+                                            LPVOID *ppvObj)
+{
+    dprintf(("OLE32: OleCreateStaticFromData - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew)
+{
+    dprintf(("OLE32: OleDoAutoConvert - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleDraw(IUnknown *pUnk, DWORD dwAspect, HDC hdcDraw,
+                            LPCRECT lprcBounds)
+{
+    dprintf(("OLE32: OleDraw - stub"));
+    return(E_INVALIDARG);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleDuplicateData(HANDLE hSrc, CLIPFORMAT cfFormat, UINT uiFlags)
+{
+    dprintf(("OLE32: OleDuplicateData - stub"));
+    return(NULL);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew)
+{
+    dprintf(("OLE32: OleGetAutoConvert - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HGLOBAL WIN32API OleGetIconOfClass(REFCLSID rclsid, LPOLESTR lpszLabel, BOOL fUseTypeAsLabel)
+{
+    dprintf(("OLE32: OleGetIconOfClass - stub"));
+    return(NULL);
+}
+//*******************************************************************************
+//*******************************************************************************
+HGLOBAL WIN32API OleGetIconOfFile(LPOLESTR lpszPath, BOOL fUseTypeAsLabel)
+{
+    dprintf(("OLE32: OleGetIconOfFile - stub"));
+    return(NULL);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleInitializeWOW()
+{
+    dprintf(("OLE32: OleInitializeWOW, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+BOOL WIN32API OleIsRunning(LPOLEOBJECT pObject)
+{
+    dprintf(("OLE32: OleIsRunning - stub"));
+    return(FALSE);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses)
+{
+    dprintf(("OLE32: OleLockRunning - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HGLOBAL WIN32API OleMetafilePictFromIconAndLabel(HICON hIcon, LPOLESTR lpszLabel,
+                                                    LPOLESTR lpszSourceFile,
+                                                    UINT iIconIndex)
+{
+    dprintf(("OLE32: OleMetafilePictFromIconAndLabel - stub"));
+    return(NULL);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleNoteObjectVisible(LPUNKNOWN pUnknown, BOOL fVisible)
+{
+    dprintf(("OLE32: OleNoteObjectVisible - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleQueryLinkFromData(IDataObject *pSrcDataObject)
+{
+    dprintf(("OLE32: OleQueryLinkFromData - stub"));
+    return(S_FALSE);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleRegEnumFormatEtc(REFCLSID clsid, DWORD dwDirection,
+                                        LPENUMFORMATETC *ppenumFormatetc)
+{
+    dprintf(("OLE32: OleRegEnumFormatEtc - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleRegEnumVerbs(REFCLSID clsid, LPENUMOLEVERB *ppenumOleVerb)
+{
+    dprintf(("OLE32: OleRegEnumVerbs - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleRun(LPUNKNOWN pUnknown)
+{
+    dprintf(("OLE32: OleRun - stub"));
+    return(E_UNEXPECTED);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew)
+{
+    dprintf(("OLE32: OleSetAutoConvert - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OleTranslateAccelerator
+   (LPOLEINPLACEFRAME		lpFrame,
+    LPOLEINPLACEFRAMEINFO	lpFrameInfo,
+    struct tagMSG *		lpmsg)
+{
+    dprintf(("OLE32: OleTranslateAccelerator - stub"));
+    return(S_FALSE);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API OpenOrCreateStream()
+{
+    dprintf(("OLE32: OpenOrCreateStream, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API ReadFmtUserTypeStg(IStorage *pStg, CLIPFORMAT *pcf,
+                                       LPWSTR *lplpszUserType)
+{
+    dprintf(("OLE32: ReadFmtUserTypeStg - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API ReadOleStg()
+{
+    dprintf(("OLE32: ReadOleStg, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API ReadStringStream()
+{
+    dprintf(("OLE32: ReadStringStream, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API SetConvertStg(IStorage *pStg, BOOL fConvert)
+{
+    dprintf(("OLE32: SetConvertStg - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API SetDocumentBitStg()
+{
+    dprintf(("OLE32: SetDocumentBitStg, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API StgSetTimes(WCHAR const *lpszName, FILETIME const *pctime,
+                                FILETIME const *patime, FILETIME const *pmtime)
+{
+    dprintf(("OLE32: StgSetTimes - stub"));
+    return(STG_E_FILENOTFOUND);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API UtConvertDvtd16toDvtd32()
+{
+    dprintf(("OLE32: UtConvertDvtd16toDvtd32, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API UtConvertDvtd32toDvtd16()
+{
+    dprintf(("OLE32: UtConvertDvtd32toDvtd16, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API UtGetDvtd16Info()
+{
+    dprintf(("OLE32: UtGetDvtd16Info, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API UtGetDvtd32Info()
+{
+    dprintf(("OLE32: UtGetDvtd32Info, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API WriteFmtUserTypeStg(LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType)
+{
+    dprintf(("OLE32: WriteFmtUserTypeStg - stub"));
+    return(STG_E_MEDIUMFULL);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API WriteOleStg()
+{
+    dprintf(("OLE32: WriteOleStg, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API WriteStringStream()
+{
+    dprintf(("OLE32: WriteStringStream, UNKNOWN API - stub"));
+    return(E_OUTOFMEMORY);
+}
+//*******************************************************************************
+//*******************************************************************************
+
+HRESULT WIN32API CoImpersonateClient()		// DCOM - obj_clientserver.h
+{
+    dprintf(("OLE32: CoImpersonateClient - Stub"));
+    return(S_OK);
+}
+
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoInitializeSecurity(		// DCOM - obj_clientserver.h
+    PSECURITY_DESCRIPTOR         pSecDesc,
+    LONG                         cAuthSvc,
+    SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
+    void                        *pReserved1,
+    DWORD                        dwAuthnLevel,
+    DWORD                        dwImpLevel,
+    void                        *pReserved2,
+    DWORD                        dwCapabilities,
+    void                        *pReserved3 )
+{
+    dprintf(("OLE32: CoInitializeSecurity - Stub"));
+    return(S_OK);
+}
+
+//*******************************************************************************
+//*******************************************************************************
+HRESULT WIN32API CoRegisterSurrogate(LPSURROGATE pSurrogate)	// NT4 SP2, Win95b+
+{
+    dprintf(("OLE32: CoRegisterSurrogate - Stub"));
+    return(S_OK);
+}
+
Index: trunk/src/ole32/new/taskmem.cpp
===================================================================
--- trunk/src/ole32/new/taskmem.cpp	(revision 3456)
+++ trunk/src/ole32/new/taskmem.cpp	(revision 3456)
@@ -0,0 +1,253 @@
+/* $Id: taskmem.cpp,v 1.1 2000-04-27 22:18:30 davidr Exp $ */
+/*
+ *
+ * Project Odin Software License can be found in LICENSE.TXT
+ *
+ */
+/*
+ * COM/OLE memory management functions.
+ *
+ * 7/7/99
+ *
+ * Copyright 1999 David J. Raison
+ *
+ * Some portions from Wine Implementation
+ *	Copyright 1997	Marcus Meissner
+ */
+
+#include "ole32.h"
+
+#include "oString.h"
+
+// ======================================================================
+// Prototypes.
+// ======================================================================
+static HRESULT WIN32API IMalloc_fnQueryInterface(LPMALLOC iface, REFIID refiid, LPVOID * obj) ;
+static ULONG WIN32API IMalloc_fnAddRef(LPMALLOC iface) ;
+static ULONG WIN32API IMalloc_fnRelease(LPMALLOC iface) ;
+static LPVOID WIN32API IMalloc_fnAlloc(LPMALLOC iface, DWORD cb);
+static LPVOID WIN32API IMalloc_fnRealloc(LPMALLOC iface, LPVOID pv, DWORD cb);
+static VOID WIN32API IMalloc_fnFree(LPMALLOC iface, LPVOID pv);
+static DWORD WIN32API IMalloc_fnGetSize(const IMalloc* iface, LPVOID pv);
+static INT WIN32API IMalloc_fnDidAlloc(const IMalloc* iface, LPVOID pv);
+static LPVOID WIN32API IMalloc_fnHeapMinimize(LPMALLOC iface);
+static LPMALLOC IMalloc_Constructor();
+
+// ======================================================================
+// Local Data
+// ======================================================================
+typedef struct
+{
+        /* IUnknown fields */
+        ICOM_VTABLE(IMalloc)* lpvtbl;
+        DWORD                   ref;
+} IMallocImpl;
+
+static ICOM_VTABLE(IMalloc) VT_IMalloc =
+{
+    IMalloc_fnQueryInterface,
+    IMalloc_fnAddRef,
+    IMalloc_fnRelease,
+    IMalloc_fnAlloc,
+    IMalloc_fnRealloc,
+    IMalloc_fnFree,
+    IMalloc_fnGetSize,
+    IMalloc_fnDidAlloc,
+    IMalloc_fnHeapMinimize
+};
+
+LPMALLOC currentMalloc32 = NULL;
+
+// ======================================================================
+// Public API's
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// CoTaskMemAlloc
+// ----------------------------------------------------------------------
+LPVOID WIN32API CoTaskMemAlloc(ULONG cb)
+{
+    dprintf(("OLE32: CoTaskMemAlloc(%lu)", cb));
+
+    return HeapAlloc(GetProcessHeap(), 0, cb);
+}
+
+// ----------------------------------------------------------------------
+// CoTaskMemFree
+// ----------------------------------------------------------------------
+void WIN32API CoTaskMemFree(void *pv)
+{
+    dprintf(("OLE32: CoTaskMemFree"));
+
+    HeapFree(GetProcessHeap(), 0, pv);
+}
+
+// ----------------------------------------------------------------------
+// CoTaskMemRealloc
+// ----------------------------------------------------------------------
+LPVOID WIN32API CoTaskMemRealloc(LPVOID pv, ULONG cb)
+{
+    dprintf(("OLE32: CoTaskMemRealloc(%lu)", cb));
+
+    return HeapReAlloc(GetProcessHeap(), 0, pv, cb);
+}
+
+// ----------------------------------------------------------------------
+// CoGetMalloc
+// ----------------------------------------------------------------------
+HRESULT WIN32API CoGetMalloc(DWORD dwMemContext, LPMALLOC *ppMalloc)
+{
+    dprintf(("OLE32: CoGetMalloc"));
+
+    if(!currentMalloc32)
+	currentMalloc32 = IMalloc_Constructor();
+
+    *ppMalloc = currentMalloc32;
+    return S_OK;
+}
+
+// ----------------------------------------------------------------------
+// IsValidInterface32
+// ----------------------------------------------------------------------
+BOOL WIN32API IsValidInterface( LPUNKNOWN punk)	/* [in] interface to be tested */
+{
+    dprintf(("OLE32: IsValidInterface"));
+
+    return !(IsBadReadPtr(punk, 4)
+        || IsBadReadPtr(ICOM_VTBL(punk), 4)
+        || IsBadReadPtr(ICOM_VTBL(punk)->fnQueryInterface, 9)
+        || IsBadCodePtr((FARPROC)ICOM_VTBL(punk)->fnQueryInterface) );
+}
+
+// ======================================================================
+// IMalloc implementation
+// ======================================================================
+
+// ----------------------------------------------------------------------
+// IMalloc_Constructor
+// ----------------------------------------------------------------------
+static LPMALLOC IMalloc_Constructor()
+{
+    IMallocImpl* This;
+
+    This = (IMallocImpl*)HeapAlloc(GetProcessHeap(), 0, sizeof(IMallocImpl));
+    This->lpvtbl = &VT_IMalloc;
+    This->ref = 1;
+    return (LPMALLOC)This;
+}
+
+// ----------------------------------------------------------------------
+// IMalloc_fnQueryInterface
+// ----------------------------------------------------------------------
+static HRESULT WIN32API IMalloc_fnQueryInterface(LPMALLOC iface, REFIID refiid, LPVOID * obj)
+{
+    ICOM_THIS(IMallocImpl, iface);
+
+    oStringA	tRefiid(refiid);
+    dprintf(("OLE32: IMalloc_fnQueryInterface(%s)", (char *)tRefiid));
+
+    if (!memcmp(&IID_IUnknown, refiid, sizeof(IID_IUnknown))
+    	|| !memcmp(&IID_IMalloc, refiid, sizeof(IID_IMalloc)))
+    {
+	*obj = This;
+	return S_OK;
+    }
+    return OLE_E_ENUM_NOMORE;
+}
+
+// ----------------------------------------------------------------------
+// IMalloc_fnAddRef
+// ----------------------------------------------------------------------
+static ULONG WIN32API IMalloc_fnAddRef(LPMALLOC iface)
+{
+    ICOM_THIS(IMallocImpl, iface);
+
+    dprintf(("OLE32: IMalloc_fnAddRef"));
+
+    return 1; /* cannot be freed */
+}
+
+// ----------------------------------------------------------------------
+// IMalloc_fnRelease
+// ----------------------------------------------------------------------
+static ULONG WIN32API IMalloc_fnRelease(LPMALLOC iface)
+{
+    ICOM_THIS(IMallocImpl, iface);
+
+    dprintf(("OLE32: IMalloc_fnRelease"));
+
+    return 1; /* cannot be freed */
+}
+
+// ----------------------------------------------------------------------
+// IMalloc_fnAlloc
+// ----------------------------------------------------------------------
+static LPVOID WIN32API IMalloc_fnAlloc(LPMALLOC iface, DWORD cb)
+{
+    ICOM_THIS(IMallocImpl, iface);
+
+    dprintf(("OLE32: IMalloc_fnAlloc"));
+
+    return HeapAlloc(GetProcessHeap(), 0, cb);
+}
+
+// ----------------------------------------------------------------------
+// IMalloc_fnRealloc
+// ----------------------------------------------------------------------
+static LPVOID WIN32API IMalloc_fnRealloc(LPMALLOC iface, LPVOID pv, DWORD cb)
+{
+    ICOM_THIS(IMallocImpl, iface);
+
+    dprintf(("OLE32: IMalloc_fnRealloc"));
+
+    return HeapReAlloc(GetProcessHeap(), 0, pv, cb);
+}
+
+// ----------------------------------------------------------------------
+// IMalloc_fnFree
+// ----------------------------------------------------------------------
+static VOID WIN32API IMalloc_fnFree(LPMALLOC iface, LPVOID pv)
+{
+    ICOM_THIS(IMallocImpl, iface);
+
+    dprintf(("OLE32: IMalloc_fnFree"));
+
+    HeapFree(GetProcessHeap(), 0, pv);
+}
+
+// ----------------------------------------------------------------------
+// IMalloc_fnGetSize
+// ----------------------------------------------------------------------
+static DWORD WIN32API IMalloc_fnGetSize(const IMalloc* iface, LPVOID pv)
+{
+    ICOM_THIS(IMallocImpl, iface);
+
+    dprintf(("OLE32: IMalloc_fnGetSize"));
+
+    return HeapSize(GetProcessHeap(), 0, pv);
+}
+
+// ----------------------------------------------------------------------
+// IMalloc_fnDidAlloc
+// ----------------------------------------------------------------------
+static INT WIN32API IMalloc_fnDidAlloc(const IMalloc* iface, LPVOID pv)
+{
+    ICOM_THIS(IMallocImpl, iface);
+
+    dprintf(("OLE32: IMalloc_fnDidAlloc"));
+
+    return -1;
+}
+
+// ----------------------------------------------------------------------
+// IMalloc_fnHeapMinimize
+// ----------------------------------------------------------------------
+static LPVOID WIN32API IMalloc_fnHeapMinimize(LPMALLOC iface)
+{
+    ICOM_THIS(IMallocImpl, iface);
+
+    dprintf(("OLE32: IMalloc_fnHeapMinimize"));
+
+    return NULL;
+}
+
