set svn:eol-style to native
[reactos.git] / reactos / lib / ole32 / compositemoniker.c
index 9ab1d0c..cb3015c 100644 (file)
-/*\r
- * CompositeMonikers implementation\r
- *\r
- * Copyright 1999  Noomen Hamza\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- */\r
-\r
-#include <assert.h>\r
-#include <stdarg.h>\r
-#include <string.h>\r
-\r
-#define COBJMACROS\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "winuser.h"\r
-#include "winerror.h"\r
-#include "wine/debug.h"\r
-#include "wine/unicode.h"\r
-#include "ole2.h"\r
-#include "moniker.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(ole);\r
-\r
-const CLSID CLSID_CompositeMoniker = {\r
-  0x309, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}\r
-};\r
-\r
-#define  BLOCK_TAB_SIZE 5 /* represent the first size table and it's increment block size */\r
-\r
-/* CompositeMoniker data structure */\r
-typedef struct CompositeMonikerImpl{\r
-\r
-    IMonikerVtbl*  lpvtbl1;  /* VTable relative to the IMoniker interface.*/\r
-\r
-    /* The ROT (RunningObjectTable implementation) uses the IROTData\r
-     * interface to test whether two monikers are equal. That's why IROTData\r
-     * interface is implemented by monikers.\r
-     */\r
-    IROTDataVtbl*  lpvtbl2;  /* VTable relative to the IROTData interface.*/\r
-\r
-    ULONG ref; /* reference counter for this object */\r
-\r
-    IMoniker** tabMoniker; /* dynamaic table containing all components (monikers) of this composite moniker */\r
-\r
-    ULONG    tabSize;      /* size of tabMoniker */\r
-\r
-    ULONG    tabLastIndex;  /* first free index in tabMoniker */\r
-\r
-} CompositeMonikerImpl;\r
-\r
-\r
-/* EnumMoniker data structure */\r
-typedef struct EnumMonikerImpl{\r
-\r
-    IEnumMonikerVtbl *lpVtbl;  /* VTable relative to the IEnumMoniker interface.*/\r
-\r
-    ULONG ref; /* reference counter for this object */\r
-\r
-    IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */\r
-\r
-    ULONG      tabSize; /* size of tabMoniker */\r
-\r
-    ULONG      currentPos;  /* index pointer on the current moniker */\r
-\r
-} EnumMonikerImpl;\r
-\r
-\r
-static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk);\r
-\r
-/*******************************************************************************\r
- *        CompositeMoniker_QueryInterface\r
- *******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)\r
-{\r
-    CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;\r
-\r
-    TRACE("(%p,%p,%p)\n",This,riid,ppvObject);\r
-\r
-    /* Perform a sanity check on the parameters.*/\r
-    if ( (This==0) || (ppvObject==0) )\r
-       return E_INVALIDARG;\r
-\r
-    /* Initialize the return parameter */\r
-    *ppvObject = 0;\r
-\r
-    /* Compare the riid with the interface IDs implemented by this object.*/\r
-    if (IsEqualIID(&IID_IUnknown, riid) ||\r
-        IsEqualIID(&IID_IPersist, riid) ||\r
-        IsEqualIID(&IID_IPersistStream, riid) ||\r
-        IsEqualIID(&IID_IMoniker, riid)\r
-       )\r
-        *ppvObject = iface;\r
-    else if (IsEqualIID(&IID_IROTData, riid))\r
-        *ppvObject = (IROTData*)&(This->lpvtbl2);\r
-\r
-    /* Check that we obtained an interface.*/\r
-    if ((*ppvObject)==0)\r
-        return E_NOINTERFACE;\r
-\r
-    /* Query Interface always increases the reference count by one when it is successful */\r
-    IMoniker_AddRef(iface);\r
-\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_AddRef\r
- ******************************************************************************/\r
-static ULONG WINAPI\r
-CompositeMonikerImpl_AddRef(IMoniker* iface)\r
-{\r
-    CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;\r
-\r
-    TRACE("(%p)\n",This);\r
-\r
-    return InterlockedIncrement(&This->ref);\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_Release\r
- ******************************************************************************/\r
-static ULONG WINAPI\r
-CompositeMonikerImpl_Release(IMoniker* iface)\r
-{\r
-    CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;\r
-    ULONG i;\r
-    ULONG ref;\r
-\r
-    TRACE("(%p)\n",This);\r
-\r
-    ref = InterlockedDecrement(&This->ref);\r
-\r
-    /* destroy the object if there's no more reference on it */\r
-    if (ref == 0){\r
-\r
-        /* release all the components before destroying this object */\r
-        for (i=0;i<This->tabLastIndex;i++)\r
-            IMoniker_Release(This->tabMoniker[i]);\r
-\r
-        HeapFree(GetProcessHeap(),0,This->tabMoniker);\r
-        HeapFree(GetProcessHeap(),0,This);\r
-    }\r
-    return ref;\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_GetClassID\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)\r
-{\r
-    TRACE("(%p,%p),stub!\n",iface,pClassID);\r
-\r
-    if (pClassID==NULL)\r
-        return E_POINTER;\r
-\r
-    *pClassID = CLSID_CompositeMoniker;\r
-\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_IsDirty\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_IsDirty(IMoniker* iface)\r
-{\r
-    /* Note that the OLE-provided implementations of the IPersistStream::IsDirty\r
-       method in the OLE-provided moniker interfaces always return S_FALSE because\r
-       their internal state never changes. */\r
-\r
-    TRACE("(%p)\n",iface);\r
-\r
-    return S_FALSE;\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_Load\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)\r
-{\r
-    HRESULT res;\r
-    DWORD constant;\r
-    CLSID clsid;\r
-    WCHAR string[1]={0};\r
-\r
-    CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;\r
-\r
-    TRACE("(%p,%p)\n",iface,pStm);\r
-\r
-    /* this function call OleLoadFromStream function for each moniker within this object */\r
-\r
-    /* read the a constant written by CompositeMonikerImpl_Save (see CompositeMonikerImpl_Save for more details)*/\r
-    res=IStream_Read(pStm,&constant,sizeof(DWORD),NULL);\r
-\r
-    if (SUCCEEDED(res)&& constant!=3)\r
-        return E_FAIL;\r
-\r
-    while(1){\r
-#if 0\r
-        res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);\r
-#endif\r
-        res=ReadClassStm(pStm,&clsid);\r
-        DPRINTF("res=%ld",res);\r
-        if (FAILED(res))\r
-            break;\r
-\r
-        if (IsEqualIID(&clsid,&CLSID_FileMoniker)){\r
-            res=CreateFileMoniker(string,&This->tabMoniker[This->tabLastIndex]);\r
-            if (FAILED(res))\r
-                break;\r
-            res=IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);\r
-            if (FAILED(res))\r
-                break;\r
-        }\r
-        else if (IsEqualIID(&clsid,&CLSID_ItemMoniker)){\r
-            CreateItemMoniker(string,string,&This->tabMoniker[This->tabLastIndex]);\r
-            if (res!=S_OK)\r
-                break;\r
-            IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);\r
-            if (FAILED(res))\r
-                break;\r
-        }\r
-        else if (IsEqualIID(&clsid,&CLSID_AntiMoniker)){\r
-            CreateAntiMoniker(&This->tabMoniker[This->tabLastIndex]);\r
-            if (FAILED(res))\r
-                break;\r
-            IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);\r
-            if (FAILED(res))\r
-                break;\r
-        }\r
-        else if (IsEqualIID(&clsid,&CLSID_CompositeMoniker))\r
-            return E_FAIL;\r
-\r
-        else\r
-        {\r
-            FIXME("()\n");\r
-            /* FIXME: To whoever wrote this code: It's either return or break. it cannot be both! */\r
-            break;\r
-            return E_NOTIMPL;\r
-        }\r
-\r
-        /* resize the table if needed */\r
-        if (++This->tabLastIndex==This->tabSize){\r
-\r
-            This->tabSize+=BLOCK_TAB_SIZE;\r
-            This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));\r
-\r
-            if (This->tabMoniker==NULL)\r
-            return E_OUTOFMEMORY;\r
-        }\r
-    }\r
-\r
-    return res;\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_Save\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)\r
-{\r
-    HRESULT res;\r
-    IEnumMoniker *enumMk;\r
-    IMoniker *pmk;\r
-    DWORD constant=3;\r
-\r
-    TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);\r
-\r
-    /* This function calls OleSaveToStream function for each moniker within\r
-     * this object.\r
-     * When I tested this function in windows, I usually found this constant\r
-     * at the beginning of the stream. I don't known why (there's no\r
-     * indication in the specification) !\r
-     */\r
-    res=IStream_Write(pStm,&constant,sizeof(constant),NULL);\r
-\r
-    IMoniker_Enum(iface,TRUE,&enumMk);\r
-\r
-    while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){\r
-\r
-        res=OleSaveToStream((IPersistStream*)pmk,pStm);\r
-\r
-        IMoniker_Release(pmk);\r
-\r
-        if (FAILED(res)){\r
-\r
-            IEnumMoniker_Release(pmk);\r
-            return res;\r
-        }\r
-    }\r
-\r
-    IEnumMoniker_Release(enumMk);\r
-\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_GetSizeMax\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)\r
-{\r
-    IEnumMoniker *enumMk;\r
-    IMoniker *pmk;\r
-    ULARGE_INTEGER ptmpSize;\r
-\r
-    /* The sizeMax of this object is calculated by calling  GetSizeMax on\r
-     * each moniker within this object then summing all returned values\r
-     */\r
-\r
-    TRACE("(%p,%p)\n",iface,pcbSize);\r
-\r
-    if (pcbSize!=NULL)\r
-        return E_POINTER;\r
-\r
-    pcbSize->u.LowPart =0;\r
-    pcbSize->u.HighPart=0;\r
-\r
-    IMoniker_Enum(iface,TRUE,&enumMk);\r
-\r
-    while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)){\r
-\r
-        IMoniker_GetSizeMax(pmk,&ptmpSize);\r
-\r
-        IMoniker_Release(pmk);\r
-\r
-        pcbSize->u.LowPart +=ptmpSize.u.LowPart;\r
-        pcbSize->u.HighPart+=ptmpSize.u.HighPart;\r
-    }\r
-\r
-    IEnumMoniker_Release(enumMk);\r
-\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *                  CompositeMoniker_BindToObject\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,\r
-               IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)\r
-{\r
-    HRESULT   res;\r
-    IRunningObjectTable *prot;\r
-    IMoniker *tempMk,*antiMk,*mostRigthMk;\r
-    IEnumMoniker *enumMoniker;\r
-\r
-    TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);\r
-\r
-    if (ppvResult==NULL)\r
-        return E_POINTER;\r
-\r
-    *ppvResult=0;\r
-    /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */\r
-    /* object for the requested interface pointer. */\r
-    if(pmkToLeft==NULL){\r
-\r
-        res=IBindCtx_GetRunningObjectTable(pbc,&prot);\r
-\r
-        if (SUCCEEDED(res)){\r
-\r
-            /* if the requested class was loaded before ! we don't need to reload it */\r
-            res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);\r
-\r
-            if (res==S_OK)\r
-                return res;\r
-        }\r
-    }\r
-    else{\r
-        /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */\r
-        /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */\r
-\r
-        IMoniker_Enum(iface,FALSE,&enumMoniker);\r
-        IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);\r
-        IEnumMoniker_Release(enumMoniker);\r
-\r
-        res=CreateAntiMoniker(&antiMk);\r
-        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);\r
-        IMoniker_Release(antiMk);\r
-\r
-        res=CompositeMonikerImpl_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult);\r
-\r
-        IMoniker_Release(tempMk);\r
-        IMoniker_Release(mostRigthMk);\r
-    }\r
-\r
-    return res;\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_BindToStorage\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,\r
-               IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)\r
-{\r
-    HRESULT   res;\r
-    IMoniker *tempMk,*antiMk,*mostRigthMk;\r
-    IEnumMoniker *enumMoniker;\r
-\r
-    TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);\r
-\r
-    *ppvResult=0;\r
-\r
-    /* This method recursively calls BindToStorage on the rightmost component of the composite, */\r
-    /* passing the rest of the composite as the pmkToLeft parameter for that call. */\r
-\r
-    if (pmkToLeft!=NULL){\r
-\r
-        IMoniker_Enum(iface,FALSE,&enumMoniker);\r
-        IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);\r
-        IEnumMoniker_Release(enumMoniker);\r
-\r
-        res=CreateAntiMoniker(&antiMk);\r
-        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);\r
-        IMoniker_Release(antiMk);\r
-\r
-        res=CompositeMonikerImpl_BindToStorage(mostRigthMk,pbc,tempMk,riid,ppvResult);\r
-\r
-        IMoniker_Release(tempMk);\r
-\r
-        IMoniker_Release(mostRigthMk);\r
-\r
-        return res;\r
-    }\r
-    else\r
-        return IMoniker_BindToStorage(iface,pbc,NULL,riid,ppvResult);\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_Reduce\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,\r
-               IMoniker** ppmkToLeft, IMoniker** ppmkReduced)\r
-{\r
-    HRESULT   res;\r
-    IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk;\r
-    IEnumMoniker *enumMoniker;\r
-\r
-    TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);\r
-\r
-    if (ppmkReduced==NULL)\r
-        return E_POINTER;\r
-\r
-    /* This method recursively calls Reduce for each of its component monikers. */\r
-\r
-    if (ppmkToLeft==NULL){\r
-\r
-        IMoniker_Enum(iface,FALSE,&enumMoniker);\r
-        IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);\r
-        IEnumMoniker_Release(enumMoniker);\r
-\r
-        res=CreateAntiMoniker(&antiMk);\r
-        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);\r
-        IMoniker_Release(antiMk);\r
-\r
-        return CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);\r
-    }\r
-    else if (*ppmkToLeft==NULL)\r
-\r
-        return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);\r
-\r
-    else{\r
-\r
-        /* separate the composite moniker in to left and right moniker */\r
-        IMoniker_Enum(iface,FALSE,&enumMoniker);\r
-        IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);\r
-        IEnumMoniker_Release(enumMoniker);\r
-\r
-        res=CreateAntiMoniker(&antiMk);\r
-        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);\r
-        IMoniker_Release(antiMk);\r
-\r
-        /* If any of the components  reduces itself, the method returns S_OK and passes back a composite */\r
-        /* of the reduced components */\r
-        if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) &&\r
-            CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk)\r
-           )\r
-\r
-            return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced);\r
-\r
-        else{\r
-            /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/\r
-\r
-            IMoniker_AddRef(iface);\r
-\r
-            *ppmkReduced=iface;\r
-\r
-            return MK_S_REDUCED_TO_SELF;\r
-        }\r
-    }\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_ComposeWith\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,\r
-               BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)\r
-{\r
-    TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);\r
-\r
-    if ((ppmkComposite==NULL)||(pmkRight==NULL))\r
-       return E_POINTER;\r
-\r
-    *ppmkComposite=0;\r
-\r
-    /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */\r
-    /* otherwise, the method returns the result of combining the two monikers by calling the */\r
-    /* CreateGenericComposite function */\r
-\r
-    if (fOnlyIfNotGeneric)\r
-        return MK_E_NEEDGENERIC;\r
-\r
-    return CreateGenericComposite(iface,pmkRight,ppmkComposite);\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_Enum\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)\r
-{\r
-    CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;\r
-\r
-    TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);\r
-\r
-    if (ppenumMoniker == NULL)\r
-        return E_POINTER;\r
-\r
-    return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_IsEqual\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)\r
-{\r
-    IEnumMoniker *enumMoniker1,*enumMoniker2;\r
-    IMoniker *tempMk1,*tempMk2;\r
-    HRESULT res1,res2,res;\r
-\r
-    TRACE("(%p,%p)\n",iface,pmkOtherMoniker);\r
-\r
-    if (pmkOtherMoniker==NULL)\r
-        return S_FALSE;\r
-\r
-    /* This method returns S_OK if the components of both monikers are equal when compared in the */\r
-    /* left-to-right order.*/\r
-    IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);\r
-\r
-    if (enumMoniker1==NULL)\r
-        return S_FALSE;\r
-\r
-    IMoniker_Enum(iface,TRUE,&enumMoniker2);\r
-\r
-    while(1){\r
-\r
-        res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);\r
-        res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);\r
-\r
-        if((res1==S_OK)&&(res2==S_OK)){\r
-\r
-            if(IMoniker_IsEqual(tempMk1,tempMk2)==S_FALSE){\r
-                res= S_FALSE;\r
-                break;\r
-            }\r
-            else\r
-                continue;\r
-        }\r
-        else if ( (res1==S_FALSE) && (res2==S_FALSE) ){\r
-                res = S_OK;\r
-                break;\r
-        }\r
-        else{\r
-            res = S_FALSE;\r
-            break;\r
-        }\r
-\r
-        if (res1==S_OK)\r
-            IMoniker_Release(tempMk1);\r
-\r
-        if (res2==S_OK)\r
-            IMoniker_Release(tempMk2);\r
-    }\r
-\r
-    IEnumMoniker_Release(enumMoniker1);\r
-    IEnumMoniker_Release(enumMoniker2);\r
-\r
-    return res;\r
-}\r
-/******************************************************************************\r
- *        CompositeMoniker_Hash\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)\r
-{\r
-    IEnumMoniker *enumMoniker;\r
-    IMoniker *tempMk;\r
-    HRESULT res;\r
-    DWORD tempHash;\r
-\r
-    TRACE("(%p,%p)\n",iface,pdwHash);\r
-\r
-    if (pdwHash==NULL)\r
-        return E_POINTER;\r
-\r
-    res = IMoniker_Enum(iface,TRUE,&enumMoniker);\r
-    if(FAILED(res))\r
-        return res;\r
-\r
-    while(1){\r
-        res=IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL);\r
-        if(FAILED(res))\r
-            break;\r
-            \r
-        res = IMoniker_Hash(tempMk, &tempHash);\r
-        if(FAILED(res))\r
-            break;\r
-        *pdwHash = (*pdwHash * 37) + tempHash;\r
-        \r
-        IMoniker_Release(tempMk);\r
-    }\r
-\r
-    IEnumMoniker_Release(enumMoniker);\r
-\r
-    return res;\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_IsRunning\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc,\r
-               IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)\r
-{\r
-    IRunningObjectTable* rot;\r
-    HRESULT res;\r
-    IMoniker *tempMk,*antiMk,*mostRigthMk;\r
-    IEnumMoniker *enumMoniker;\r
-\r
-    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);\r
-\r
-    /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/\r
-    if (pmkToLeft!=NULL){\r
-\r
-        CreateGenericComposite(pmkToLeft,iface,&tempMk);\r
-\r
-        res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);\r
-\r
-        IMoniker_Release(tempMk);\r
-\r
-        return res;\r
-    }\r
-    else\r
-        /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */\r
-        /* to this moniker */\r
-\r
-        if (pmkNewlyRunning!=NULL)\r
-\r
-            if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)\r
-                return S_OK;\r
-\r
-            else\r
-                return S_FALSE;\r
-\r
-        else{\r
-\r
-            if (pbc==NULL)\r
-                return E_POINTER;\r
-\r
-            /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */\r
-            /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls   */\r
-            /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */\r
-            /* the composite as the pmkToLeft parameter for that call.                                   */\r
-\r
-             res=IBindCtx_GetRunningObjectTable(pbc,&rot);\r
-\r
-            if (FAILED(res))\r
-                return res;\r
-\r
-            res = IRunningObjectTable_IsRunning(rot,iface);\r
-            IRunningObjectTable_Release(rot);\r
-\r
-            if(res==S_OK)\r
-                return S_OK;\r
-\r
-            else{\r
-\r
-                IMoniker_Enum(iface,FALSE,&enumMoniker);\r
-                IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);\r
-                IEnumMoniker_Release(enumMoniker);\r
-\r
-                res=CreateAntiMoniker(&antiMk);\r
-                res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);\r
-                IMoniker_Release(antiMk);\r
-\r
-                res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning);\r
-\r
-                IMoniker_Release(tempMk);\r
-                IMoniker_Release(mostRigthMk);\r
-\r
-                return res;\r
-            }\r
-        }\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_GetTimeOfLastChange\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,\r
-               IMoniker* pmkToLeft, FILETIME* pCompositeTime)\r
-{\r
-    IRunningObjectTable* rot;\r
-    HRESULT res;\r
-    IMoniker *tempMk,*antiMk,*mostRigthMk;\r
-    IEnumMoniker *enumMoniker;\r
-\r
-    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);\r
-\r
-    if (pCompositeTime==NULL)\r
-        return E_INVALIDARG;\r
-\r
-    /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to  */\r
-    /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls  */\r
-    /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */\r
-    /* of the composite as the pmkToLeft parameter for that call.                                       */\r
-    if (pmkToLeft!=NULL){\r
-\r
-        res=CreateGenericComposite(pmkToLeft,iface,&tempMk);\r
-\r
-        res=IBindCtx_GetRunningObjectTable(pbc,&rot);\r
-\r
-        if (FAILED(res))\r
-            return res;\r
-\r
-        if (IRunningObjectTable_GetTimeOfLastChange(rot,tempMk,pCompositeTime)==S_OK)\r
-            return res;\r
-        else\r
-\r
-            IMoniker_Enum(iface,FALSE,&enumMoniker);\r
-            IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);\r
-            IEnumMoniker_Release(enumMoniker);\r
-\r
-            res=CreateAntiMoniker(&antiMk);\r
-            res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);\r
-            IMoniker_Release(antiMk);\r
-\r
-            res=CompositeMonikerImpl_GetTimeOfLastChange(mostRigthMk,pbc,tempMk,pCompositeTime);\r
-\r
-            IMoniker_Release(tempMk);\r
-            IMoniker_Release(mostRigthMk);\r
-\r
-            return res;\r
-    }\r
-    else\r
-        return IMoniker_GetTimeOfLastChange(iface,pbc,NULL,pCompositeTime);\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_Inverse\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)\r
-{\r
-    HRESULT res;\r
-    IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk;\r
-    IEnumMoniker *enumMoniker;\r
-\r
-    TRACE("(%p,%p)\n",iface,ppmk);\r
-\r
-    if (ppmk==NULL)\r
-        return E_POINTER;\r
-\r
-    /* This method returns a composite moniker that consists of the inverses of each of the components */\r
-    /* of the original composite, stored in reverse order */\r
-\r
-    res=CreateAntiMoniker(&antiMk);\r
-    res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);\r
-    IMoniker_Release(antiMk);\r
-\r
-    if (tempMk==NULL)\r
-\r
-        return IMoniker_Inverse(iface,ppmk);\r
-\r
-    else{\r
-\r
-        IMoniker_Enum(iface,FALSE,&enumMoniker);\r
-        IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);\r
-        IEnumMoniker_Release(enumMoniker);\r
-\r
-        IMoniker_Inverse(mostRigthMk,&mostRigthInvMk);\r
-        CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);\r
-\r
-        res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk);\r
-\r
-        IMoniker_Release(tempMk);\r
-        IMoniker_Release(mostRigthMk);\r
-        IMoniker_Release(tempInvMk);\r
-        IMoniker_Release(mostRigthInvMk);\r
-\r
-        return res;\r
-    }\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_CommonPrefixWith\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,\r
-               IMoniker** ppmkPrefix)\r
-{\r
-    DWORD mkSys;\r
-    HRESULT res1,res2;\r
-    IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;\r
-    IEnumMoniker *enumMoniker1,*enumMoniker2;\r
-    ULONG i,nbCommonMk=0;\r
-\r
-    /* If the other moniker is a composite, this method compares the components of each composite from left  */\r
-    /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */\r
-    /* of the leftmost components were common to both monikers.                                              */\r
-\r
-    if (ppmkPrefix==NULL)\r
-        return E_POINTER;\r
-\r
-    *ppmkPrefix=0;\r
-\r
-    if (pmkOther==NULL)\r
-        return MK_E_NOPREFIX;\r
-\r
-    IMoniker_IsSystemMoniker(pmkOther,&mkSys);\r
-\r
-    if((mkSys==MKSYS_GENERICCOMPOSITE)){\r
-\r
-        IMoniker_Enum(iface,TRUE,&enumMoniker1);\r
-        IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);\r
-\r
-        while(1){\r
-\r
-            res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);\r
-            res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);\r
-\r
-            if ((res1==S_FALSE) && (res2==S_FALSE)){\r
-\r
-                /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/\r
-                *ppmkPrefix=iface;\r
-                IMoniker_AddRef(iface);\r
-                return  MK_S_US;\r
-            }\r
-            else if ((res1==S_OK) && (res2==S_OK)){\r
-\r
-                if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)\r
-\r
-                    nbCommonMk++;\r
-\r
-                else\r
-                    break;\r
-\r
-            }\r
-            else if (res1==S_OK){\r
-\r
-                /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */\r
-                /* ppmkPrefix to the other moniker.                                                       */\r
-                *ppmkPrefix=pmkOther;\r
-                return MK_S_HIM;\r
-            }\r
-            else{\r
-                /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */\r
-                /* to this moniker.                                                                          */\r
-                *ppmkPrefix=iface;\r
-                return MK_S_ME;\r
-            }\r
-        }\r
-\r
-        IEnumMoniker_Release(enumMoniker1);\r
-        IEnumMoniker_Release(enumMoniker2);\r
-\r
-        /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */\r
-        if (nbCommonMk==0)\r
-            return MK_E_NOPREFIX;\r
-\r
-        IEnumMoniker_Reset(enumMoniker1);\r
-\r
-        IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);\r
-\r
-        /* if we have more than one commun moniker the result will be a composite moniker */\r
-        if (nbCommonMk>1){\r
-\r
-            /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/\r
-            IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);\r
-            CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);\r
-            IMoniker_Release(tempMk1);\r
-            IMoniker_Release(tempMk2);\r
-\r
-            /* compose all common monikers in a composite moniker */\r
-            for(i=0;i<nbCommonMk;i++){\r
-\r
-                IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);\r
-\r
-                CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);\r
-\r
-                IMoniker_Release(*ppmkPrefix);\r
-\r
-                IMoniker_Release(tempMk1);\r
-\r
-                *ppmkPrefix=tempMk2;\r
-            }\r
-            return S_OK;\r
-        }\r
-        else{\r
-            /* if we have only one commun moniker the result will be a simple moniker which is the most-left one*/\r
-            *ppmkPrefix=tempMk1;\r
-\r
-            return S_OK;\r
-        }\r
-    }\r
-    else{\r
-        /* If the other moniker is not a composite, the method simply compares it to the leftmost component\r
-         of this moniker.*/\r
-\r
-        IMoniker_Enum(iface,TRUE,&enumMoniker1);\r
-\r
-        IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);\r
-\r
-        if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){\r
-\r
-            *ppmkPrefix=pmkOther;\r
-\r
-            return MK_S_HIM;\r
-        }\r
-        else\r
-            return MK_E_NOPREFIX;\r
-    }\r
-}\r
-\r
-/***************************************************************************************************\r
- *        GetAfterCommonPrefix (local function)\r
- *  This function returns a moniker that consist of the remainder when the common prefix is removed\r
- ***************************************************************************************************/\r
-static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk)\r
-{\r
-    IMoniker *tempMk,*tempMk1,*tempMk2;\r
-    IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3;\r
-    ULONG nbRestMk=0;\r
-    DWORD mkSys;\r
-    HRESULT res1,res2;\r
-\r
-    *restMk=0;\r
-\r
-    /* to create an enumerator for pGenMk with current position pointed on the first element after common  */\r
-    /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop  */\r
-    /* on the first difference. */\r
-    IMoniker_Enum(pGenMk,TRUE,&enumMoniker1);\r
-\r
-    IMoniker_IsSystemMoniker(commonMk,&mkSys);\r
-\r
-    if (mkSys==MKSYS_GENERICCOMPOSITE){\r
-\r
-        IMoniker_Enum(commonMk,TRUE,&enumMoniker2);\r
-        while(1){\r
-\r
-            res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);\r
-            res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);\r
-\r
-            if ((res1==S_FALSE)||(res2==S_FALSE)){\r
-\r
-                if (res1==S_OK)\r
-\r
-                    nbRestMk++;\r
-\r
-                IMoniker_Release(tempMk1);\r
-                IMoniker_Release(tempMk1);\r
-\r
-                break;\r
-            }\r
-            IMoniker_Release(tempMk1);\r
-            IMoniker_Release(tempMk1);\r
-        }\r
-    }\r
-    else{\r
-        IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);\r
-        IMoniker_Release(tempMk1);\r
-    }\r
-\r
-    /* count the number of elements in the enumerator after the common prefix */\r
-    IEnumMoniker_Clone(enumMoniker1,&enumMoniker3);\r
-\r
-    for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++)\r
-\r
-        IMoniker_Release(tempMk);\r
-\r
-    if (nbRestMk==0)\r
-        return;\r
-\r
-    /* create a generic composite moniker with monikers located after the common prefix */\r
-    IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);\r
-\r
-    if (nbRestMk==1){\r
-\r
-        *restMk= tempMk1;\r
-        return;\r
-    }\r
-    else {\r
-\r
-        IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);\r
-\r
-        CreateGenericComposite(tempMk1,tempMk2,restMk);\r
-\r
-        IMoniker_Release(tempMk1);\r
-\r
-        IMoniker_Release(tempMk2);\r
-\r
-        while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){\r
-\r
-            CreateGenericComposite(*restMk,tempMk1,&tempMk2);\r
-\r
-            IMoniker_Release(tempMk1);\r
-\r
-            IMoniker_Release(*restMk);\r
-\r
-            *restMk=tempMk2;\r
-        }\r
-    }\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_RelativePathTo\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther,\r
-               IMoniker** ppmkRelPath)\r
-{\r
-    HRESULT res;\r
-    IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0;\r
-\r
-    TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath);\r
-\r
-    if (ppmkRelPath==NULL)\r
-        return E_POINTER;\r
-\r
-    *ppmkRelPath=0;\r
-\r
-    /* This method finds the common prefix of the two monikers and creates two monikers that consist     */\r
-    /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */\r
-    /* of this moniker and composes the remainder of the other moniker on the right of it.               */\r
-\r
-    /* finds the common prefix of the two monikers */\r
-    res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk);\r
-\r
-    /* if there's no common prefix or the two moniker are equal the relative is the other moniker */\r
-    if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){\r
-\r
-        *ppmkRelPath=pmkOther;\r
-        IMoniker_AddRef(pmkOther);\r
-        return MK_S_HIM;\r
-    }\r
-\r
-    GetAfterCommonPrefix(iface,commonMk,&restThisMk);\r
-    GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk);\r
-\r
-    /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */\r
-    /* moniker when the common prefix is removed                                                           */\r
-    if (res==MK_S_HIM){\r
-\r
-        IMoniker_Inverse(restThisMk,ppmkRelPath);\r
-        IMoniker_Release(restThisMk);\r
-    }\r
-    /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */\r
-    /* when the common prefix is removed                                                                     */\r
-    else if (res==MK_S_ME){\r
-\r
-        *ppmkRelPath=restOtherMk;\r
-        IMoniker_AddRef(restOtherMk);\r
-    }\r
-    /* the relative path is the inverse for the remainder of this moniker and the remainder of the other  */\r
-    /* moniker on the right of it.                                                                        */\r
-    else if (res==S_OK){\r
-\r
-        IMoniker_Inverse(restThisMk,&invRestThisMk);\r
-        IMoniker_Release(restThisMk);\r
-        CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath);\r
-        IMoniker_Release(invRestThisMk);\r
-        IMoniker_Release(restOtherMk);\r
-    }\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_GetDisplayName\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,\r
-               IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)\r
-{\r
-    ULONG lengthStr=1;\r
-    IEnumMoniker *enumMoniker;\r
-    IMoniker* tempMk;\r
-    LPOLESTR tempStr;\r
-\r
-    TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);\r
-\r
-    if (ppszDisplayName==NULL)\r
-        return E_POINTER;\r
-\r
-    *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR));\r
-\r
-    if (*ppszDisplayName==NULL)\r
-        return E_OUTOFMEMORY;\r
-\r
-    /* This method returns the concatenation of the display names returned by each component moniker of */\r
-    /* the composite */\r
-\r
-    **ppszDisplayName=0;\r
-\r
-    IMoniker_Enum(iface,TRUE,&enumMoniker);\r
-\r
-    while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){\r
-\r
-        IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr);\r
-\r
-        lengthStr+=lstrlenW(tempStr);\r
-\r
-        *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));\r
-\r
-        if (*ppszDisplayName==NULL)\r
-            return E_OUTOFMEMORY;\r
-\r
-        strcatW(*ppszDisplayName,tempStr);\r
-\r
-        CoTaskMemFree(tempStr);\r
-        IMoniker_Release(tempMk);\r
-    }\r
-\r
-    IEnumMoniker_Release(enumMoniker);\r
-\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_ParseDisplayName\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc,\r
-               IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten,\r
-               IMoniker** ppmkOut)\r
-{\r
-    IEnumMoniker *enumMoniker;\r
-    IMoniker *tempMk,*mostRigthMk,*antiMk;\r
-    /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/\r
-    /* passing everything else as the pmkToLeft parameter for that call. */\r
-\r
-    /* get the most right moniker */\r
-    IMoniker_Enum(iface,FALSE,&enumMoniker);\r
-    IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);\r
-    IEnumMoniker_Release(enumMoniker);\r
-\r
-    /* get the left moniker */\r
-    CreateAntiMoniker(&antiMk);\r
-    IMoniker_ComposeWith(iface,antiMk,0,&tempMk);\r
-    IMoniker_Release(antiMk);\r
-\r
-    return IMoniker_ParseDisplayName(mostRigthMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut);\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMoniker_IsSystemMoniker\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)\r
-{\r
-    TRACE("(%p,%p)\n",iface,pwdMksys);\r
-\r
-    if (!pwdMksys)\r
-        return E_POINTER;\r
-\r
-    (*pwdMksys)=MKSYS_GENERICCOMPOSITE;\r
-\r
-    return S_OK;\r
-}\r
-\r
-/*******************************************************************************\r
- *        CompositeMonikerIROTData_QueryInterface\r
- *******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,\r
-               VOID** ppvObject)\r
-{\r
-\r
-    ICOM_THIS_From_IROTData(IMoniker, iface);\r
-\r
-    TRACE("(%p,%p,%p)\n",iface,riid,ppvObject);\r
-\r
-    return CompositeMonikerImpl_QueryInterface(This, riid, ppvObject);\r
-}\r
-\r
-/***********************************************************************\r
- *        CompositeMonikerIROTData_AddRef\r
- */\r
-static ULONG WINAPI\r
-CompositeMonikerROTDataImpl_AddRef(IROTData *iface)\r
-{\r
-    ICOM_THIS_From_IROTData(IMoniker, iface);\r
-\r
-    TRACE("(%p)\n",iface);\r
-\r
-    return IMoniker_AddRef(This);\r
-}\r
-\r
-/***********************************************************************\r
- *        CompositeMonikerIROTData_Release\r
- */\r
-static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)\r
-{\r
-    ICOM_THIS_From_IROTData(IMoniker, iface);\r
-\r
-    TRACE("(%p)\n",iface);\r
-\r
-    return IMoniker_Release(This);\r
-}\r
-\r
-/******************************************************************************\r
- *        CompositeMonikerIROTData_GetComparaisonData\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-CompositeMonikerROTDataImpl_GetComparaisonData(IROTData* iface,\r
-               BYTE* pbData, ULONG cbMax, ULONG* pcbData)\r
-{\r
-    FIXME("(),stub!\n");\r
-    return E_NOTIMPL;\r
-}\r
-\r
-/******************************************************************************\r
- *        EnumMonikerImpl_QueryInterface\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)\r
-{\r
-    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;\r
-\r
-    TRACE("(%p,%p,%p)\n",This,riid,ppvObject);\r
-\r
-    /* Perform a sanity check on the parameters.*/\r
-    if ( (This==0) || (ppvObject==0) )\r
-       return E_INVALIDARG;\r
-\r
-    /* Initialize the return parameter */\r
-    *ppvObject = 0;\r
-\r
-    /* Compare the riid with the interface IDs implemented by this object.*/\r
-    if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))\r
-        *ppvObject = iface;\r
-\r
-    /* Check that we obtained an interface.*/\r
-    if ((*ppvObject)==0)\r
-        return E_NOINTERFACE;\r
-\r
-    /* Query Interface always increases the reference count by one when it is successful */\r
-    IEnumMoniker_AddRef(iface);\r
-\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *        EnumMonikerImpl_AddRef\r
- ******************************************************************************/\r
-static ULONG WINAPI\r
-EnumMonikerImpl_AddRef(IEnumMoniker* iface)\r
-{\r
-    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;\r
-\r
-    TRACE("(%p)\n",This);\r
-\r
-    return InterlockedIncrement(&This->ref);\r
-\r
-}\r
-\r
-/******************************************************************************\r
- *        EnumMonikerImpl_Release\r
- ******************************************************************************/\r
-static ULONG WINAPI\r
-EnumMonikerImpl_Release(IEnumMoniker* iface)\r
-{\r
-    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;\r
-    ULONG i;\r
-    ULONG ref;\r
-    TRACE("(%p)\n",This);\r
-\r
-    ref = InterlockedDecrement(&This->ref);\r
-\r
-    /* destroy the object if there's no more reference on it */\r
-    if (ref == 0) {\r
-\r
-        for(i=0;i<This->tabSize;i++)\r
-            IMoniker_Release(This->tabMoniker[i]);\r
-\r
-        HeapFree(GetProcessHeap(),0,This->tabMoniker);\r
-        HeapFree(GetProcessHeap(),0,This);\r
-    }\r
-    return ref;\r
-}\r
-\r
-/******************************************************************************\r
- *        EnumMonikerImpl_Next\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt,\r
-               ULONG* pceltFethed)\r
-{\r
-    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;\r
-    ULONG i;\r
-\r
-    /* retrieve the requested number of moniker from the current position */\r
-    for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++)\r
-\r
-        rgelt[i]=This->tabMoniker[This->currentPos++];\r
-\r
-    if (pceltFethed!=NULL)\r
-        *pceltFethed= i;\r
-\r
-    if (i==celt)\r
-        return S_OK;\r
-    else\r
-        return S_FALSE;\r
-}\r
-\r
-/******************************************************************************\r
- *        EnumMonikerImpl_Skip\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt)\r
-{\r
-    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;\r
-\r
-    if ((This->currentPos+celt) >= This->tabSize)\r
-        return S_FALSE;\r
-\r
-    This->currentPos+=celt;\r
-\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *        EnumMonikerImpl_Reset\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-EnumMonikerImpl_Reset(IEnumMoniker* iface)\r
-{\r
-\r
-    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;\r
-\r
-    This->currentPos=0;\r
-\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *        EnumMonikerImpl_Clone\r
- ******************************************************************************/\r
-static HRESULT WINAPI\r
-EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)\r
-{\r
-    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;\r
-\r
-    return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);\r
-}\r
-\r
-/********************************************************************************/\r
-/* Virtual function table for the IROTData class                                */\r
-static IEnumMonikerVtbl VT_EnumMonikerImpl =\r
-{\r
-    EnumMonikerImpl_QueryInterface,\r
-    EnumMonikerImpl_AddRef,\r
-    EnumMonikerImpl_Release,\r
-    EnumMonikerImpl_Next,\r
-    EnumMonikerImpl_Skip,\r
-    EnumMonikerImpl_Reset,\r
-    EnumMonikerImpl_Clone\r
-};\r
-\r
-/******************************************************************************\r
- *        EnumMonikerImpl_CreateEnumMoniker\r
- ******************************************************************************/\r
-static HRESULT\r
-EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize,\r
-               ULONG currentPos, BOOL leftToRigth, IEnumMoniker ** ppmk)\r
-{\r
-    EnumMonikerImpl* newEnumMoniker;\r
-    int i;\r
-\r
-    if (currentPos > tabSize)\r
-        return E_INVALIDARG;\r
-\r
-    newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));\r
-\r
-    if (newEnumMoniker == 0)\r
-        return STG_E_INSUFFICIENTMEMORY;\r
-\r
-    /* Initialize the virtual function table. */\r
-    newEnumMoniker->lpVtbl       = &VT_EnumMonikerImpl;\r
-    newEnumMoniker->ref          = 0;\r
-\r
-    newEnumMoniker->tabSize=tabSize;\r
-    newEnumMoniker->currentPos=currentPos;\r
-\r
-    newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(IMoniker));\r
-\r
-    if (newEnumMoniker->tabMoniker==NULL) {\r
-        HeapFree(GetProcessHeap(), 0, newEnumMoniker);\r
-        return E_OUTOFMEMORY;\r
-    }\r
-\r
-    if (leftToRigth)\r
-        for (i=0;i<tabSize;i++){\r
-\r
-            newEnumMoniker->tabMoniker[i]=tabMoniker[i];\r
-            IMoniker_AddRef(tabMoniker[i]);\r
-        }\r
-    else\r
-        for (i=tabSize-1;i>=0;i--){\r
-\r
-            newEnumMoniker->tabMoniker[tabSize-i-1]=tabMoniker[i];\r
-            IMoniker_AddRef(tabMoniker[i]);\r
-        }\r
-\r
-    *ppmk=(IEnumMoniker*)newEnumMoniker;\r
-\r
-    return S_OK;\r
-}\r
-\r
-/********************************************************************************/\r
-/* Virtual function table for the CompositeMonikerImpl class which includes     */\r
-/* IPersist, IPersistStream and IMoniker functions.                             */\r
-\r
-static IMonikerVtbl VT_CompositeMonikerImpl =\r
-{\r
-    CompositeMonikerImpl_QueryInterface,\r
-    CompositeMonikerImpl_AddRef,\r
-    CompositeMonikerImpl_Release,\r
-    CompositeMonikerImpl_GetClassID,\r
-    CompositeMonikerImpl_IsDirty,\r
-    CompositeMonikerImpl_Load,\r
-    CompositeMonikerImpl_Save,\r
-    CompositeMonikerImpl_GetSizeMax,\r
-    CompositeMonikerImpl_BindToObject,\r
-    CompositeMonikerImpl_BindToStorage,\r
-    CompositeMonikerImpl_Reduce,\r
-    CompositeMonikerImpl_ComposeWith,\r
-    CompositeMonikerImpl_Enum,\r
-    CompositeMonikerImpl_IsEqual,\r
-    CompositeMonikerImpl_Hash,\r
-    CompositeMonikerImpl_IsRunning,\r
-    CompositeMonikerImpl_GetTimeOfLastChange,\r
-    CompositeMonikerImpl_Inverse,\r
-    CompositeMonikerImpl_CommonPrefixWith,\r
-    CompositeMonikerImpl_RelativePathTo,\r
-    CompositeMonikerImpl_GetDisplayName,\r
-    CompositeMonikerImpl_ParseDisplayName,\r
-    CompositeMonikerImpl_IsSystemMoniker\r
-};\r
-\r
-/********************************************************************************/\r
-/* Virtual function table for the IROTData class.                               */\r
-static IROTDataVtbl VT_ROTDataImpl =\r
-{\r
-    CompositeMonikerROTDataImpl_QueryInterface,\r
-    CompositeMonikerROTDataImpl_AddRef,\r
-    CompositeMonikerROTDataImpl_Release,\r
-    CompositeMonikerROTDataImpl_GetComparaisonData\r
-};\r
-\r
-/******************************************************************************\r
- *         Composite-Moniker_Construct (local function)\r
- *******************************************************************************/\r
-static HRESULT\r
-CompositeMonikerImpl_Construct(CompositeMonikerImpl* This,\r
-               LPMONIKER pmkFirst, LPMONIKER pmkRest)\r
-{\r
-    DWORD mkSys;\r
-    IEnumMoniker *enumMoniker;\r
-    IMoniker *tempMk;\r
-    HRESULT res;\r
-\r
-    TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);\r
-\r
-    /* Initialize the virtual function table. */\r
-    This->lpvtbl1      = &VT_CompositeMonikerImpl;\r
-    This->lpvtbl2      = &VT_ROTDataImpl;\r
-    This->ref          = 0;\r
-\r
-    This->tabSize=BLOCK_TAB_SIZE;\r
-    This->tabLastIndex=0;\r
-\r
-    This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(IMoniker));\r
-    if (This->tabMoniker==NULL)\r
-        return E_OUTOFMEMORY;\r
-\r
-    IMoniker_IsSystemMoniker(pmkFirst,&mkSys);\r
-\r
-    /* put the first moniker contents in the beginning of the table */\r
-    if (mkSys!=MKSYS_GENERICCOMPOSITE){\r
-\r
-        This->tabMoniker[(This->tabLastIndex)++]=pmkFirst;\r
-        IMoniker_AddRef(pmkFirst);\r
-    }\r
-    else{\r
-\r
-        IMoniker_Enum(pmkFirst,TRUE,&enumMoniker);\r
-\r
-        while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){\r
-\r
-\r
-            if (++This->tabLastIndex==This->tabSize){\r
-\r
-                This->tabSize+=BLOCK_TAB_SIZE;\r
-                This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));\r
-\r
-                if (This->tabMoniker==NULL)\r
-                    return E_OUTOFMEMORY;\r
-            }\r
-        }\r
-\r
-        IEnumMoniker_Release(enumMoniker);\r
-    }\r
-\r
-    /* put the rest moniker contents after the first one and make simplification if needed */\r
-\r
-    IMoniker_IsSystemMoniker(pmkRest,&mkSys);\r
-\r
-    if (mkSys!=MKSYS_GENERICCOMPOSITE){\r
-\r
-        /* add a simple moniker to the moniker table */\r
-\r
-        res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk);\r
-\r
-        if (res==MK_E_NEEDGENERIC){\r
-\r
-            /* there's no simplification in this case */\r
-            This->tabMoniker[This->tabLastIndex]=pmkRest;\r
-\r
-            This->tabLastIndex++;\r
-\r
-            IMoniker_AddRef(pmkRest);\r
-        }\r
-        else if (tempMk==NULL){\r
-\r
-            /* we have an antimoniker after a simple moniker so we can make a simplification in this case */\r
-            IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);\r
-\r
-            This->tabLastIndex--;\r
-        }\r
-        else if (SUCCEEDED(res)){\r
-\r
-            /* the non-generic composition was successful so we can make a simplification in this case */\r
-            IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);\r
-\r
-            This->tabMoniker[This->tabLastIndex-1]=tempMk;\r
-        } else\r
-            return res;\r
-\r
-        /* resize tabMoniker if needed */\r
-        if (This->tabLastIndex==This->tabSize){\r
-\r
-            This->tabSize+=BLOCK_TAB_SIZE;\r
-\r
-            This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));\r
-\r
-            if (This->tabMoniker==NULL)\r
-            return E_OUTOFMEMORY;\r
-        }\r
-    }\r
-    else{\r
-\r
-        /* add a composite moniker to the moniker table (do the same thing\r
-         * for each moniker within the composite moniker as a simple moniker\r
-         * (see above for how to add a simple moniker case) )\r
-         */\r
-        IMoniker_Enum(pmkRest,TRUE,&enumMoniker);\r
-\r
-        while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){\r
-\r
-            res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk);\r
-\r
-            if (res==MK_E_NEEDGENERIC){\r
-\r
-                This->tabLastIndex++;\r
-            }\r
-            else if (tempMk==NULL){\r
-\r
-                IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);\r
-                IMoniker_Release(This->tabMoniker[This->tabLastIndex]);\r
-                This->tabLastIndex--;\r
-            }\r
-            else{\r
-\r
-                IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);\r
-\r
-                This->tabMoniker[This->tabLastIndex-1]=tempMk;\r
-            }\r
-\r
-            if (This->tabLastIndex==This->tabSize){\r
-\r
-                This->tabSize+=BLOCK_TAB_SIZE;\r
-\r
-                This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));\r
-\r
-                if (This->tabMoniker==NULL)\r
-                    return E_OUTOFMEMORY;\r
-            }\r
-        }\r
-\r
-        IEnumMoniker_Release(enumMoniker);\r
-    }\r
-\r
-    return S_OK;\r
-}\r
-\r
-/******************************************************************************\r
- *        CreateGenericComposite       [OLE32.@]\r
- ******************************************************************************/\r
-HRESULT WINAPI\r
-CreateGenericComposite(LPMONIKER pmkFirst, LPMONIKER pmkRest,\r
-               LPMONIKER* ppmkComposite)\r
-{\r
-    CompositeMonikerImpl* newCompositeMoniker = 0;\r
-    HRESULT        hr = S_OK;\r
-\r
-    TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite);\r
-\r
-    if (ppmkComposite==NULL)\r
-        return E_POINTER;\r
-\r
-    *ppmkComposite=0;\r
-\r
-    if (pmkFirst==NULL && pmkRest!=NULL){\r
-\r
-        *ppmkComposite=pmkRest;\r
-        return S_OK;\r
-    }\r
-    else if (pmkFirst!=NULL && pmkRest==NULL){\r
-        *ppmkComposite=pmkFirst;\r
-        return S_OK;\r
-    }\r
-    else  if (pmkFirst==NULL && pmkRest==NULL)\r
-        return S_OK;\r
-\r
-    newCompositeMoniker = HeapAlloc(GetProcessHeap(), 0,sizeof(CompositeMonikerImpl));\r
-\r
-    if (newCompositeMoniker == 0)\r
-        return STG_E_INSUFFICIENTMEMORY;\r
-\r
-    hr = CompositeMonikerImpl_Construct(newCompositeMoniker,pmkFirst,pmkRest);\r
-\r
-    if (FAILED(hr)){\r
-\r
-        HeapFree(GetProcessHeap(),0,newCompositeMoniker);\r
-        return hr;\r
-    }\r
-    if (newCompositeMoniker->tabLastIndex==1)\r
-\r
-        hr = IMoniker_QueryInterface(newCompositeMoniker->tabMoniker[0],&IID_IMoniker,(void**)ppmkComposite);\r
-    else\r
-\r
-        hr = IMoniker_QueryInterface((IMoniker*)newCompositeMoniker,&IID_IMoniker,(void**)ppmkComposite);\r
-\r
-    return hr;\r
-}\r
-\r
-/******************************************************************************\r
- *        MonikerCommonPrefixWith      [OLE32.@]\r
- ******************************************************************************/\r
-HRESULT WINAPI\r
-MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)\r
-{\r
-    FIXME("(),stub!\n");\r
-    return E_NOTIMPL;\r
-}\r
+/*
+ * CompositeMonikers implementation
+ *
+ * Copyright 1999  Noomen Hamza
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include <string.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winerror.h"
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "ole2.h"
+#include "moniker.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ole);
+
+const CLSID CLSID_CompositeMoniker = {
+  0x309, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}
+};
+
+#define  BLOCK_TAB_SIZE 5 /* represent the first size table and it's increment block size */
+
+/* CompositeMoniker data structure */
+typedef struct CompositeMonikerImpl{
+
+    IMonikerVtbl*  lpvtbl1;  /* VTable relative to the IMoniker interface.*/
+
+    /* The ROT (RunningObjectTable implementation) uses the IROTData
+     * interface to test whether two monikers are equal. That's why IROTData
+     * interface is implemented by monikers.
+     */
+    IROTDataVtbl*  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{
+
+    IEnumMonikerVtbl *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;
+
+
+static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk);
+
+/*******************************************************************************
+ *        CompositeMoniker_QueryInterface
+ *******************************************************************************/
+static HRESULT WINAPI
+CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
+{
+    CompositeMonikerImpl *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 */
+    IMoniker_AddRef(iface);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_AddRef
+ ******************************************************************************/
+static ULONG WINAPI
+CompositeMonikerImpl_AddRef(IMoniker* iface)
+{
+    CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
+
+    TRACE("(%p)\n",This);
+
+    return InterlockedIncrement(&This->ref);
+}
+
+/******************************************************************************
+ *        CompositeMoniker_Release
+ ******************************************************************************/
+static ULONG WINAPI
+CompositeMonikerImpl_Release(IMoniker* iface)
+{
+    CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
+    ULONG i;
+    ULONG ref;
+
+    TRACE("(%p)\n",This);
+
+    ref = InterlockedDecrement(&This->ref);
+
+    /* destroy the object if there's no more reference on it */
+    if (ref == 0){
+
+        /* release all the components before destroying this object */
+        for (i=0;i<This->tabLastIndex;i++)
+            IMoniker_Release(This->tabMoniker[i]);
+
+        HeapFree(GetProcessHeap(),0,This->tabMoniker);
+        HeapFree(GetProcessHeap(),0,This);
+    }
+    return ref;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_GetClassID
+ ******************************************************************************/
+static 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
+ ******************************************************************************/
+static 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
+ ******************************************************************************/
+static HRESULT WINAPI
+CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
+{
+    HRESULT res;
+    DWORD constant;
+    CLSID clsid;
+    WCHAR string[1]={0};
+
+    CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
+
+    TRACE("(%p,%p)\n",iface,pStm);
+
+    /* this function call OleLoadFromStream function for each moniker within this object */
+
+    /* read the a constant written 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);
+        DPRINTF("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("()\n");
+            /* FIXME: To whoever wrote this code: It's either return or break. it cannot be both! */
+            break;
+            return E_NOTIMPL;
+        }
+
+        /* resize the table if needed */
+        if (++This->tabLastIndex==This->tabSize){
+
+            This->tabSize+=BLOCK_TAB_SIZE;
+            This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
+
+            if (This->tabMoniker==NULL)
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    return res;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_Save
+ ******************************************************************************/
+static 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 calls OleSaveToStream function for each moniker within
+     * this object.
+     * When I tested this function in windows, I usually found this constant
+     * at the beginning of the stream. I don't known why (there's no
+     * indication in the 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
+ ******************************************************************************/
+static 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 summing all returned values
+     */
+
+    TRACE("(%p,%p)\n",iface,pcbSize);
+
+    if (pcbSize!=NULL)
+        return E_POINTER;
+
+    pcbSize->u.LowPart =0;
+    pcbSize->u.HighPart=0;
+
+    IMoniker_Enum(iface,TRUE,&enumMk);
+
+    while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)){
+
+        IMoniker_GetSizeMax(pmk,&ptmpSize);
+
+        IMoniker_Release(pmk);
+
+        pcbSize->u.LowPart +=ptmpSize.u.LowPart;
+        pcbSize->u.HighPart+=ptmpSize.u.HighPart;
+    }
+
+    IEnumMoniker_Release(enumMk);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *                  CompositeMoniker_BindToObject
+ ******************************************************************************/
+static 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 before ! we don't 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
+ ******************************************************************************/
+static 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
+ ******************************************************************************/
+static 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 composite moniker in to left and right 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
+ ******************************************************************************/
+static 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
+ ******************************************************************************/
+static HRESULT WINAPI
+CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
+{
+    CompositeMonikerImpl *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
+ ******************************************************************************/
+static 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
+ ******************************************************************************/
+static HRESULT WINAPI
+CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
+{
+    IEnumMoniker *enumMoniker;
+    IMoniker *tempMk;
+    HRESULT res;
+    DWORD tempHash;
+
+    TRACE("(%p,%p)\n",iface,pdwHash);
+
+    if (pdwHash==NULL)
+        return E_POINTER;
+
+    res = IMoniker_Enum(iface,TRUE,&enumMoniker);
+    if(FAILED(res))
+        return res;
+
+    while(1){
+        res=IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL);
+        if(FAILED(res))
+            break;
+            
+        res = IMoniker_Hash(tempMk, &tempHash);
+        if(FAILED(res))
+            break;
+        *pdwHash = (*pdwHash * 37) + tempHash;
+        
+        IMoniker_Release(tempMk);
+    }
+
+    IEnumMoniker_Release(enumMoniker);
+
+    return res;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_IsRunning
+ ******************************************************************************/
+static 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
+ ******************************************************************************/
+static 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
+ ******************************************************************************/
+static 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
+ ******************************************************************************/
+static 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
+ ***************************************************************************************************/
+static VOID 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-right) then compare these enumerations (left-right) 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
+ ******************************************************************************/
+static 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
+ ******************************************************************************/
+static 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=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=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));
+
+        if (*ppszDisplayName==NULL)
+            return E_OUTOFMEMORY;
+
+        strcatW(*ppszDisplayName,tempStr);
+
+        CoTaskMemFree(tempStr);
+        IMoniker_Release(tempMk);
+    }
+
+    IEnumMoniker_Release(enumMoniker);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        CompositeMoniker_ParseDisplayName
+ ******************************************************************************/
+static 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 right 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_IsSystemMoniker
+ ******************************************************************************/
+static 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
+ *******************************************************************************/
+static 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
+ */
+static ULONG WINAPI
+CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
+{
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+
+    TRACE("(%p)\n",iface);
+
+    return IMoniker_AddRef(This);
+}
+
+/***********************************************************************
+ *        CompositeMonikerIROTData_Release
+ */
+static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
+{
+    ICOM_THIS_From_IROTData(IMoniker, iface);
+
+    TRACE("(%p)\n",iface);
+
+    return IMoniker_Release(This);
+}
+
+/******************************************************************************
+ *        CompositeMonikerIROTData_GetComparaisonData
+ ******************************************************************************/
+static HRESULT WINAPI
+CompositeMonikerROTDataImpl_GetComparaisonData(IROTData* iface,
+               BYTE* pbData, ULONG cbMax, ULONG* pcbData)
+{
+    FIXME("(),stub!\n");
+    return E_NOTIMPL;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_QueryInterface
+ ******************************************************************************/
+static HRESULT WINAPI
+EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
+{
+    EnumMonikerImpl *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 */
+    IEnumMoniker_AddRef(iface);
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_AddRef
+ ******************************************************************************/
+static ULONG WINAPI
+EnumMonikerImpl_AddRef(IEnumMoniker* iface)
+{
+    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
+
+    TRACE("(%p)\n",This);
+
+    return InterlockedIncrement(&This->ref);
+
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_Release
+ ******************************************************************************/
+static ULONG WINAPI
+EnumMonikerImpl_Release(IEnumMoniker* iface)
+{
+    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
+    ULONG i;
+    ULONG ref;
+    TRACE("(%p)\n",This);
+
+    ref = InterlockedDecrement(&This->ref);
+
+    /* destroy the object if there's no more reference on it */
+    if (ref == 0) {
+
+        for(i=0;i<This->tabSize;i++)
+            IMoniker_Release(This->tabMoniker[i]);
+
+        HeapFree(GetProcessHeap(),0,This->tabMoniker);
+        HeapFree(GetProcessHeap(),0,This);
+    }
+    return ref;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_Next
+ ******************************************************************************/
+static HRESULT WINAPI
+EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt,
+               ULONG* pceltFethed)
+{
+    EnumMonikerImpl *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
+ ******************************************************************************/
+static HRESULT WINAPI
+EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt)
+{
+    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
+
+    if ((This->currentPos+celt) >= This->tabSize)
+        return S_FALSE;
+
+    This->currentPos+=celt;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_Reset
+ ******************************************************************************/
+static HRESULT WINAPI
+EnumMonikerImpl_Reset(IEnumMoniker* iface)
+{
+
+    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
+
+    This->currentPos=0;
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        EnumMonikerImpl_Clone
+ ******************************************************************************/
+static HRESULT WINAPI
+EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)
+{
+    EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
+
+    return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
+}
+
+/********************************************************************************/
+/* Virtual function table for the IROTData class                                */
+static IEnumMonikerVtbl VT_EnumMonikerImpl =
+{
+    EnumMonikerImpl_QueryInterface,
+    EnumMonikerImpl_AddRef,
+    EnumMonikerImpl_Release,
+    EnumMonikerImpl_Next,
+    EnumMonikerImpl_Skip,
+    EnumMonikerImpl_Reset,
+    EnumMonikerImpl_Clone
+};
+
+/******************************************************************************
+ *        EnumMonikerImpl_CreateEnumMoniker
+ ******************************************************************************/
+static HRESULT
+EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize,
+               ULONG currentPos, BOOL leftToRigth, IEnumMoniker ** ppmk)
+{
+    EnumMonikerImpl* newEnumMoniker;
+    int i;
+
+    if (currentPos > tabSize)
+        return E_INVALIDARG;
+
+    newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
+
+    if (newEnumMoniker == 0)
+        return STG_E_INSUFFICIENTMEMORY;
+
+    /* Initialize the virtual function table. */
+    newEnumMoniker->lpVtbl       = &VT_EnumMonikerImpl;
+    newEnumMoniker->ref          = 0;
+
+    newEnumMoniker->tabSize=tabSize;
+    newEnumMoniker->currentPos=currentPos;
+
+    newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(IMoniker));
+
+    if (newEnumMoniker->tabMoniker==NULL) {
+        HeapFree(GetProcessHeap(), 0, newEnumMoniker);
+        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;
+}
+
+/********************************************************************************/
+/* Virtual function table for the CompositeMonikerImpl class which includes     */
+/* IPersist, IPersistStream and IMoniker functions.                             */
+
+static IMonikerVtbl VT_CompositeMonikerImpl =
+{
+    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 IROTDataVtbl VT_ROTDataImpl =
+{
+    CompositeMonikerROTDataImpl_QueryInterface,
+    CompositeMonikerROTDataImpl_AddRef,
+    CompositeMonikerROTDataImpl_Release,
+    CompositeMonikerROTDataImpl_GetComparaisonData
+};
+
+/******************************************************************************
+ *         Composite-Moniker_Construct (local function)
+ *******************************************************************************/
+static HRESULT
+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 function table. */
+    This->lpvtbl1      = &VT_CompositeMonikerImpl;
+    This->lpvtbl2      = &VT_ROTDataImpl;
+    This->ref          = 0;
+
+    This->tabSize=BLOCK_TAB_SIZE;
+    This->tabLastIndex=0;
+
+    This->tabMoniker=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 beginning 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=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=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 for 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=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
+
+                if (This->tabMoniker==NULL)
+                    return E_OUTOFMEMORY;
+            }
+        }
+
+        IEnumMoniker_Release(enumMoniker);
+    }
+
+    return S_OK;
+}
+
+/******************************************************************************
+ *        CreateGenericComposite       [OLE32.@]
+ ******************************************************************************/
+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 = 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 = IMoniker_QueryInterface((IMoniker*)newCompositeMoniker,&IID_IMoniker,(void**)ppmkComposite);
+
+    return hr;
+}
+
+/******************************************************************************
+ *        MonikerCommonPrefixWith      [OLE32.@]
+ ******************************************************************************/
+HRESULT WINAPI
+MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
+{
+    FIXME("(),stub!\n");
+    return E_NOTIMPL;
+}