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