/*
 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <assert.h>
#include <stdarg.h>
#include <string.h>

#define COBJMACROS

#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winerror.h"
#include "wine/debug.h"
#include "ole2.h"
#include "moniker.h"

WINE_DEFAULT_DEBUG_CHANNEL(ole);

#define  BLOCK_TAB_SIZE 5 /* represent the first size table and its increment block size */

/* CompositeMoniker data structure */
typedef struct CompositeMonikerImpl{
    IMoniker IMoniker_iface;
    IROTData IROTData_iface;
    IMarshal IMarshal_iface;
    LONG ref;
    IMoniker** tabMoniker; /* dynamic table containing all components (monikers) of this composite moniker */
    ULONG    tabSize;      /* size of tabMoniker */
    ULONG    tabLastIndex; /* first free index in tabMoniker */
} CompositeMonikerImpl;

static inline CompositeMonikerImpl *impl_from_IMoniker(IMoniker *iface)
{
    return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMoniker_iface);
}

static inline CompositeMonikerImpl *impl_from_IROTData(IROTData *iface)
{
    return CONTAINING_RECORD(iface, CompositeMonikerImpl, IROTData_iface);
}

static inline CompositeMonikerImpl *impl_from_IMarshal(IMarshal *iface)
{
    return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMarshal_iface);
}

/* EnumMoniker data structure */
typedef struct EnumMonikerImpl{
    IEnumMoniker IEnumMoniker_iface;
    LONG ref;
    IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
    ULONG      tabSize; /* size of tabMoniker */
    ULONG      currentPos;  /* index pointer on the current moniker */
} EnumMonikerImpl;

static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
{
    return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
}

static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRight,IEnumMoniker ** ppmk);

/*******************************************************************************
 *        CompositeMoniker_QueryInterface
 *******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
{
    CompositeMonikerImpl *This = impl_from_IMoniker(iface);

    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);

    /* Perform a sanity check on the parameters.*/
    if ( ppvObject==0 )
	return E_INVALIDARG;

    /* Initialize the return parameter */
    *ppvObject = 0;

    /* Compare the riid with the interface IDs implemented by this object.*/
    if (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 = &This->IROTData_iface;
    else if (IsEqualIID(&IID_IMarshal, riid))
        *ppvObject = &This->IMarshal_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 */
    IMoniker_AddRef(iface);

    return S_OK;
}

/******************************************************************************
 *        CompositeMoniker_AddRef
 ******************************************************************************/
static ULONG WINAPI
CompositeMonikerImpl_AddRef(IMoniker* iface)
{
    CompositeMonikerImpl *This = impl_from_IMoniker(iface);

    TRACE("(%p)\n",This);

    return InterlockedIncrement(&This->ref);
}

static void CompositeMonikerImpl_ReleaseMonikersInTable(CompositeMonikerImpl *This)
{
    ULONG i;

    for (i = 0; i < This->tabLastIndex; i++)
        IMoniker_Release(This->tabMoniker[i]);

    This->tabLastIndex = 0;
}

/******************************************************************************
 *        CompositeMoniker_Release
 ******************************************************************************/
static ULONG WINAPI
CompositeMonikerImpl_Release(IMoniker* iface)
{
    CompositeMonikerImpl *This = impl_from_IMoniker(iface);
    ULONG ref;

    TRACE("(%p)\n",This);

    ref = InterlockedDecrement(&This->ref);

    /* destroy the object if there are no more references to it */
    if (ref == 0){

        /* release all the components before destroying this object */
        CompositeMonikerImpl_ReleaseMonikersInTable(This);

        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)\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)
{
    CompositeMonikerImpl *This = impl_from_IMoniker(iface);
    HRESULT res;
    DWORD moniker_count;
    DWORD i;

    TRACE("(%p,%p)\n",iface,pStm);

    /* this function call OleLoadFromStream function for each moniker within this object */

    res=IStream_Read(pStm,&moniker_count,sizeof(DWORD),NULL);
    if (res != S_OK)
    {
        ERR("couldn't reading moniker count from stream\n");
        return E_FAIL;
    }

    CompositeMonikerImpl_ReleaseMonikersInTable(This);

    for (i = 0; i < moniker_count; i++)
    {
        res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
        if (FAILED(res))
        {
            ERR("couldn't load moniker from stream, res = 0x%08x\n", res);
            break;
        }

        /* 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(This->tabMoniker[0]));

            if (This->tabMoniker==NULL)
            return E_OUTOFMEMORY;
        }
    }

    return res;
}

/******************************************************************************
 *        CompositeMoniker_Save
 ******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
{
    CompositeMonikerImpl *This = impl_from_IMoniker(iface);
    HRESULT res;
    IEnumMoniker *enumMk;
    IMoniker *pmk;
    DWORD moniker_count = This->tabLastIndex;

    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,&moniker_count,sizeof(moniker_count),NULL);
    if (FAILED(res)) return res;

    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(enumMk);
            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)
        return E_POINTER;

    pcbSize->QuadPart = sizeof(DWORD);

    IMoniker_Enum(iface,TRUE,&enumMk);

    while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){

        IMoniker_GetSizeMax(pmk,&ptmpSize);

        IMoniker_Release(pmk);

        pcbSize->QuadPart = ptmpSize.QuadPart + sizeof(CLSID);
    }

    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,*rightMostMk;
    IEnumMoniker *enumMoniker;

    TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(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,&rightMostMk,NULL);
        IEnumMoniker_Release(enumMoniker);

        res=CreateAntiMoniker(&antiMk);
        res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
        IMoniker_Release(antiMk);

        res=IMoniker_BindToObject(rightMostMk,pbc,tempMk,riid,ppvResult);

        IMoniker_Release(tempMk);
        IMoniker_Release(rightMostMk);
    }

    return res;
}

/******************************************************************************
 *        CompositeMoniker_BindToStorage
 ******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
               IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
{
    HRESULT   res;
    IMoniker *tempMk,*antiMk,*rightMostMk,*leftMk;
    IEnumMoniker *enumMoniker;

    TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(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)
    {
        res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
        if (FAILED(res)) return res;
    }
    else
        leftMk = iface;

    IMoniker_Enum(iface, FALSE, &enumMoniker);
    IEnumMoniker_Next(enumMoniker, 1, &rightMostMk, NULL);
    IEnumMoniker_Release(enumMoniker);

    res = CreateAntiMoniker(&antiMk);
    if (FAILED(res)) return res;
    res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
    if (FAILED(res)) return res;
    IMoniker_Release(antiMk);

    res = IMoniker_BindToStorage(rightMostMk, pbc, tempMk, riid, ppvResult);

    IMoniker_Release(tempMk);

    IMoniker_Release(rightMostMk);

    if (pmkToLeft)
        IMoniker_Release(leftMk);

    return res;
}

/******************************************************************************
 *        CompositeMoniker_Reduce
 ******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
               IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
{
    HRESULT   res;
    IMoniker *tempMk,*antiMk,*rightMostMk,*leftReducedComposedMk,*rightMostReducedMk;
    IEnumMoniker *enumMoniker;

    TRACE("(%p,%p,%d,%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,&rightMostMk,NULL);
        IEnumMoniker_Release(enumMoniker);

        CreateAntiMoniker(&antiMk);
        IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
        IMoniker_Release(antiMk);

        res = IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
        IMoniker_Release(tempMk);
        IMoniker_Release(rightMostMk);

        return res;
    }
    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,&rightMostMk,NULL);
        IEnumMoniker_Release(enumMoniker);

        CreateAntiMoniker(&antiMk);
        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(rightMostMk,pbc,dwReduceHowFar,NULL,&rightMostReducedMk) &&
            IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk) ){
            IMoniker_Release(tempMk);
            IMoniker_Release(rightMostMk);

            return CreateGenericComposite(leftReducedComposedMk,rightMostReducedMk,ppmkReduced);
        }
        else{
            /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
            IMoniker_Release(tempMk);
            IMoniker_Release(rightMostMk);

            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 = impl_from_IMoniker(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;
    BOOL done;

    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);

    do {

        res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
        res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);

        if((res1==S_OK)&&(res2==S_OK)){
            done = (res = IMoniker_IsEqual(tempMk1,tempMk2)) == S_FALSE;
        }
        else
        {
            res = (res1==S_FALSE) && (res2==S_FALSE);
            done = TRUE;
        }

        if (res1==S_OK)
            IMoniker_Release(tempMk1);

        if (res2==S_OK)
            IMoniker_Release(tempMk2);
    } while (!done);

    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;

    *pdwHash = 0;

    while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
        res = IMoniker_Hash(tempMk, &tempHash);
        if(FAILED(res))
            break;
        *pdwHash = *pdwHash ^ 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,*rightMostMk;
    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_INVALIDARG;

            /* 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,&rightMostMk,NULL);
                IEnumMoniker_Release(enumMoniker);

                res=CreateAntiMoniker(&antiMk);
                res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
                IMoniker_Release(antiMk);

                res=IMoniker_IsRunning(rightMostMk,pbc,tempMk,pmkNewlyRunning);

                IMoniker_Release(tempMk);
                IMoniker_Release(rightMostMk);

                return res;
            }
        }
}

/******************************************************************************
 *        CompositeMoniker_GetTimeOfLastChange
 ******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
               IMoniker* pmkToLeft, FILETIME* pCompositeTime)
{
    HRESULT res;
    IMoniker *tempMk,*antiMk,*rightMostMk,*leftMk;
    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)
    {
        IRunningObjectTable* rot;

        res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
        if (FAILED(res))
            return res;

        res = IBindCtx_GetRunningObjectTable(pbc,&rot);
        if (FAILED(res))
        {
            IMoniker_Release(leftMk);
            return res;
        }

        if (IRunningObjectTable_GetTimeOfLastChange(rot,leftMk,pCompositeTime)==S_OK)
        {
            IMoniker_Release(leftMk);
            return res;
        }
    }
    else
        leftMk = iface;

    IMoniker_Enum(iface, FALSE, &enumMoniker);
    IEnumMoniker_Next(enumMoniker, 1, &rightMostMk, NULL);
    IEnumMoniker_Release(enumMoniker);

    res = CreateAntiMoniker(&antiMk);
    res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
    IMoniker_Release(antiMk);

    res = IMoniker_GetTimeOfLastChange(rightMostMk, pbc, tempMk, pCompositeTime);

    IMoniker_Release(tempMk);
    IMoniker_Release(rightMostMk);

    if (pmkToLeft)
        IMoniker_Release(leftMk);

    return res;
}

/******************************************************************************
 *        CompositeMoniker_Inverse
 ******************************************************************************/
static HRESULT WINAPI
CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
{
    HRESULT res;
    IMoniker *tempMk,*antiMk,*rightMostMk,*tempInvMk,*rightMostInvMk;
    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 */

    *ppmk = NULL;

    res=CreateAntiMoniker(&antiMk);
    if (FAILED(res))
        return res;

    res=IMoniker_ComposeWith(iface,antiMk,FALSE,&tempMk);
    IMoniker_Release(antiMk);
    if (FAILED(res))
        return res;

    if (tempMk==NULL)

        return IMoniker_Inverse(iface,ppmk);

    else{

        IMoniker_Enum(iface,FALSE,&enumMoniker);
        IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
        IEnumMoniker_Release(enumMoniker);

        IMoniker_Inverse(rightMostMk,&rightMostInvMk);
        CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);

        res=CreateGenericComposite(rightMostInvMk,tempInvMk,ppmk);

        IMoniker_Release(tempMk);
        IMoniker_Release(rightMostMk);
        IMoniker_Release(tempInvMk);
        IMoniker_Release(rightMostInvMk);

        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 common 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 common 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(tempMk2);

                break;
            }
            IMoniker_Release(tempMk1);
            IMoniker_Release(tempMk2);
        }
    }
    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;

        lstrcatW(*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,*rightMostMk,*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,&rightMostMk,NULL);
    IEnumMoniker_Release(enumMoniker);

    /* get the left moniker */
    CreateAntiMoniker(&antiMk);
    IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
    IMoniker_Release(antiMk);

    return IMoniker_ParseDisplayName(rightMostMk,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)
{
    CompositeMonikerImpl *This = impl_from_IROTData(iface);

    TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject);

    return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
}

/***********************************************************************
 *        CompositeMonikerIROTData_AddRef
 */
static ULONG WINAPI
CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
{
    CompositeMonikerImpl *This = impl_from_IROTData(iface);

    TRACE("(%p)\n",iface);

    return IMoniker_AddRef(&This->IMoniker_iface);
}

/***********************************************************************
 *        CompositeMonikerIROTData_Release
 */
static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
{
    CompositeMonikerImpl *This = impl_from_IROTData(iface);

    TRACE("(%p)\n",iface);

    return IMoniker_Release(&This->IMoniker_iface);
}

/******************************************************************************
 *        CompositeMonikerIROTData_GetComparisonData
 ******************************************************************************/
static HRESULT WINAPI
CompositeMonikerROTDataImpl_GetComparisonData(IROTData* iface,
               BYTE* pbData, ULONG cbMax, ULONG* pcbData)
{
    CompositeMonikerImpl *This = impl_from_IROTData(iface);
    IEnumMoniker *pEnumMk;
    IMoniker *pmk;
    HRESULT hr;

    TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);

    *pcbData = sizeof(CLSID);

    hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
    if (FAILED(hr)) return hr;

    while(IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
    {
        IROTData *pROTData;
        hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
        if (FAILED(hr))
            ERR("moniker doesn't support IROTData interface\n");

        if (SUCCEEDED(hr))
        {
            ULONG cbData;
            hr = IROTData_GetComparisonData(pROTData, NULL, 0, &cbData);
            IROTData_Release(pROTData);
            if (SUCCEEDED(hr) || (hr == E_OUTOFMEMORY))
            {
                *pcbData += cbData;
                hr = S_OK;
            }
            else
                ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
        }

        IMoniker_Release(pmk);

        if (FAILED(hr))
        {
            IEnumMoniker_Release(pEnumMk);
            return hr;
        }
    }
    if (cbMax < *pcbData)
        return E_OUTOFMEMORY;

    IEnumMoniker_Reset(pEnumMk);

    memcpy(pbData, &CLSID_CompositeMoniker, sizeof(CLSID));
    pbData += sizeof(CLSID);
    cbMax -= sizeof(CLSID);

    while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
    {
        IROTData *pROTData;
        hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
        if (FAILED(hr))
            ERR("moniker doesn't support IROTData interface\n");

        if (SUCCEEDED(hr))
        {
            ULONG cbData;
            hr = IROTData_GetComparisonData(pROTData, pbData, cbMax, &cbData);
            IROTData_Release(pROTData);
            if (SUCCEEDED(hr))
            {
                pbData += cbData;
                cbMax -= cbData;
            }
            else
                ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
        }

        IMoniker_Release(pmk);

        if (FAILED(hr))
        {
            IEnumMoniker_Release(pEnumMk);
            return hr;
        }
    }

    IEnumMoniker_Release(pEnumMk);

    return S_OK;
}

static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
{
    CompositeMonikerImpl *This = impl_from_IMarshal(iface);

    TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);

    return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppv);
}

static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
{
    CompositeMonikerImpl *This = impl_from_IMarshal(iface);

    TRACE("(%p)\n",iface);

    return CompositeMonikerImpl_AddRef(&This->IMoniker_iface);
}

static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
{
    CompositeMonikerImpl *This = impl_from_IMarshal(iface);

    TRACE("(%p)\n",iface);

    return CompositeMonikerImpl_Release(&This->IMoniker_iface);
}

static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
  IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
  void* pvDestContext, DWORD mshlflags, CLSID* pCid)
{
    CompositeMonikerImpl *This = impl_from_IMarshal(iface);

    TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
        dwDestContext, pvDestContext, mshlflags, pCid);

    return IMoniker_GetClassID(&This->IMoniker_iface, pCid);
}

static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
  IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
  void* pvDestContext, DWORD mshlflags, DWORD* pSize)
{
    CompositeMonikerImpl *This = impl_from_IMarshal(iface);
    IEnumMoniker *pEnumMk;
    IMoniker *pmk;
    HRESULT hr;
    ULARGE_INTEGER size;

    TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
        dwDestContext, pvDestContext, mshlflags, pSize);

    *pSize = 0x10; /* to match native */

    hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
    if (FAILED(hr)) return hr;

    hr = IMoniker_GetSizeMax(&This->IMoniker_iface, &size);

    while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
    {
        ULONG size;

        hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
        if (SUCCEEDED(hr))
            *pSize += size;

        IMoniker_Release(pmk);

        if (FAILED(hr))
        {
            IEnumMoniker_Release(pEnumMk);
            return hr;
        }
    }

    IEnumMoniker_Release(pEnumMk);

    return S_OK;
}

static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(IMarshal *iface, IStream *pStm,
    REFIID riid, void* pv, DWORD dwDestContext,
    void* pvDestContext, DWORD mshlflags)
{
    CompositeMonikerImpl *This = impl_from_IMarshal(iface);
    IEnumMoniker *pEnumMk;
    IMoniker *pmk;
    HRESULT hr;
    ULONG i = 0;

    TRACE("(%p, %s, %p, %x, %p, %x)\n", pStm, debugstr_guid(riid), pv,
        dwDestContext, pvDestContext, mshlflags);

    hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
    if (FAILED(hr)) return hr;

    while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
    {
        hr = CoMarshalInterface(pStm, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);

        IMoniker_Release(pmk);

        if (FAILED(hr))
        {
            IEnumMoniker_Release(pEnumMk);
            return hr;
        }
        i++;
    }

    if (i != 2)
        FIXME("moniker count of %d not supported\n", i);

    IEnumMoniker_Release(pEnumMk);

    return S_OK;
}

static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm,
    REFIID riid, void **ppv)
{
    CompositeMonikerImpl *This = impl_from_IMarshal(iface);
    HRESULT hr;

    TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);

    CompositeMonikerImpl_ReleaseMonikersInTable(This);

    /* resize the table if needed */
    if (This->tabLastIndex + 2 > This->tabSize)
    {
        This->tabSize += max(BLOCK_TAB_SIZE, 2);
        This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));

        if (This->tabMoniker==NULL)
            return E_OUTOFMEMORY;
    }

    hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
    if (FAILED(hr))
    {
        ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
        return hr;
    }
    This->tabLastIndex++;
    hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
    if (FAILED(hr))
    {
        ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
        return hr;
    }
    This->tabLastIndex++;

    return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppv);
}

static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
{
    TRACE("(%p)\n", pStm);
    /* can't release a state-based marshal as nothing on server side to
     * release */
    return S_OK;
}

static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(IMarshal *iface,
    DWORD dwReserved)
{
    TRACE("(0x%x)\n", dwReserved);
    /* can't disconnect a state-based marshal as nothing on server side to
     * disconnect from */
    return S_OK;
}

/******************************************************************************
 *        EnumMonikerImpl_QueryInterface
 ******************************************************************************/
static HRESULT WINAPI
EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
{
    EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);

    TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);

    /* Perform a sanity check on the parameters.*/
    if ( ppvObject==0 )
	return E_INVALIDARG;

    /* Initialize the return parameter */
    *ppvObject = 0;

    /* Compare the riid with the interface IDs implemented by this object.*/
    if (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 = impl_from_IEnumMoniker(iface);

    TRACE("(%p)\n",This);

    return InterlockedIncrement(&This->ref);

}

/******************************************************************************
 *        EnumMonikerImpl_Release
 ******************************************************************************/
static ULONG WINAPI
EnumMonikerImpl_Release(IEnumMoniker* iface)
{
    EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
    ULONG i;
    ULONG ref;
    TRACE("(%p)\n",This);

    ref = InterlockedDecrement(&This->ref);

    /* destroy the object if there are no more references to 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 = impl_from_IEnumMoniker(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++];
        IMoniker_AddRef(rgelt[i]);
    }

    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 = impl_from_IEnumMoniker(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 = impl_from_IEnumMoniker(iface);

    This->currentPos=0;

    return S_OK;
}

/******************************************************************************
 *        EnumMonikerImpl_Clone
 ******************************************************************************/
static HRESULT WINAPI
EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)
{
    EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);

    return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
}

/********************************************************************************/
/* Virtual function table for the IROTData class                                */
static const 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 leftToRight, IEnumMoniker ** ppmk)
{
    EnumMonikerImpl* newEnumMoniker;
    ULONG 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->IEnumMoniker_iface.lpVtbl = &VT_EnumMonikerImpl;
    newEnumMoniker->ref          = 1;

    newEnumMoniker->tabSize=tabSize;
    newEnumMoniker->currentPos=currentPos;

    newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(newEnumMoniker->tabMoniker[0]));

    if (newEnumMoniker->tabMoniker==NULL) {
        HeapFree(GetProcessHeap(), 0, newEnumMoniker);
        return E_OUTOFMEMORY;
    }

    if (leftToRight)
        for (i=0;i<tabSize;i++){

            newEnumMoniker->tabMoniker[i]=tabMoniker[i];
            IMoniker_AddRef(tabMoniker[i]);
        }
    else
        for (i = tabSize; i > 0; i--){

            newEnumMoniker->tabMoniker[tabSize-i]=tabMoniker[i - 1];
            IMoniker_AddRef(tabMoniker[i - 1]);
        }

    *ppmk=&newEnumMoniker->IEnumMoniker_iface;

    return S_OK;
}

/********************************************************************************/
/* Virtual function table for the CompositeMonikerImpl class which includes     */
/* IPersist, IPersistStream and IMoniker functions.                             */

static const 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 const IROTDataVtbl VT_ROTDataImpl =
{
    CompositeMonikerROTDataImpl_QueryInterface,
    CompositeMonikerROTDataImpl_AddRef,
    CompositeMonikerROTDataImpl_Release,
    CompositeMonikerROTDataImpl_GetComparisonData
};

static const IMarshalVtbl VT_MarshalImpl =
{
    CompositeMonikerMarshalImpl_QueryInterface,
    CompositeMonikerMarshalImpl_AddRef,
    CompositeMonikerMarshalImpl_Release,
    CompositeMonikerMarshalImpl_GetUnmarshalClass,
    CompositeMonikerMarshalImpl_GetMarshalSizeMax,
    CompositeMonikerMarshalImpl_MarshalInterface,
    CompositeMonikerMarshalImpl_UnmarshalInterface,
    CompositeMonikerMarshalImpl_ReleaseMarshalData,
    CompositeMonikerMarshalImpl_DisconnectObject
};

/******************************************************************************
 *         Composite-Moniker_Construct (local function)
 *******************************************************************************/
static HRESULT
CompositeMonikerImpl_Construct(IMoniker **ppMoniker, IMoniker *pmkFirst, IMoniker *pmkRest)
{
    DWORD mkSys;
    IEnumMoniker *enumMoniker;
    IMoniker *tempMk;
    HRESULT res;
    CompositeMonikerImpl *This;
    int i;

    This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));

    if (!This)
        return E_OUTOFMEMORY;

    TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);

    /* Initialize the virtual function table. */
    This->IMoniker_iface.lpVtbl = &VT_CompositeMonikerImpl;
    This->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
    This->IMarshal_iface.lpVtbl = &VT_MarshalImpl;
    This->ref          = 1;

    This->tabSize=BLOCK_TAB_SIZE;
    This->tabLastIndex=0;

    This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(This->tabMoniker[0]));
    if (This->tabMoniker==NULL) {
        HeapFree(GetProcessHeap(), 0, This);
        return E_OUTOFMEMORY;
    }

    if (!pmkFirst && !pmkRest)
    {
        *ppMoniker = &This->IMoniker_iface;
        return S_OK;
    }

    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){
                IMoniker **tab_moniker = This->tabMoniker;

                This->tabSize+=BLOCK_TAB_SIZE;
                This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));

                if (This->tabMoniker==NULL){
                    for (i = 0; i < This->tabLastIndex; i++)
                        IMoniker_Release(tab_moniker[i]);
                    HeapFree(GetProcessHeap(), 0, tab_moniker);
                    HeapFree(GetProcessHeap(), 0, This);
                    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{
            for (i = 0; i < This->tabLastIndex; i++)
                IMoniker_Release(This->tabMoniker[i]);
            HeapFree(GetProcessHeap(), 0, This->tabMoniker);
            HeapFree(GetProcessHeap(), 0, This);
            return res;
        }

        /* resize tabMoniker if needed */
        if (This->tabLastIndex==This->tabSize){
            IMoniker **tab_moniker = This->tabMoniker;

            This->tabSize+=BLOCK_TAB_SIZE;

            This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));

            if (This->tabMoniker==NULL){
                for (i = 0; i < This->tabLastIndex; i++)
                    IMoniker_Release(tab_moniker[i]);
                HeapFree(GetProcessHeap(), 0, tab_moniker);
                HeapFree(GetProcessHeap(), 0, This);
                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){
                IMoniker **tab_moniker = This->tabMoniker;

                This->tabSize+=BLOCK_TAB_SIZE;

                This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));

                if (This->tabMoniker==NULL){
                    for (i = 0; i < This->tabLastIndex; i++)
                        IMoniker_Release(tab_moniker[i]);
                    HeapFree(GetProcessHeap(), 0, tab_moniker);
                    HeapFree(GetProcessHeap(), 0, This);
                    return E_OUTOFMEMORY;
                }
            }
        }

        IEnumMoniker_Release(enumMoniker);
    }

    /* only one moniker, then just return it */
    if (This->tabLastIndex == 1)
    {
        *ppMoniker = This->tabMoniker[0];
        IMoniker_AddRef(*ppMoniker);
        IMoniker_Release(&This->IMoniker_iface);
    }
    else
        *ppMoniker = &This->IMoniker_iface;

    return S_OK;
}

/******************************************************************************
 *        CreateGenericComposite	[OLE32.@]
 ******************************************************************************/
HRESULT WINAPI
CreateGenericComposite(IMoniker *pmkFirst, IMoniker *pmkRest, IMoniker **ppmkComposite)
{
    IMoniker* moniker = 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;
        IMoniker_AddRef(pmkRest);
        return S_OK;
    }
    else if (pmkFirst!=NULL && pmkRest==NULL){
        *ppmkComposite=pmkFirst;
        IMoniker_AddRef(pmkFirst);
        return S_OK;
    }
    else  if (pmkFirst==NULL && pmkRest==NULL)
        return S_OK;

    hr = CompositeMonikerImpl_Construct(&moniker,pmkFirst,pmkRest);

    if (FAILED(hr))
        return hr;

    hr = IMoniker_QueryInterface(moniker,&IID_IMoniker,(void**)ppmkComposite);
    IMoniker_Release(moniker);

    return hr;
}

/******************************************************************************
 *        MonikerCommonPrefixWith	[OLE32.@]
 ******************************************************************************/
HRESULT WINAPI
MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
{
    FIXME("(),stub!\n");
    return E_NOTIMPL;
}

HRESULT WINAPI CompositeMoniker_CreateInstance(IClassFactory *iface,
    IUnknown *pUnk, REFIID riid, void **ppv)
{
    IMoniker* pMoniker;
    HRESULT  hr;

    TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);

    *ppv = NULL;

    if (pUnk)
        return CLASS_E_NOAGGREGATION;

    hr = CompositeMonikerImpl_Construct(&pMoniker, NULL, NULL);

    if (SUCCEEDED(hr))
    {
        hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
        IMoniker_Release(pMoniker);
    }

    return hr;
}
