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