Release 1.7.27.
[wine.git] / dlls / ole32 / compositemoniker.c
blob3e6788e2e3c74da97f229b6d8d7c5d93b59761b5
1 /*
2 * CompositeMonikers implementation
4 * Copyright 1999 Noomen Hamza
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <string.h>
25 #define COBJMACROS
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "winerror.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35 #include "ole2.h"
36 #include "moniker.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
40 #define BLOCK_TAB_SIZE 5 /* represent the first size table and its increment block size */
42 /* CompositeMoniker data structure */
43 typedef struct CompositeMonikerImpl{
44 IMoniker IMoniker_iface;
45 IROTData IROTData_iface;
46 IMarshal IMarshal_iface;
47 LONG ref;
48 IMoniker** tabMoniker; /* dynamic table containing all components (monikers) of this composite moniker */
49 ULONG tabSize; /* size of tabMoniker */
50 ULONG tabLastIndex; /* first free index in tabMoniker */
51 } CompositeMonikerImpl;
53 static inline CompositeMonikerImpl *impl_from_IMoniker(IMoniker *iface)
55 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMoniker_iface);
58 static inline CompositeMonikerImpl *impl_from_IROTData(IROTData *iface)
60 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IROTData_iface);
63 static inline CompositeMonikerImpl *impl_from_IMarshal(IMarshal *iface)
65 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMarshal_iface);
68 /* EnumMoniker data structure */
69 typedef struct EnumMonikerImpl{
70 IEnumMoniker IEnumMoniker_iface;
71 LONG ref;
72 IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
73 ULONG tabSize; /* size of tabMoniker */
74 ULONG currentPos; /* index pointer on the current moniker */
75 } EnumMonikerImpl;
77 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
79 return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
82 static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk);
84 /*******************************************************************************
85 * CompositeMoniker_QueryInterface
86 *******************************************************************************/
87 static HRESULT WINAPI
88 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
90 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
92 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
94 /* Perform a sanity check on the parameters.*/
95 if ( ppvObject==0 )
96 return E_INVALIDARG;
98 /* Initialize the return parameter */
99 *ppvObject = 0;
101 /* Compare the riid with the interface IDs implemented by this object.*/
102 if (IsEqualIID(&IID_IUnknown, riid) ||
103 IsEqualIID(&IID_IPersist, riid) ||
104 IsEqualIID(&IID_IPersistStream, riid) ||
105 IsEqualIID(&IID_IMoniker, riid)
107 *ppvObject = iface;
108 else if (IsEqualIID(&IID_IROTData, riid))
109 *ppvObject = &This->IROTData_iface;
110 else if (IsEqualIID(&IID_IMarshal, riid))
111 *ppvObject = &This->IMarshal_iface;
113 /* Check that we obtained an interface.*/
114 if ((*ppvObject)==0)
115 return E_NOINTERFACE;
117 /* Query Interface always increases the reference count by one when it is successful */
118 IMoniker_AddRef(iface);
120 return S_OK;
123 /******************************************************************************
124 * CompositeMoniker_AddRef
125 ******************************************************************************/
126 static ULONG WINAPI
127 CompositeMonikerImpl_AddRef(IMoniker* iface)
129 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
131 TRACE("(%p)\n",This);
133 return InterlockedIncrement(&This->ref);
136 static void CompositeMonikerImpl_ReleaseMonikersInTable(CompositeMonikerImpl *This)
138 ULONG i;
140 for (i = 0; i < This->tabLastIndex; i++)
141 IMoniker_Release(This->tabMoniker[i]);
143 This->tabLastIndex = 0;
146 /******************************************************************************
147 * CompositeMoniker_Release
148 ******************************************************************************/
149 static ULONG WINAPI
150 CompositeMonikerImpl_Release(IMoniker* iface)
152 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
153 ULONG ref;
155 TRACE("(%p)\n",This);
157 ref = InterlockedDecrement(&This->ref);
159 /* destroy the object if there are no more references to it */
160 if (ref == 0){
162 /* release all the components before destroying this object */
163 CompositeMonikerImpl_ReleaseMonikersInTable(This);
165 HeapFree(GetProcessHeap(),0,This->tabMoniker);
166 HeapFree(GetProcessHeap(),0,This);
168 return ref;
171 /******************************************************************************
172 * CompositeMoniker_GetClassID
173 ******************************************************************************/
174 static HRESULT WINAPI
175 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
177 TRACE("(%p,%p)\n",iface,pClassID);
179 if (pClassID==NULL)
180 return E_POINTER;
182 *pClassID = CLSID_CompositeMoniker;
184 return S_OK;
187 /******************************************************************************
188 * CompositeMoniker_IsDirty
189 ******************************************************************************/
190 static HRESULT WINAPI
191 CompositeMonikerImpl_IsDirty(IMoniker* iface)
193 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
194 method in the OLE-provided moniker interfaces always return S_FALSE because
195 their internal state never changes. */
197 TRACE("(%p)\n",iface);
199 return S_FALSE;
202 /******************************************************************************
203 * CompositeMoniker_Load
204 ******************************************************************************/
205 static HRESULT WINAPI
206 CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
208 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
209 HRESULT res;
210 DWORD moniker_count;
211 DWORD i;
213 TRACE("(%p,%p)\n",iface,pStm);
215 /* this function call OleLoadFromStream function for each moniker within this object */
217 res=IStream_Read(pStm,&moniker_count,sizeof(DWORD),NULL);
218 if (res != S_OK)
220 ERR("couldn't reading moniker count from stream\n");
221 return E_FAIL;
224 CompositeMonikerImpl_ReleaseMonikersInTable(This);
226 for (i = 0; i < moniker_count; i++)
228 res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
229 if (FAILED(res))
231 ERR("couldn't load moniker from stream, res = 0x%08x\n", res);
232 break;
235 /* resize the table if needed */
236 if (++This->tabLastIndex==This->tabSize){
238 This->tabSize+=BLOCK_TAB_SIZE;
239 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
241 if (This->tabMoniker==NULL)
242 return E_OUTOFMEMORY;
246 return res;
249 /******************************************************************************
250 * CompositeMoniker_Save
251 ******************************************************************************/
252 static HRESULT WINAPI
253 CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
255 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
256 HRESULT res;
257 IEnumMoniker *enumMk;
258 IMoniker *pmk;
259 DWORD moniker_count = This->tabLastIndex;
261 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
263 /* This function calls OleSaveToStream function for each moniker within
264 * this object.
265 * When I tested this function in windows, I usually found this constant
266 * at the beginning of the stream. I don't known why (there's no
267 * indication in the specification) !
269 res=IStream_Write(pStm,&moniker_count,sizeof(moniker_count),NULL);
270 if (FAILED(res)) return res;
272 IMoniker_Enum(iface,TRUE,&enumMk);
274 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
276 res=OleSaveToStream((IPersistStream*)pmk,pStm);
278 IMoniker_Release(pmk);
280 if (FAILED(res)){
282 IEnumMoniker_Release(enumMk);
283 return res;
287 IEnumMoniker_Release(enumMk);
289 return S_OK;
292 /******************************************************************************
293 * CompositeMoniker_GetSizeMax
294 ******************************************************************************/
295 static HRESULT WINAPI
296 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
298 IEnumMoniker *enumMk;
299 IMoniker *pmk;
300 ULARGE_INTEGER ptmpSize;
302 /* The sizeMax of this object is calculated by calling GetSizeMax on
303 * each moniker within this object then summing all returned values
306 TRACE("(%p,%p)\n",iface,pcbSize);
308 if (!pcbSize)
309 return E_POINTER;
311 pcbSize->QuadPart = sizeof(DWORD);
313 IMoniker_Enum(iface,TRUE,&enumMk);
315 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
317 IMoniker_GetSizeMax(pmk,&ptmpSize);
319 IMoniker_Release(pmk);
321 pcbSize->QuadPart = ptmpSize.QuadPart + sizeof(CLSID);
324 IEnumMoniker_Release(enumMk);
326 return S_OK;
329 /******************************************************************************
330 * CompositeMoniker_BindToObject
331 ******************************************************************************/
332 static HRESULT WINAPI
333 CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,
334 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
336 HRESULT res;
337 IRunningObjectTable *prot;
338 IMoniker *tempMk,*antiMk,*mostRigthMk;
339 IEnumMoniker *enumMoniker;
341 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
343 if (ppvResult==NULL)
344 return E_POINTER;
346 *ppvResult=0;
347 /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
348 /* object for the requested interface pointer. */
349 if(pmkToLeft==NULL){
351 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
353 if (SUCCEEDED(res)){
355 /* if the requested class was loaded before ! we don't need to reload it */
356 res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
358 if (res==S_OK)
359 return res;
362 else{
363 /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
364 /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
366 IMoniker_Enum(iface,FALSE,&enumMoniker);
367 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
368 IEnumMoniker_Release(enumMoniker);
370 res=CreateAntiMoniker(&antiMk);
371 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
372 IMoniker_Release(antiMk);
374 res=IMoniker_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult);
376 IMoniker_Release(tempMk);
377 IMoniker_Release(mostRigthMk);
380 return res;
383 /******************************************************************************
384 * CompositeMoniker_BindToStorage
385 ******************************************************************************/
386 static HRESULT WINAPI
387 CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
388 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
390 HRESULT res;
391 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk;
392 IEnumMoniker *enumMoniker;
394 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
396 *ppvResult=0;
398 /* This method recursively calls BindToStorage on the rightmost component of the composite, */
399 /* passing the rest of the composite as the pmkToLeft parameter for that call. */
401 if (pmkToLeft)
403 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
404 if (FAILED(res)) return res;
406 else
407 leftMk = iface;
409 IMoniker_Enum(iface, FALSE, &enumMoniker);
410 IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL);
411 IEnumMoniker_Release(enumMoniker);
413 res = CreateAntiMoniker(&antiMk);
414 if (FAILED(res)) return res;
415 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
416 if (FAILED(res)) return res;
417 IMoniker_Release(antiMk);
419 res = IMoniker_BindToStorage(mostRigthMk, pbc, tempMk, riid, ppvResult);
421 IMoniker_Release(tempMk);
423 IMoniker_Release(mostRigthMk);
425 if (pmkToLeft)
426 IMoniker_Release(leftMk);
428 return res;
431 /******************************************************************************
432 * CompositeMoniker_Reduce
433 ******************************************************************************/
434 static HRESULT WINAPI
435 CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
436 IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
438 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk;
439 IEnumMoniker *enumMoniker;
441 TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
443 if (ppmkReduced==NULL)
444 return E_POINTER;
446 /* This method recursively calls Reduce for each of its component monikers. */
448 if (ppmkToLeft==NULL){
450 IMoniker_Enum(iface,FALSE,&enumMoniker);
451 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
452 IEnumMoniker_Release(enumMoniker);
454 CreateAntiMoniker(&antiMk);
455 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
456 IMoniker_Release(antiMk);
458 return IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
460 else if (*ppmkToLeft==NULL)
462 return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);
464 else{
466 /* separate the composite moniker in to left and right moniker */
467 IMoniker_Enum(iface,FALSE,&enumMoniker);
468 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
469 IEnumMoniker_Release(enumMoniker);
471 CreateAntiMoniker(&antiMk);
472 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
473 IMoniker_Release(antiMk);
475 /* If any of the components reduces itself, the method returns S_OK and passes back a composite */
476 /* of the reduced components */
477 if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) &&
478 IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk)
481 return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced);
483 else{
484 /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
486 IMoniker_AddRef(iface);
488 *ppmkReduced=iface;
490 return MK_S_REDUCED_TO_SELF;
495 /******************************************************************************
496 * CompositeMoniker_ComposeWith
497 ******************************************************************************/
498 static HRESULT WINAPI
499 CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
500 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
502 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
504 if ((ppmkComposite==NULL)||(pmkRight==NULL))
505 return E_POINTER;
507 *ppmkComposite=0;
509 /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */
510 /* otherwise, the method returns the result of combining the two monikers by calling the */
511 /* CreateGenericComposite function */
513 if (fOnlyIfNotGeneric)
514 return MK_E_NEEDGENERIC;
516 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
519 /******************************************************************************
520 * CompositeMoniker_Enum
521 ******************************************************************************/
522 static HRESULT WINAPI
523 CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
525 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
527 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
529 if (ppenumMoniker == NULL)
530 return E_POINTER;
532 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);
535 /******************************************************************************
536 * CompositeMoniker_IsEqual
537 ******************************************************************************/
538 static HRESULT WINAPI
539 CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
541 IEnumMoniker *enumMoniker1,*enumMoniker2;
542 IMoniker *tempMk1,*tempMk2;
543 HRESULT res1,res2,res;
544 BOOL done;
546 TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
548 if (pmkOtherMoniker==NULL)
549 return S_FALSE;
551 /* This method returns S_OK if the components of both monikers are equal when compared in the */
552 /* left-to-right order.*/
553 IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);
555 if (enumMoniker1==NULL)
556 return S_FALSE;
558 IMoniker_Enum(iface,TRUE,&enumMoniker2);
560 do {
562 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
563 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
565 if((res1==S_OK)&&(res2==S_OK)){
566 done = (res = IMoniker_IsEqual(tempMk1,tempMk2)) == S_FALSE;
568 else
570 res = (res1==S_FALSE) && (res2==S_FALSE);
571 done = TRUE;
574 if (res1==S_OK)
575 IMoniker_Release(tempMk1);
577 if (res2==S_OK)
578 IMoniker_Release(tempMk2);
579 } while (!done);
581 IEnumMoniker_Release(enumMoniker1);
582 IEnumMoniker_Release(enumMoniker2);
584 return res;
586 /******************************************************************************
587 * CompositeMoniker_Hash
588 ******************************************************************************/
589 static HRESULT WINAPI
590 CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
592 IEnumMoniker *enumMoniker;
593 IMoniker *tempMk;
594 HRESULT res;
595 DWORD tempHash;
597 TRACE("(%p,%p)\n",iface,pdwHash);
599 if (pdwHash==NULL)
600 return E_POINTER;
602 res = IMoniker_Enum(iface,TRUE,&enumMoniker);
603 if(FAILED(res))
604 return res;
606 *pdwHash = 0;
608 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
609 res = IMoniker_Hash(tempMk, &tempHash);
610 if(FAILED(res))
611 break;
612 *pdwHash = *pdwHash ^ tempHash;
614 IMoniker_Release(tempMk);
617 IEnumMoniker_Release(enumMoniker);
619 return res;
622 /******************************************************************************
623 * CompositeMoniker_IsRunning
624 ******************************************************************************/
625 static HRESULT WINAPI
626 CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc,
627 IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
629 IRunningObjectTable* rot;
630 HRESULT res;
631 IMoniker *tempMk,*antiMk,*mostRigthMk;
632 IEnumMoniker *enumMoniker;
634 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
636 /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/
637 if (pmkToLeft!=NULL){
639 CreateGenericComposite(pmkToLeft,iface,&tempMk);
641 res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);
643 IMoniker_Release(tempMk);
645 return res;
647 else
648 /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */
649 /* to this moniker */
651 if (pmkNewlyRunning!=NULL)
653 if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)
654 return S_OK;
656 else
657 return S_FALSE;
659 else{
661 if (pbc==NULL)
662 return E_INVALIDARG;
664 /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */
665 /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */
666 /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */
667 /* the composite as the pmkToLeft parameter for that call. */
669 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
671 if (FAILED(res))
672 return res;
674 res = IRunningObjectTable_IsRunning(rot,iface);
675 IRunningObjectTable_Release(rot);
677 if(res==S_OK)
678 return S_OK;
680 else{
682 IMoniker_Enum(iface,FALSE,&enumMoniker);
683 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
684 IEnumMoniker_Release(enumMoniker);
686 res=CreateAntiMoniker(&antiMk);
687 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
688 IMoniker_Release(antiMk);
690 res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning);
692 IMoniker_Release(tempMk);
693 IMoniker_Release(mostRigthMk);
695 return res;
700 /******************************************************************************
701 * CompositeMoniker_GetTimeOfLastChange
702 ******************************************************************************/
703 static HRESULT WINAPI
704 CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
705 IMoniker* pmkToLeft, FILETIME* pCompositeTime)
707 HRESULT res;
708 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk;
709 IEnumMoniker *enumMoniker;
711 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);
713 if (pCompositeTime==NULL)
714 return E_INVALIDARG;
716 /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to */
717 /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */
718 /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */
719 /* of the composite as the pmkToLeft parameter for that call. */
720 if (pmkToLeft)
722 IRunningObjectTable* rot;
724 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
726 res = IBindCtx_GetRunningObjectTable(pbc,&rot);
727 if (FAILED(res))
729 IMoniker_Release(leftMk);
730 return res;
733 if (IRunningObjectTable_GetTimeOfLastChange(rot,leftMk,pCompositeTime)==S_OK)
735 IMoniker_Release(leftMk);
736 return res;
739 else
740 leftMk = iface;
742 IMoniker_Enum(iface, FALSE, &enumMoniker);
743 IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL);
744 IEnumMoniker_Release(enumMoniker);
746 res = CreateAntiMoniker(&antiMk);
747 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
748 IMoniker_Release(antiMk);
750 res = IMoniker_GetTimeOfLastChange(mostRigthMk, pbc, tempMk, pCompositeTime);
752 IMoniker_Release(tempMk);
753 IMoniker_Release(mostRigthMk);
755 if (pmkToLeft)
756 IMoniker_Release(leftMk);
758 return res;
761 /******************************************************************************
762 * CompositeMoniker_Inverse
763 ******************************************************************************/
764 static HRESULT WINAPI
765 CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
767 HRESULT res;
768 IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk;
769 IEnumMoniker *enumMoniker;
771 TRACE("(%p,%p)\n",iface,ppmk);
773 if (ppmk==NULL)
774 return E_POINTER;
776 /* This method returns a composite moniker that consists of the inverses of each of the components */
777 /* of the original composite, stored in reverse order */
779 res=CreateAntiMoniker(&antiMk);
780 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
781 IMoniker_Release(antiMk);
783 if (tempMk==NULL)
785 return IMoniker_Inverse(iface,ppmk);
787 else{
789 IMoniker_Enum(iface,FALSE,&enumMoniker);
790 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
791 IEnumMoniker_Release(enumMoniker);
793 IMoniker_Inverse(mostRigthMk,&mostRigthInvMk);
794 CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);
796 res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk);
798 IMoniker_Release(tempMk);
799 IMoniker_Release(mostRigthMk);
800 IMoniker_Release(tempInvMk);
801 IMoniker_Release(mostRigthInvMk);
803 return res;
807 /******************************************************************************
808 * CompositeMoniker_CommonPrefixWith
809 ******************************************************************************/
810 static HRESULT WINAPI
811 CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,
812 IMoniker** ppmkPrefix)
814 DWORD mkSys;
815 HRESULT res1,res2;
816 IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
817 IEnumMoniker *enumMoniker1,*enumMoniker2;
818 ULONG i,nbCommonMk=0;
820 /* If the other moniker is a composite, this method compares the components of each composite from left */
821 /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
822 /* of the leftmost components were common to both monikers. */
824 if (ppmkPrefix==NULL)
825 return E_POINTER;
827 *ppmkPrefix=0;
829 if (pmkOther==NULL)
830 return MK_E_NOPREFIX;
832 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
834 if(mkSys==MKSYS_GENERICCOMPOSITE){
836 IMoniker_Enum(iface,TRUE,&enumMoniker1);
837 IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
839 while(1){
841 res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
842 res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
844 if ((res1==S_FALSE) && (res2==S_FALSE)){
846 /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
847 *ppmkPrefix=iface;
848 IMoniker_AddRef(iface);
849 return MK_S_US;
851 else if ((res1==S_OK) && (res2==S_OK)){
853 if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
855 nbCommonMk++;
857 else
858 break;
861 else if (res1==S_OK){
863 /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
864 /* ppmkPrefix to the other moniker. */
865 *ppmkPrefix=pmkOther;
866 return MK_S_HIM;
868 else{
869 /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
870 /* to this moniker. */
871 *ppmkPrefix=iface;
872 return MK_S_ME;
876 IEnumMoniker_Release(enumMoniker1);
877 IEnumMoniker_Release(enumMoniker2);
879 /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
880 if (nbCommonMk==0)
881 return MK_E_NOPREFIX;
883 IEnumMoniker_Reset(enumMoniker1);
885 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
887 /* if we have more than one common moniker the result will be a composite moniker */
888 if (nbCommonMk>1){
890 /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
891 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
892 CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
893 IMoniker_Release(tempMk1);
894 IMoniker_Release(tempMk2);
896 /* compose all common monikers in a composite moniker */
897 for(i=0;i<nbCommonMk;i++){
899 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
901 CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
903 IMoniker_Release(*ppmkPrefix);
905 IMoniker_Release(tempMk1);
907 *ppmkPrefix=tempMk2;
909 return S_OK;
911 else{
912 /* if we have only one common moniker the result will be a simple moniker which is the most-left one*/
913 *ppmkPrefix=tempMk1;
915 return S_OK;
918 else{
919 /* If the other moniker is not a composite, the method simply compares it to the leftmost component
920 of this moniker.*/
922 IMoniker_Enum(iface,TRUE,&enumMoniker1);
924 IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
926 if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){
928 *ppmkPrefix=pmkOther;
930 return MK_S_HIM;
932 else
933 return MK_E_NOPREFIX;
937 /***************************************************************************************************
938 * GetAfterCommonPrefix (local function)
939 * This function returns a moniker that consist of the remainder when the common prefix is removed
940 ***************************************************************************************************/
941 static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk)
943 IMoniker *tempMk,*tempMk1,*tempMk2;
944 IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3;
945 ULONG nbRestMk=0;
946 DWORD mkSys;
947 HRESULT res1,res2;
949 *restMk=0;
951 /* to create an enumerator for pGenMk with current position pointed on the first element after common */
952 /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop */
953 /* on the first difference. */
954 IMoniker_Enum(pGenMk,TRUE,&enumMoniker1);
956 IMoniker_IsSystemMoniker(commonMk,&mkSys);
958 if (mkSys==MKSYS_GENERICCOMPOSITE){
960 IMoniker_Enum(commonMk,TRUE,&enumMoniker2);
961 while(1){
963 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
964 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
966 if ((res1==S_FALSE)||(res2==S_FALSE)){
968 if (res1==S_OK)
970 nbRestMk++;
972 IMoniker_Release(tempMk1);
973 IMoniker_Release(tempMk2);
975 break;
977 IMoniker_Release(tempMk1);
978 IMoniker_Release(tempMk2);
981 else{
982 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
983 IMoniker_Release(tempMk1);
986 /* count the number of elements in the enumerator after the common prefix */
987 IEnumMoniker_Clone(enumMoniker1,&enumMoniker3);
989 for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++)
991 IMoniker_Release(tempMk);
993 if (nbRestMk==0)
994 return;
996 /* create a generic composite moniker with monikers located after the common prefix */
997 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
999 if (nbRestMk==1){
1001 *restMk= tempMk1;
1002 return;
1004 else {
1006 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
1008 CreateGenericComposite(tempMk1,tempMk2,restMk);
1010 IMoniker_Release(tempMk1);
1012 IMoniker_Release(tempMk2);
1014 while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){
1016 CreateGenericComposite(*restMk,tempMk1,&tempMk2);
1018 IMoniker_Release(tempMk1);
1020 IMoniker_Release(*restMk);
1022 *restMk=tempMk2;
1027 /******************************************************************************
1028 * CompositeMoniker_RelativePathTo
1029 ******************************************************************************/
1030 static HRESULT WINAPI
1031 CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther,
1032 IMoniker** ppmkRelPath)
1034 HRESULT res;
1035 IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0;
1037 TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath);
1039 if (ppmkRelPath==NULL)
1040 return E_POINTER;
1042 *ppmkRelPath=0;
1044 /* This method finds the common prefix of the two monikers and creates two monikers that consist */
1045 /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */
1046 /* of this moniker and composes the remainder of the other moniker on the right of it. */
1048 /* finds the common prefix of the two monikers */
1049 res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk);
1051 /* if there's no common prefix or the two moniker are equal the relative is the other moniker */
1052 if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){
1054 *ppmkRelPath=pmkOther;
1055 IMoniker_AddRef(pmkOther);
1056 return MK_S_HIM;
1059 GetAfterCommonPrefix(iface,commonMk,&restThisMk);
1060 GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk);
1062 /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */
1063 /* moniker when the common prefix is removed */
1064 if (res==MK_S_HIM){
1066 IMoniker_Inverse(restThisMk,ppmkRelPath);
1067 IMoniker_Release(restThisMk);
1069 /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */
1070 /* when the common prefix is removed */
1071 else if (res==MK_S_ME){
1073 *ppmkRelPath=restOtherMk;
1074 IMoniker_AddRef(restOtherMk);
1076 /* the relative path is the inverse for the remainder of this moniker and the remainder of the other */
1077 /* moniker on the right of it. */
1078 else if (res==S_OK){
1080 IMoniker_Inverse(restThisMk,&invRestThisMk);
1081 IMoniker_Release(restThisMk);
1082 CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath);
1083 IMoniker_Release(invRestThisMk);
1084 IMoniker_Release(restOtherMk);
1086 return S_OK;
1089 /******************************************************************************
1090 * CompositeMoniker_GetDisplayName
1091 ******************************************************************************/
1092 static HRESULT WINAPI
1093 CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1094 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1096 ULONG lengthStr=1;
1097 IEnumMoniker *enumMoniker;
1098 IMoniker* tempMk;
1099 LPOLESTR tempStr;
1101 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1103 if (ppszDisplayName==NULL)
1104 return E_POINTER;
1106 *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR));
1108 if (*ppszDisplayName==NULL)
1109 return E_OUTOFMEMORY;
1111 /* This method returns the concatenation of the display names returned by each component moniker of */
1112 /* the composite */
1114 **ppszDisplayName=0;
1116 IMoniker_Enum(iface,TRUE,&enumMoniker);
1118 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
1120 IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr);
1122 lengthStr+=lstrlenW(tempStr);
1124 *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));
1126 if (*ppszDisplayName==NULL)
1127 return E_OUTOFMEMORY;
1129 strcatW(*ppszDisplayName,tempStr);
1131 CoTaskMemFree(tempStr);
1132 IMoniker_Release(tempMk);
1135 IEnumMoniker_Release(enumMoniker);
1137 return S_OK;
1140 /******************************************************************************
1141 * CompositeMoniker_ParseDisplayName
1142 ******************************************************************************/
1143 static HRESULT WINAPI
1144 CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc,
1145 IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten,
1146 IMoniker** ppmkOut)
1148 IEnumMoniker *enumMoniker;
1149 IMoniker *tempMk,*mostRigthMk,*antiMk;
1150 /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/
1151 /* passing everything else as the pmkToLeft parameter for that call. */
1153 /* get the most right moniker */
1154 IMoniker_Enum(iface,FALSE,&enumMoniker);
1155 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
1156 IEnumMoniker_Release(enumMoniker);
1158 /* get the left moniker */
1159 CreateAntiMoniker(&antiMk);
1160 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
1161 IMoniker_Release(antiMk);
1163 return IMoniker_ParseDisplayName(mostRigthMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut);
1166 /******************************************************************************
1167 * CompositeMoniker_IsSystemMoniker
1168 ******************************************************************************/
1169 static HRESULT WINAPI
1170 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1172 TRACE("(%p,%p)\n",iface,pwdMksys);
1174 if (!pwdMksys)
1175 return E_POINTER;
1177 (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
1179 return S_OK;
1182 /*******************************************************************************
1183 * CompositeMonikerIROTData_QueryInterface
1184 *******************************************************************************/
1185 static HRESULT WINAPI
1186 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
1187 VOID** ppvObject)
1189 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1191 TRACE("(%p,%p,%p)\n",iface,riid,ppvObject);
1193 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
1196 /***********************************************************************
1197 * CompositeMonikerIROTData_AddRef
1199 static ULONG WINAPI
1200 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
1202 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1204 TRACE("(%p)\n",iface);
1206 return IMoniker_AddRef(&This->IMoniker_iface);
1209 /***********************************************************************
1210 * CompositeMonikerIROTData_Release
1212 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1214 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1216 TRACE("(%p)\n",iface);
1218 return IMoniker_Release(&This->IMoniker_iface);
1221 /******************************************************************************
1222 * CompositeMonikerIROTData_GetComparisonData
1223 ******************************************************************************/
1224 static HRESULT WINAPI
1225 CompositeMonikerROTDataImpl_GetComparisonData(IROTData* iface,
1226 BYTE* pbData, ULONG cbMax, ULONG* pcbData)
1228 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1229 IEnumMoniker *pEnumMk;
1230 IMoniker *pmk;
1231 HRESULT hr;
1233 TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
1235 *pcbData = sizeof(CLSID);
1237 hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1238 if (FAILED(hr)) return hr;
1240 while(IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1242 IROTData *pROTData;
1243 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1244 if (FAILED(hr))
1245 ERR("moniker doesn't support IROTData interface\n");
1247 if (SUCCEEDED(hr))
1249 ULONG cbData;
1250 hr = IROTData_GetComparisonData(pROTData, NULL, 0, &cbData);
1251 IROTData_Release(pROTData);
1252 if (SUCCEEDED(hr) || (hr == E_OUTOFMEMORY))
1254 *pcbData += cbData;
1255 hr = S_OK;
1257 else
1258 ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
1261 IMoniker_Release(pmk);
1263 if (FAILED(hr))
1265 IEnumMoniker_Release(pEnumMk);
1266 return hr;
1269 if (cbMax < *pcbData)
1270 return E_OUTOFMEMORY;
1272 IEnumMoniker_Reset(pEnumMk);
1274 memcpy(pbData, &CLSID_CompositeMoniker, sizeof(CLSID));
1275 pbData += sizeof(CLSID);
1276 cbMax -= sizeof(CLSID);
1278 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1280 IROTData *pROTData;
1281 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1282 if (FAILED(hr))
1283 ERR("moniker doesn't support IROTData interface\n");
1285 if (SUCCEEDED(hr))
1287 ULONG cbData;
1288 hr = IROTData_GetComparisonData(pROTData, pbData, cbMax, &cbData);
1289 IROTData_Release(pROTData);
1290 if (SUCCEEDED(hr))
1292 pbData += cbData;
1293 cbMax -= cbData;
1295 else
1296 ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
1299 IMoniker_Release(pmk);
1301 if (FAILED(hr))
1303 IEnumMoniker_Release(pEnumMk);
1304 return hr;
1308 IEnumMoniker_Release(pEnumMk);
1310 return S_OK;
1313 static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1315 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1317 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);
1319 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppv);
1322 static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
1324 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1326 TRACE("(%p)\n",iface);
1328 return CompositeMonikerImpl_AddRef(&This->IMoniker_iface);
1331 static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
1333 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1335 TRACE("(%p)\n",iface);
1337 return CompositeMonikerImpl_Release(&This->IMoniker_iface);
1340 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
1341 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1342 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1344 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1346 TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1347 dwDestContext, pvDestContext, mshlflags, pCid);
1349 return IMoniker_GetClassID(&This->IMoniker_iface, pCid);
1352 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
1353 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1354 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1356 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1357 IEnumMoniker *pEnumMk;
1358 IMoniker *pmk;
1359 HRESULT hr;
1360 ULARGE_INTEGER size;
1362 TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1363 dwDestContext, pvDestContext, mshlflags, pSize);
1365 *pSize = 0x10; /* to match native */
1367 hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1368 if (FAILED(hr)) return hr;
1370 hr = IMoniker_GetSizeMax(&This->IMoniker_iface, &size);
1372 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1374 ULONG size;
1376 hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1377 if (SUCCEEDED(hr))
1378 *pSize += size;
1380 IMoniker_Release(pmk);
1382 if (FAILED(hr))
1384 IEnumMoniker_Release(pEnumMk);
1385 return hr;
1389 IEnumMoniker_Release(pEnumMk);
1391 return S_OK;
1394 static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(IMarshal *iface, IStream *pStm,
1395 REFIID riid, void* pv, DWORD dwDestContext,
1396 void* pvDestContext, DWORD mshlflags)
1398 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1399 IEnumMoniker *pEnumMk;
1400 IMoniker *pmk;
1401 HRESULT hr;
1402 ULONG i = 0;
1404 TRACE("(%p, %s, %p, %x, %p, %x)\n", pStm, debugstr_guid(riid), pv,
1405 dwDestContext, pvDestContext, mshlflags);
1407 hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1408 if (FAILED(hr)) return hr;
1410 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1412 hr = CoMarshalInterface(pStm, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1414 IMoniker_Release(pmk);
1416 if (FAILED(hr))
1418 IEnumMoniker_Release(pEnumMk);
1419 return hr;
1421 i++;
1424 if (i != 2)
1425 FIXME("moniker count of %d not supported\n", i);
1427 IEnumMoniker_Release(pEnumMk);
1429 return S_OK;
1432 static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm,
1433 REFIID riid, void **ppv)
1435 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1436 HRESULT hr;
1438 TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1440 CompositeMonikerImpl_ReleaseMonikersInTable(This);
1442 /* resize the table if needed */
1443 if (This->tabLastIndex + 2 > This->tabSize)
1445 This->tabSize += max(BLOCK_TAB_SIZE, 2);
1446 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1448 if (This->tabMoniker==NULL)
1449 return E_OUTOFMEMORY;
1452 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1453 if (FAILED(hr))
1455 ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
1456 return hr;
1458 This->tabLastIndex++;
1459 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1460 if (FAILED(hr))
1462 ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
1463 return hr;
1465 This->tabLastIndex++;
1467 return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppv);
1470 static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1472 TRACE("(%p)\n", pStm);
1473 /* can't release a state-based marshal as nothing on server side to
1474 * release */
1475 return S_OK;
1478 static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(IMarshal *iface,
1479 DWORD dwReserved)
1481 TRACE("(0x%x)\n", dwReserved);
1482 /* can't disconnect a state-based marshal as nothing on server side to
1483 * disconnect from */
1484 return S_OK;
1487 /******************************************************************************
1488 * EnumMonikerImpl_QueryInterface
1489 ******************************************************************************/
1490 static HRESULT WINAPI
1491 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1493 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1495 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
1497 /* Perform a sanity check on the parameters.*/
1498 if ( ppvObject==0 )
1499 return E_INVALIDARG;
1501 /* Initialize the return parameter */
1502 *ppvObject = 0;
1504 /* Compare the riid with the interface IDs implemented by this object.*/
1505 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
1506 *ppvObject = iface;
1508 /* Check that we obtained an interface.*/
1509 if ((*ppvObject)==0)
1510 return E_NOINTERFACE;
1512 /* Query Interface always increases the reference count by one when it is successful */
1513 IEnumMoniker_AddRef(iface);
1515 return S_OK;
1518 /******************************************************************************
1519 * EnumMonikerImpl_AddRef
1520 ******************************************************************************/
1521 static ULONG WINAPI
1522 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1524 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1526 TRACE("(%p)\n",This);
1528 return InterlockedIncrement(&This->ref);
1532 /******************************************************************************
1533 * EnumMonikerImpl_Release
1534 ******************************************************************************/
1535 static ULONG WINAPI
1536 EnumMonikerImpl_Release(IEnumMoniker* iface)
1538 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1539 ULONG i;
1540 ULONG ref;
1541 TRACE("(%p)\n",This);
1543 ref = InterlockedDecrement(&This->ref);
1545 /* destroy the object if there are no more references to it */
1546 if (ref == 0) {
1548 for(i=0;i<This->tabSize;i++)
1549 IMoniker_Release(This->tabMoniker[i]);
1551 HeapFree(GetProcessHeap(),0,This->tabMoniker);
1552 HeapFree(GetProcessHeap(),0,This);
1554 return ref;
1557 /******************************************************************************
1558 * EnumMonikerImpl_Next
1559 ******************************************************************************/
1560 static HRESULT WINAPI
1561 EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt,
1562 ULONG* pceltFethed)
1564 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1565 ULONG i;
1567 /* retrieve the requested number of moniker from the current position */
1568 for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++)
1570 rgelt[i]=This->tabMoniker[This->currentPos++];
1571 IMoniker_AddRef(rgelt[i]);
1574 if (pceltFethed!=NULL)
1575 *pceltFethed= i;
1577 if (i==celt)
1578 return S_OK;
1579 else
1580 return S_FALSE;
1583 /******************************************************************************
1584 * EnumMonikerImpl_Skip
1585 ******************************************************************************/
1586 static HRESULT WINAPI
1587 EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt)
1589 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1591 if ((This->currentPos+celt) >= This->tabSize)
1592 return S_FALSE;
1594 This->currentPos+=celt;
1596 return S_OK;
1599 /******************************************************************************
1600 * EnumMonikerImpl_Reset
1601 ******************************************************************************/
1602 static HRESULT WINAPI
1603 EnumMonikerImpl_Reset(IEnumMoniker* iface)
1605 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1607 This->currentPos=0;
1609 return S_OK;
1612 /******************************************************************************
1613 * EnumMonikerImpl_Clone
1614 ******************************************************************************/
1615 static HRESULT WINAPI
1616 EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)
1618 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1620 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
1623 /********************************************************************************/
1624 /* Virtual function table for the IROTData class */
1625 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1627 EnumMonikerImpl_QueryInterface,
1628 EnumMonikerImpl_AddRef,
1629 EnumMonikerImpl_Release,
1630 EnumMonikerImpl_Next,
1631 EnumMonikerImpl_Skip,
1632 EnumMonikerImpl_Reset,
1633 EnumMonikerImpl_Clone
1636 /******************************************************************************
1637 * EnumMonikerImpl_CreateEnumMoniker
1638 ******************************************************************************/
1639 static HRESULT
1640 EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize,
1641 ULONG currentPos, BOOL leftToRight, IEnumMoniker ** ppmk)
1643 EnumMonikerImpl* newEnumMoniker;
1644 ULONG i;
1646 if (currentPos > tabSize)
1647 return E_INVALIDARG;
1649 newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
1651 if (newEnumMoniker == 0)
1652 return STG_E_INSUFFICIENTMEMORY;
1654 /* Initialize the virtual function table. */
1655 newEnumMoniker->IEnumMoniker_iface.lpVtbl = &VT_EnumMonikerImpl;
1656 newEnumMoniker->ref = 1;
1658 newEnumMoniker->tabSize=tabSize;
1659 newEnumMoniker->currentPos=currentPos;
1661 newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(newEnumMoniker->tabMoniker[0]));
1663 if (newEnumMoniker->tabMoniker==NULL) {
1664 HeapFree(GetProcessHeap(), 0, newEnumMoniker);
1665 return E_OUTOFMEMORY;
1668 if (leftToRight)
1669 for (i=0;i<tabSize;i++){
1671 newEnumMoniker->tabMoniker[i]=tabMoniker[i];
1672 IMoniker_AddRef(tabMoniker[i]);
1674 else
1675 for (i = tabSize; i > 0; i--){
1677 newEnumMoniker->tabMoniker[tabSize-i]=tabMoniker[i - 1];
1678 IMoniker_AddRef(tabMoniker[i - 1]);
1681 *ppmk=&newEnumMoniker->IEnumMoniker_iface;
1683 return S_OK;
1686 /********************************************************************************/
1687 /* Virtual function table for the CompositeMonikerImpl class which includes */
1688 /* IPersist, IPersistStream and IMoniker functions. */
1690 static const IMonikerVtbl VT_CompositeMonikerImpl =
1692 CompositeMonikerImpl_QueryInterface,
1693 CompositeMonikerImpl_AddRef,
1694 CompositeMonikerImpl_Release,
1695 CompositeMonikerImpl_GetClassID,
1696 CompositeMonikerImpl_IsDirty,
1697 CompositeMonikerImpl_Load,
1698 CompositeMonikerImpl_Save,
1699 CompositeMonikerImpl_GetSizeMax,
1700 CompositeMonikerImpl_BindToObject,
1701 CompositeMonikerImpl_BindToStorage,
1702 CompositeMonikerImpl_Reduce,
1703 CompositeMonikerImpl_ComposeWith,
1704 CompositeMonikerImpl_Enum,
1705 CompositeMonikerImpl_IsEqual,
1706 CompositeMonikerImpl_Hash,
1707 CompositeMonikerImpl_IsRunning,
1708 CompositeMonikerImpl_GetTimeOfLastChange,
1709 CompositeMonikerImpl_Inverse,
1710 CompositeMonikerImpl_CommonPrefixWith,
1711 CompositeMonikerImpl_RelativePathTo,
1712 CompositeMonikerImpl_GetDisplayName,
1713 CompositeMonikerImpl_ParseDisplayName,
1714 CompositeMonikerImpl_IsSystemMoniker
1717 /********************************************************************************/
1718 /* Virtual function table for the IROTData class. */
1719 static const IROTDataVtbl VT_ROTDataImpl =
1721 CompositeMonikerROTDataImpl_QueryInterface,
1722 CompositeMonikerROTDataImpl_AddRef,
1723 CompositeMonikerROTDataImpl_Release,
1724 CompositeMonikerROTDataImpl_GetComparisonData
1727 static const IMarshalVtbl VT_MarshalImpl =
1729 CompositeMonikerMarshalImpl_QueryInterface,
1730 CompositeMonikerMarshalImpl_AddRef,
1731 CompositeMonikerMarshalImpl_Release,
1732 CompositeMonikerMarshalImpl_GetUnmarshalClass,
1733 CompositeMonikerMarshalImpl_GetMarshalSizeMax,
1734 CompositeMonikerMarshalImpl_MarshalInterface,
1735 CompositeMonikerMarshalImpl_UnmarshalInterface,
1736 CompositeMonikerMarshalImpl_ReleaseMarshalData,
1737 CompositeMonikerMarshalImpl_DisconnectObject
1740 /******************************************************************************
1741 * Composite-Moniker_Construct (local function)
1742 *******************************************************************************/
1743 static HRESULT
1744 CompositeMonikerImpl_Construct(IMoniker **ppMoniker, IMoniker *pmkFirst, IMoniker *pmkRest)
1746 DWORD mkSys;
1747 IEnumMoniker *enumMoniker;
1748 IMoniker *tempMk;
1749 HRESULT res;
1750 CompositeMonikerImpl *This;
1752 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1754 if (!This)
1755 return E_OUTOFMEMORY;
1757 TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);
1759 /* Initialize the virtual function table. */
1760 This->IMoniker_iface.lpVtbl = &VT_CompositeMonikerImpl;
1761 This->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
1762 This->IMarshal_iface.lpVtbl = &VT_MarshalImpl;
1763 This->ref = 1;
1765 This->tabSize=BLOCK_TAB_SIZE;
1766 This->tabLastIndex=0;
1768 This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(This->tabMoniker[0]));
1769 if (This->tabMoniker==NULL) {
1770 HeapFree(GetProcessHeap(), 0, This);
1771 return E_OUTOFMEMORY;
1774 if (!pmkFirst && !pmkRest)
1776 *ppMoniker = &This->IMoniker_iface;
1777 return S_OK;
1780 IMoniker_IsSystemMoniker(pmkFirst,&mkSys);
1782 /* put the first moniker contents in the beginning of the table */
1783 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1785 This->tabMoniker[(This->tabLastIndex)++]=pmkFirst;
1786 IMoniker_AddRef(pmkFirst);
1788 else{
1790 IMoniker_Enum(pmkFirst,TRUE,&enumMoniker);
1792 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1795 if (++This->tabLastIndex==This->tabSize){
1796 LPVOID tab_moniker = This->tabMoniker;
1798 This->tabSize+=BLOCK_TAB_SIZE;
1799 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1801 if (This->tabMoniker==NULL){
1802 HeapFree(GetProcessHeap(), 0, tab_moniker);
1803 HeapFree(GetProcessHeap(), 0, This);
1804 return E_OUTOFMEMORY;
1809 IEnumMoniker_Release(enumMoniker);
1812 /* put the rest moniker contents after the first one and make simplification if needed */
1814 IMoniker_IsSystemMoniker(pmkRest,&mkSys);
1816 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1818 /* add a simple moniker to the moniker table */
1820 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk);
1822 if (res==MK_E_NEEDGENERIC){
1824 /* there's no simplification in this case */
1825 This->tabMoniker[This->tabLastIndex]=pmkRest;
1827 This->tabLastIndex++;
1829 IMoniker_AddRef(pmkRest);
1831 else if (tempMk==NULL){
1833 /* we have an antimoniker after a simple moniker so we can make a simplification in this case */
1834 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1836 This->tabLastIndex--;
1838 else if (SUCCEEDED(res)){
1840 /* the non-generic composition was successful so we can make a simplification in this case */
1841 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1843 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1844 } else
1845 return res;
1847 /* resize tabMoniker if needed */
1848 if (This->tabLastIndex==This->tabSize){
1849 LPVOID tab_moniker = This->tabMoniker;
1851 This->tabSize+=BLOCK_TAB_SIZE;
1853 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1855 if (This->tabMoniker==NULL){
1856 HeapFree(GetProcessHeap(), 0, tab_moniker);
1857 HeapFree(GetProcessHeap(), 0, This);
1858 return E_OUTOFMEMORY;
1862 else{
1864 /* add a composite moniker to the moniker table (do the same thing
1865 * for each moniker within the composite moniker as a simple moniker
1866 * (see above for how to add a simple moniker case) )
1868 IMoniker_Enum(pmkRest,TRUE,&enumMoniker);
1870 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1872 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk);
1874 if (res==MK_E_NEEDGENERIC){
1876 This->tabLastIndex++;
1878 else if (tempMk==NULL){
1880 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1881 IMoniker_Release(This->tabMoniker[This->tabLastIndex]);
1882 This->tabLastIndex--;
1884 else{
1886 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1888 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1891 if (This->tabLastIndex==This->tabSize){
1892 LPVOID tab_moniker = This->tabMoniker;
1894 This->tabSize+=BLOCK_TAB_SIZE;
1896 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1898 if (This->tabMoniker==NULL){
1899 HeapFree(GetProcessHeap(), 0, tab_moniker);
1900 HeapFree(GetProcessHeap(), 0, This);
1901 return E_OUTOFMEMORY;
1906 IEnumMoniker_Release(enumMoniker);
1909 /* only one moniker, then just return it */
1910 if (This->tabLastIndex == 1)
1912 *ppMoniker = This->tabMoniker[0];
1913 IMoniker_AddRef(*ppMoniker);
1914 IMoniker_Release(&This->IMoniker_iface);
1916 else
1917 *ppMoniker = &This->IMoniker_iface;
1919 return S_OK;
1922 /******************************************************************************
1923 * CreateGenericComposite [OLE32.@]
1924 ******************************************************************************/
1925 HRESULT WINAPI
1926 CreateGenericComposite(IMoniker *pmkFirst, IMoniker *pmkRest, IMoniker **ppmkComposite)
1928 IMoniker* moniker = 0;
1929 HRESULT hr = S_OK;
1931 TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite);
1933 if (ppmkComposite==NULL)
1934 return E_POINTER;
1936 *ppmkComposite=0;
1938 if (pmkFirst==NULL && pmkRest!=NULL){
1940 *ppmkComposite=pmkRest;
1941 IMoniker_AddRef(pmkRest);
1942 return S_OK;
1944 else if (pmkFirst!=NULL && pmkRest==NULL){
1945 *ppmkComposite=pmkFirst;
1946 IMoniker_AddRef(pmkFirst);
1947 return S_OK;
1949 else if (pmkFirst==NULL && pmkRest==NULL)
1950 return S_OK;
1952 hr = CompositeMonikerImpl_Construct(&moniker,pmkFirst,pmkRest);
1954 if (FAILED(hr))
1955 return hr;
1957 hr = IMoniker_QueryInterface(moniker,&IID_IMoniker,(void**)ppmkComposite);
1958 IMoniker_Release(moniker);
1960 return hr;
1963 /******************************************************************************
1964 * MonikerCommonPrefixWith [OLE32.@]
1965 ******************************************************************************/
1966 HRESULT WINAPI
1967 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1969 FIXME("(),stub!\n");
1970 return E_NOTIMPL;
1973 static HRESULT WINAPI CompositeMonikerCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
1975 *ppv = NULL;
1976 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1978 *ppv = iface;
1979 IClassFactory_AddRef(iface);
1980 return S_OK;
1982 return E_NOINTERFACE;
1985 static ULONG WINAPI CompositeMonikerCF_AddRef(LPCLASSFACTORY iface)
1987 return 2; /* non-heap based object */
1990 static ULONG WINAPI CompositeMonikerCF_Release(LPCLASSFACTORY iface)
1992 return 1; /* non-heap based object */
1995 static HRESULT WINAPI CompositeMonikerCF_CreateInstance(LPCLASSFACTORY iface,
1996 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
1998 IMoniker* pMoniker;
1999 HRESULT hr;
2001 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
2003 *ppv = NULL;
2005 if (pUnk)
2006 return CLASS_E_NOAGGREGATION;
2008 hr = CompositeMonikerImpl_Construct(&pMoniker, NULL, NULL);
2010 if (SUCCEEDED(hr))
2012 hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
2013 IMoniker_Release(pMoniker);
2016 return hr;
2019 static HRESULT WINAPI CompositeMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
2021 FIXME("(%d), stub!\n",fLock);
2022 return S_OK;
2025 static const IClassFactoryVtbl CompositeMonikerCFVtbl =
2027 CompositeMonikerCF_QueryInterface,
2028 CompositeMonikerCF_AddRef,
2029 CompositeMonikerCF_Release,
2030 CompositeMonikerCF_CreateInstance,
2031 CompositeMonikerCF_LockServer
2033 static const IClassFactoryVtbl *CompositeMonikerCF = &CompositeMonikerCFVtbl;
2035 HRESULT CompositeMonikerCF_Create(REFIID riid, LPVOID *ppv)
2037 return IClassFactory_QueryInterface((IClassFactory *)&CompositeMonikerCF, riid, ppv);