-/*\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;
+}