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