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