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