ole32: Fix infinite recursion in CompositeMonikerImpl_BindToStorage.
[wine/wine64.git] / dlls / ole32 / compositemoniker.c
blobfbeaa74e3e845b5e47fb1bfe77d407d44126546c
1 /*
2 * CompositeMonikers implementation
4 * Copyright 1999 Noomen Hamza
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <string.h>
25 #define COBJMACROS
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "winerror.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35 #include "ole2.h"
36 #include "moniker.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
40 const CLSID CLSID_CompositeMoniker = {
41 0x309, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}
44 #define BLOCK_TAB_SIZE 5 /* represent the first size table and it's increment block size */
46 /* CompositeMoniker data structure */
47 typedef struct CompositeMonikerImpl{
49 const IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/
51 /* The ROT (RunningObjectTable implementation) uses the IROTData
52 * interface to test whether two monikers are equal. That's why IROTData
53 * interface is implemented by monikers.
55 const IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/
57 const IMarshalVtbl* lpvtblMarshal; /* VTable relative to the IMarshal interface.*/
59 LONG ref; /* reference counter for this object */
61 IMoniker** tabMoniker; /* dynamaic table containing all components (monikers) of this composite moniker */
63 ULONG tabSize; /* size of tabMoniker */
65 ULONG tabLastIndex; /* first free index in tabMoniker */
67 } CompositeMonikerImpl;
70 /* EnumMoniker data structure */
71 typedef struct EnumMonikerImpl{
73 const IEnumMonikerVtbl *lpVtbl; /* VTable relative to the IEnumMoniker interface.*/
75 LONG ref; /* reference counter for this object */
77 IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
79 ULONG tabSize; /* size of tabMoniker */
81 ULONG currentPos; /* index pointer on the current moniker */
83 } EnumMonikerImpl;
85 static inline IMoniker *impl_from_IROTData( IROTData *iface )
87 return (IMoniker *)((char*)iface - FIELD_OFFSET(CompositeMonikerImpl, lpvtbl2));
90 static inline IMoniker *impl_from_IMarshal( IMarshal *iface )
92 return (IMoniker *)((char*)iface - FIELD_OFFSET(CompositeMonikerImpl, lpvtblMarshal));
95 static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk);
97 /*******************************************************************************
98 * CompositeMoniker_QueryInterface
99 *******************************************************************************/
100 static HRESULT WINAPI
101 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
103 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
105 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
107 /* Perform a sanity check on the parameters.*/
108 if ( (This==0) || (ppvObject==0) )
109 return E_INVALIDARG;
111 /* Initialize the return parameter */
112 *ppvObject = 0;
114 /* Compare the riid with the interface IDs implemented by this object.*/
115 if (IsEqualIID(&IID_IUnknown, riid) ||
116 IsEqualIID(&IID_IPersist, riid) ||
117 IsEqualIID(&IID_IPersistStream, riid) ||
118 IsEqualIID(&IID_IMoniker, riid)
120 *ppvObject = iface;
121 else if (IsEqualIID(&IID_IROTData, riid))
122 *ppvObject = (IROTData*)&(This->lpvtbl2);
123 else if (IsEqualIID(&IID_IMarshal, riid))
124 *ppvObject = (IROTData*)&(This->lpvtblMarshal);
126 /* Check that we obtained an interface.*/
127 if ((*ppvObject)==0)
128 return E_NOINTERFACE;
130 /* Query Interface always increases the reference count by one when it is successful */
131 IMoniker_AddRef(iface);
133 return S_OK;
136 /******************************************************************************
137 * CompositeMoniker_AddRef
138 ******************************************************************************/
139 static ULONG WINAPI
140 CompositeMonikerImpl_AddRef(IMoniker* iface)
142 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
144 TRACE("(%p)\n",This);
146 return InterlockedIncrement(&This->ref);
149 static void CompositeMonikerImpl_ReleaseMonikersInTable(CompositeMonikerImpl *This)
151 ULONG i;
153 for (i = 0; i < This->tabLastIndex; i++)
154 IMoniker_Release(This->tabMoniker[i]);
156 This->tabLastIndex = 0;
159 /******************************************************************************
160 * CompositeMoniker_Release
161 ******************************************************************************/
162 static ULONG WINAPI
163 CompositeMonikerImpl_Release(IMoniker* iface)
165 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
166 ULONG ref;
168 TRACE("(%p)\n",This);
170 ref = InterlockedDecrement(&This->ref);
172 /* destroy the object if there's no more reference on it */
173 if (ref == 0){
175 /* release all the components before destroying this object */
176 CompositeMonikerImpl_ReleaseMonikersInTable(This);
178 HeapFree(GetProcessHeap(),0,This->tabMoniker);
179 HeapFree(GetProcessHeap(),0,This);
181 return ref;
184 /******************************************************************************
185 * CompositeMoniker_GetClassID
186 ******************************************************************************/
187 static HRESULT WINAPI
188 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
190 TRACE("(%p,%p)\n",iface,pClassID);
192 if (pClassID==NULL)
193 return E_POINTER;
195 *pClassID = CLSID_CompositeMoniker;
197 return S_OK;
200 /******************************************************************************
201 * CompositeMoniker_IsDirty
202 ******************************************************************************/
203 static HRESULT WINAPI
204 CompositeMonikerImpl_IsDirty(IMoniker* iface)
206 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
207 method in the OLE-provided moniker interfaces always return S_FALSE because
208 their internal state never changes. */
210 TRACE("(%p)\n",iface);
212 return S_FALSE;
215 /******************************************************************************
216 * CompositeMoniker_Load
217 ******************************************************************************/
218 static HRESULT WINAPI
219 CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
221 HRESULT res;
222 DWORD moniker_count;
223 DWORD i;
225 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
227 TRACE("(%p,%p)\n",iface,pStm);
229 /* this function call OleLoadFromStream function for each moniker within this object */
231 res=IStream_Read(pStm,&moniker_count,sizeof(DWORD),NULL);
232 if (res != S_OK)
234 ERR("couldn't reading moniker count from stream\n");
235 return E_FAIL;
238 CompositeMonikerImpl_ReleaseMonikersInTable(This);
240 for (i = 0; i < moniker_count; i++)
242 res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
243 if (FAILED(res))
245 ERR("couldn't load moniker from stream, res = 0x%08lx\n", res);
246 break;
249 /* resize the table if needed */
250 if (++This->tabLastIndex==This->tabSize){
252 This->tabSize+=BLOCK_TAB_SIZE;
253 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
255 if (This->tabMoniker==NULL)
256 return E_OUTOFMEMORY;
260 return res;
263 /******************************************************************************
264 * CompositeMoniker_Save
265 ******************************************************************************/
266 static HRESULT WINAPI
267 CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
269 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
270 HRESULT res;
271 IEnumMoniker *enumMk;
272 IMoniker *pmk;
273 DWORD moniker_count = This->tabLastIndex;
275 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
277 /* This function calls OleSaveToStream function for each moniker within
278 * this object.
279 * When I tested this function in windows, I usually found this constant
280 * at the beginning of the stream. I don't known why (there's no
281 * indication in the specification) !
283 res=IStream_Write(pStm,&moniker_count,sizeof(moniker_count),NULL);
284 if (FAILED(res)) return res;
286 IMoniker_Enum(iface,TRUE,&enumMk);
288 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
290 res=OleSaveToStream((IPersistStream*)pmk,pStm);
292 IMoniker_Release(pmk);
294 if (FAILED(res)){
296 IEnumMoniker_Release(enumMk);
297 return res;
301 IEnumMoniker_Release(enumMk);
303 return S_OK;
306 /******************************************************************************
307 * CompositeMoniker_GetSizeMax
308 ******************************************************************************/
309 static HRESULT WINAPI
310 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
312 IEnumMoniker *enumMk;
313 IMoniker *pmk;
314 ULARGE_INTEGER ptmpSize;
316 /* The sizeMax of this object is calculated by calling GetSizeMax on
317 * each moniker within this object then summing all returned values
320 TRACE("(%p,%p)\n",iface,pcbSize);
322 if (!pcbSize)
323 return E_POINTER;
325 pcbSize->QuadPart = sizeof(DWORD);
327 IMoniker_Enum(iface,TRUE,&enumMk);
329 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
331 IMoniker_GetSizeMax(pmk,&ptmpSize);
333 IMoniker_Release(pmk);
335 pcbSize->QuadPart = ptmpSize.QuadPart + sizeof(CLSID);
338 IEnumMoniker_Release(enumMk);
340 return S_OK;
343 /******************************************************************************
344 * CompositeMoniker_BindToObject
345 ******************************************************************************/
346 static HRESULT WINAPI
347 CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,
348 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
350 HRESULT res;
351 IRunningObjectTable *prot;
352 IMoniker *tempMk,*antiMk,*mostRigthMk;
353 IEnumMoniker *enumMoniker;
355 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
357 if (ppvResult==NULL)
358 return E_POINTER;
360 *ppvResult=0;
361 /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
362 /* object for the requested interface pointer. */
363 if(pmkToLeft==NULL){
365 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
367 if (SUCCEEDED(res)){
369 /* if the requested class was loaded before ! we don't need to reload it */
370 res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
372 if (res==S_OK)
373 return res;
376 else{
377 /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
378 /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
380 IMoniker_Enum(iface,FALSE,&enumMoniker);
381 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
382 IEnumMoniker_Release(enumMoniker);
384 res=CreateAntiMoniker(&antiMk);
385 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
386 IMoniker_Release(antiMk);
388 res=IMoniker_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult);
390 IMoniker_Release(tempMk);
391 IMoniker_Release(mostRigthMk);
394 return res;
397 /******************************************************************************
398 * CompositeMoniker_BindToStorage
399 ******************************************************************************/
400 static HRESULT WINAPI
401 CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
402 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
404 HRESULT res;
405 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk;
406 IEnumMoniker *enumMoniker;
408 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
410 *ppvResult=0;
412 /* This method recursively calls BindToStorage on the rightmost component of the composite, */
413 /* passing the rest of the composite as the pmkToLeft parameter for that call. */
415 if (pmkToLeft)
417 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
418 if (FAILED(res)) return res;
420 else
421 leftMk = iface;
423 IMoniker_Enum(iface, FALSE, &enumMoniker);
424 IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL);
425 IEnumMoniker_Release(enumMoniker);
427 res = CreateAntiMoniker(&antiMk);
428 if (FAILED(res)) return res;
429 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
430 if (FAILED(res)) return res;
431 IMoniker_Release(antiMk);
433 res = IMoniker_BindToStorage(mostRigthMk, pbc, tempMk, riid, ppvResult);
435 IMoniker_Release(tempMk);
437 IMoniker_Release(mostRigthMk);
439 if (pmkToLeft)
440 IMoniker_Release(leftMk);
442 return res;
445 /******************************************************************************
446 * CompositeMoniker_Reduce
447 ******************************************************************************/
448 static HRESULT WINAPI
449 CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
450 IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
452 HRESULT res;
453 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk;
454 IEnumMoniker *enumMoniker;
456 TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
458 if (ppmkReduced==NULL)
459 return E_POINTER;
461 /* This method recursively calls Reduce for each of its component monikers. */
463 if (ppmkToLeft==NULL){
465 IMoniker_Enum(iface,FALSE,&enumMoniker);
466 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
467 IEnumMoniker_Release(enumMoniker);
469 res=CreateAntiMoniker(&antiMk);
470 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
471 IMoniker_Release(antiMk);
473 return CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
475 else if (*ppmkToLeft==NULL)
477 return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);
479 else{
481 /* separate the composite moniker in to left and right moniker */
482 IMoniker_Enum(iface,FALSE,&enumMoniker);
483 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
484 IEnumMoniker_Release(enumMoniker);
486 res=CreateAntiMoniker(&antiMk);
487 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
488 IMoniker_Release(antiMk);
490 /* If any of the components reduces itself, the method returns S_OK and passes back a composite */
491 /* of the reduced components */
492 if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) &&
493 CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk)
496 return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced);
498 else{
499 /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
501 IMoniker_AddRef(iface);
503 *ppmkReduced=iface;
505 return MK_S_REDUCED_TO_SELF;
510 /******************************************************************************
511 * CompositeMoniker_ComposeWith
512 ******************************************************************************/
513 static HRESULT WINAPI
514 CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
515 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
517 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
519 if ((ppmkComposite==NULL)||(pmkRight==NULL))
520 return E_POINTER;
522 *ppmkComposite=0;
524 /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */
525 /* otherwise, the method returns the result of combining the two monikers by calling the */
526 /* CreateGenericComposite function */
528 if (fOnlyIfNotGeneric)
529 return MK_E_NEEDGENERIC;
531 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
534 /******************************************************************************
535 * CompositeMoniker_Enum
536 ******************************************************************************/
537 static HRESULT WINAPI
538 CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
540 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
542 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
544 if (ppenumMoniker == NULL)
545 return E_POINTER;
547 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);
550 /******************************************************************************
551 * CompositeMoniker_IsEqual
552 ******************************************************************************/
553 static HRESULT WINAPI
554 CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
556 IEnumMoniker *enumMoniker1,*enumMoniker2;
557 IMoniker *tempMk1,*tempMk2;
558 HRESULT res1,res2,res;
560 TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
562 if (pmkOtherMoniker==NULL)
563 return S_FALSE;
565 /* This method returns S_OK if the components of both monikers are equal when compared in the */
566 /* left-to-right order.*/
567 IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);
569 if (enumMoniker1==NULL)
570 return S_FALSE;
572 IMoniker_Enum(iface,TRUE,&enumMoniker2);
574 while(1){
576 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
577 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
579 if((res1==S_OK)&&(res2==S_OK)){
581 if(IMoniker_IsEqual(tempMk1,tempMk2)==S_FALSE){
582 res= S_FALSE;
583 break;
585 else
586 continue;
588 else if ( (res1==S_FALSE) && (res2==S_FALSE) ){
589 res = S_OK;
590 break;
592 else{
593 res = S_FALSE;
594 break;
597 if (res1==S_OK)
598 IMoniker_Release(tempMk1);
600 if (res2==S_OK)
601 IMoniker_Release(tempMk2);
604 IEnumMoniker_Release(enumMoniker1);
605 IEnumMoniker_Release(enumMoniker2);
607 return res;
609 /******************************************************************************
610 * CompositeMoniker_Hash
611 ******************************************************************************/
612 static HRESULT WINAPI
613 CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
615 IEnumMoniker *enumMoniker;
616 IMoniker *tempMk;
617 HRESULT res;
618 DWORD tempHash;
620 TRACE("(%p,%p)\n",iface,pdwHash);
622 if (pdwHash==NULL)
623 return E_POINTER;
625 res = IMoniker_Enum(iface,TRUE,&enumMoniker);
626 if(FAILED(res))
627 return res;
629 *pdwHash = 0;
631 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
632 res = IMoniker_Hash(tempMk, &tempHash);
633 if(FAILED(res))
634 break;
635 *pdwHash = *pdwHash ^ tempHash;
637 IMoniker_Release(tempMk);
640 IEnumMoniker_Release(enumMoniker);
642 return res;
645 /******************************************************************************
646 * CompositeMoniker_IsRunning
647 ******************************************************************************/
648 static HRESULT WINAPI
649 CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc,
650 IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
652 IRunningObjectTable* rot;
653 HRESULT res;
654 IMoniker *tempMk,*antiMk,*mostRigthMk;
655 IEnumMoniker *enumMoniker;
657 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
659 /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/
660 if (pmkToLeft!=NULL){
662 CreateGenericComposite(pmkToLeft,iface,&tempMk);
664 res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);
666 IMoniker_Release(tempMk);
668 return res;
670 else
671 /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */
672 /* to this moniker */
674 if (pmkNewlyRunning!=NULL)
676 if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)
677 return S_OK;
679 else
680 return S_FALSE;
682 else{
684 if (pbc==NULL)
685 return E_POINTER;
687 /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */
688 /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */
689 /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */
690 /* the composite as the pmkToLeft parameter for that call. */
692 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
694 if (FAILED(res))
695 return res;
697 res = IRunningObjectTable_IsRunning(rot,iface);
698 IRunningObjectTable_Release(rot);
700 if(res==S_OK)
701 return S_OK;
703 else{
705 IMoniker_Enum(iface,FALSE,&enumMoniker);
706 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
707 IEnumMoniker_Release(enumMoniker);
709 res=CreateAntiMoniker(&antiMk);
710 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
711 IMoniker_Release(antiMk);
713 res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning);
715 IMoniker_Release(tempMk);
716 IMoniker_Release(mostRigthMk);
718 return res;
723 /******************************************************************************
724 * CompositeMoniker_GetTimeOfLastChange
725 ******************************************************************************/
726 static HRESULT WINAPI
727 CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
728 IMoniker* pmkToLeft, FILETIME* pCompositeTime)
730 IRunningObjectTable* rot;
731 HRESULT res;
732 IMoniker *tempMk,*antiMk,*mostRigthMk;
733 IEnumMoniker *enumMoniker;
735 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);
737 if (pCompositeTime==NULL)
738 return E_INVALIDARG;
740 /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to */
741 /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */
742 /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */
743 /* of the composite as the pmkToLeft parameter for that call. */
744 if (pmkToLeft!=NULL){
746 res=CreateGenericComposite(pmkToLeft,iface,&tempMk);
748 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
750 if (FAILED(res))
751 return res;
753 if (IRunningObjectTable_GetTimeOfLastChange(rot,tempMk,pCompositeTime)==S_OK)
754 return res;
755 else
757 IMoniker_Enum(iface,FALSE,&enumMoniker);
758 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
759 IEnumMoniker_Release(enumMoniker);
761 res=CreateAntiMoniker(&antiMk);
762 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
763 IMoniker_Release(antiMk);
765 res=CompositeMonikerImpl_GetTimeOfLastChange(mostRigthMk,pbc,tempMk,pCompositeTime);
767 IMoniker_Release(tempMk);
768 IMoniker_Release(mostRigthMk);
770 return res;
772 else
773 return IMoniker_GetTimeOfLastChange(iface,pbc,NULL,pCompositeTime);
776 /******************************************************************************
777 * CompositeMoniker_Inverse
778 ******************************************************************************/
779 static HRESULT WINAPI
780 CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
782 HRESULT res;
783 IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk;
784 IEnumMoniker *enumMoniker;
786 TRACE("(%p,%p)\n",iface,ppmk);
788 if (ppmk==NULL)
789 return E_POINTER;
791 /* This method returns a composite moniker that consists of the inverses of each of the components */
792 /* of the original composite, stored in reverse order */
794 res=CreateAntiMoniker(&antiMk);
795 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
796 IMoniker_Release(antiMk);
798 if (tempMk==NULL)
800 return IMoniker_Inverse(iface,ppmk);
802 else{
804 IMoniker_Enum(iface,FALSE,&enumMoniker);
805 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
806 IEnumMoniker_Release(enumMoniker);
808 IMoniker_Inverse(mostRigthMk,&mostRigthInvMk);
809 CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);
811 res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk);
813 IMoniker_Release(tempMk);
814 IMoniker_Release(mostRigthMk);
815 IMoniker_Release(tempInvMk);
816 IMoniker_Release(mostRigthInvMk);
818 return res;
822 /******************************************************************************
823 * CompositeMoniker_CommonPrefixWith
824 ******************************************************************************/
825 static HRESULT WINAPI
826 CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,
827 IMoniker** ppmkPrefix)
829 DWORD mkSys;
830 HRESULT res1,res2;
831 IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
832 IEnumMoniker *enumMoniker1,*enumMoniker2;
833 ULONG i,nbCommonMk=0;
835 /* If the other moniker is a composite, this method compares the components of each composite from left */
836 /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
837 /* of the leftmost components were common to both monikers. */
839 if (ppmkPrefix==NULL)
840 return E_POINTER;
842 *ppmkPrefix=0;
844 if (pmkOther==NULL)
845 return MK_E_NOPREFIX;
847 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
849 if((mkSys==MKSYS_GENERICCOMPOSITE)){
851 IMoniker_Enum(iface,TRUE,&enumMoniker1);
852 IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
854 while(1){
856 res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
857 res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
859 if ((res1==S_FALSE) && (res2==S_FALSE)){
861 /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
862 *ppmkPrefix=iface;
863 IMoniker_AddRef(iface);
864 return MK_S_US;
866 else if ((res1==S_OK) && (res2==S_OK)){
868 if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
870 nbCommonMk++;
872 else
873 break;
876 else if (res1==S_OK){
878 /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
879 /* ppmkPrefix to the other moniker. */
880 *ppmkPrefix=pmkOther;
881 return MK_S_HIM;
883 else{
884 /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
885 /* to this moniker. */
886 *ppmkPrefix=iface;
887 return MK_S_ME;
891 IEnumMoniker_Release(enumMoniker1);
892 IEnumMoniker_Release(enumMoniker2);
894 /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
895 if (nbCommonMk==0)
896 return MK_E_NOPREFIX;
898 IEnumMoniker_Reset(enumMoniker1);
900 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
902 /* if we have more than one commun moniker the result will be a composite moniker */
903 if (nbCommonMk>1){
905 /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
906 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
907 CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
908 IMoniker_Release(tempMk1);
909 IMoniker_Release(tempMk2);
911 /* compose all common monikers in a composite moniker */
912 for(i=0;i<nbCommonMk;i++){
914 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
916 CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
918 IMoniker_Release(*ppmkPrefix);
920 IMoniker_Release(tempMk1);
922 *ppmkPrefix=tempMk2;
924 return S_OK;
926 else{
927 /* if we have only one commun moniker the result will be a simple moniker which is the most-left one*/
928 *ppmkPrefix=tempMk1;
930 return S_OK;
933 else{
934 /* If the other moniker is not a composite, the method simply compares it to the leftmost component
935 of this moniker.*/
937 IMoniker_Enum(iface,TRUE,&enumMoniker1);
939 IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
941 if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){
943 *ppmkPrefix=pmkOther;
945 return MK_S_HIM;
947 else
948 return MK_E_NOPREFIX;
952 /***************************************************************************************************
953 * GetAfterCommonPrefix (local function)
954 * This function returns a moniker that consist of the remainder when the common prefix is removed
955 ***************************************************************************************************/
956 static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk)
958 IMoniker *tempMk,*tempMk1,*tempMk2;
959 IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3;
960 ULONG nbRestMk=0;
961 DWORD mkSys;
962 HRESULT res1,res2;
964 *restMk=0;
966 /* to create an enumerator for pGenMk with current position pointed on the first element after common */
967 /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop */
968 /* on the first difference. */
969 IMoniker_Enum(pGenMk,TRUE,&enumMoniker1);
971 IMoniker_IsSystemMoniker(commonMk,&mkSys);
973 if (mkSys==MKSYS_GENERICCOMPOSITE){
975 IMoniker_Enum(commonMk,TRUE,&enumMoniker2);
976 while(1){
978 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
979 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
981 if ((res1==S_FALSE)||(res2==S_FALSE)){
983 if (res1==S_OK)
985 nbRestMk++;
987 IMoniker_Release(tempMk1);
988 IMoniker_Release(tempMk1);
990 break;
992 IMoniker_Release(tempMk1);
993 IMoniker_Release(tempMk1);
996 else{
997 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
998 IMoniker_Release(tempMk1);
1001 /* count the number of elements in the enumerator after the common prefix */
1002 IEnumMoniker_Clone(enumMoniker1,&enumMoniker3);
1004 for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++)
1006 IMoniker_Release(tempMk);
1008 if (nbRestMk==0)
1009 return;
1011 /* create a generic composite moniker with monikers located after the common prefix */
1012 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
1014 if (nbRestMk==1){
1016 *restMk= tempMk1;
1017 return;
1019 else {
1021 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
1023 CreateGenericComposite(tempMk1,tempMk2,restMk);
1025 IMoniker_Release(tempMk1);
1027 IMoniker_Release(tempMk2);
1029 while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){
1031 CreateGenericComposite(*restMk,tempMk1,&tempMk2);
1033 IMoniker_Release(tempMk1);
1035 IMoniker_Release(*restMk);
1037 *restMk=tempMk2;
1042 /******************************************************************************
1043 * CompositeMoniker_RelativePathTo
1044 ******************************************************************************/
1045 static HRESULT WINAPI
1046 CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther,
1047 IMoniker** ppmkRelPath)
1049 HRESULT res;
1050 IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0;
1052 TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath);
1054 if (ppmkRelPath==NULL)
1055 return E_POINTER;
1057 *ppmkRelPath=0;
1059 /* This method finds the common prefix of the two monikers and creates two monikers that consist */
1060 /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */
1061 /* of this moniker and composes the remainder of the other moniker on the right of it. */
1063 /* finds the common prefix of the two monikers */
1064 res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk);
1066 /* if there's no common prefix or the two moniker are equal the relative is the other moniker */
1067 if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){
1069 *ppmkRelPath=pmkOther;
1070 IMoniker_AddRef(pmkOther);
1071 return MK_S_HIM;
1074 GetAfterCommonPrefix(iface,commonMk,&restThisMk);
1075 GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk);
1077 /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */
1078 /* moniker when the common prefix is removed */
1079 if (res==MK_S_HIM){
1081 IMoniker_Inverse(restThisMk,ppmkRelPath);
1082 IMoniker_Release(restThisMk);
1084 /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */
1085 /* when the common prefix is removed */
1086 else if (res==MK_S_ME){
1088 *ppmkRelPath=restOtherMk;
1089 IMoniker_AddRef(restOtherMk);
1091 /* the relative path is the inverse for the remainder of this moniker and the remainder of the other */
1092 /* moniker on the right of it. */
1093 else if (res==S_OK){
1095 IMoniker_Inverse(restThisMk,&invRestThisMk);
1096 IMoniker_Release(restThisMk);
1097 CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath);
1098 IMoniker_Release(invRestThisMk);
1099 IMoniker_Release(restOtherMk);
1101 return S_OK;
1104 /******************************************************************************
1105 * CompositeMoniker_GetDisplayName
1106 ******************************************************************************/
1107 static HRESULT WINAPI
1108 CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1109 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1111 ULONG lengthStr=1;
1112 IEnumMoniker *enumMoniker;
1113 IMoniker* tempMk;
1114 LPOLESTR tempStr;
1116 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1118 if (ppszDisplayName==NULL)
1119 return E_POINTER;
1121 *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR));
1123 if (*ppszDisplayName==NULL)
1124 return E_OUTOFMEMORY;
1126 /* This method returns the concatenation of the display names returned by each component moniker of */
1127 /* the composite */
1129 **ppszDisplayName=0;
1131 IMoniker_Enum(iface,TRUE,&enumMoniker);
1133 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
1135 IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr);
1137 lengthStr+=lstrlenW(tempStr);
1139 *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));
1141 if (*ppszDisplayName==NULL)
1142 return E_OUTOFMEMORY;
1144 strcatW(*ppszDisplayName,tempStr);
1146 CoTaskMemFree(tempStr);
1147 IMoniker_Release(tempMk);
1150 IEnumMoniker_Release(enumMoniker);
1152 return S_OK;
1155 /******************************************************************************
1156 * CompositeMoniker_ParseDisplayName
1157 ******************************************************************************/
1158 static HRESULT WINAPI
1159 CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc,
1160 IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten,
1161 IMoniker** ppmkOut)
1163 IEnumMoniker *enumMoniker;
1164 IMoniker *tempMk,*mostRigthMk,*antiMk;
1165 /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/
1166 /* passing everything else as the pmkToLeft parameter for that call. */
1168 /* get the most right moniker */
1169 IMoniker_Enum(iface,FALSE,&enumMoniker);
1170 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
1171 IEnumMoniker_Release(enumMoniker);
1173 /* get the left moniker */
1174 CreateAntiMoniker(&antiMk);
1175 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
1176 IMoniker_Release(antiMk);
1178 return IMoniker_ParseDisplayName(mostRigthMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut);
1181 /******************************************************************************
1182 * CompositeMoniker_IsSystemMoniker
1183 ******************************************************************************/
1184 static HRESULT WINAPI
1185 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1187 TRACE("(%p,%p)\n",iface,pwdMksys);
1189 if (!pwdMksys)
1190 return E_POINTER;
1192 (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
1194 return S_OK;
1197 /*******************************************************************************
1198 * CompositeMonikerIROTData_QueryInterface
1199 *******************************************************************************/
1200 static HRESULT WINAPI
1201 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
1202 VOID** ppvObject)
1205 IMoniker *This = impl_from_IROTData(iface);
1207 TRACE("(%p,%p,%p)\n",iface,riid,ppvObject);
1209 return CompositeMonikerImpl_QueryInterface(This, riid, ppvObject);
1212 /***********************************************************************
1213 * CompositeMonikerIROTData_AddRef
1215 static ULONG WINAPI
1216 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
1218 IMoniker *This = impl_from_IROTData(iface);
1220 TRACE("(%p)\n",iface);
1222 return IMoniker_AddRef(This);
1225 /***********************************************************************
1226 * CompositeMonikerIROTData_Release
1228 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1230 IMoniker *This = impl_from_IROTData(iface);
1232 TRACE("(%p)\n",iface);
1234 return IMoniker_Release(This);
1237 /******************************************************************************
1238 * CompositeMonikerIROTData_GetComparisonData
1239 ******************************************************************************/
1240 static HRESULT WINAPI
1241 CompositeMonikerROTDataImpl_GetComparisonData(IROTData* iface,
1242 BYTE* pbData, ULONG cbMax, ULONG* pcbData)
1244 IMoniker *This = impl_from_IROTData(iface);
1245 IEnumMoniker *pEnumMk;
1246 IMoniker *pmk;
1247 HRESULT hr;
1249 TRACE("(%p, %lu, %p)\n", pbData, cbMax, pcbData);
1251 *pcbData = sizeof(CLSID);
1253 hr = IMoniker_Enum(This, TRUE, &pEnumMk);
1254 if (FAILED(hr)) return hr;
1256 while(IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1258 IROTData *pROTData;
1259 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1260 if (FAILED(hr))
1261 ERR("moniker doesn't support IROTData interface\n");
1263 if (SUCCEEDED(hr))
1265 ULONG cbData;
1266 hr = IROTData_GetComparisonData(pROTData, NULL, 0, &cbData);
1267 IROTData_Release(pROTData);
1268 if (SUCCEEDED(hr) || (hr == E_OUTOFMEMORY))
1270 *pcbData += cbData;
1271 hr = S_OK;
1273 else
1274 ERR("IROTData_GetComparisonData failed with error 0x%08lx\n", hr);
1277 IMoniker_Release(pmk);
1279 if (FAILED(hr))
1281 IEnumMoniker_Release(pEnumMk);
1282 return hr;
1285 if (cbMax < *pcbData)
1286 return E_OUTOFMEMORY;
1288 IEnumMoniker_Reset(pEnumMk);
1290 memcpy(pbData, &CLSID_CompositeMoniker, sizeof(CLSID));
1291 pbData += sizeof(CLSID);
1292 cbMax -= sizeof(CLSID);
1294 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1296 IROTData *pROTData;
1297 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1298 if (FAILED(hr))
1299 ERR("moniker doesn't support IROTData interface\n");
1301 if (SUCCEEDED(hr))
1303 ULONG cbData;
1304 hr = IROTData_GetComparisonData(pROTData, pbData, cbMax, &cbData);
1305 IROTData_Release(pROTData);
1306 if (SUCCEEDED(hr))
1308 pbData += cbData;
1309 cbMax -= cbData;
1311 else
1312 ERR("IROTData_GetComparisonData failed with error 0x%08lx\n", hr);
1315 IMoniker_Release(pmk);
1317 if (FAILED(hr))
1319 IEnumMoniker_Release(pEnumMk);
1320 return hr;
1324 IEnumMoniker_Release(pEnumMk);
1326 return S_OK;
1329 static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1331 IMoniker *This = impl_from_IMarshal(iface);
1333 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);
1335 return CompositeMonikerImpl_QueryInterface(This, riid, ppv);
1338 static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
1340 IMoniker *This = impl_from_IMarshal(iface);
1342 TRACE("(%p)\n",iface);
1344 return CompositeMonikerImpl_AddRef(This);
1347 static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
1349 IMoniker *This = impl_from_IMarshal(iface);
1351 TRACE("(%p)\n",iface);
1353 return CompositeMonikerImpl_Release(This);
1356 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
1357 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1358 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1360 IMoniker *This = impl_from_IMarshal(iface);
1362 TRACE("(%s, %p, %lx, %p, %lx, %p)\n", debugstr_guid(riid), pv,
1363 dwDestContext, pvDestContext, mshlflags, pCid);
1365 return IMoniker_GetClassID(This, pCid);
1368 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
1369 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1370 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1372 IMoniker *This = impl_from_IMarshal(iface);
1373 IEnumMoniker *pEnumMk;
1374 IMoniker *pmk;
1375 HRESULT hr;
1376 ULARGE_INTEGER size;
1378 TRACE("(%s, %p, %lx, %p, %lx, %p)\n", debugstr_guid(riid), pv,
1379 dwDestContext, pvDestContext, mshlflags, pSize);
1381 *pSize = 0x10; /* to match native */
1383 hr = IMoniker_Enum(This, TRUE, &pEnumMk);
1384 if (FAILED(hr)) return hr;
1386 hr = IMoniker_GetSizeMax(This, &size);
1388 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1390 ULONG size;
1392 hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1393 if (SUCCEEDED(hr))
1394 *pSize += size;
1396 IMoniker_Release(pmk);
1398 if (FAILED(hr))
1400 IEnumMoniker_Release(pEnumMk);
1401 return hr;
1405 IEnumMoniker_Release(pEnumMk);
1407 return S_OK;
1410 static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(LPMARSHAL iface, IStream *pStm,
1411 REFIID riid, void* pv, DWORD dwDestContext,
1412 void* pvDestContext, DWORD mshlflags)
1414 IMoniker *This = impl_from_IMarshal(iface);
1415 IEnumMoniker *pEnumMk;
1416 IMoniker *pmk;
1417 HRESULT hr;
1418 ULONG i = 0;
1420 TRACE("(%p, %s, %p, %lx, %p, %lx)\n", pStm, debugstr_guid(riid), pv,
1421 dwDestContext, pvDestContext, mshlflags);
1423 hr = IMoniker_Enum(This, TRUE, &pEnumMk);
1424 if (FAILED(hr)) return hr;
1426 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1428 hr = CoMarshalInterface(pStm, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1430 IMoniker_Release(pmk);
1432 if (FAILED(hr))
1434 IEnumMoniker_Release(pEnumMk);
1435 return hr;
1437 i++;
1440 if (i != 2)
1441 FIXME("moniker count of %ld not supported\n", i);
1443 IEnumMoniker_Release(pEnumMk);
1445 return S_OK;
1448 static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
1450 CompositeMonikerImpl *This = (CompositeMonikerImpl *)impl_from_IMarshal(iface);
1451 HRESULT hr;
1453 TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1455 CompositeMonikerImpl_ReleaseMonikersInTable(This);
1457 /* resize the table if needed */
1458 if (This->tabLastIndex + 2 > This->tabSize)
1460 This->tabSize += max(BLOCK_TAB_SIZE, 2);
1461 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1463 if (This->tabMoniker==NULL)
1464 return E_OUTOFMEMORY;
1467 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1468 if (FAILED(hr))
1470 ERR("couldn't unmarshal moniker, hr = 0x%08lx\n", hr);
1471 return hr;
1473 This->tabLastIndex++;
1474 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1475 if (FAILED(hr))
1477 ERR("couldn't unmarshal moniker, hr = 0x%08lx\n", hr);
1478 return hr;
1480 This->tabLastIndex++;
1482 return IMoniker_QueryInterface((IMoniker *)&This->lpvtbl1, riid, ppv);
1485 static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
1487 TRACE("(%p)\n", pStm);
1488 /* can't release a state-based marshal as nothing on server side to
1489 * release */
1490 return S_OK;
1493 static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
1495 TRACE("(0x%lx)\n", dwReserved);
1496 /* can't disconnect a state-based marshal as nothing on server side to
1497 * disconnect from */
1498 return S_OK;
1501 /******************************************************************************
1502 * EnumMonikerImpl_QueryInterface
1503 ******************************************************************************/
1504 static HRESULT WINAPI
1505 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1507 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1509 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
1511 /* Perform a sanity check on the parameters.*/
1512 if ( (This==0) || (ppvObject==0) )
1513 return E_INVALIDARG;
1515 /* Initialize the return parameter */
1516 *ppvObject = 0;
1518 /* Compare the riid with the interface IDs implemented by this object.*/
1519 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
1520 *ppvObject = iface;
1522 /* Check that we obtained an interface.*/
1523 if ((*ppvObject)==0)
1524 return E_NOINTERFACE;
1526 /* Query Interface always increases the reference count by one when it is successful */
1527 IEnumMoniker_AddRef(iface);
1529 return S_OK;
1532 /******************************************************************************
1533 * EnumMonikerImpl_AddRef
1534 ******************************************************************************/
1535 static ULONG WINAPI
1536 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1538 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1540 TRACE("(%p)\n",This);
1542 return InterlockedIncrement(&This->ref);
1546 /******************************************************************************
1547 * EnumMonikerImpl_Release
1548 ******************************************************************************/
1549 static ULONG WINAPI
1550 EnumMonikerImpl_Release(IEnumMoniker* iface)
1552 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1553 ULONG i;
1554 ULONG ref;
1555 TRACE("(%p)\n",This);
1557 ref = InterlockedDecrement(&This->ref);
1559 /* destroy the object if there's no more reference on it */
1560 if (ref == 0) {
1562 for(i=0;i<This->tabSize;i++)
1563 IMoniker_Release(This->tabMoniker[i]);
1565 HeapFree(GetProcessHeap(),0,This->tabMoniker);
1566 HeapFree(GetProcessHeap(),0,This);
1568 return ref;
1571 /******************************************************************************
1572 * EnumMonikerImpl_Next
1573 ******************************************************************************/
1574 static HRESULT WINAPI
1575 EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt,
1576 ULONG* pceltFethed)
1578 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1579 ULONG i;
1581 /* retrieve the requested number of moniker from the current position */
1582 for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++)
1584 rgelt[i]=This->tabMoniker[This->currentPos++];
1585 IMoniker_AddRef(rgelt[i]);
1588 if (pceltFethed!=NULL)
1589 *pceltFethed= i;
1591 if (i==celt)
1592 return S_OK;
1593 else
1594 return S_FALSE;
1597 /******************************************************************************
1598 * EnumMonikerImpl_Skip
1599 ******************************************************************************/
1600 static HRESULT WINAPI
1601 EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt)
1603 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1605 if ((This->currentPos+celt) >= This->tabSize)
1606 return S_FALSE;
1608 This->currentPos+=celt;
1610 return S_OK;
1613 /******************************************************************************
1614 * EnumMonikerImpl_Reset
1615 ******************************************************************************/
1616 static HRESULT WINAPI
1617 EnumMonikerImpl_Reset(IEnumMoniker* iface)
1620 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1622 This->currentPos=0;
1624 return S_OK;
1627 /******************************************************************************
1628 * EnumMonikerImpl_Clone
1629 ******************************************************************************/
1630 static HRESULT WINAPI
1631 EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)
1633 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1635 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
1638 /********************************************************************************/
1639 /* Virtual function table for the IROTData class */
1640 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1642 EnumMonikerImpl_QueryInterface,
1643 EnumMonikerImpl_AddRef,
1644 EnumMonikerImpl_Release,
1645 EnumMonikerImpl_Next,
1646 EnumMonikerImpl_Skip,
1647 EnumMonikerImpl_Reset,
1648 EnumMonikerImpl_Clone
1651 /******************************************************************************
1652 * EnumMonikerImpl_CreateEnumMoniker
1653 ******************************************************************************/
1654 static HRESULT
1655 EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize,
1656 ULONG currentPos, BOOL leftToRigth, IEnumMoniker ** ppmk)
1658 EnumMonikerImpl* newEnumMoniker;
1659 int i;
1661 if (currentPos > tabSize)
1662 return E_INVALIDARG;
1664 newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
1666 if (newEnumMoniker == 0)
1667 return STG_E_INSUFFICIENTMEMORY;
1669 /* Initialize the virtual function table. */
1670 newEnumMoniker->lpVtbl = &VT_EnumMonikerImpl;
1671 newEnumMoniker->ref = 1;
1673 newEnumMoniker->tabSize=tabSize;
1674 newEnumMoniker->currentPos=currentPos;
1676 newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(IMoniker));
1678 if (newEnumMoniker->tabMoniker==NULL) {
1679 HeapFree(GetProcessHeap(), 0, newEnumMoniker);
1680 return E_OUTOFMEMORY;
1683 if (leftToRigth)
1684 for (i=0;i<tabSize;i++){
1686 newEnumMoniker->tabMoniker[i]=tabMoniker[i];
1687 IMoniker_AddRef(tabMoniker[i]);
1689 else
1690 for (i=tabSize-1;i>=0;i--){
1692 newEnumMoniker->tabMoniker[tabSize-i-1]=tabMoniker[i];
1693 IMoniker_AddRef(tabMoniker[i]);
1696 *ppmk=(IEnumMoniker*)newEnumMoniker;
1698 return S_OK;
1701 /********************************************************************************/
1702 /* Virtual function table for the CompositeMonikerImpl class which includes */
1703 /* IPersist, IPersistStream and IMoniker functions. */
1705 static const IMonikerVtbl VT_CompositeMonikerImpl =
1707 CompositeMonikerImpl_QueryInterface,
1708 CompositeMonikerImpl_AddRef,
1709 CompositeMonikerImpl_Release,
1710 CompositeMonikerImpl_GetClassID,
1711 CompositeMonikerImpl_IsDirty,
1712 CompositeMonikerImpl_Load,
1713 CompositeMonikerImpl_Save,
1714 CompositeMonikerImpl_GetSizeMax,
1715 CompositeMonikerImpl_BindToObject,
1716 CompositeMonikerImpl_BindToStorage,
1717 CompositeMonikerImpl_Reduce,
1718 CompositeMonikerImpl_ComposeWith,
1719 CompositeMonikerImpl_Enum,
1720 CompositeMonikerImpl_IsEqual,
1721 CompositeMonikerImpl_Hash,
1722 CompositeMonikerImpl_IsRunning,
1723 CompositeMonikerImpl_GetTimeOfLastChange,
1724 CompositeMonikerImpl_Inverse,
1725 CompositeMonikerImpl_CommonPrefixWith,
1726 CompositeMonikerImpl_RelativePathTo,
1727 CompositeMonikerImpl_GetDisplayName,
1728 CompositeMonikerImpl_ParseDisplayName,
1729 CompositeMonikerImpl_IsSystemMoniker
1732 /********************************************************************************/
1733 /* Virtual function table for the IROTData class. */
1734 static const IROTDataVtbl VT_ROTDataImpl =
1736 CompositeMonikerROTDataImpl_QueryInterface,
1737 CompositeMonikerROTDataImpl_AddRef,
1738 CompositeMonikerROTDataImpl_Release,
1739 CompositeMonikerROTDataImpl_GetComparisonData
1742 static const IMarshalVtbl VT_MarshalImpl =
1744 CompositeMonikerMarshalImpl_QueryInterface,
1745 CompositeMonikerMarshalImpl_AddRef,
1746 CompositeMonikerMarshalImpl_Release,
1747 CompositeMonikerMarshalImpl_GetUnmarshalClass,
1748 CompositeMonikerMarshalImpl_GetMarshalSizeMax,
1749 CompositeMonikerMarshalImpl_MarshalInterface,
1750 CompositeMonikerMarshalImpl_UnmarshalInterface,
1751 CompositeMonikerMarshalImpl_ReleaseMarshalData,
1752 CompositeMonikerMarshalImpl_DisconnectObject
1755 /******************************************************************************
1756 * Composite-Moniker_Construct (local function)
1757 *******************************************************************************/
1758 static HRESULT
1759 CompositeMonikerImpl_Construct(CompositeMonikerImpl** ppThis,
1760 LPMONIKER pmkFirst, LPMONIKER pmkRest)
1762 DWORD mkSys;
1763 IEnumMoniker *enumMoniker;
1764 IMoniker *tempMk;
1765 HRESULT res;
1766 CompositeMonikerImpl *This;
1768 *ppThis = This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1770 if (!This)
1771 return E_OUTOFMEMORY;
1773 TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);
1775 /* Initialize the virtual function table. */
1776 This->lpvtbl1 = &VT_CompositeMonikerImpl;
1777 This->lpvtbl2 = &VT_ROTDataImpl;
1778 This->lpvtblMarshal= &VT_MarshalImpl;
1779 This->ref = 0;
1781 This->tabSize=BLOCK_TAB_SIZE;
1782 This->tabLastIndex=0;
1784 This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(IMoniker));
1785 if (This->tabMoniker==NULL)
1786 return E_OUTOFMEMORY;
1788 if (!pmkFirst && !pmkRest)
1789 return S_OK;
1791 IMoniker_IsSystemMoniker(pmkFirst,&mkSys);
1793 /* put the first moniker contents in the beginning of the table */
1794 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1796 This->tabMoniker[(This->tabLastIndex)++]=pmkFirst;
1797 IMoniker_AddRef(pmkFirst);
1799 else{
1801 IMoniker_Enum(pmkFirst,TRUE,&enumMoniker);
1803 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1806 if (++This->tabLastIndex==This->tabSize){
1808 This->tabSize+=BLOCK_TAB_SIZE;
1809 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1811 if (This->tabMoniker==NULL)
1812 return E_OUTOFMEMORY;
1816 IEnumMoniker_Release(enumMoniker);
1819 /* put the rest moniker contents after the first one and make simplification if needed */
1821 IMoniker_IsSystemMoniker(pmkRest,&mkSys);
1823 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1825 /* add a simple moniker to the moniker table */
1827 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk);
1829 if (res==MK_E_NEEDGENERIC){
1831 /* there's no simplification in this case */
1832 This->tabMoniker[This->tabLastIndex]=pmkRest;
1834 This->tabLastIndex++;
1836 IMoniker_AddRef(pmkRest);
1838 else if (tempMk==NULL){
1840 /* we have an antimoniker after a simple moniker so we can make a simplification in this case */
1841 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1843 This->tabLastIndex--;
1845 else if (SUCCEEDED(res)){
1847 /* the non-generic composition was successful so we can make a simplification in this case */
1848 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1850 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1851 } else
1852 return res;
1854 /* resize tabMoniker if needed */
1855 if (This->tabLastIndex==This->tabSize){
1857 This->tabSize+=BLOCK_TAB_SIZE;
1859 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1861 if (This->tabMoniker==NULL)
1862 return E_OUTOFMEMORY;
1865 else{
1867 /* add a composite moniker to the moniker table (do the same thing
1868 * for each moniker within the composite moniker as a simple moniker
1869 * (see above for how to add a simple moniker case) )
1871 IMoniker_Enum(pmkRest,TRUE,&enumMoniker);
1873 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1875 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk);
1877 if (res==MK_E_NEEDGENERIC){
1879 This->tabLastIndex++;
1881 else if (tempMk==NULL){
1883 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1884 IMoniker_Release(This->tabMoniker[This->tabLastIndex]);
1885 This->tabLastIndex--;
1887 else{
1889 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1891 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1894 if (This->tabLastIndex==This->tabSize){
1896 This->tabSize+=BLOCK_TAB_SIZE;
1898 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1900 if (This->tabMoniker==NULL)
1901 return E_OUTOFMEMORY;
1905 IEnumMoniker_Release(enumMoniker);
1908 return S_OK;
1911 /******************************************************************************
1912 * CreateGenericComposite [OLE32.@]
1913 ******************************************************************************/
1914 HRESULT WINAPI
1915 CreateGenericComposite(LPMONIKER pmkFirst, LPMONIKER pmkRest,
1916 LPMONIKER* ppmkComposite)
1918 CompositeMonikerImpl* newCompositeMoniker = 0;
1919 HRESULT hr = S_OK;
1921 TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite);
1923 if (ppmkComposite==NULL)
1924 return E_POINTER;
1926 *ppmkComposite=0;
1928 if (pmkFirst==NULL && pmkRest!=NULL){
1930 *ppmkComposite=pmkRest;
1931 return S_OK;
1933 else if (pmkFirst!=NULL && pmkRest==NULL){
1934 *ppmkComposite=pmkFirst;
1935 return S_OK;
1937 else if (pmkFirst==NULL && pmkRest==NULL)
1938 return S_OK;
1940 hr = CompositeMonikerImpl_Construct(&newCompositeMoniker,pmkFirst,pmkRest);
1942 if (FAILED(hr))
1943 return hr;
1945 return IMoniker_QueryInterface((IMoniker*)newCompositeMoniker,&IID_IMoniker,(void**)ppmkComposite);
1948 /******************************************************************************
1949 * MonikerCommonPrefixWith [OLE32.@]
1950 ******************************************************************************/
1951 HRESULT WINAPI
1952 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1954 FIXME("(),stub!\n");
1955 return E_NOTIMPL;
1958 static HRESULT WINAPI CompositeMonikerCF_QueryInterface(LPCLASSFACTORY iface,
1959 REFIID riid, LPVOID *ppv)
1961 *ppv = NULL;
1962 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1964 *ppv = iface;
1965 IUnknown_AddRef(iface);
1966 return S_OK;
1968 return E_NOINTERFACE;
1971 static ULONG WINAPI CompositeMonikerCF_AddRef(LPCLASSFACTORY iface)
1973 return 2; /* non-heap based object */
1976 static ULONG WINAPI CompositeMonikerCF_Release(LPCLASSFACTORY iface)
1978 return 1; /* non-heap based object */
1981 static HRESULT WINAPI CompositeMonikerCF_CreateInstance(LPCLASSFACTORY iface,
1982 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1984 CompositeMonikerImpl* newCompositeMoniker;
1985 HRESULT hr;
1987 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
1989 *ppv = NULL;
1991 if (pUnk)
1992 return CLASS_E_NOAGGREGATION;
1994 hr = CompositeMonikerImpl_Construct(&newCompositeMoniker, NULL, NULL);
1996 if (SUCCEEDED(hr))
1997 hr = CompositeMonikerImpl_QueryInterface((IMoniker*)newCompositeMoniker, riid, ppv);
1998 if (FAILED(hr))
1999 HeapFree(GetProcessHeap(),0,newCompositeMoniker);
2001 return hr;
2004 static HRESULT WINAPI CompositeMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
2006 FIXME("(%d), stub!\n",fLock);
2007 return S_OK;
2010 static const IClassFactoryVtbl CompositeMonikerCFVtbl =
2012 CompositeMonikerCF_QueryInterface,
2013 CompositeMonikerCF_AddRef,
2014 CompositeMonikerCF_Release,
2015 CompositeMonikerCF_CreateInstance,
2016 CompositeMonikerCF_LockServer
2018 static const IClassFactoryVtbl *CompositeMonikerCF = &CompositeMonikerCFVtbl;
2020 HRESULT CompositeMonikerCF_Create(REFIID riid, LPVOID *ppv)
2022 return IClassFactory_QueryInterface((IClassFactory *)&CompositeMonikerCF, riid, ppv);