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