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