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