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