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