|  | /* | 
|  | *	                      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; | 
|  |  | 
|  |  | 
|  | /********************************************************************************/ | 
|  | /* CompositeMoniker prototype functions :                                       */ | 
|  |  | 
|  | /* IUnknown prototype functions */ | 
|  | static HRESULT WINAPI CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject); | 
|  | static ULONG   WINAPI CompositeMonikerImpl_AddRef(IMoniker* iface); | 
|  | static ULONG   WINAPI CompositeMonikerImpl_Release(IMoniker* iface); | 
|  |  | 
|  | /* IPersist prototype functions */ | 
|  | static HRESULT WINAPI CompositeMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID); | 
|  |  | 
|  | /* IPersistStream prototype functions */ | 
|  | static HRESULT WINAPI CompositeMonikerImpl_IsDirty(IMoniker* iface); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_Load(IMoniker* iface, IStream* pStm); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize); | 
|  |  | 
|  | /* IMoniker prototype functions */ | 
|  | static HRESULT WINAPI CompositeMonikerImpl_BindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_BindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_Reduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_ComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_IsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pCompositeTime); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_GetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_ParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut); | 
|  | static HRESULT WINAPI CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys); | 
|  |  | 
|  | /********************************************************************************/ | 
|  | /* IROTData prototype functions                                                 */ | 
|  |  | 
|  | /* IUnknown prototype functions */ | 
|  | static HRESULT WINAPI CompositeMonikerROTDataImpl_QueryInterface(IROTData* iface,REFIID riid,VOID** ppvObject); | 
|  | static ULONG   WINAPI CompositeMonikerROTDataImpl_AddRef(IROTData* iface); | 
|  | static ULONG   WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface); | 
|  |  | 
|  | /* IROTData prototype function */ | 
|  | static HRESULT WINAPI CompositeMonikerROTDataImpl_GetComparaisonData(IROTData* iface,BYTE* pbData,ULONG cbMax,ULONG* pcbData); | 
|  |  | 
|  | /* Local function used by CompositeMoniker implementation */ | 
|  | HRESULT WINAPI CompositeMonikerImpl_Construct(CompositeMonikerImpl* This,LPMONIKER pmkFirst, LPMONIKER pmkRest); | 
|  | HRESULT WINAPI CompositeMonikerImpl_Destroy(CompositeMonikerImpl* iface); | 
|  |  | 
|  | /********************************************************************************/ | 
|  | /* IEnumMoniker prototype functions                                             */ | 
|  |  | 
|  | /* IUnknown prototype functions */ | 
|  | static HRESULT WINAPI EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject); | 
|  | static ULONG   WINAPI EnumMonikerImpl_AddRef(IEnumMoniker* iface); | 
|  | static ULONG   WINAPI EnumMonikerImpl_Release(IEnumMoniker* iface); | 
|  |  | 
|  | /* IEnumMoniker prototype functions */ | 
|  | static HRESULT WINAPI EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt,IMoniker** rgelt,ULONG* pceltFetched); | 
|  | static HRESULT WINAPI EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt); | 
|  | static HRESULT WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface); | 
|  | static HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum); | 
|  |  | 
|  | HRESULT WINAPI EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk); | 
|  |  | 
|  | /********************************************************************************/ | 
|  | /* Virtual function table for the CompositeMonikerImpl class 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 | 
|  | }; | 
|  |  | 
|  | /********************************************************************************/ | 
|  | /* 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 | 
|  | }; | 
|  |  | 
|  | /******************************************************************************* | 
|  | *        CompositeMoniker_QueryInterface | 
|  | *******************************************************************************/ | 
|  | 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 */ | 
|  | CompositeMonikerImpl_AddRef(iface); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_AddRef | 
|  | ******************************************************************************/ | 
|  | ULONG WINAPI CompositeMonikerImpl_AddRef(IMoniker* iface) | 
|  | { | 
|  | CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)\n",This); | 
|  |  | 
|  | return InterlockedIncrement(&This->ref); | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_Release | 
|  | ******************************************************************************/ | 
|  | 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]); | 
|  |  | 
|  | CompositeMonikerImpl_Destroy(This); | 
|  | } | 
|  | return ref; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_GetClassID | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) | 
|  | { | 
|  | TRACE("(%p,%p),stub!\n",iface,pClassID); | 
|  |  | 
|  | if (pClassID==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | *pClassID = CLSID_CompositeMoniker; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_IsDirty | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_IsDirty(IMoniker* iface) | 
|  | { | 
|  | /* Note that the OLE-provided implementations of the IPersistStream::IsDirty | 
|  | method in the OLE-provided moniker interfaces always return S_FALSE because | 
|  | their internal state never changes. */ | 
|  |  | 
|  | TRACE("(%p)\n",iface); | 
|  |  | 
|  | return S_FALSE; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_Load | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm) | 
|  | { | 
|  | HRESULT res; | 
|  | DWORD constant; | 
|  | CLSID clsid; | 
|  | WCHAR string[1]={0}; | 
|  |  | 
|  | 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 | 
|  | ******************************************************************************/ | 
|  | 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 | 
|  | ******************************************************************************/ | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *         Composite-Moniker_Construct (local function) | 
|  | *******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_Construct(CompositeMonikerImpl* This,LPMONIKER pmkFirst, LPMONIKER pmkRest) | 
|  | { | 
|  | DWORD mkSys; | 
|  | IEnumMoniker *enumMoniker; | 
|  | IMoniker *tempMk; | 
|  | HRESULT res; | 
|  |  | 
|  | TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest); | 
|  |  | 
|  | /* Initialize the virtual 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; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_Destroy (local function) | 
|  | *******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_Destroy(CompositeMonikerImpl* This) | 
|  | { | 
|  | TRACE("(%p)\n",This); | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0,This->tabMoniker); | 
|  |  | 
|  | HeapFree(GetProcessHeap(),0,This); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *                  CompositeMoniker_BindToObject | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_BindToObject(IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | REFIID riid, | 
|  | VOID** ppvResult) | 
|  | { | 
|  | HRESULT   res; | 
|  | IRunningObjectTable *prot; | 
|  | IMoniker *tempMk,*antiMk,*mostRigthMk; | 
|  | IEnumMoniker *enumMoniker; | 
|  |  | 
|  | TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); | 
|  |  | 
|  | if (ppvResult==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | *ppvResult=0; | 
|  | /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */ | 
|  | /* object for the requested interface pointer. */ | 
|  | if(pmkToLeft==NULL){ | 
|  |  | 
|  | res=IBindCtx_GetRunningObjectTable(pbc,&prot); | 
|  |  | 
|  | if (SUCCEEDED(res)){ | 
|  |  | 
|  | /* if the requested class was loaded 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 | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_BindToStorage(IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | REFIID riid, | 
|  | VOID** ppvResult) | 
|  | { | 
|  | HRESULT   res; | 
|  | IMoniker *tempMk,*antiMk,*mostRigthMk; | 
|  | IEnumMoniker *enumMoniker; | 
|  |  | 
|  | TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); | 
|  |  | 
|  | *ppvResult=0; | 
|  |  | 
|  | /* This method recursively calls BindToStorage on the rightmost component of the composite, */ | 
|  | /* passing the rest of the composite as the pmkToLeft parameter for that call. */ | 
|  |  | 
|  | if (pmkToLeft!=NULL){ | 
|  |  | 
|  | IMoniker_Enum(iface,FALSE,&enumMoniker); | 
|  | IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); | 
|  | IEnumMoniker_Release(enumMoniker); | 
|  |  | 
|  | res=CreateAntiMoniker(&antiMk); | 
|  | res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); | 
|  | IMoniker_Release(antiMk); | 
|  |  | 
|  | res=CompositeMonikerImpl_BindToStorage(mostRigthMk,pbc,tempMk,riid,ppvResult); | 
|  |  | 
|  | IMoniker_Release(tempMk); | 
|  |  | 
|  | IMoniker_Release(mostRigthMk); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | else | 
|  | return IMoniker_BindToStorage(iface,pbc,NULL,riid,ppvResult); | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_Reduce | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_Reduce(IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | DWORD dwReduceHowFar, | 
|  | IMoniker** ppmkToLeft, | 
|  | IMoniker** ppmkReduced) | 
|  | { | 
|  | HRESULT   res; | 
|  | IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk; | 
|  | IEnumMoniker *enumMoniker; | 
|  |  | 
|  | TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); | 
|  |  | 
|  | if (ppmkReduced==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | /* This method recursively calls Reduce for each of its component monikers. */ | 
|  |  | 
|  | if (ppmkToLeft==NULL){ | 
|  |  | 
|  | IMoniker_Enum(iface,FALSE,&enumMoniker); | 
|  | IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); | 
|  | IEnumMoniker_Release(enumMoniker); | 
|  |  | 
|  | res=CreateAntiMoniker(&antiMk); | 
|  | res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); | 
|  | IMoniker_Release(antiMk); | 
|  |  | 
|  | return CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced); | 
|  | } | 
|  | else if (*ppmkToLeft==NULL) | 
|  |  | 
|  | return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced); | 
|  |  | 
|  | else{ | 
|  |  | 
|  | /* separate the 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 | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_ComposeWith(IMoniker* iface, | 
|  | IMoniker* pmkRight, | 
|  | BOOL fOnlyIfNotGeneric, | 
|  | IMoniker** ppmkComposite) | 
|  | { | 
|  | TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite); | 
|  |  | 
|  | if ((ppmkComposite==NULL)||(pmkRight==NULL)) | 
|  | return E_POINTER; | 
|  |  | 
|  | *ppmkComposite=0; | 
|  |  | 
|  | /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */ | 
|  | /* otherwise, the method returns the result of combining the two monikers by calling the */ | 
|  | /* CreateGenericComposite function */ | 
|  |  | 
|  | if (fOnlyIfNotGeneric) | 
|  | return MK_E_NEEDGENERIC; | 
|  |  | 
|  | return CreateGenericComposite(iface,pmkRight,ppmkComposite); | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_Enum | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) | 
|  | { | 
|  | 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 | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) | 
|  | { | 
|  | IEnumMoniker *enumMoniker1,*enumMoniker2; | 
|  | IMoniker *tempMk1,*tempMk2; | 
|  | HRESULT res1,res2,res; | 
|  |  | 
|  | TRACE("(%p,%p)\n",iface,pmkOtherMoniker); | 
|  |  | 
|  | if (pmkOtherMoniker==NULL) | 
|  | return S_FALSE; | 
|  |  | 
|  | /* This method returns S_OK if the components of both monikers are equal when compared in the */ | 
|  | /* left-to-right order.*/ | 
|  | IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1); | 
|  |  | 
|  | if (enumMoniker1==NULL) | 
|  | return S_FALSE; | 
|  |  | 
|  | IMoniker_Enum(iface,TRUE,&enumMoniker2); | 
|  |  | 
|  | while(1){ | 
|  |  | 
|  | res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); | 
|  | res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL); | 
|  |  | 
|  | if((res1==S_OK)&&(res2==S_OK)){ | 
|  |  | 
|  | if(IMoniker_IsEqual(tempMk1,tempMk2)==S_FALSE){ | 
|  | res= S_FALSE; | 
|  | break; | 
|  | } | 
|  | else | 
|  | continue; | 
|  | } | 
|  | else if ( (res1==S_FALSE) && (res2==S_FALSE) ){ | 
|  | res = S_OK; | 
|  | break; | 
|  | } | 
|  | else{ | 
|  | res = S_FALSE; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (res1==S_OK) | 
|  | IMoniker_Release(tempMk1); | 
|  |  | 
|  | if (res2==S_OK) | 
|  | IMoniker_Release(tempMk2); | 
|  | } | 
|  |  | 
|  | IEnumMoniker_Release(enumMoniker1); | 
|  | IEnumMoniker_Release(enumMoniker2); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_Hash | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) | 
|  | { | 
|  | FIXME("(),stub!\n"); | 
|  |  | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_IsRunning | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_IsRunning(IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | IMoniker* pmkNewlyRunning) | 
|  | { | 
|  | IRunningObjectTable* rot; | 
|  | HRESULT res; | 
|  | IMoniker *tempMk,*antiMk,*mostRigthMk; | 
|  | IEnumMoniker *enumMoniker; | 
|  |  | 
|  | TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning); | 
|  |  | 
|  | /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/ | 
|  | if (pmkToLeft!=NULL){ | 
|  |  | 
|  | CreateGenericComposite(pmkToLeft,iface,&tempMk); | 
|  |  | 
|  | res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning); | 
|  |  | 
|  | IMoniker_Release(tempMk); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | else | 
|  | /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */ | 
|  | /* to this moniker */ | 
|  |  | 
|  | if (pmkNewlyRunning!=NULL) | 
|  |  | 
|  | if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK) | 
|  | return S_OK; | 
|  |  | 
|  | else | 
|  | return S_FALSE; | 
|  |  | 
|  | else{ | 
|  |  | 
|  | if (pbc==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */ | 
|  | /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls   */ | 
|  | /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */ | 
|  | /* the composite as the pmkToLeft parameter for that call.                                   */ | 
|  |  | 
|  | res=IBindCtx_GetRunningObjectTable(pbc,&rot); | 
|  |  | 
|  | if (FAILED(res)) | 
|  | return res; | 
|  |  | 
|  | res = IRunningObjectTable_IsRunning(rot,iface); | 
|  | IRunningObjectTable_Release(rot); | 
|  |  | 
|  | if(res==S_OK) | 
|  | return S_OK; | 
|  |  | 
|  | else{ | 
|  |  | 
|  | IMoniker_Enum(iface,FALSE,&enumMoniker); | 
|  | IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); | 
|  | IEnumMoniker_Release(enumMoniker); | 
|  |  | 
|  | res=CreateAntiMoniker(&antiMk); | 
|  | res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); | 
|  | IMoniker_Release(antiMk); | 
|  |  | 
|  | res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning); | 
|  |  | 
|  | IMoniker_Release(tempMk); | 
|  | IMoniker_Release(mostRigthMk); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_GetTimeOfLastChange | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | FILETIME* pCompositeTime) | 
|  | { | 
|  | IRunningObjectTable* rot; | 
|  | HRESULT res; | 
|  | IMoniker *tempMk,*antiMk,*mostRigthMk; | 
|  | IEnumMoniker *enumMoniker; | 
|  |  | 
|  | TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime); | 
|  |  | 
|  | if (pCompositeTime==NULL) | 
|  | return E_INVALIDARG; | 
|  |  | 
|  | /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to  */ | 
|  | /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls  */ | 
|  | /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */ | 
|  | /* of the composite as the pmkToLeft parameter for that call.                                       */ | 
|  | if (pmkToLeft!=NULL){ | 
|  |  | 
|  | res=CreateGenericComposite(pmkToLeft,iface,&tempMk); | 
|  |  | 
|  | res=IBindCtx_GetRunningObjectTable(pbc,&rot); | 
|  |  | 
|  | if (FAILED(res)) | 
|  | return res; | 
|  |  | 
|  | if (IRunningObjectTable_GetTimeOfLastChange(rot,tempMk,pCompositeTime)==S_OK) | 
|  | return res; | 
|  | else | 
|  |  | 
|  | IMoniker_Enum(iface,FALSE,&enumMoniker); | 
|  | IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); | 
|  | IEnumMoniker_Release(enumMoniker); | 
|  |  | 
|  | res=CreateAntiMoniker(&antiMk); | 
|  | res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); | 
|  | IMoniker_Release(antiMk); | 
|  |  | 
|  | res=CompositeMonikerImpl_GetTimeOfLastChange(mostRigthMk,pbc,tempMk,pCompositeTime); | 
|  |  | 
|  | IMoniker_Release(tempMk); | 
|  | IMoniker_Release(mostRigthMk); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | else | 
|  | return IMoniker_GetTimeOfLastChange(iface,pbc,NULL,pCompositeTime); | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_Inverse | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) | 
|  | { | 
|  | HRESULT res; | 
|  | IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk; | 
|  | IEnumMoniker *enumMoniker; | 
|  |  | 
|  | TRACE("(%p,%p)\n",iface,ppmk); | 
|  |  | 
|  | if (ppmk==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | /* This method returns a composite moniker that consists of the inverses of each of the components */ | 
|  | /* of the original composite, stored in reverse order */ | 
|  |  | 
|  | res=CreateAntiMoniker(&antiMk); | 
|  | res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); | 
|  | IMoniker_Release(antiMk); | 
|  |  | 
|  | if (tempMk==NULL) | 
|  |  | 
|  | return IMoniker_Inverse(iface,ppmk); | 
|  |  | 
|  | else{ | 
|  |  | 
|  | IMoniker_Enum(iface,FALSE,&enumMoniker); | 
|  | IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); | 
|  | IEnumMoniker_Release(enumMoniker); | 
|  |  | 
|  | IMoniker_Inverse(mostRigthMk,&mostRigthInvMk); | 
|  | CompositeMonikerImpl_Inverse(tempMk,&tempInvMk); | 
|  |  | 
|  | res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk); | 
|  |  | 
|  | IMoniker_Release(tempMk); | 
|  | IMoniker_Release(mostRigthMk); | 
|  | IMoniker_Release(tempInvMk); | 
|  | IMoniker_Release(mostRigthInvMk); | 
|  |  | 
|  | return res; | 
|  | } | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_CommonPrefixWith | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) | 
|  | { | 
|  | DWORD mkSys; | 
|  | HRESULT res1,res2; | 
|  | IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2; | 
|  | IEnumMoniker *enumMoniker1,*enumMoniker2; | 
|  | ULONG i,nbCommonMk=0; | 
|  |  | 
|  | /* If the other moniker is a composite, this method compares the components of each composite from left  */ | 
|  | /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */ | 
|  | /* of the leftmost components were common to both monikers.                                              */ | 
|  |  | 
|  | if (ppmkPrefix==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | *ppmkPrefix=0; | 
|  |  | 
|  | if (pmkOther==NULL) | 
|  | return MK_E_NOPREFIX; | 
|  |  | 
|  | IMoniker_IsSystemMoniker(pmkOther,&mkSys); | 
|  |  | 
|  | if((mkSys==MKSYS_GENERICCOMPOSITE)){ | 
|  |  | 
|  | IMoniker_Enum(iface,TRUE,&enumMoniker1); | 
|  | IMoniker_Enum(pmkOther,TRUE,&enumMoniker2); | 
|  |  | 
|  | while(1){ | 
|  |  | 
|  | res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL); | 
|  | res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL); | 
|  |  | 
|  | if ((res1==S_FALSE) && (res2==S_FALSE)){ | 
|  |  | 
|  | /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/ | 
|  | *ppmkPrefix=iface; | 
|  | IMoniker_AddRef(iface); | 
|  | return  MK_S_US; | 
|  | } | 
|  | else if ((res1==S_OK) && (res2==S_OK)){ | 
|  |  | 
|  | if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK) | 
|  |  | 
|  | nbCommonMk++; | 
|  |  | 
|  | else | 
|  | break; | 
|  |  | 
|  | } | 
|  | else if (res1==S_OK){ | 
|  |  | 
|  | /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */ | 
|  | /* ppmkPrefix to the other moniker.                                                       */ | 
|  | *ppmkPrefix=pmkOther; | 
|  | return MK_S_HIM; | 
|  | } | 
|  | else{ | 
|  | /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */ | 
|  | /* to this moniker.                                                                          */ | 
|  | *ppmkPrefix=iface; | 
|  | return MK_S_ME; | 
|  | } | 
|  | } | 
|  |  | 
|  | IEnumMoniker_Release(enumMoniker1); | 
|  | IEnumMoniker_Release(enumMoniker2); | 
|  |  | 
|  | /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */ | 
|  | if (nbCommonMk==0) | 
|  | return MK_E_NOPREFIX; | 
|  |  | 
|  | IEnumMoniker_Reset(enumMoniker1); | 
|  |  | 
|  | IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); | 
|  |  | 
|  | /* if we have more than one commun moniker the result will be a composite moniker */ | 
|  | if (nbCommonMk>1){ | 
|  |  | 
|  | /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/ | 
|  | IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL); | 
|  | CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix); | 
|  | IMoniker_Release(tempMk1); | 
|  | IMoniker_Release(tempMk2); | 
|  |  | 
|  | /* compose all common monikers in a composite moniker */ | 
|  | for(i=0;i<nbCommonMk;i++){ | 
|  |  | 
|  | IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); | 
|  |  | 
|  | CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2); | 
|  |  | 
|  | IMoniker_Release(*ppmkPrefix); | 
|  |  | 
|  | IMoniker_Release(tempMk1); | 
|  |  | 
|  | *ppmkPrefix=tempMk2; | 
|  | } | 
|  | return S_OK; | 
|  | } | 
|  | else{ | 
|  | /* if we have only one commun moniker the result will be a simple moniker which is the most-left one*/ | 
|  | *ppmkPrefix=tempMk1; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  | } | 
|  | else{ | 
|  | /* If the other moniker is not a composite, the method simply compares it to the leftmost component | 
|  | of this moniker.*/ | 
|  |  | 
|  | IMoniker_Enum(iface,TRUE,&enumMoniker1); | 
|  |  | 
|  | IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL); | 
|  |  | 
|  | if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){ | 
|  |  | 
|  | *ppmkPrefix=pmkOther; | 
|  |  | 
|  | return MK_S_HIM; | 
|  | } | 
|  | else | 
|  | return MK_E_NOPREFIX; | 
|  | } | 
|  | } | 
|  | /*************************************************************************************************** | 
|  | *        GetAfterCommonPrefix (local function) | 
|  | *  This function returns a moniker that consist of the remainder when the common prefix is removed | 
|  | ***************************************************************************************************/ | 
|  | VOID WINAPI GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk) | 
|  | { | 
|  | IMoniker *tempMk,*tempMk1,*tempMk2; | 
|  | IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3; | 
|  | ULONG nbRestMk=0; | 
|  | DWORD mkSys; | 
|  | HRESULT res1,res2; | 
|  |  | 
|  | *restMk=0; | 
|  |  | 
|  | /* to create an enumerator for pGenMk with current position pointed on the first element after common  */ | 
|  | /* prefix: enum the two monikers (left-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 | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkRelPath) | 
|  | { | 
|  | HRESULT res; | 
|  | IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0; | 
|  |  | 
|  | TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath); | 
|  |  | 
|  | if (ppmkRelPath==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | *ppmkRelPath=0; | 
|  |  | 
|  | /* This method finds the common prefix of the two monikers and creates two monikers that consist     */ | 
|  | /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */ | 
|  | /* of this moniker and composes the remainder of the other moniker on the right of it.               */ | 
|  |  | 
|  | /* finds the common prefix of the two monikers */ | 
|  | res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk); | 
|  |  | 
|  | /* if there's no common prefix or the two moniker are equal the relative is the other moniker */ | 
|  | if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){ | 
|  |  | 
|  | *ppmkRelPath=pmkOther; | 
|  | IMoniker_AddRef(pmkOther); | 
|  | return MK_S_HIM; | 
|  | } | 
|  |  | 
|  | GetAfterCommonPrefix(iface,commonMk,&restThisMk); | 
|  | GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk); | 
|  |  | 
|  | /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */ | 
|  | /* moniker when the common prefix is removed                                                           */ | 
|  | if (res==MK_S_HIM){ | 
|  |  | 
|  | IMoniker_Inverse(restThisMk,ppmkRelPath); | 
|  | IMoniker_Release(restThisMk); | 
|  | } | 
|  | /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */ | 
|  | /* when the common prefix is removed                                                                     */ | 
|  | else if (res==MK_S_ME){ | 
|  |  | 
|  | *ppmkRelPath=restOtherMk; | 
|  | IMoniker_AddRef(restOtherMk); | 
|  | } | 
|  | /* the relative path is the inverse for the remainder of this moniker and the remainder of the other  */ | 
|  | /* moniker on the right of it.                                                                        */ | 
|  | else if (res==S_OK){ | 
|  |  | 
|  | IMoniker_Inverse(restThisMk,&invRestThisMk); | 
|  | IMoniker_Release(restThisMk); | 
|  | CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath); | 
|  | IMoniker_Release(invRestThisMk); | 
|  | IMoniker_Release(restOtherMk); | 
|  | } | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMoniker_GetDisplayName | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_GetDisplayName(IMoniker* iface, | 
|  | IBindCtx* pbc, | 
|  | IMoniker* pmkToLeft, | 
|  | LPOLESTR *ppszDisplayName) | 
|  | { | 
|  | ULONG lengthStr=1; | 
|  | IEnumMoniker *enumMoniker; | 
|  | IMoniker* tempMk; | 
|  | LPOLESTR tempStr; | 
|  |  | 
|  | TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName); | 
|  |  | 
|  | if (ppszDisplayName==NULL) | 
|  | return E_POINTER; | 
|  |  | 
|  | *ppszDisplayName=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 | 
|  | ******************************************************************************/ | 
|  | 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 | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) | 
|  | { | 
|  | TRACE("(%p,%p)\n",iface,pwdMksys); | 
|  |  | 
|  | if (!pwdMksys) | 
|  | return E_POINTER; | 
|  |  | 
|  | (*pwdMksys)=MKSYS_GENERICCOMPOSITE; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /******************************************************************************* | 
|  | *        CompositeMonikerIROTData_QueryInterface | 
|  | *******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) | 
|  | { | 
|  |  | 
|  | ICOM_THIS_From_IROTData(IMoniker, iface); | 
|  |  | 
|  | TRACE("(%p,%p,%p)\n",iface,riid,ppvObject); | 
|  |  | 
|  | return CompositeMonikerImpl_QueryInterface(This, riid, ppvObject); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *        CompositeMonikerIROTData_AddRef | 
|  | */ | 
|  | ULONG   WINAPI CompositeMonikerROTDataImpl_AddRef(IROTData *iface) | 
|  | { | 
|  | ICOM_THIS_From_IROTData(IMoniker, iface); | 
|  |  | 
|  | TRACE("(%p)\n",iface); | 
|  |  | 
|  | return CompositeMonikerImpl_AddRef(This); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *        CompositeMonikerIROTData_Release | 
|  | */ | 
|  | ULONG   WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface) | 
|  | { | 
|  | ICOM_THIS_From_IROTData(IMoniker, iface); | 
|  |  | 
|  | TRACE("(%p)\n",iface); | 
|  |  | 
|  | return CompositeMonikerImpl_Release(This); | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        CompositeMonikerIROTData_GetComparaisonData | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI CompositeMonikerROTDataImpl_GetComparaisonData(IROTData* iface, | 
|  | BYTE* pbData, | 
|  | ULONG cbMax, | 
|  | ULONG* pcbData) | 
|  | { | 
|  | FIXME("(),stub!\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        EnumMonikerImpl_QueryInterface | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject) | 
|  | { | 
|  | 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 */ | 
|  | EnumMonikerImpl_AddRef(iface); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        EnumMonikerImpl_AddRef | 
|  | ******************************************************************************/ | 
|  | ULONG   WINAPI EnumMonikerImpl_AddRef(IEnumMoniker* iface) | 
|  | { | 
|  | EnumMonikerImpl *This = (EnumMonikerImpl *)iface; | 
|  |  | 
|  | TRACE("(%p)\n",This); | 
|  |  | 
|  | return InterlockedIncrement(&This->ref); | 
|  |  | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        EnumMonikerImpl_Release | 
|  | ******************************************************************************/ | 
|  | 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 | 
|  | ******************************************************************************/ | 
|  | 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 | 
|  | ******************************************************************************/ | 
|  | 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 | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface){ | 
|  |  | 
|  | EnumMonikerImpl *This = (EnumMonikerImpl *)iface; | 
|  |  | 
|  | This->currentPos=0; | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        EnumMonikerImpl_Clone | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum){ | 
|  |  | 
|  | EnumMonikerImpl *This = (EnumMonikerImpl *)iface; | 
|  |  | 
|  | return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum); | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        EnumMonikerImpl_CreateEnumMoniker | 
|  | ******************************************************************************/ | 
|  | HRESULT WINAPI EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, | 
|  | ULONG tabSize, | 
|  | ULONG currentPos, | 
|  | BOOL leftToRigth, | 
|  | IEnumMoniker ** ppmk) | 
|  | { | 
|  | EnumMonikerImpl* newEnumMoniker; | 
|  | int i; | 
|  |  | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /****************************************************************************** | 
|  | *        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 = CompositeMonikerImpl_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; | 
|  | } |