xref: /reactos/dll/win32/ole32/compositemoniker.c (revision 40462c92)
1 /*
2  * CompositeMonikers implementation
3  *
4  * Copyright 1999  Noomen Hamza
5  *
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.
10  *
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.
15  *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <string.h>
24 
25 #define COBJMACROS
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winerror.h"
31 #include "wine/debug.h"
32 #include "ole2.h"
33 #include "moniker.h"
34 
35 WINE_DEFAULT_DEBUG_CHANNEL(ole);
36 
37 #define  BLOCK_TAB_SIZE 5 /* represent the first size table and its increment block size */
38 
39 /* CompositeMoniker data structure */
40 typedef struct CompositeMonikerImpl{
41     IMoniker IMoniker_iface;
42     IROTData IROTData_iface;
43     IMarshal IMarshal_iface;
44     LONG ref;
45     IMoniker** tabMoniker; /* dynamic table containing all components (monikers) of this composite moniker */
46     ULONG    tabSize;      /* size of tabMoniker */
47     ULONG    tabLastIndex; /* first free index in tabMoniker */
48 } CompositeMonikerImpl;
49 
50 static inline CompositeMonikerImpl *impl_from_IMoniker(IMoniker *iface)
51 {
52     return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMoniker_iface);
53 }
54 
55 static inline CompositeMonikerImpl *impl_from_IROTData(IROTData *iface)
56 {
57     return CONTAINING_RECORD(iface, CompositeMonikerImpl, IROTData_iface);
58 }
59 
60 static inline CompositeMonikerImpl *impl_from_IMarshal(IMarshal *iface)
61 {
62     return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMarshal_iface);
63 }
64 
65 /* EnumMoniker data structure */
66 typedef struct EnumMonikerImpl{
67     IEnumMoniker IEnumMoniker_iface;
68     LONG ref;
69     IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
70     ULONG      tabSize; /* size of tabMoniker */
71     ULONG      currentPos;  /* index pointer on the current moniker */
72 } EnumMonikerImpl;
73 
74 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
75 {
76     return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
77 }
78 
79 static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRight,IEnumMoniker ** ppmk);
80 
81 /*******************************************************************************
82  *        CompositeMoniker_QueryInterface
83  *******************************************************************************/
84 static HRESULT WINAPI
85 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
86 {
87     CompositeMonikerImpl *This = impl_from_IMoniker(iface);
88 
89     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
90 
91     /* Perform a sanity check on the parameters.*/
92     if ( ppvObject==0 )
93 	return E_INVALIDARG;
94 
95     /* Initialize the return parameter */
96     *ppvObject = 0;
97 
98     /* Compare the riid with the interface IDs implemented by this object.*/
99     if (IsEqualIID(&IID_IUnknown, riid) ||
100         IsEqualIID(&IID_IPersist, riid) ||
101         IsEqualIID(&IID_IPersistStream, riid) ||
102         IsEqualIID(&IID_IMoniker, riid)
103        )
104         *ppvObject = iface;
105     else if (IsEqualIID(&IID_IROTData, riid))
106         *ppvObject = &This->IROTData_iface;
107     else if (IsEqualIID(&IID_IMarshal, riid))
108         *ppvObject = &This->IMarshal_iface;
109 
110     /* Check that we obtained an interface.*/
111     if ((*ppvObject)==0)
112         return E_NOINTERFACE;
113 
114     /* Query Interface always increases the reference count by one when it is successful */
115     IMoniker_AddRef(iface);
116 
117     return S_OK;
118 }
119 
120 /******************************************************************************
121  *        CompositeMoniker_AddRef
122  ******************************************************************************/
123 static ULONG WINAPI
124 CompositeMonikerImpl_AddRef(IMoniker* iface)
125 {
126     CompositeMonikerImpl *This = impl_from_IMoniker(iface);
127 
128     TRACE("(%p)\n",This);
129 
130     return InterlockedIncrement(&This->ref);
131 }
132 
133 static void CompositeMonikerImpl_ReleaseMonikersInTable(CompositeMonikerImpl *This)
134 {
135     ULONG i;
136 
137     for (i = 0; i < This->tabLastIndex; i++)
138         IMoniker_Release(This->tabMoniker[i]);
139 
140     This->tabLastIndex = 0;
141 }
142 
143 /******************************************************************************
144  *        CompositeMoniker_Release
145  ******************************************************************************/
146 static ULONG WINAPI
147 CompositeMonikerImpl_Release(IMoniker* iface)
148 {
149     CompositeMonikerImpl *This = impl_from_IMoniker(iface);
150     ULONG ref;
151 
152     TRACE("(%p)\n",This);
153 
154     ref = InterlockedDecrement(&This->ref);
155 
156     /* destroy the object if there are no more references to it */
157     if (ref == 0){
158 
159         /* release all the components before destroying this object */
160         CompositeMonikerImpl_ReleaseMonikersInTable(This);
161 
162         HeapFree(GetProcessHeap(),0,This->tabMoniker);
163         HeapFree(GetProcessHeap(),0,This);
164     }
165     return ref;
166 }
167 
168 /******************************************************************************
169  *        CompositeMoniker_GetClassID
170  ******************************************************************************/
171 static HRESULT WINAPI
172 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
173 {
174     TRACE("(%p,%p)\n",iface,pClassID);
175 
176     if (pClassID==NULL)
177         return E_POINTER;
178 
179     *pClassID = CLSID_CompositeMoniker;
180 
181     return S_OK;
182 }
183 
184 /******************************************************************************
185  *        CompositeMoniker_IsDirty
186  ******************************************************************************/
187 static HRESULT WINAPI
188 CompositeMonikerImpl_IsDirty(IMoniker* iface)
189 {
190     /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
191        method in the OLE-provided moniker interfaces always return S_FALSE because
192        their internal state never changes. */
193 
194     TRACE("(%p)\n",iface);
195 
196     return S_FALSE;
197 }
198 
199 /******************************************************************************
200  *        CompositeMoniker_Load
201  ******************************************************************************/
202 static HRESULT WINAPI
203 CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
204 {
205     CompositeMonikerImpl *This = impl_from_IMoniker(iface);
206     HRESULT res;
207     DWORD moniker_count;
208     DWORD i;
209 
210     TRACE("(%p,%p)\n",iface,pStm);
211 
212     /* this function call OleLoadFromStream function for each moniker within this object */
213 
214     res=IStream_Read(pStm,&moniker_count,sizeof(DWORD),NULL);
215     if (res != S_OK)
216     {
217         ERR("couldn't reading moniker count from stream\n");
218         return E_FAIL;
219     }
220 
221     CompositeMonikerImpl_ReleaseMonikersInTable(This);
222 
223     for (i = 0; i < moniker_count; i++)
224     {
225         res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
226         if (FAILED(res))
227         {
228             ERR("couldn't load moniker from stream, res = 0x%08x\n", res);
229             break;
230         }
231 
232         /* resize the table if needed */
233         if (++This->tabLastIndex==This->tabSize){
234 
235             This->tabSize+=BLOCK_TAB_SIZE;
236             This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
237 
238             if (This->tabMoniker==NULL)
239             return E_OUTOFMEMORY;
240         }
241     }
242 
243     return res;
244 }
245 
246 /******************************************************************************
247  *        CompositeMoniker_Save
248  ******************************************************************************/
249 static HRESULT WINAPI
250 CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
251 {
252     CompositeMonikerImpl *This = impl_from_IMoniker(iface);
253     HRESULT res;
254     IEnumMoniker *enumMk;
255     IMoniker *pmk;
256     DWORD moniker_count = This->tabLastIndex;
257 
258     TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
259 
260     /* This function calls OleSaveToStream function for each moniker within
261      * this object.
262      * When I tested this function in windows, I usually found this constant
263      * at the beginning of the stream. I don't known why (there's no
264      * indication in the specification) !
265      */
266     res=IStream_Write(pStm,&moniker_count,sizeof(moniker_count),NULL);
267     if (FAILED(res)) return res;
268 
269     IMoniker_Enum(iface,TRUE,&enumMk);
270 
271     while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
272 
273         res=OleSaveToStream((IPersistStream*)pmk,pStm);
274 
275         IMoniker_Release(pmk);
276 
277         if (FAILED(res)){
278 
279             IEnumMoniker_Release(enumMk);
280             return res;
281         }
282     }
283 
284     IEnumMoniker_Release(enumMk);
285 
286     return S_OK;
287 }
288 
289 /******************************************************************************
290  *        CompositeMoniker_GetSizeMax
291  ******************************************************************************/
292 static HRESULT WINAPI
293 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
294 {
295     IEnumMoniker *enumMk;
296     IMoniker *pmk;
297     ULARGE_INTEGER ptmpSize;
298 
299     /* The sizeMax of this object is calculated by calling  GetSizeMax on
300      * each moniker within this object then summing all returned values
301      */
302 
303     TRACE("(%p,%p)\n",iface,pcbSize);
304 
305     if (!pcbSize)
306         return E_POINTER;
307 
308     pcbSize->QuadPart = sizeof(DWORD);
309 
310     IMoniker_Enum(iface,TRUE,&enumMk);
311 
312     while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
313 
314         IMoniker_GetSizeMax(pmk,&ptmpSize);
315 
316         IMoniker_Release(pmk);
317 
318         pcbSize->QuadPart = ptmpSize.QuadPart + sizeof(CLSID);
319     }
320 
321     IEnumMoniker_Release(enumMk);
322 
323     return S_OK;
324 }
325 
326 /******************************************************************************
327  *                  CompositeMoniker_BindToObject
328  ******************************************************************************/
329 static HRESULT WINAPI
330 CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,
331                IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
332 {
333     HRESULT   res;
334     IRunningObjectTable *prot;
335     IMoniker *tempMk,*antiMk,*rightMostMk;
336     IEnumMoniker *enumMoniker;
337 
338     TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
339 
340     if (ppvResult==NULL)
341         return E_POINTER;
342 
343     *ppvResult=0;
344     /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
345     /* object for the requested interface pointer. */
346     if(pmkToLeft==NULL){
347 
348         res=IBindCtx_GetRunningObjectTable(pbc,&prot);
349 
350         if (SUCCEEDED(res)){
351 
352             /* if the requested class was loaded before ! we don't need to reload it */
353             res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
354 
355             if (res==S_OK)
356                 return res;
357         }
358     }
359     else{
360         /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
361         /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
362 
363         IMoniker_Enum(iface,FALSE,&enumMoniker);
364         IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
365         IEnumMoniker_Release(enumMoniker);
366 
367         res=CreateAntiMoniker(&antiMk);
368         res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
369         IMoniker_Release(antiMk);
370 
371         res=IMoniker_BindToObject(rightMostMk,pbc,tempMk,riid,ppvResult);
372 
373         IMoniker_Release(tempMk);
374         IMoniker_Release(rightMostMk);
375     }
376 
377     return res;
378 }
379 
380 /******************************************************************************
381  *        CompositeMoniker_BindToStorage
382  ******************************************************************************/
383 static HRESULT WINAPI
384 CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
385                IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
386 {
387     HRESULT   res;
388     IMoniker *tempMk,*antiMk,*rightMostMk,*leftMk;
389     IEnumMoniker *enumMoniker;
390 
391     TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
392 
393     *ppvResult=0;
394 
395     /* This method recursively calls BindToStorage on the rightmost component of the composite, */
396     /* passing the rest of the composite as the pmkToLeft parameter for that call. */
397 
398     if (pmkToLeft)
399     {
400         res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
401         if (FAILED(res)) return res;
402     }
403     else
404         leftMk = iface;
405 
406     IMoniker_Enum(iface, FALSE, &enumMoniker);
407     IEnumMoniker_Next(enumMoniker, 1, &rightMostMk, NULL);
408     IEnumMoniker_Release(enumMoniker);
409 
410     res = CreateAntiMoniker(&antiMk);
411     if (FAILED(res)) return res;
412     res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
413     if (FAILED(res)) return res;
414     IMoniker_Release(antiMk);
415 
416     res = IMoniker_BindToStorage(rightMostMk, pbc, tempMk, riid, ppvResult);
417 
418     IMoniker_Release(tempMk);
419 
420     IMoniker_Release(rightMostMk);
421 
422     if (pmkToLeft)
423         IMoniker_Release(leftMk);
424 
425     return res;
426 }
427 
428 /******************************************************************************
429  *        CompositeMoniker_Reduce
430  ******************************************************************************/
431 static HRESULT WINAPI
432 CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
433                IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
434 {
435     HRESULT   res;
436     IMoniker *tempMk,*antiMk,*rightMostMk,*leftReducedComposedMk,*rightMostReducedMk;
437     IEnumMoniker *enumMoniker;
438 
439     TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
440 
441     if (ppmkReduced==NULL)
442         return E_POINTER;
443 
444     /* This method recursively calls Reduce for each of its component monikers. */
445 
446     if (ppmkToLeft==NULL){
447 
448         IMoniker_Enum(iface,FALSE,&enumMoniker);
449         IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
450         IEnumMoniker_Release(enumMoniker);
451 
452         CreateAntiMoniker(&antiMk);
453         IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
454         IMoniker_Release(antiMk);
455 
456         res = IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
457         IMoniker_Release(tempMk);
458         IMoniker_Release(rightMostMk);
459 
460         return res;
461     }
462     else if (*ppmkToLeft==NULL)
463 
464         return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);
465 
466     else{
467 
468         /* separate the composite moniker in to left and right moniker */
469         IMoniker_Enum(iface,FALSE,&enumMoniker);
470         IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
471         IEnumMoniker_Release(enumMoniker);
472 
473         CreateAntiMoniker(&antiMk);
474         IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
475         IMoniker_Release(antiMk);
476 
477         /* If any of the components  reduces itself, the method returns S_OK and passes back a composite */
478         /* of the reduced components */
479         if (IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,NULL,&rightMostReducedMk) &&
480             IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk) ){
481             IMoniker_Release(tempMk);
482             IMoniker_Release(rightMostMk);
483 
484             return CreateGenericComposite(leftReducedComposedMk,rightMostReducedMk,ppmkReduced);
485         }
486         else{
487             /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
488             IMoniker_Release(tempMk);
489             IMoniker_Release(rightMostMk);
490 
491             IMoniker_AddRef(iface);
492 
493             *ppmkReduced=iface;
494 
495             return MK_S_REDUCED_TO_SELF;
496         }
497     }
498 }
499 
500 /******************************************************************************
501  *        CompositeMoniker_ComposeWith
502  ******************************************************************************/
503 static HRESULT WINAPI
504 CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
505                BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
506 {
507     TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
508 
509     if ((ppmkComposite==NULL)||(pmkRight==NULL))
510 	return E_POINTER;
511 
512     *ppmkComposite=0;
513 
514     /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */
515     /* otherwise, the method returns the result of combining the two monikers by calling the */
516     /* CreateGenericComposite function */
517 
518     if (fOnlyIfNotGeneric)
519         return MK_E_NEEDGENERIC;
520 
521     return CreateGenericComposite(iface,pmkRight,ppmkComposite);
522 }
523 
524 /******************************************************************************
525  *        CompositeMoniker_Enum
526  ******************************************************************************/
527 static HRESULT WINAPI
528 CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
529 {
530     CompositeMonikerImpl *This = impl_from_IMoniker(iface);
531 
532     TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
533 
534     if (ppenumMoniker == NULL)
535         return E_POINTER;
536 
537     return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);
538 }
539 
540 /******************************************************************************
541  *        CompositeMoniker_IsEqual
542  ******************************************************************************/
543 static HRESULT WINAPI
544 CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
545 {
546     IEnumMoniker *enumMoniker1,*enumMoniker2;
547     IMoniker *tempMk1,*tempMk2;
548     HRESULT res1,res2,res;
549     BOOL done;
550 
551     TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
552 
553     if (pmkOtherMoniker==NULL)
554         return S_FALSE;
555 
556     /* This method returns S_OK if the components of both monikers are equal when compared in the */
557     /* left-to-right order.*/
558     IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);
559 
560     if (enumMoniker1==NULL)
561         return S_FALSE;
562 
563     IMoniker_Enum(iface,TRUE,&enumMoniker2);
564 
565     do {
566 
567         res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
568         res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
569 
570         if((res1==S_OK)&&(res2==S_OK)){
571             done = (res = IMoniker_IsEqual(tempMk1,tempMk2)) == S_FALSE;
572         }
573         else
574         {
575             res = (res1==S_FALSE) && (res2==S_FALSE);
576             done = TRUE;
577         }
578 
579         if (res1==S_OK)
580             IMoniker_Release(tempMk1);
581 
582         if (res2==S_OK)
583             IMoniker_Release(tempMk2);
584     } while (!done);
585 
586     IEnumMoniker_Release(enumMoniker1);
587     IEnumMoniker_Release(enumMoniker2);
588 
589     return res;
590 }
591 /******************************************************************************
592  *        CompositeMoniker_Hash
593  ******************************************************************************/
594 static HRESULT WINAPI
595 CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
596 {
597     IEnumMoniker *enumMoniker;
598     IMoniker *tempMk;
599     HRESULT res;
600     DWORD tempHash;
601 
602     TRACE("(%p,%p)\n",iface,pdwHash);
603 
604     if (pdwHash==NULL)
605         return E_POINTER;
606 
607     res = IMoniker_Enum(iface,TRUE,&enumMoniker);
608     if(FAILED(res))
609         return res;
610 
611     *pdwHash = 0;
612 
613     while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
614         res = IMoniker_Hash(tempMk, &tempHash);
615         if(FAILED(res))
616             break;
617         *pdwHash = *pdwHash ^ tempHash;
618 
619         IMoniker_Release(tempMk);
620     }
621 
622     IEnumMoniker_Release(enumMoniker);
623 
624     return res;
625 }
626 
627 /******************************************************************************
628  *        CompositeMoniker_IsRunning
629  ******************************************************************************/
630 static HRESULT WINAPI
631 CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc,
632                IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
633 {
634     IRunningObjectTable* rot;
635     HRESULT res;
636     IMoniker *tempMk,*antiMk,*rightMostMk;
637     IEnumMoniker *enumMoniker;
638 
639     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
640 
641     /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/
642     if (pmkToLeft!=NULL){
643 
644         CreateGenericComposite(pmkToLeft,iface,&tempMk);
645 
646         res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);
647 
648         IMoniker_Release(tempMk);
649 
650         return res;
651     }
652     else
653         /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */
654         /* to this moniker */
655 
656         if (pmkNewlyRunning!=NULL)
657 
658             if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)
659                 return S_OK;
660 
661             else
662                 return S_FALSE;
663 
664         else{
665 
666             if (pbc==NULL)
667                 return E_INVALIDARG;
668 
669             /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */
670             /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls   */
671             /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */
672             /* the composite as the pmkToLeft parameter for that call.                                   */
673 
674              res=IBindCtx_GetRunningObjectTable(pbc,&rot);
675 
676             if (FAILED(res))
677                 return res;
678 
679             res = IRunningObjectTable_IsRunning(rot,iface);
680             IRunningObjectTable_Release(rot);
681 
682             if(res==S_OK)
683                 return S_OK;
684 
685             else{
686 
687                 IMoniker_Enum(iface,FALSE,&enumMoniker);
688                 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
689                 IEnumMoniker_Release(enumMoniker);
690 
691                 res=CreateAntiMoniker(&antiMk);
692                 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
693                 IMoniker_Release(antiMk);
694 
695                 res=IMoniker_IsRunning(rightMostMk,pbc,tempMk,pmkNewlyRunning);
696 
697                 IMoniker_Release(tempMk);
698                 IMoniker_Release(rightMostMk);
699 
700                 return res;
701             }
702         }
703 }
704 
705 /******************************************************************************
706  *        CompositeMoniker_GetTimeOfLastChange
707  ******************************************************************************/
708 static HRESULT WINAPI
709 CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
710                IMoniker* pmkToLeft, FILETIME* pCompositeTime)
711 {
712     HRESULT res;
713     IMoniker *tempMk,*antiMk,*rightMostMk,*leftMk;
714     IEnumMoniker *enumMoniker;
715 
716     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);
717 
718     if (pCompositeTime==NULL)
719         return E_INVALIDARG;
720 
721     /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to  */
722     /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls  */
723     /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */
724     /* of the composite as the pmkToLeft parameter for that call.                                       */
725     if (pmkToLeft)
726     {
727         IRunningObjectTable* rot;
728 
729         res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
730         if (FAILED(res))
731             return res;
732 
733         res = IBindCtx_GetRunningObjectTable(pbc,&rot);
734         if (FAILED(res))
735         {
736             IMoniker_Release(leftMk);
737             return res;
738         }
739 
740         if (IRunningObjectTable_GetTimeOfLastChange(rot,leftMk,pCompositeTime)==S_OK)
741         {
742             IMoniker_Release(leftMk);
743             return res;
744         }
745     }
746     else
747         leftMk = iface;
748 
749     IMoniker_Enum(iface, FALSE, &enumMoniker);
750     IEnumMoniker_Next(enumMoniker, 1, &rightMostMk, NULL);
751     IEnumMoniker_Release(enumMoniker);
752 
753     res = CreateAntiMoniker(&antiMk);
754     res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
755     IMoniker_Release(antiMk);
756 
757     res = IMoniker_GetTimeOfLastChange(rightMostMk, pbc, tempMk, pCompositeTime);
758 
759     IMoniker_Release(tempMk);
760     IMoniker_Release(rightMostMk);
761 
762     if (pmkToLeft)
763         IMoniker_Release(leftMk);
764 
765     return res;
766 }
767 
768 /******************************************************************************
769  *        CompositeMoniker_Inverse
770  ******************************************************************************/
771 static HRESULT WINAPI
772 CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
773 {
774     HRESULT res;
775     IMoniker *tempMk,*antiMk,*rightMostMk,*tempInvMk,*rightMostInvMk;
776     IEnumMoniker *enumMoniker;
777 
778     TRACE("(%p,%p)\n",iface,ppmk);
779 
780     if (ppmk==NULL)
781         return E_POINTER;
782 
783     /* This method returns a composite moniker that consists of the inverses of each of the components */
784     /* of the original composite, stored in reverse order */
785 
786     *ppmk = NULL;
787 
788     res=CreateAntiMoniker(&antiMk);
789     if (FAILED(res))
790         return res;
791 
792     res=IMoniker_ComposeWith(iface,antiMk,FALSE,&tempMk);
793     IMoniker_Release(antiMk);
794     if (FAILED(res))
795         return res;
796 
797     if (tempMk==NULL)
798 
799         return IMoniker_Inverse(iface,ppmk);
800 
801     else{
802 
803         IMoniker_Enum(iface,FALSE,&enumMoniker);
804         IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
805         IEnumMoniker_Release(enumMoniker);
806 
807         IMoniker_Inverse(rightMostMk,&rightMostInvMk);
808         CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);
809 
810         res=CreateGenericComposite(rightMostInvMk,tempInvMk,ppmk);
811 
812         IMoniker_Release(tempMk);
813         IMoniker_Release(rightMostMk);
814         IMoniker_Release(tempInvMk);
815         IMoniker_Release(rightMostInvMk);
816 
817         return res;
818     }
819 }
820 
821 /******************************************************************************
822  *        CompositeMoniker_CommonPrefixWith
823  ******************************************************************************/
824 static HRESULT WINAPI
825 CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,
826                IMoniker** ppmkPrefix)
827 {
828     DWORD mkSys;
829     HRESULT res1,res2;
830     IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
831     IEnumMoniker *enumMoniker1,*enumMoniker2;
832     ULONG i,nbCommonMk=0;
833 
834     /* If the other moniker is a composite, this method compares the components of each composite from left  */
835     /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
836     /* of the leftmost components were common to both monikers.                                              */
837 
838     if (ppmkPrefix==NULL)
839         return E_POINTER;
840 
841     *ppmkPrefix=0;
842 
843     if (pmkOther==NULL)
844         return MK_E_NOPREFIX;
845 
846     IMoniker_IsSystemMoniker(pmkOther,&mkSys);
847 
848     if(mkSys==MKSYS_GENERICCOMPOSITE){
849 
850         IMoniker_Enum(iface,TRUE,&enumMoniker1);
851         IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
852 
853         while(1){
854 
855             res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
856             res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
857 
858             if ((res1==S_FALSE) && (res2==S_FALSE)){
859 
860                 /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
861                 *ppmkPrefix=iface;
862                 IMoniker_AddRef(iface);
863                 return  MK_S_US;
864             }
865             else if ((res1==S_OK) && (res2==S_OK)){
866 
867                 if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
868 
869                     nbCommonMk++;
870 
871                 else
872                     break;
873 
874             }
875             else if (res1==S_OK){
876 
877                 /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
878                 /* ppmkPrefix to the other moniker.                                                       */
879                 *ppmkPrefix=pmkOther;
880                 return MK_S_HIM;
881             }
882             else{
883                 /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
884                 /* to this moniker.                                                                          */
885                 *ppmkPrefix=iface;
886                 return MK_S_ME;
887             }
888         }
889 
890         IEnumMoniker_Release(enumMoniker1);
891         IEnumMoniker_Release(enumMoniker2);
892 
893         /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
894         if (nbCommonMk==0)
895             return MK_E_NOPREFIX;
896 
897         IEnumMoniker_Reset(enumMoniker1);
898 
899         IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
900 
901         /* if we have more than one common moniker the result will be a composite moniker */
902         if (nbCommonMk>1){
903 
904             /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
905             IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
906             CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
907             IMoniker_Release(tempMk1);
908             IMoniker_Release(tempMk2);
909 
910             /* compose all common monikers in a composite moniker */
911             for(i=0;i<nbCommonMk;i++){
912 
913                 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
914 
915                 CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
916 
917                 IMoniker_Release(*ppmkPrefix);
918 
919                 IMoniker_Release(tempMk1);
920 
921                 *ppmkPrefix=tempMk2;
922             }
923             return S_OK;
924         }
925         else{
926             /* if we have only one common moniker the result will be a simple moniker which is the most-left one*/
927             *ppmkPrefix=tempMk1;
928 
929             return S_OK;
930         }
931     }
932     else{
933         /* If the other moniker is not a composite, the method simply compares it to the leftmost component
934          of this moniker.*/
935 
936         IMoniker_Enum(iface,TRUE,&enumMoniker1);
937 
938         IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
939 
940         if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){
941 
942             *ppmkPrefix=pmkOther;
943 
944             return MK_S_HIM;
945         }
946         else
947             return MK_E_NOPREFIX;
948     }
949 }
950 
951 /***************************************************************************************************
952  *        GetAfterCommonPrefix (local function)
953  *  This function returns a moniker that consist of the remainder when the common prefix is removed
954  ***************************************************************************************************/
955 static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk)
956 {
957     IMoniker *tempMk,*tempMk1,*tempMk2;
958     IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3;
959     ULONG nbRestMk=0;
960     DWORD mkSys;
961     HRESULT res1,res2;
962 
963     *restMk=0;
964 
965     /* to create an enumerator for pGenMk with current position pointed on the first element after common  */
966     /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop  */
967     /* on the first difference. */
968     IMoniker_Enum(pGenMk,TRUE,&enumMoniker1);
969 
970     IMoniker_IsSystemMoniker(commonMk,&mkSys);
971 
972     if (mkSys==MKSYS_GENERICCOMPOSITE){
973 
974         IMoniker_Enum(commonMk,TRUE,&enumMoniker2);
975         while(1){
976 
977             res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
978             res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
979 
980             if ((res1==S_FALSE)||(res2==S_FALSE)){
981 
982                 if (res1==S_OK)
983 
984                     nbRestMk++;
985 
986                 IMoniker_Release(tempMk1);
987                 IMoniker_Release(tempMk2);
988 
989                 break;
990             }
991             IMoniker_Release(tempMk1);
992             IMoniker_Release(tempMk2);
993         }
994     }
995     else{
996         IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
997         IMoniker_Release(tempMk1);
998     }
999 
1000     /* count the number of elements in the enumerator after the common prefix */
1001     IEnumMoniker_Clone(enumMoniker1,&enumMoniker3);
1002 
1003     for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++)
1004 
1005         IMoniker_Release(tempMk);
1006 
1007     if (nbRestMk==0)
1008         return;
1009 
1010     /* create a generic composite moniker with monikers located after the common prefix */
1011     IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
1012 
1013     if (nbRestMk==1){
1014 
1015         *restMk= tempMk1;
1016         return;
1017     }
1018     else {
1019 
1020         IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
1021 
1022         CreateGenericComposite(tempMk1,tempMk2,restMk);
1023 
1024         IMoniker_Release(tempMk1);
1025 
1026         IMoniker_Release(tempMk2);
1027 
1028         while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){
1029 
1030             CreateGenericComposite(*restMk,tempMk1,&tempMk2);
1031 
1032             IMoniker_Release(tempMk1);
1033 
1034             IMoniker_Release(*restMk);
1035 
1036             *restMk=tempMk2;
1037         }
1038     }
1039 }
1040 
1041 /******************************************************************************
1042  *        CompositeMoniker_RelativePathTo
1043  ******************************************************************************/
1044 static HRESULT WINAPI
1045 CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther,
1046                IMoniker** ppmkRelPath)
1047 {
1048     HRESULT res;
1049     IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0;
1050 
1051     TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath);
1052 
1053     if (ppmkRelPath==NULL)
1054         return E_POINTER;
1055 
1056     *ppmkRelPath=0;
1057 
1058     /* This method finds the common prefix of the two monikers and creates two monikers that consist     */
1059     /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */
1060     /* of this moniker and composes the remainder of the other moniker on the right of it.               */
1061 
1062     /* finds the common prefix of the two monikers */
1063     res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk);
1064 
1065     /* if there's no common prefix or the two moniker are equal the relative is the other moniker */
1066     if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){
1067 
1068         *ppmkRelPath=pmkOther;
1069         IMoniker_AddRef(pmkOther);
1070         return MK_S_HIM;
1071     }
1072 
1073     GetAfterCommonPrefix(iface,commonMk,&restThisMk);
1074     GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk);
1075 
1076     /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */
1077     /* moniker when the common prefix is removed                                                           */
1078     if (res==MK_S_HIM){
1079 
1080         IMoniker_Inverse(restThisMk,ppmkRelPath);
1081         IMoniker_Release(restThisMk);
1082     }
1083     /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */
1084     /* when the common prefix is removed                                                                     */
1085     else if (res==MK_S_ME){
1086 
1087         *ppmkRelPath=restOtherMk;
1088         IMoniker_AddRef(restOtherMk);
1089     }
1090     /* the relative path is the inverse for the remainder of this moniker and the remainder of the other  */
1091     /* moniker on the right of it.                                                                        */
1092     else if (res==S_OK){
1093 
1094         IMoniker_Inverse(restThisMk,&invRestThisMk);
1095         IMoniker_Release(restThisMk);
1096         CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath);
1097         IMoniker_Release(invRestThisMk);
1098         IMoniker_Release(restOtherMk);
1099     }
1100     return S_OK;
1101 }
1102 
1103 /******************************************************************************
1104  *        CompositeMoniker_GetDisplayName
1105  ******************************************************************************/
1106 static HRESULT WINAPI
1107 CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1108                IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1109 {
1110     ULONG lengthStr=1;
1111     IEnumMoniker *enumMoniker;
1112     IMoniker* tempMk;
1113     LPOLESTR tempStr;
1114 
1115     TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1116 
1117     if (ppszDisplayName==NULL)
1118         return E_POINTER;
1119 
1120     *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR));
1121 
1122     if (*ppszDisplayName==NULL)
1123         return E_OUTOFMEMORY;
1124 
1125     /* This method returns the concatenation of the display names returned by each component moniker of */
1126     /* the composite */
1127 
1128     **ppszDisplayName=0;
1129 
1130     IMoniker_Enum(iface,TRUE,&enumMoniker);
1131 
1132     while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
1133 
1134         IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr);
1135 
1136         lengthStr+=lstrlenW(tempStr);
1137 
1138         *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));
1139 
1140         if (*ppszDisplayName==NULL)
1141             return E_OUTOFMEMORY;
1142 
1143         lstrcatW(*ppszDisplayName,tempStr);
1144 
1145         CoTaskMemFree(tempStr);
1146         IMoniker_Release(tempMk);
1147     }
1148 
1149     IEnumMoniker_Release(enumMoniker);
1150 
1151     return S_OK;
1152 }
1153 
1154 /******************************************************************************
1155  *        CompositeMoniker_ParseDisplayName
1156  ******************************************************************************/
1157 static HRESULT WINAPI
1158 CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc,
1159                IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten,
1160                IMoniker** ppmkOut)
1161 {
1162     IEnumMoniker *enumMoniker;
1163     IMoniker *tempMk,*rightMostMk,*antiMk;
1164     /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/
1165     /* passing everything else as the pmkToLeft parameter for that call. */
1166 
1167     /* get the most right moniker */
1168     IMoniker_Enum(iface,FALSE,&enumMoniker);
1169     IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
1170     IEnumMoniker_Release(enumMoniker);
1171 
1172     /* get the left moniker */
1173     CreateAntiMoniker(&antiMk);
1174     IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
1175     IMoniker_Release(antiMk);
1176 
1177     return IMoniker_ParseDisplayName(rightMostMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut);
1178 }
1179 
1180 /******************************************************************************
1181  *        CompositeMoniker_IsSystemMoniker
1182  ******************************************************************************/
1183 static HRESULT WINAPI
1184 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1185 {
1186     TRACE("(%p,%p)\n",iface,pwdMksys);
1187 
1188     if (!pwdMksys)
1189         return E_POINTER;
1190 
1191     (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
1192 
1193     return S_OK;
1194 }
1195 
1196 /*******************************************************************************
1197  *        CompositeMonikerIROTData_QueryInterface
1198  *******************************************************************************/
1199 static HRESULT WINAPI
1200 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
1201                VOID** ppvObject)
1202 {
1203     CompositeMonikerImpl *This = impl_from_IROTData(iface);
1204 
1205     TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject);
1206 
1207     return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
1208 }
1209 
1210 /***********************************************************************
1211  *        CompositeMonikerIROTData_AddRef
1212  */
1213 static ULONG WINAPI
1214 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
1215 {
1216     CompositeMonikerImpl *This = impl_from_IROTData(iface);
1217 
1218     TRACE("(%p)\n",iface);
1219 
1220     return IMoniker_AddRef(&This->IMoniker_iface);
1221 }
1222 
1223 /***********************************************************************
1224  *        CompositeMonikerIROTData_Release
1225  */
1226 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1227 {
1228     CompositeMonikerImpl *This = impl_from_IROTData(iface);
1229 
1230     TRACE("(%p)\n",iface);
1231 
1232     return IMoniker_Release(&This->IMoniker_iface);
1233 }
1234 
1235 /******************************************************************************
1236  *        CompositeMonikerIROTData_GetComparisonData
1237  ******************************************************************************/
1238 static HRESULT WINAPI
1239 CompositeMonikerROTDataImpl_GetComparisonData(IROTData* iface,
1240                BYTE* pbData, ULONG cbMax, ULONG* pcbData)
1241 {
1242     CompositeMonikerImpl *This = impl_from_IROTData(iface);
1243     IEnumMoniker *pEnumMk;
1244     IMoniker *pmk;
1245     HRESULT hr;
1246 
1247     TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
1248 
1249     *pcbData = sizeof(CLSID);
1250 
1251     hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1252     if (FAILED(hr)) return hr;
1253 
1254     while(IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1255     {
1256         IROTData *pROTData;
1257         hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1258         if (FAILED(hr))
1259             ERR("moniker doesn't support IROTData interface\n");
1260 
1261         if (SUCCEEDED(hr))
1262         {
1263             ULONG cbData;
1264             hr = IROTData_GetComparisonData(pROTData, NULL, 0, &cbData);
1265             IROTData_Release(pROTData);
1266             if (SUCCEEDED(hr) || (hr == E_OUTOFMEMORY))
1267             {
1268                 *pcbData += cbData;
1269                 hr = S_OK;
1270             }
1271             else
1272                 ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
1273         }
1274 
1275         IMoniker_Release(pmk);
1276 
1277         if (FAILED(hr))
1278         {
1279             IEnumMoniker_Release(pEnumMk);
1280             return hr;
1281         }
1282     }
1283     if (cbMax < *pcbData)
1284         return E_OUTOFMEMORY;
1285 
1286     IEnumMoniker_Reset(pEnumMk);
1287 
1288     memcpy(pbData, &CLSID_CompositeMoniker, sizeof(CLSID));
1289     pbData += sizeof(CLSID);
1290     cbMax -= sizeof(CLSID);
1291 
1292     while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1293     {
1294         IROTData *pROTData;
1295         hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1296         if (FAILED(hr))
1297             ERR("moniker doesn't support IROTData interface\n");
1298 
1299         if (SUCCEEDED(hr))
1300         {
1301             ULONG cbData;
1302             hr = IROTData_GetComparisonData(pROTData, pbData, cbMax, &cbData);
1303             IROTData_Release(pROTData);
1304             if (SUCCEEDED(hr))
1305             {
1306                 pbData += cbData;
1307                 cbMax -= cbData;
1308             }
1309             else
1310                 ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
1311         }
1312 
1313         IMoniker_Release(pmk);
1314 
1315         if (FAILED(hr))
1316         {
1317             IEnumMoniker_Release(pEnumMk);
1318             return hr;
1319         }
1320     }
1321 
1322     IEnumMoniker_Release(pEnumMk);
1323 
1324     return S_OK;
1325 }
1326 
1327 static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1328 {
1329     CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1330 
1331     TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);
1332 
1333     return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppv);
1334 }
1335 
1336 static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
1337 {
1338     CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1339 
1340     TRACE("(%p)\n",iface);
1341 
1342     return CompositeMonikerImpl_AddRef(&This->IMoniker_iface);
1343 }
1344 
1345 static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
1346 {
1347     CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1348 
1349     TRACE("(%p)\n",iface);
1350 
1351     return CompositeMonikerImpl_Release(&This->IMoniker_iface);
1352 }
1353 
1354 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
1355   IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1356   void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1357 {
1358     CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1359 
1360     TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1361         dwDestContext, pvDestContext, mshlflags, pCid);
1362 
1363     return IMoniker_GetClassID(&This->IMoniker_iface, pCid);
1364 }
1365 
1366 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
1367   IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1368   void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1369 {
1370     CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1371     IEnumMoniker *pEnumMk;
1372     IMoniker *pmk;
1373     HRESULT hr;
1374     ULARGE_INTEGER size;
1375 
1376     TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1377         dwDestContext, pvDestContext, mshlflags, pSize);
1378 
1379     *pSize = 0x10; /* to match native */
1380 
1381     hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1382     if (FAILED(hr)) return hr;
1383 
1384     hr = IMoniker_GetSizeMax(&This->IMoniker_iface, &size);
1385 
1386     while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1387     {
1388         ULONG size;
1389 
1390         hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1391         if (SUCCEEDED(hr))
1392             *pSize += size;
1393 
1394         IMoniker_Release(pmk);
1395 
1396         if (FAILED(hr))
1397         {
1398             IEnumMoniker_Release(pEnumMk);
1399             return hr;
1400         }
1401     }
1402 
1403     IEnumMoniker_Release(pEnumMk);
1404 
1405     return S_OK;
1406 }
1407 
1408 static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(IMarshal *iface, IStream *pStm,
1409     REFIID riid, void* pv, DWORD dwDestContext,
1410     void* pvDestContext, DWORD mshlflags)
1411 {
1412     CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1413     IEnumMoniker *pEnumMk;
1414     IMoniker *pmk;
1415     HRESULT hr;
1416     ULONG i = 0;
1417 
1418     TRACE("(%p, %s, %p, %x, %p, %x)\n", pStm, debugstr_guid(riid), pv,
1419         dwDestContext, pvDestContext, mshlflags);
1420 
1421     hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1422     if (FAILED(hr)) return hr;
1423 
1424     while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1425     {
1426         hr = CoMarshalInterface(pStm, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1427 
1428         IMoniker_Release(pmk);
1429 
1430         if (FAILED(hr))
1431         {
1432             IEnumMoniker_Release(pEnumMk);
1433             return hr;
1434         }
1435         i++;
1436     }
1437 
1438     if (i != 2)
1439         FIXME("moniker count of %d not supported\n", i);
1440 
1441     IEnumMoniker_Release(pEnumMk);
1442 
1443     return S_OK;
1444 }
1445 
1446 static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm,
1447     REFIID riid, void **ppv)
1448 {
1449     CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1450     HRESULT hr;
1451 
1452     TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1453 
1454     CompositeMonikerImpl_ReleaseMonikersInTable(This);
1455 
1456     /* resize the table if needed */
1457     if (This->tabLastIndex + 2 > This->tabSize)
1458     {
1459         This->tabSize += max(BLOCK_TAB_SIZE, 2);
1460         This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1461 
1462         if (This->tabMoniker==NULL)
1463             return E_OUTOFMEMORY;
1464     }
1465 
1466     hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1467     if (FAILED(hr))
1468     {
1469         ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
1470         return hr;
1471     }
1472     This->tabLastIndex++;
1473     hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1474     if (FAILED(hr))
1475     {
1476         ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
1477         return hr;
1478     }
1479     This->tabLastIndex++;
1480 
1481     return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppv);
1482 }
1483 
1484 static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1485 {
1486     TRACE("(%p)\n", pStm);
1487     /* can't release a state-based marshal as nothing on server side to
1488      * release */
1489     return S_OK;
1490 }
1491 
1492 static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(IMarshal *iface,
1493     DWORD dwReserved)
1494 {
1495     TRACE("(0x%x)\n", dwReserved);
1496     /* can't disconnect a state-based marshal as nothing on server side to
1497      * disconnect from */
1498     return S_OK;
1499 }
1500 
1501 /******************************************************************************
1502  *        EnumMonikerImpl_QueryInterface
1503  ******************************************************************************/
1504 static HRESULT WINAPI
1505 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1506 {
1507     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1508 
1509     TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1510 
1511     /* Perform a sanity check on the parameters.*/
1512     if ( ppvObject==0 )
1513 	return E_INVALIDARG;
1514 
1515     /* Initialize the return parameter */
1516     *ppvObject = 0;
1517 
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;
1521 
1522     /* Check that we obtained an interface.*/
1523     if ((*ppvObject)==0)
1524         return E_NOINTERFACE;
1525 
1526     /* Query Interface always increases the reference count by one when it is successful */
1527     IEnumMoniker_AddRef(iface);
1528 
1529     return S_OK;
1530 }
1531 
1532 /******************************************************************************
1533  *        EnumMonikerImpl_AddRef
1534  ******************************************************************************/
1535 static ULONG WINAPI
1536 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1537 {
1538     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1539 
1540     TRACE("(%p)\n",This);
1541 
1542     return InterlockedIncrement(&This->ref);
1543 
1544 }
1545 
1546 /******************************************************************************
1547  *        EnumMonikerImpl_Release
1548  ******************************************************************************/
1549 static ULONG WINAPI
1550 EnumMonikerImpl_Release(IEnumMoniker* iface)
1551 {
1552     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1553     ULONG i;
1554     ULONG ref;
1555     TRACE("(%p)\n",This);
1556 
1557     ref = InterlockedDecrement(&This->ref);
1558 
1559     /* destroy the object if there are no more references to it */
1560     if (ref == 0) {
1561 
1562         for(i=0;i<This->tabSize;i++)
1563             IMoniker_Release(This->tabMoniker[i]);
1564 
1565         HeapFree(GetProcessHeap(),0,This->tabMoniker);
1566         HeapFree(GetProcessHeap(),0,This);
1567     }
1568     return ref;
1569 }
1570 
1571 /******************************************************************************
1572  *        EnumMonikerImpl_Next
1573  ******************************************************************************/
1574 static HRESULT WINAPI
1575 EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt,
1576                ULONG* pceltFethed)
1577 {
1578     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1579     ULONG i;
1580 
1581     /* retrieve the requested number of moniker from the current position */
1582     for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++)
1583     {
1584         rgelt[i]=This->tabMoniker[This->currentPos++];
1585         IMoniker_AddRef(rgelt[i]);
1586     }
1587 
1588     if (pceltFethed!=NULL)
1589         *pceltFethed= i;
1590 
1591     if (i==celt)
1592         return S_OK;
1593     else
1594         return S_FALSE;
1595 }
1596 
1597 /******************************************************************************
1598  *        EnumMonikerImpl_Skip
1599  ******************************************************************************/
1600 static HRESULT WINAPI
1601 EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt)
1602 {
1603     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1604 
1605     if ((This->currentPos+celt) >= This->tabSize)
1606         return S_FALSE;
1607 
1608     This->currentPos+=celt;
1609 
1610     return S_OK;
1611 }
1612 
1613 /******************************************************************************
1614  *        EnumMonikerImpl_Reset
1615  ******************************************************************************/
1616 static HRESULT WINAPI
1617 EnumMonikerImpl_Reset(IEnumMoniker* iface)
1618 {
1619     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1620 
1621     This->currentPos=0;
1622 
1623     return S_OK;
1624 }
1625 
1626 /******************************************************************************
1627  *        EnumMonikerImpl_Clone
1628  ******************************************************************************/
1629 static HRESULT WINAPI
1630 EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)
1631 {
1632     EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1633 
1634     return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
1635 }
1636 
1637 /********************************************************************************/
1638 /* Virtual function table for the IROTData class                                */
1639 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1640 {
1641     EnumMonikerImpl_QueryInterface,
1642     EnumMonikerImpl_AddRef,
1643     EnumMonikerImpl_Release,
1644     EnumMonikerImpl_Next,
1645     EnumMonikerImpl_Skip,
1646     EnumMonikerImpl_Reset,
1647     EnumMonikerImpl_Clone
1648 };
1649 
1650 /******************************************************************************
1651  *        EnumMonikerImpl_CreateEnumMoniker
1652  ******************************************************************************/
1653 static HRESULT
1654 EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize,
1655                ULONG currentPos, BOOL leftToRight, IEnumMoniker ** ppmk)
1656 {
1657     EnumMonikerImpl* newEnumMoniker;
1658     ULONG i;
1659 
1660     if (currentPos > tabSize)
1661         return E_INVALIDARG;
1662 
1663     newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
1664 
1665     if (newEnumMoniker == 0)
1666         return STG_E_INSUFFICIENTMEMORY;
1667 
1668     /* Initialize the virtual function table. */
1669     newEnumMoniker->IEnumMoniker_iface.lpVtbl = &VT_EnumMonikerImpl;
1670     newEnumMoniker->ref          = 1;
1671 
1672     newEnumMoniker->tabSize=tabSize;
1673     newEnumMoniker->currentPos=currentPos;
1674 
1675     newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(newEnumMoniker->tabMoniker[0]));
1676 
1677     if (newEnumMoniker->tabMoniker==NULL) {
1678         HeapFree(GetProcessHeap(), 0, newEnumMoniker);
1679         return E_OUTOFMEMORY;
1680     }
1681 
1682     if (leftToRight)
1683         for (i=0;i<tabSize;i++){
1684 
1685             newEnumMoniker->tabMoniker[i]=tabMoniker[i];
1686             IMoniker_AddRef(tabMoniker[i]);
1687         }
1688     else
1689         for (i = tabSize; i > 0; i--){
1690 
1691             newEnumMoniker->tabMoniker[tabSize-i]=tabMoniker[i - 1];
1692             IMoniker_AddRef(tabMoniker[i - 1]);
1693         }
1694 
1695     *ppmk=&newEnumMoniker->IEnumMoniker_iface;
1696 
1697     return S_OK;
1698 }
1699 
1700 /********************************************************************************/
1701 /* Virtual function table for the CompositeMonikerImpl class which includes     */
1702 /* IPersist, IPersistStream and IMoniker functions.                             */
1703 
1704 static const IMonikerVtbl VT_CompositeMonikerImpl =
1705 {
1706     CompositeMonikerImpl_QueryInterface,
1707     CompositeMonikerImpl_AddRef,
1708     CompositeMonikerImpl_Release,
1709     CompositeMonikerImpl_GetClassID,
1710     CompositeMonikerImpl_IsDirty,
1711     CompositeMonikerImpl_Load,
1712     CompositeMonikerImpl_Save,
1713     CompositeMonikerImpl_GetSizeMax,
1714     CompositeMonikerImpl_BindToObject,
1715     CompositeMonikerImpl_BindToStorage,
1716     CompositeMonikerImpl_Reduce,
1717     CompositeMonikerImpl_ComposeWith,
1718     CompositeMonikerImpl_Enum,
1719     CompositeMonikerImpl_IsEqual,
1720     CompositeMonikerImpl_Hash,
1721     CompositeMonikerImpl_IsRunning,
1722     CompositeMonikerImpl_GetTimeOfLastChange,
1723     CompositeMonikerImpl_Inverse,
1724     CompositeMonikerImpl_CommonPrefixWith,
1725     CompositeMonikerImpl_RelativePathTo,
1726     CompositeMonikerImpl_GetDisplayName,
1727     CompositeMonikerImpl_ParseDisplayName,
1728     CompositeMonikerImpl_IsSystemMoniker
1729 };
1730 
1731 /********************************************************************************/
1732 /* Virtual function table for the IROTData class.                               */
1733 static const IROTDataVtbl VT_ROTDataImpl =
1734 {
1735     CompositeMonikerROTDataImpl_QueryInterface,
1736     CompositeMonikerROTDataImpl_AddRef,
1737     CompositeMonikerROTDataImpl_Release,
1738     CompositeMonikerROTDataImpl_GetComparisonData
1739 };
1740 
1741 static const IMarshalVtbl VT_MarshalImpl =
1742 {
1743     CompositeMonikerMarshalImpl_QueryInterface,
1744     CompositeMonikerMarshalImpl_AddRef,
1745     CompositeMonikerMarshalImpl_Release,
1746     CompositeMonikerMarshalImpl_GetUnmarshalClass,
1747     CompositeMonikerMarshalImpl_GetMarshalSizeMax,
1748     CompositeMonikerMarshalImpl_MarshalInterface,
1749     CompositeMonikerMarshalImpl_UnmarshalInterface,
1750     CompositeMonikerMarshalImpl_ReleaseMarshalData,
1751     CompositeMonikerMarshalImpl_DisconnectObject
1752 };
1753 
1754 /******************************************************************************
1755  *         Composite-Moniker_Construct (local function)
1756  *******************************************************************************/
1757 static HRESULT
1758 CompositeMonikerImpl_Construct(IMoniker **ppMoniker, IMoniker *pmkFirst, IMoniker *pmkRest)
1759 {
1760     DWORD mkSys;
1761     IEnumMoniker *enumMoniker;
1762     IMoniker *tempMk;
1763     HRESULT res;
1764     CompositeMonikerImpl *This;
1765     int i;
1766 
1767     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1768 
1769     if (!This)
1770         return E_OUTOFMEMORY;
1771 
1772     TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);
1773 
1774     /* Initialize the virtual function table. */
1775     This->IMoniker_iface.lpVtbl = &VT_CompositeMonikerImpl;
1776     This->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
1777     This->IMarshal_iface.lpVtbl = &VT_MarshalImpl;
1778     This->ref          = 1;
1779 
1780     This->tabSize=BLOCK_TAB_SIZE;
1781     This->tabLastIndex=0;
1782 
1783     This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(This->tabMoniker[0]));
1784     if (This->tabMoniker==NULL) {
1785         HeapFree(GetProcessHeap(), 0, This);
1786         return E_OUTOFMEMORY;
1787     }
1788 
1789     if (!pmkFirst && !pmkRest)
1790     {
1791         *ppMoniker = &This->IMoniker_iface;
1792         return S_OK;
1793     }
1794 
1795     IMoniker_IsSystemMoniker(pmkFirst,&mkSys);
1796 
1797     /* put the first moniker contents in the beginning of the table */
1798     if (mkSys!=MKSYS_GENERICCOMPOSITE){
1799 
1800         This->tabMoniker[(This->tabLastIndex)++]=pmkFirst;
1801         IMoniker_AddRef(pmkFirst);
1802     }
1803     else{
1804 
1805         IMoniker_Enum(pmkFirst,TRUE,&enumMoniker);
1806 
1807         while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1808 
1809 
1810             if (++This->tabLastIndex==This->tabSize){
1811                 IMoniker **tab_moniker = This->tabMoniker;
1812 
1813                 This->tabSize+=BLOCK_TAB_SIZE;
1814                 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1815 
1816                 if (This->tabMoniker==NULL){
1817                     for (i = 0; i < This->tabLastIndex; i++)
1818                         IMoniker_Release(tab_moniker[i]);
1819                     HeapFree(GetProcessHeap(), 0, tab_moniker);
1820                     HeapFree(GetProcessHeap(), 0, This);
1821                     return E_OUTOFMEMORY;
1822                 }
1823             }
1824         }
1825 
1826         IEnumMoniker_Release(enumMoniker);
1827     }
1828 
1829     /* put the rest moniker contents after the first one and make simplification if needed */
1830 
1831     IMoniker_IsSystemMoniker(pmkRest,&mkSys);
1832 
1833     if (mkSys!=MKSYS_GENERICCOMPOSITE){
1834 
1835         /* add a simple moniker to the moniker table */
1836 
1837         res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk);
1838 
1839         if (res==MK_E_NEEDGENERIC){
1840 
1841             /* there's no simplification in this case */
1842             This->tabMoniker[This->tabLastIndex]=pmkRest;
1843 
1844             This->tabLastIndex++;
1845 
1846             IMoniker_AddRef(pmkRest);
1847         }
1848         else if (tempMk==NULL){
1849 
1850             /* we have an antimoniker after a simple moniker so we can make a simplification in this case */
1851             IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1852 
1853             This->tabLastIndex--;
1854         }
1855         else if (SUCCEEDED(res)){
1856 
1857             /* the non-generic composition was successful so we can make a simplification in this case */
1858             IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1859 
1860             This->tabMoniker[This->tabLastIndex-1]=tempMk;
1861         } else{
1862             for (i = 0; i < This->tabLastIndex; i++)
1863                 IMoniker_Release(This->tabMoniker[i]);
1864             HeapFree(GetProcessHeap(), 0, This->tabMoniker);
1865             HeapFree(GetProcessHeap(), 0, This);
1866             return res;
1867         }
1868 
1869         /* resize tabMoniker if needed */
1870         if (This->tabLastIndex==This->tabSize){
1871             IMoniker **tab_moniker = This->tabMoniker;
1872 
1873             This->tabSize+=BLOCK_TAB_SIZE;
1874 
1875             This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1876 
1877             if (This->tabMoniker==NULL){
1878                 for (i = 0; i < This->tabLastIndex; i++)
1879                     IMoniker_Release(tab_moniker[i]);
1880                 HeapFree(GetProcessHeap(), 0, tab_moniker);
1881                 HeapFree(GetProcessHeap(), 0, This);
1882                 return E_OUTOFMEMORY;
1883             }
1884         }
1885     }
1886     else{
1887 
1888         /* add a composite moniker to the moniker table (do the same thing
1889          * for each moniker within the composite moniker as a simple moniker
1890          * (see above for how to add a simple moniker case) )
1891          */
1892         IMoniker_Enum(pmkRest,TRUE,&enumMoniker);
1893 
1894         while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1895 
1896             res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk);
1897 
1898             if (res==MK_E_NEEDGENERIC){
1899 
1900                 This->tabLastIndex++;
1901             }
1902             else if (tempMk==NULL){
1903 
1904                 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1905                 IMoniker_Release(This->tabMoniker[This->tabLastIndex]);
1906                 This->tabLastIndex--;
1907             }
1908             else{
1909 
1910                 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1911 
1912                 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1913             }
1914 
1915             if (This->tabLastIndex==This->tabSize){
1916                 IMoniker **tab_moniker = This->tabMoniker;
1917 
1918                 This->tabSize+=BLOCK_TAB_SIZE;
1919 
1920                 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1921 
1922                 if (This->tabMoniker==NULL){
1923                     for (i = 0; i < This->tabLastIndex; i++)
1924                         IMoniker_Release(tab_moniker[i]);
1925                     HeapFree(GetProcessHeap(), 0, tab_moniker);
1926                     HeapFree(GetProcessHeap(), 0, This);
1927                     return E_OUTOFMEMORY;
1928                 }
1929             }
1930         }
1931 
1932         IEnumMoniker_Release(enumMoniker);
1933     }
1934 
1935     /* only one moniker, then just return it */
1936     if (This->tabLastIndex == 1)
1937     {
1938         *ppMoniker = This->tabMoniker[0];
1939         IMoniker_AddRef(*ppMoniker);
1940         IMoniker_Release(&This->IMoniker_iface);
1941     }
1942     else
1943         *ppMoniker = &This->IMoniker_iface;
1944 
1945     return S_OK;
1946 }
1947 
1948 /******************************************************************************
1949  *        CreateGenericComposite	[OLE32.@]
1950  ******************************************************************************/
1951 HRESULT WINAPI
1952 CreateGenericComposite(IMoniker *pmkFirst, IMoniker *pmkRest, IMoniker **ppmkComposite)
1953 {
1954     IMoniker* moniker = 0;
1955     HRESULT        hr = S_OK;
1956 
1957     TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite);
1958 
1959     if (ppmkComposite==NULL)
1960         return E_POINTER;
1961 
1962     *ppmkComposite=0;
1963 
1964     if (pmkFirst==NULL && pmkRest!=NULL){
1965 
1966         *ppmkComposite=pmkRest;
1967         IMoniker_AddRef(pmkRest);
1968         return S_OK;
1969     }
1970     else if (pmkFirst!=NULL && pmkRest==NULL){
1971         *ppmkComposite=pmkFirst;
1972         IMoniker_AddRef(pmkFirst);
1973         return S_OK;
1974     }
1975     else  if (pmkFirst==NULL && pmkRest==NULL)
1976         return S_OK;
1977 
1978     hr = CompositeMonikerImpl_Construct(&moniker,pmkFirst,pmkRest);
1979 
1980     if (FAILED(hr))
1981         return hr;
1982 
1983     hr = IMoniker_QueryInterface(moniker,&IID_IMoniker,(void**)ppmkComposite);
1984     IMoniker_Release(moniker);
1985 
1986     return hr;
1987 }
1988 
1989 /******************************************************************************
1990  *        MonikerCommonPrefixWith	[OLE32.@]
1991  ******************************************************************************/
1992 HRESULT WINAPI
1993 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1994 {
1995     FIXME("(),stub!\n");
1996     return E_NOTIMPL;
1997 }
1998 
1999 HRESULT WINAPI CompositeMoniker_CreateInstance(IClassFactory *iface,
2000     IUnknown *pUnk, REFIID riid, void **ppv)
2001 {
2002     IMoniker* pMoniker;
2003     HRESULT  hr;
2004 
2005     TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
2006 
2007     *ppv = NULL;
2008 
2009     if (pUnk)
2010         return CLASS_E_NOAGGREGATION;
2011 
2012     hr = CompositeMonikerImpl_Construct(&pMoniker, NULL, NULL);
2013 
2014     if (SUCCEEDED(hr))
2015     {
2016         hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
2017         IMoniker_Release(pMoniker);
2018     }
2019 
2020     return hr;
2021 }
2022