Release 0.9.14.
[wine/multimedia.git] / dlls / ole32 / compositemoniker.c
blob860e8d0a75af4362ac9b3b69b54928d78f775e44
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 const CLSID CLSID_CompositeMoniker = {
41 0x309, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}
44 #define BLOCK_TAB_SIZE 5 /* represent the first size table and it's increment block size */
46 /* CompositeMoniker data structure */
47 typedef struct CompositeMonikerImpl{
49 const IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/
51 /* The ROT (RunningObjectTable implementation) uses the IROTData
52 * interface to test whether two monikers are equal. That's why IROTData
53 * interface is implemented by monikers.
55 const IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/
57 const IMarshalVtbl* lpvtblMarshal; /* VTable relative to the IMarshal interface.*/
59 LONG ref; /* reference counter for this object */
61 IMoniker** tabMoniker; /* dynamaic table containing all components (monikers) of this composite moniker */
63 ULONG tabSize; /* size of tabMoniker */
65 ULONG tabLastIndex; /* first free index in tabMoniker */
67 } CompositeMonikerImpl;
70 /* EnumMoniker data structure */
71 typedef struct EnumMonikerImpl{
73 const IEnumMonikerVtbl *lpVtbl; /* VTable relative to the IEnumMoniker interface.*/
75 LONG ref; /* reference counter for this object */
77 IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
79 ULONG tabSize; /* size of tabMoniker */
81 ULONG currentPos; /* index pointer on the current moniker */
83 } EnumMonikerImpl;
85 static inline IMoniker *impl_from_IROTData( IROTData *iface )
87 return (IMoniker *)((char*)iface - FIELD_OFFSET(CompositeMonikerImpl, lpvtbl2));
90 static inline IMoniker *impl_from_IMarshal( IMarshal *iface )
92 return (IMoniker *)((char*)iface - FIELD_OFFSET(CompositeMonikerImpl, lpvtblMarshal));
95 static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk);
97 /*******************************************************************************
98 * CompositeMoniker_QueryInterface
99 *******************************************************************************/
100 static HRESULT WINAPI
101 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
103 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
105 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
107 /* Perform a sanity check on the parameters.*/
108 if ( (This==0) || (ppvObject==0) )
109 return E_INVALIDARG;
111 /* Initialize the return parameter */
112 *ppvObject = 0;
114 /* Compare the riid with the interface IDs implemented by this object.*/
115 if (IsEqualIID(&IID_IUnknown, riid) ||
116 IsEqualIID(&IID_IPersist, riid) ||
117 IsEqualIID(&IID_IPersistStream, riid) ||
118 IsEqualIID(&IID_IMoniker, riid)
120 *ppvObject = iface;
121 else if (IsEqualIID(&IID_IROTData, riid))
122 *ppvObject = (IROTData*)&(This->lpvtbl2);
123 else if (IsEqualIID(&IID_IMarshal, riid))
124 *ppvObject = (IROTData*)&(This->lpvtblMarshal);
126 /* Check that we obtained an interface.*/
127 if ((*ppvObject)==0)
128 return E_NOINTERFACE;
130 /* Query Interface always increases the reference count by one when it is successful */
131 IMoniker_AddRef(iface);
133 return S_OK;
136 /******************************************************************************
137 * CompositeMoniker_AddRef
138 ******************************************************************************/
139 static ULONG WINAPI
140 CompositeMonikerImpl_AddRef(IMoniker* iface)
142 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
144 TRACE("(%p)\n",This);
146 return InterlockedIncrement(&This->ref);
149 static void CompositeMonikerImpl_ReleaseMonikersInTable(CompositeMonikerImpl *This)
151 ULONG i;
153 for (i = 0; i < This->tabLastIndex; i++)
154 IMoniker_Release(This->tabMoniker[i]);
156 This->tabLastIndex = 0;
159 /******************************************************************************
160 * CompositeMoniker_Release
161 ******************************************************************************/
162 static ULONG WINAPI
163 CompositeMonikerImpl_Release(IMoniker* iface)
165 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
166 ULONG ref;
168 TRACE("(%p)\n",This);
170 ref = InterlockedDecrement(&This->ref);
172 /* destroy the object if there's no more reference on it */
173 if (ref == 0){
175 /* release all the components before destroying this object */
176 CompositeMonikerImpl_ReleaseMonikersInTable(This);
178 HeapFree(GetProcessHeap(),0,This->tabMoniker);
179 HeapFree(GetProcessHeap(),0,This);
181 return ref;
184 /******************************************************************************
185 * CompositeMoniker_GetClassID
186 ******************************************************************************/
187 static HRESULT WINAPI
188 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
190 TRACE("(%p,%p)\n",iface,pClassID);
192 if (pClassID==NULL)
193 return E_POINTER;
195 *pClassID = CLSID_CompositeMoniker;
197 return S_OK;
200 /******************************************************************************
201 * CompositeMoniker_IsDirty
202 ******************************************************************************/
203 static HRESULT WINAPI
204 CompositeMonikerImpl_IsDirty(IMoniker* iface)
206 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
207 method in the OLE-provided moniker interfaces always return S_FALSE because
208 their internal state never changes. */
210 TRACE("(%p)\n",iface);
212 return S_FALSE;
215 /******************************************************************************
216 * CompositeMoniker_Load
217 ******************************************************************************/
218 static HRESULT WINAPI
219 CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
221 HRESULT res;
222 DWORD moniker_count;
223 DWORD i;
225 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
227 TRACE("(%p,%p)\n",iface,pStm);
229 /* this function call OleLoadFromStream function for each moniker within this object */
231 res=IStream_Read(pStm,&moniker_count,sizeof(DWORD),NULL);
232 if (res != S_OK)
234 ERR("couldn't reading moniker count from stream\n");
235 return E_FAIL;
238 CompositeMonikerImpl_ReleaseMonikersInTable(This);
240 for (i = 0; i < moniker_count; i++)
242 res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
243 if (FAILED(res))
245 ERR("couldn't load moniker from stream, res = 0x%08lx\n", res);
246 break;
249 /* resize the table if needed */
250 if (++This->tabLastIndex==This->tabSize){
252 This->tabSize+=BLOCK_TAB_SIZE;
253 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
255 if (This->tabMoniker==NULL)
256 return E_OUTOFMEMORY;
260 return res;
263 /******************************************************************************
264 * CompositeMoniker_Save
265 ******************************************************************************/
266 static HRESULT WINAPI
267 CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
269 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
270 HRESULT res;
271 IEnumMoniker *enumMk;
272 IMoniker *pmk;
273 DWORD moniker_count = This->tabLastIndex;
275 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
277 /* This function calls OleSaveToStream function for each moniker within
278 * this object.
279 * When I tested this function in windows, I usually found this constant
280 * at the beginning of the stream. I don't known why (there's no
281 * indication in the specification) !
283 res=IStream_Write(pStm,&moniker_count,sizeof(moniker_count),NULL);
284 if (FAILED(res)) return res;
286 IMoniker_Enum(iface,TRUE,&enumMk);
288 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
290 res=OleSaveToStream((IPersistStream*)pmk,pStm);
292 IMoniker_Release(pmk);
294 if (FAILED(res)){
296 IEnumMoniker_Release(enumMk);
297 return res;
301 IEnumMoniker_Release(enumMk);
303 return S_OK;
306 /******************************************************************************
307 * CompositeMoniker_GetSizeMax
308 ******************************************************************************/
309 static HRESULT WINAPI
310 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
312 IEnumMoniker *enumMk;
313 IMoniker *pmk;
314 ULARGE_INTEGER ptmpSize;
316 /* The sizeMax of this object is calculated by calling GetSizeMax on
317 * each moniker within this object then summing all returned values
320 TRACE("(%p,%p)\n",iface,pcbSize);
322 if (!pcbSize)
323 return E_POINTER;
325 pcbSize->QuadPart = sizeof(DWORD);
327 IMoniker_Enum(iface,TRUE,&enumMk);
329 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
331 IMoniker_GetSizeMax(pmk,&ptmpSize);
333 IMoniker_Release(pmk);
335 pcbSize->QuadPart = ptmpSize.QuadPart + sizeof(CLSID);
338 IEnumMoniker_Release(enumMk);
340 return S_OK;
343 /******************************************************************************
344 * CompositeMoniker_BindToObject
345 ******************************************************************************/
346 static HRESULT WINAPI
347 CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,
348 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
350 HRESULT res;
351 IRunningObjectTable *prot;
352 IMoniker *tempMk,*antiMk,*mostRigthMk;
353 IEnumMoniker *enumMoniker;
355 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
357 if (ppvResult==NULL)
358 return E_POINTER;
360 *ppvResult=0;
361 /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
362 /* object for the requested interface pointer. */
363 if(pmkToLeft==NULL){
365 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
367 if (SUCCEEDED(res)){
369 /* if the requested class was loaded before ! we don't need to reload it */
370 res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
372 if (res==S_OK)
373 return res;
376 else{
377 /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
378 /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
380 IMoniker_Enum(iface,FALSE,&enumMoniker);
381 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
382 IEnumMoniker_Release(enumMoniker);
384 res=CreateAntiMoniker(&antiMk);
385 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
386 IMoniker_Release(antiMk);
388 res=IMoniker_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult);
390 IMoniker_Release(tempMk);
391 IMoniker_Release(mostRigthMk);
394 return res;
397 /******************************************************************************
398 * CompositeMoniker_BindToStorage
399 ******************************************************************************/
400 static HRESULT WINAPI
401 CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
402 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
404 HRESULT res;
405 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk;
406 IEnumMoniker *enumMoniker;
408 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
410 *ppvResult=0;
412 /* This method recursively calls BindToStorage on the rightmost component of the composite, */
413 /* passing the rest of the composite as the pmkToLeft parameter for that call. */
415 if (pmkToLeft)
417 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
418 if (FAILED(res)) return res;
420 else
421 leftMk = iface;
423 IMoniker_Enum(iface, FALSE, &enumMoniker);
424 IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL);
425 IEnumMoniker_Release(enumMoniker);
427 res = CreateAntiMoniker(&antiMk);
428 if (FAILED(res)) return res;
429 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
430 if (FAILED(res)) return res;
431 IMoniker_Release(antiMk);
433 res = IMoniker_BindToStorage(mostRigthMk, pbc, tempMk, riid, ppvResult);
435 IMoniker_Release(tempMk);
437 IMoniker_Release(mostRigthMk);
439 if (pmkToLeft)
440 IMoniker_Release(leftMk);
442 return res;
445 /******************************************************************************
446 * CompositeMoniker_Reduce
447 ******************************************************************************/
448 static HRESULT WINAPI
449 CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
450 IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
452 HRESULT res;
453 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk;
454 IEnumMoniker *enumMoniker;
456 TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
458 if (ppmkReduced==NULL)
459 return E_POINTER;
461 /* This method recursively calls Reduce for each of its component monikers. */
463 if (ppmkToLeft==NULL){
465 IMoniker_Enum(iface,FALSE,&enumMoniker);
466 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
467 IEnumMoniker_Release(enumMoniker);
469 res=CreateAntiMoniker(&antiMk);
470 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
471 IMoniker_Release(antiMk);
473 return CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
475 else if (*ppmkToLeft==NULL)
477 return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);
479 else{
481 /* separate the composite moniker in to left and right moniker */
482 IMoniker_Enum(iface,FALSE,&enumMoniker);
483 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
484 IEnumMoniker_Release(enumMoniker);
486 res=CreateAntiMoniker(&antiMk);
487 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
488 IMoniker_Release(antiMk);
490 /* If any of the components reduces itself, the method returns S_OK and passes back a composite */
491 /* of the reduced components */
492 if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) &&
493 CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk)
496 return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced);
498 else{
499 /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
501 IMoniker_AddRef(iface);
503 *ppmkReduced=iface;
505 return MK_S_REDUCED_TO_SELF;
510 /******************************************************************************
511 * CompositeMoniker_ComposeWith
512 ******************************************************************************/
513 static HRESULT WINAPI
514 CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
515 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
517 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
519 if ((ppmkComposite==NULL)||(pmkRight==NULL))
520 return E_POINTER;
522 *ppmkComposite=0;
524 /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */
525 /* otherwise, the method returns the result of combining the two monikers by calling the */
526 /* CreateGenericComposite function */
528 if (fOnlyIfNotGeneric)
529 return MK_E_NEEDGENERIC;
531 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
534 /******************************************************************************
535 * CompositeMoniker_Enum
536 ******************************************************************************/
537 static HRESULT WINAPI
538 CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
540 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
542 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
544 if (ppenumMoniker == NULL)
545 return E_POINTER;
547 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);
550 /******************************************************************************
551 * CompositeMoniker_IsEqual
552 ******************************************************************************/
553 static HRESULT WINAPI
554 CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
556 IEnumMoniker *enumMoniker1,*enumMoniker2;
557 IMoniker *tempMk1,*tempMk2;
558 HRESULT res1,res2,res;
560 TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
562 if (pmkOtherMoniker==NULL)
563 return S_FALSE;
565 /* This method returns S_OK if the components of both monikers are equal when compared in the */
566 /* left-to-right order.*/
567 IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);
569 if (enumMoniker1==NULL)
570 return S_FALSE;
572 IMoniker_Enum(iface,TRUE,&enumMoniker2);
574 while(1){
576 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
577 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
579 if((res1==S_OK)&&(res2==S_OK)){
581 if(IMoniker_IsEqual(tempMk1,tempMk2)==S_FALSE){
582 res= S_FALSE;
583 break;
585 else
586 continue;
588 else if ( (res1==S_FALSE) && (res2==S_FALSE) ){
589 res = S_OK;
590 break;
592 else{
593 res = S_FALSE;
594 break;
597 if (res1==S_OK)
598 IMoniker_Release(tempMk1);
600 if (res2==S_OK)
601 IMoniker_Release(tempMk2);
604 IEnumMoniker_Release(enumMoniker1);
605 IEnumMoniker_Release(enumMoniker2);
607 return res;
609 /******************************************************************************
610 * CompositeMoniker_Hash
611 ******************************************************************************/
612 static HRESULT WINAPI
613 CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
615 IEnumMoniker *enumMoniker;
616 IMoniker *tempMk;
617 HRESULT res;
618 DWORD tempHash;
620 TRACE("(%p,%p)\n",iface,pdwHash);
622 if (pdwHash==NULL)
623 return E_POINTER;
625 res = IMoniker_Enum(iface,TRUE,&enumMoniker);
626 if(FAILED(res))
627 return res;
629 *pdwHash = 0;
631 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
632 res = IMoniker_Hash(tempMk, &tempHash);
633 if(FAILED(res))
634 break;
635 *pdwHash = *pdwHash ^ tempHash;
637 IMoniker_Release(tempMk);
640 IEnumMoniker_Release(enumMoniker);
642 return res;
645 /******************************************************************************
646 * CompositeMoniker_IsRunning
647 ******************************************************************************/
648 static HRESULT WINAPI
649 CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc,
650 IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
652 IRunningObjectTable* rot;
653 HRESULT res;
654 IMoniker *tempMk,*antiMk,*mostRigthMk;
655 IEnumMoniker *enumMoniker;
657 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
659 /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/
660 if (pmkToLeft!=NULL){
662 CreateGenericComposite(pmkToLeft,iface,&tempMk);
664 res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);
666 IMoniker_Release(tempMk);
668 return res;
670 else
671 /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */
672 /* to this moniker */
674 if (pmkNewlyRunning!=NULL)
676 if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)
677 return S_OK;
679 else
680 return S_FALSE;
682 else{
684 if (pbc==NULL)
685 return E_POINTER;
687 /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */
688 /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */
689 /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */
690 /* the composite as the pmkToLeft parameter for that call. */
692 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
694 if (FAILED(res))
695 return res;
697 res = IRunningObjectTable_IsRunning(rot,iface);
698 IRunningObjectTable_Release(rot);
700 if(res==S_OK)
701 return S_OK;
703 else{
705 IMoniker_Enum(iface,FALSE,&enumMoniker);
706 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
707 IEnumMoniker_Release(enumMoniker);
709 res=CreateAntiMoniker(&antiMk);
710 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
711 IMoniker_Release(antiMk);
713 res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning);
715 IMoniker_Release(tempMk);
716 IMoniker_Release(mostRigthMk);
718 return res;
723 /******************************************************************************
724 * CompositeMoniker_GetTimeOfLastChange
725 ******************************************************************************/
726 static HRESULT WINAPI
727 CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
728 IMoniker* pmkToLeft, FILETIME* pCompositeTime)
730 HRESULT res;
731 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk;
732 IEnumMoniker *enumMoniker;
734 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);
736 if (pCompositeTime==NULL)
737 return E_INVALIDARG;
739 /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to */
740 /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */
741 /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */
742 /* of the composite as the pmkToLeft parameter for that call. */
743 if (pmkToLeft)
745 IRunningObjectTable* rot;
747 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
749 res = IBindCtx_GetRunningObjectTable(pbc,&rot);
750 if (FAILED(res))
752 IMoniker_Release(leftMk);
753 return res;
756 if (IRunningObjectTable_GetTimeOfLastChange(rot,leftMk,pCompositeTime)==S_OK)
758 IMoniker_Release(leftMk);
759 return res;
762 else
763 leftMk = iface;
765 IMoniker_Enum(iface, FALSE, &enumMoniker);
766 IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL);
767 IEnumMoniker_Release(enumMoniker);
769 res = CreateAntiMoniker(&antiMk);
770 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
771 IMoniker_Release(antiMk);
773 res = IMoniker_GetTimeOfLastChange(mostRigthMk, pbc, tempMk, pCompositeTime);
775 IMoniker_Release(tempMk);
776 IMoniker_Release(mostRigthMk);
778 if (pmkToLeft)
779 IMoniker_Release(leftMk);
781 return res;
784 /******************************************************************************
785 * CompositeMoniker_Inverse
786 ******************************************************************************/
787 static HRESULT WINAPI
788 CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
790 HRESULT res;
791 IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk;
792 IEnumMoniker *enumMoniker;
794 TRACE("(%p,%p)\n",iface,ppmk);
796 if (ppmk==NULL)
797 return E_POINTER;
799 /* This method returns a composite moniker that consists of the inverses of each of the components */
800 /* of the original composite, stored in reverse order */
802 res=CreateAntiMoniker(&antiMk);
803 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
804 IMoniker_Release(antiMk);
806 if (tempMk==NULL)
808 return IMoniker_Inverse(iface,ppmk);
810 else{
812 IMoniker_Enum(iface,FALSE,&enumMoniker);
813 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
814 IEnumMoniker_Release(enumMoniker);
816 IMoniker_Inverse(mostRigthMk,&mostRigthInvMk);
817 CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);
819 res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk);
821 IMoniker_Release(tempMk);
822 IMoniker_Release(mostRigthMk);
823 IMoniker_Release(tempInvMk);
824 IMoniker_Release(mostRigthInvMk);
826 return res;
830 /******************************************************************************
831 * CompositeMoniker_CommonPrefixWith
832 ******************************************************************************/
833 static HRESULT WINAPI
834 CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,
835 IMoniker** ppmkPrefix)
837 DWORD mkSys;
838 HRESULT res1,res2;
839 IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
840 IEnumMoniker *enumMoniker1,*enumMoniker2;
841 ULONG i,nbCommonMk=0;
843 /* If the other moniker is a composite, this method compares the components of each composite from left */
844 /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
845 /* of the leftmost components were common to both monikers. */
847 if (ppmkPrefix==NULL)
848 return E_POINTER;
850 *ppmkPrefix=0;
852 if (pmkOther==NULL)
853 return MK_E_NOPREFIX;
855 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
857 if((mkSys==MKSYS_GENERICCOMPOSITE)){
859 IMoniker_Enum(iface,TRUE,&enumMoniker1);
860 IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
862 while(1){
864 res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
865 res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
867 if ((res1==S_FALSE) && (res2==S_FALSE)){
869 /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
870 *ppmkPrefix=iface;
871 IMoniker_AddRef(iface);
872 return MK_S_US;
874 else if ((res1==S_OK) && (res2==S_OK)){
876 if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
878 nbCommonMk++;
880 else
881 break;
884 else if (res1==S_OK){
886 /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
887 /* ppmkPrefix to the other moniker. */
888 *ppmkPrefix=pmkOther;
889 return MK_S_HIM;
891 else{
892 /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
893 /* to this moniker. */
894 *ppmkPrefix=iface;
895 return MK_S_ME;
899 IEnumMoniker_Release(enumMoniker1);
900 IEnumMoniker_Release(enumMoniker2);
902 /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
903 if (nbCommonMk==0)
904 return MK_E_NOPREFIX;
906 IEnumMoniker_Reset(enumMoniker1);
908 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
910 /* if we have more than one commun moniker the result will be a composite moniker */
911 if (nbCommonMk>1){
913 /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
914 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
915 CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
916 IMoniker_Release(tempMk1);
917 IMoniker_Release(tempMk2);
919 /* compose all common monikers in a composite moniker */
920 for(i=0;i<nbCommonMk;i++){
922 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
924 CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
926 IMoniker_Release(*ppmkPrefix);
928 IMoniker_Release(tempMk1);
930 *ppmkPrefix=tempMk2;
932 return S_OK;
934 else{
935 /* if we have only one commun moniker the result will be a simple moniker which is the most-left one*/
936 *ppmkPrefix=tempMk1;
938 return S_OK;
941 else{
942 /* If the other moniker is not a composite, the method simply compares it to the leftmost component
943 of this moniker.*/
945 IMoniker_Enum(iface,TRUE,&enumMoniker1);
947 IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
949 if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){
951 *ppmkPrefix=pmkOther;
953 return MK_S_HIM;
955 else
956 return MK_E_NOPREFIX;
960 /***************************************************************************************************
961 * GetAfterCommonPrefix (local function)
962 * This function returns a moniker that consist of the remainder when the common prefix is removed
963 ***************************************************************************************************/
964 static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk)
966 IMoniker *tempMk,*tempMk1,*tempMk2;
967 IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3;
968 ULONG nbRestMk=0;
969 DWORD mkSys;
970 HRESULT res1,res2;
972 *restMk=0;
974 /* to create an enumerator for pGenMk with current position pointed on the first element after common */
975 /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop */
976 /* on the first difference. */
977 IMoniker_Enum(pGenMk,TRUE,&enumMoniker1);
979 IMoniker_IsSystemMoniker(commonMk,&mkSys);
981 if (mkSys==MKSYS_GENERICCOMPOSITE){
983 IMoniker_Enum(commonMk,TRUE,&enumMoniker2);
984 while(1){
986 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
987 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
989 if ((res1==S_FALSE)||(res2==S_FALSE)){
991 if (res1==S_OK)
993 nbRestMk++;
995 IMoniker_Release(tempMk1);
996 IMoniker_Release(tempMk1);
998 break;
1000 IMoniker_Release(tempMk1);
1001 IMoniker_Release(tempMk1);
1004 else{
1005 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
1006 IMoniker_Release(tempMk1);
1009 /* count the number of elements in the enumerator after the common prefix */
1010 IEnumMoniker_Clone(enumMoniker1,&enumMoniker3);
1012 for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++)
1014 IMoniker_Release(tempMk);
1016 if (nbRestMk==0)
1017 return;
1019 /* create a generic composite moniker with monikers located after the common prefix */
1020 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
1022 if (nbRestMk==1){
1024 *restMk= tempMk1;
1025 return;
1027 else {
1029 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
1031 CreateGenericComposite(tempMk1,tempMk2,restMk);
1033 IMoniker_Release(tempMk1);
1035 IMoniker_Release(tempMk2);
1037 while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){
1039 CreateGenericComposite(*restMk,tempMk1,&tempMk2);
1041 IMoniker_Release(tempMk1);
1043 IMoniker_Release(*restMk);
1045 *restMk=tempMk2;
1050 /******************************************************************************
1051 * CompositeMoniker_RelativePathTo
1052 ******************************************************************************/
1053 static HRESULT WINAPI
1054 CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther,
1055 IMoniker** ppmkRelPath)
1057 HRESULT res;
1058 IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0;
1060 TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath);
1062 if (ppmkRelPath==NULL)
1063 return E_POINTER;
1065 *ppmkRelPath=0;
1067 /* This method finds the common prefix of the two monikers and creates two monikers that consist */
1068 /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */
1069 /* of this moniker and composes the remainder of the other moniker on the right of it. */
1071 /* finds the common prefix of the two monikers */
1072 res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk);
1074 /* if there's no common prefix or the two moniker are equal the relative is the other moniker */
1075 if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){
1077 *ppmkRelPath=pmkOther;
1078 IMoniker_AddRef(pmkOther);
1079 return MK_S_HIM;
1082 GetAfterCommonPrefix(iface,commonMk,&restThisMk);
1083 GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk);
1085 /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */
1086 /* moniker when the common prefix is removed */
1087 if (res==MK_S_HIM){
1089 IMoniker_Inverse(restThisMk,ppmkRelPath);
1090 IMoniker_Release(restThisMk);
1092 /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */
1093 /* when the common prefix is removed */
1094 else if (res==MK_S_ME){
1096 *ppmkRelPath=restOtherMk;
1097 IMoniker_AddRef(restOtherMk);
1099 /* the relative path is the inverse for the remainder of this moniker and the remainder of the other */
1100 /* moniker on the right of it. */
1101 else if (res==S_OK){
1103 IMoniker_Inverse(restThisMk,&invRestThisMk);
1104 IMoniker_Release(restThisMk);
1105 CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath);
1106 IMoniker_Release(invRestThisMk);
1107 IMoniker_Release(restOtherMk);
1109 return S_OK;
1112 /******************************************************************************
1113 * CompositeMoniker_GetDisplayName
1114 ******************************************************************************/
1115 static HRESULT WINAPI
1116 CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1117 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1119 ULONG lengthStr=1;
1120 IEnumMoniker *enumMoniker;
1121 IMoniker* tempMk;
1122 LPOLESTR tempStr;
1124 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1126 if (ppszDisplayName==NULL)
1127 return E_POINTER;
1129 *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR));
1131 if (*ppszDisplayName==NULL)
1132 return E_OUTOFMEMORY;
1134 /* This method returns the concatenation of the display names returned by each component moniker of */
1135 /* the composite */
1137 **ppszDisplayName=0;
1139 IMoniker_Enum(iface,TRUE,&enumMoniker);
1141 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
1143 IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr);
1145 lengthStr+=lstrlenW(tempStr);
1147 *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));
1149 if (*ppszDisplayName==NULL)
1150 return E_OUTOFMEMORY;
1152 strcatW(*ppszDisplayName,tempStr);
1154 CoTaskMemFree(tempStr);
1155 IMoniker_Release(tempMk);
1158 IEnumMoniker_Release(enumMoniker);
1160 return S_OK;
1163 /******************************************************************************
1164 * CompositeMoniker_ParseDisplayName
1165 ******************************************************************************/
1166 static HRESULT WINAPI
1167 CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc,
1168 IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten,
1169 IMoniker** ppmkOut)
1171 IEnumMoniker *enumMoniker;
1172 IMoniker *tempMk,*mostRigthMk,*antiMk;
1173 /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/
1174 /* passing everything else as the pmkToLeft parameter for that call. */
1176 /* get the most right moniker */
1177 IMoniker_Enum(iface,FALSE,&enumMoniker);
1178 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
1179 IEnumMoniker_Release(enumMoniker);
1181 /* get the left moniker */
1182 CreateAntiMoniker(&antiMk);
1183 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
1184 IMoniker_Release(antiMk);
1186 return IMoniker_ParseDisplayName(mostRigthMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut);
1189 /******************************************************************************
1190 * CompositeMoniker_IsSystemMoniker
1191 ******************************************************************************/
1192 static HRESULT WINAPI
1193 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1195 TRACE("(%p,%p)\n",iface,pwdMksys);
1197 if (!pwdMksys)
1198 return E_POINTER;
1200 (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
1202 return S_OK;
1205 /*******************************************************************************
1206 * CompositeMonikerIROTData_QueryInterface
1207 *******************************************************************************/
1208 static HRESULT WINAPI
1209 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
1210 VOID** ppvObject)
1213 IMoniker *This = impl_from_IROTData(iface);
1215 TRACE("(%p,%p,%p)\n",iface,riid,ppvObject);
1217 return CompositeMonikerImpl_QueryInterface(This, riid, ppvObject);
1220 /***********************************************************************
1221 * CompositeMonikerIROTData_AddRef
1223 static ULONG WINAPI
1224 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
1226 IMoniker *This = impl_from_IROTData(iface);
1228 TRACE("(%p)\n",iface);
1230 return IMoniker_AddRef(This);
1233 /***********************************************************************
1234 * CompositeMonikerIROTData_Release
1236 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1238 IMoniker *This = impl_from_IROTData(iface);
1240 TRACE("(%p)\n",iface);
1242 return IMoniker_Release(This);
1245 /******************************************************************************
1246 * CompositeMonikerIROTData_GetComparisonData
1247 ******************************************************************************/
1248 static HRESULT WINAPI
1249 CompositeMonikerROTDataImpl_GetComparisonData(IROTData* iface,
1250 BYTE* pbData, ULONG cbMax, ULONG* pcbData)
1252 IMoniker *This = impl_from_IROTData(iface);
1253 IEnumMoniker *pEnumMk;
1254 IMoniker *pmk;
1255 HRESULT hr;
1257 TRACE("(%p, %lu, %p)\n", pbData, cbMax, pcbData);
1259 *pcbData = sizeof(CLSID);
1261 hr = IMoniker_Enum(This, TRUE, &pEnumMk);
1262 if (FAILED(hr)) return hr;
1264 while(IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1266 IROTData *pROTData;
1267 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1268 if (FAILED(hr))
1269 ERR("moniker doesn't support IROTData interface\n");
1271 if (SUCCEEDED(hr))
1273 ULONG cbData;
1274 hr = IROTData_GetComparisonData(pROTData, NULL, 0, &cbData);
1275 IROTData_Release(pROTData);
1276 if (SUCCEEDED(hr) || (hr == E_OUTOFMEMORY))
1278 *pcbData += cbData;
1279 hr = S_OK;
1281 else
1282 ERR("IROTData_GetComparisonData failed with error 0x%08lx\n", hr);
1285 IMoniker_Release(pmk);
1287 if (FAILED(hr))
1289 IEnumMoniker_Release(pEnumMk);
1290 return hr;
1293 if (cbMax < *pcbData)
1294 return E_OUTOFMEMORY;
1296 IEnumMoniker_Reset(pEnumMk);
1298 memcpy(pbData, &CLSID_CompositeMoniker, sizeof(CLSID));
1299 pbData += sizeof(CLSID);
1300 cbMax -= sizeof(CLSID);
1302 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1304 IROTData *pROTData;
1305 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1306 if (FAILED(hr))
1307 ERR("moniker doesn't support IROTData interface\n");
1309 if (SUCCEEDED(hr))
1311 ULONG cbData;
1312 hr = IROTData_GetComparisonData(pROTData, pbData, cbMax, &cbData);
1313 IROTData_Release(pROTData);
1314 if (SUCCEEDED(hr))
1316 pbData += cbData;
1317 cbMax -= cbData;
1319 else
1320 ERR("IROTData_GetComparisonData failed with error 0x%08lx\n", hr);
1323 IMoniker_Release(pmk);
1325 if (FAILED(hr))
1327 IEnumMoniker_Release(pEnumMk);
1328 return hr;
1332 IEnumMoniker_Release(pEnumMk);
1334 return S_OK;
1337 static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1339 IMoniker *This = impl_from_IMarshal(iface);
1341 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);
1343 return CompositeMonikerImpl_QueryInterface(This, riid, ppv);
1346 static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
1348 IMoniker *This = impl_from_IMarshal(iface);
1350 TRACE("(%p)\n",iface);
1352 return CompositeMonikerImpl_AddRef(This);
1355 static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
1357 IMoniker *This = impl_from_IMarshal(iface);
1359 TRACE("(%p)\n",iface);
1361 return CompositeMonikerImpl_Release(This);
1364 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
1365 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1366 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1368 IMoniker *This = impl_from_IMarshal(iface);
1370 TRACE("(%s, %p, %lx, %p, %lx, %p)\n", debugstr_guid(riid), pv,
1371 dwDestContext, pvDestContext, mshlflags, pCid);
1373 return IMoniker_GetClassID(This, pCid);
1376 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
1377 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1378 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1380 IMoniker *This = impl_from_IMarshal(iface);
1381 IEnumMoniker *pEnumMk;
1382 IMoniker *pmk;
1383 HRESULT hr;
1384 ULARGE_INTEGER size;
1386 TRACE("(%s, %p, %lx, %p, %lx, %p)\n", debugstr_guid(riid), pv,
1387 dwDestContext, pvDestContext, mshlflags, pSize);
1389 *pSize = 0x10; /* to match native */
1391 hr = IMoniker_Enum(This, TRUE, &pEnumMk);
1392 if (FAILED(hr)) return hr;
1394 hr = IMoniker_GetSizeMax(This, &size);
1396 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1398 ULONG size;
1400 hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1401 if (SUCCEEDED(hr))
1402 *pSize += size;
1404 IMoniker_Release(pmk);
1406 if (FAILED(hr))
1408 IEnumMoniker_Release(pEnumMk);
1409 return hr;
1413 IEnumMoniker_Release(pEnumMk);
1415 return S_OK;
1418 static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(LPMARSHAL iface, IStream *pStm,
1419 REFIID riid, void* pv, DWORD dwDestContext,
1420 void* pvDestContext, DWORD mshlflags)
1422 IMoniker *This = impl_from_IMarshal(iface);
1423 IEnumMoniker *pEnumMk;
1424 IMoniker *pmk;
1425 HRESULT hr;
1426 ULONG i = 0;
1428 TRACE("(%p, %s, %p, %lx, %p, %lx)\n", pStm, debugstr_guid(riid), pv,
1429 dwDestContext, pvDestContext, mshlflags);
1431 hr = IMoniker_Enum(This, TRUE, &pEnumMk);
1432 if (FAILED(hr)) return hr;
1434 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1436 hr = CoMarshalInterface(pStm, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1438 IMoniker_Release(pmk);
1440 if (FAILED(hr))
1442 IEnumMoniker_Release(pEnumMk);
1443 return hr;
1445 i++;
1448 if (i != 2)
1449 FIXME("moniker count of %ld not supported\n", i);
1451 IEnumMoniker_Release(pEnumMk);
1453 return S_OK;
1456 static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
1458 CompositeMonikerImpl *This = (CompositeMonikerImpl *)impl_from_IMarshal(iface);
1459 HRESULT hr;
1461 TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1463 CompositeMonikerImpl_ReleaseMonikersInTable(This);
1465 /* resize the table if needed */
1466 if (This->tabLastIndex + 2 > This->tabSize)
1468 This->tabSize += max(BLOCK_TAB_SIZE, 2);
1469 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1471 if (This->tabMoniker==NULL)
1472 return E_OUTOFMEMORY;
1475 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1476 if (FAILED(hr))
1478 ERR("couldn't unmarshal moniker, hr = 0x%08lx\n", hr);
1479 return hr;
1481 This->tabLastIndex++;
1482 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1483 if (FAILED(hr))
1485 ERR("couldn't unmarshal moniker, hr = 0x%08lx\n", hr);
1486 return hr;
1488 This->tabLastIndex++;
1490 return IMoniker_QueryInterface((IMoniker *)&This->lpvtbl1, riid, ppv);
1493 static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
1495 TRACE("(%p)\n", pStm);
1496 /* can't release a state-based marshal as nothing on server side to
1497 * release */
1498 return S_OK;
1501 static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
1503 TRACE("(0x%lx)\n", dwReserved);
1504 /* can't disconnect a state-based marshal as nothing on server side to
1505 * disconnect from */
1506 return S_OK;
1509 /******************************************************************************
1510 * EnumMonikerImpl_QueryInterface
1511 ******************************************************************************/
1512 static HRESULT WINAPI
1513 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1515 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1517 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
1519 /* Perform a sanity check on the parameters.*/
1520 if ( (This==0) || (ppvObject==0) )
1521 return E_INVALIDARG;
1523 /* Initialize the return parameter */
1524 *ppvObject = 0;
1526 /* Compare the riid with the interface IDs implemented by this object.*/
1527 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
1528 *ppvObject = iface;
1530 /* Check that we obtained an interface.*/
1531 if ((*ppvObject)==0)
1532 return E_NOINTERFACE;
1534 /* Query Interface always increases the reference count by one when it is successful */
1535 IEnumMoniker_AddRef(iface);
1537 return S_OK;
1540 /******************************************************************************
1541 * EnumMonikerImpl_AddRef
1542 ******************************************************************************/
1543 static ULONG WINAPI
1544 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1546 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1548 TRACE("(%p)\n",This);
1550 return InterlockedIncrement(&This->ref);
1554 /******************************************************************************
1555 * EnumMonikerImpl_Release
1556 ******************************************************************************/
1557 static ULONG WINAPI
1558 EnumMonikerImpl_Release(IEnumMoniker* iface)
1560 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1561 ULONG i;
1562 ULONG ref;
1563 TRACE("(%p)\n",This);
1565 ref = InterlockedDecrement(&This->ref);
1567 /* destroy the object if there's no more reference on it */
1568 if (ref == 0) {
1570 for(i=0;i<This->tabSize;i++)
1571 IMoniker_Release(This->tabMoniker[i]);
1573 HeapFree(GetProcessHeap(),0,This->tabMoniker);
1574 HeapFree(GetProcessHeap(),0,This);
1576 return ref;
1579 /******************************************************************************
1580 * EnumMonikerImpl_Next
1581 ******************************************************************************/
1582 static HRESULT WINAPI
1583 EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt,
1584 ULONG* pceltFethed)
1586 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1587 ULONG i;
1589 /* retrieve the requested number of moniker from the current position */
1590 for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++)
1592 rgelt[i]=This->tabMoniker[This->currentPos++];
1593 IMoniker_AddRef(rgelt[i]);
1596 if (pceltFethed!=NULL)
1597 *pceltFethed= i;
1599 if (i==celt)
1600 return S_OK;
1601 else
1602 return S_FALSE;
1605 /******************************************************************************
1606 * EnumMonikerImpl_Skip
1607 ******************************************************************************/
1608 static HRESULT WINAPI
1609 EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt)
1611 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1613 if ((This->currentPos+celt) >= This->tabSize)
1614 return S_FALSE;
1616 This->currentPos+=celt;
1618 return S_OK;
1621 /******************************************************************************
1622 * EnumMonikerImpl_Reset
1623 ******************************************************************************/
1624 static HRESULT WINAPI
1625 EnumMonikerImpl_Reset(IEnumMoniker* iface)
1628 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1630 This->currentPos=0;
1632 return S_OK;
1635 /******************************************************************************
1636 * EnumMonikerImpl_Clone
1637 ******************************************************************************/
1638 static HRESULT WINAPI
1639 EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)
1641 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1643 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
1646 /********************************************************************************/
1647 /* Virtual function table for the IROTData class */
1648 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1650 EnumMonikerImpl_QueryInterface,
1651 EnumMonikerImpl_AddRef,
1652 EnumMonikerImpl_Release,
1653 EnumMonikerImpl_Next,
1654 EnumMonikerImpl_Skip,
1655 EnumMonikerImpl_Reset,
1656 EnumMonikerImpl_Clone
1659 /******************************************************************************
1660 * EnumMonikerImpl_CreateEnumMoniker
1661 ******************************************************************************/
1662 static HRESULT
1663 EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize,
1664 ULONG currentPos, BOOL leftToRigth, IEnumMoniker ** ppmk)
1666 EnumMonikerImpl* newEnumMoniker;
1667 int i;
1669 if (currentPos > tabSize)
1670 return E_INVALIDARG;
1672 newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
1674 if (newEnumMoniker == 0)
1675 return STG_E_INSUFFICIENTMEMORY;
1677 /* Initialize the virtual function table. */
1678 newEnumMoniker->lpVtbl = &VT_EnumMonikerImpl;
1679 newEnumMoniker->ref = 1;
1681 newEnumMoniker->tabSize=tabSize;
1682 newEnumMoniker->currentPos=currentPos;
1684 newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(IMoniker));
1686 if (newEnumMoniker->tabMoniker==NULL) {
1687 HeapFree(GetProcessHeap(), 0, newEnumMoniker);
1688 return E_OUTOFMEMORY;
1691 if (leftToRigth)
1692 for (i=0;i<tabSize;i++){
1694 newEnumMoniker->tabMoniker[i]=tabMoniker[i];
1695 IMoniker_AddRef(tabMoniker[i]);
1697 else
1698 for (i=tabSize-1;i>=0;i--){
1700 newEnumMoniker->tabMoniker[tabSize-i-1]=tabMoniker[i];
1701 IMoniker_AddRef(tabMoniker[i]);
1704 *ppmk=(IEnumMoniker*)newEnumMoniker;
1706 return S_OK;
1709 /********************************************************************************/
1710 /* Virtual function table for the CompositeMonikerImpl class which includes */
1711 /* IPersist, IPersistStream and IMoniker functions. */
1713 static const IMonikerVtbl VT_CompositeMonikerImpl =
1715 CompositeMonikerImpl_QueryInterface,
1716 CompositeMonikerImpl_AddRef,
1717 CompositeMonikerImpl_Release,
1718 CompositeMonikerImpl_GetClassID,
1719 CompositeMonikerImpl_IsDirty,
1720 CompositeMonikerImpl_Load,
1721 CompositeMonikerImpl_Save,
1722 CompositeMonikerImpl_GetSizeMax,
1723 CompositeMonikerImpl_BindToObject,
1724 CompositeMonikerImpl_BindToStorage,
1725 CompositeMonikerImpl_Reduce,
1726 CompositeMonikerImpl_ComposeWith,
1727 CompositeMonikerImpl_Enum,
1728 CompositeMonikerImpl_IsEqual,
1729 CompositeMonikerImpl_Hash,
1730 CompositeMonikerImpl_IsRunning,
1731 CompositeMonikerImpl_GetTimeOfLastChange,
1732 CompositeMonikerImpl_Inverse,
1733 CompositeMonikerImpl_CommonPrefixWith,
1734 CompositeMonikerImpl_RelativePathTo,
1735 CompositeMonikerImpl_GetDisplayName,
1736 CompositeMonikerImpl_ParseDisplayName,
1737 CompositeMonikerImpl_IsSystemMoniker
1740 /********************************************************************************/
1741 /* Virtual function table for the IROTData class. */
1742 static const IROTDataVtbl VT_ROTDataImpl =
1744 CompositeMonikerROTDataImpl_QueryInterface,
1745 CompositeMonikerROTDataImpl_AddRef,
1746 CompositeMonikerROTDataImpl_Release,
1747 CompositeMonikerROTDataImpl_GetComparisonData
1750 static const IMarshalVtbl VT_MarshalImpl =
1752 CompositeMonikerMarshalImpl_QueryInterface,
1753 CompositeMonikerMarshalImpl_AddRef,
1754 CompositeMonikerMarshalImpl_Release,
1755 CompositeMonikerMarshalImpl_GetUnmarshalClass,
1756 CompositeMonikerMarshalImpl_GetMarshalSizeMax,
1757 CompositeMonikerMarshalImpl_MarshalInterface,
1758 CompositeMonikerMarshalImpl_UnmarshalInterface,
1759 CompositeMonikerMarshalImpl_ReleaseMarshalData,
1760 CompositeMonikerMarshalImpl_DisconnectObject
1763 /******************************************************************************
1764 * Composite-Moniker_Construct (local function)
1765 *******************************************************************************/
1766 static HRESULT
1767 CompositeMonikerImpl_Construct(IMoniker** ppMoniker,
1768 LPMONIKER pmkFirst, LPMONIKER pmkRest)
1770 DWORD mkSys;
1771 IEnumMoniker *enumMoniker;
1772 IMoniker *tempMk;
1773 HRESULT res;
1774 CompositeMonikerImpl *This;
1776 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1778 if (!This)
1779 return E_OUTOFMEMORY;
1781 TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);
1783 /* Initialize the virtual function table. */
1784 This->lpvtbl1 = &VT_CompositeMonikerImpl;
1785 This->lpvtbl2 = &VT_ROTDataImpl;
1786 This->lpvtblMarshal= &VT_MarshalImpl;
1787 This->ref = 1;
1789 This->tabSize=BLOCK_TAB_SIZE;
1790 This->tabLastIndex=0;
1792 This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(IMoniker));
1793 if (This->tabMoniker==NULL)
1794 return E_OUTOFMEMORY;
1796 if (!pmkFirst && !pmkRest)
1798 *ppMoniker = (IMoniker *)This;
1799 return S_OK;
1802 IMoniker_IsSystemMoniker(pmkFirst,&mkSys);
1804 /* put the first moniker contents in the beginning of the table */
1805 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1807 This->tabMoniker[(This->tabLastIndex)++]=pmkFirst;
1808 IMoniker_AddRef(pmkFirst);
1810 else{
1812 IMoniker_Enum(pmkFirst,TRUE,&enumMoniker);
1814 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1817 if (++This->tabLastIndex==This->tabSize){
1819 This->tabSize+=BLOCK_TAB_SIZE;
1820 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1822 if (This->tabMoniker==NULL)
1823 return E_OUTOFMEMORY;
1827 IEnumMoniker_Release(enumMoniker);
1830 /* put the rest moniker contents after the first one and make simplification if needed */
1832 IMoniker_IsSystemMoniker(pmkRest,&mkSys);
1834 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1836 /* add a simple moniker to the moniker table */
1838 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk);
1840 if (res==MK_E_NEEDGENERIC){
1842 /* there's no simplification in this case */
1843 This->tabMoniker[This->tabLastIndex]=pmkRest;
1845 This->tabLastIndex++;
1847 IMoniker_AddRef(pmkRest);
1849 else if (tempMk==NULL){
1851 /* we have an antimoniker after a simple moniker so we can make a simplification in this case */
1852 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1854 This->tabLastIndex--;
1856 else if (SUCCEEDED(res)){
1858 /* the non-generic composition was successful so we can make a simplification in this case */
1859 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1861 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1862 } else
1863 return res;
1865 /* resize tabMoniker if needed */
1866 if (This->tabLastIndex==This->tabSize){
1868 This->tabSize+=BLOCK_TAB_SIZE;
1870 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1872 if (This->tabMoniker==NULL)
1873 return E_OUTOFMEMORY;
1876 else{
1878 /* add a composite moniker to the moniker table (do the same thing
1879 * for each moniker within the composite moniker as a simple moniker
1880 * (see above for how to add a simple moniker case) )
1882 IMoniker_Enum(pmkRest,TRUE,&enumMoniker);
1884 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1886 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk);
1888 if (res==MK_E_NEEDGENERIC){
1890 This->tabLastIndex++;
1892 else if (tempMk==NULL){
1894 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1895 IMoniker_Release(This->tabMoniker[This->tabLastIndex]);
1896 This->tabLastIndex--;
1898 else{
1900 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1902 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1905 if (This->tabLastIndex==This->tabSize){
1907 This->tabSize+=BLOCK_TAB_SIZE;
1909 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1911 if (This->tabMoniker==NULL)
1912 return E_OUTOFMEMORY;
1916 IEnumMoniker_Release(enumMoniker);
1919 /* only one moniker, then just return it */
1920 if (This->tabLastIndex == 1)
1922 *ppMoniker = This->tabMoniker[0];
1923 IMoniker_AddRef(*ppMoniker);
1924 IMoniker_Release((IMoniker *)This);
1926 else
1927 *ppMoniker = (IMoniker *)This;
1929 return S_OK;
1932 /******************************************************************************
1933 * CreateGenericComposite [OLE32.@]
1934 ******************************************************************************/
1935 HRESULT WINAPI
1936 CreateGenericComposite(LPMONIKER pmkFirst, LPMONIKER pmkRest,
1937 LPMONIKER* ppmkComposite)
1939 IMoniker* moniker = 0;
1940 HRESULT hr = S_OK;
1942 TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite);
1944 if (ppmkComposite==NULL)
1945 return E_POINTER;
1947 *ppmkComposite=0;
1949 if (pmkFirst==NULL && pmkRest!=NULL){
1951 *ppmkComposite=pmkRest;
1952 return S_OK;
1954 else if (pmkFirst!=NULL && pmkRest==NULL){
1955 *ppmkComposite=pmkFirst;
1956 return S_OK;
1958 else if (pmkFirst==NULL && pmkRest==NULL)
1959 return S_OK;
1961 hr = CompositeMonikerImpl_Construct(&moniker,pmkFirst,pmkRest);
1963 if (FAILED(hr))
1964 return hr;
1966 hr = IMoniker_QueryInterface(moniker,&IID_IMoniker,(void**)ppmkComposite);
1967 IMoniker_Release(moniker);
1969 return hr;
1972 /******************************************************************************
1973 * MonikerCommonPrefixWith [OLE32.@]
1974 ******************************************************************************/
1975 HRESULT WINAPI
1976 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1978 FIXME("(),stub!\n");
1979 return E_NOTIMPL;
1982 static HRESULT WINAPI CompositeMonikerCF_QueryInterface(LPCLASSFACTORY iface,
1983 REFIID riid, LPVOID *ppv)
1985 *ppv = NULL;
1986 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1988 *ppv = iface;
1989 IUnknown_AddRef(iface);
1990 return S_OK;
1992 return E_NOINTERFACE;
1995 static ULONG WINAPI CompositeMonikerCF_AddRef(LPCLASSFACTORY iface)
1997 return 2; /* non-heap based object */
2000 static ULONG WINAPI CompositeMonikerCF_Release(LPCLASSFACTORY iface)
2002 return 1; /* non-heap based object */
2005 static HRESULT WINAPI CompositeMonikerCF_CreateInstance(LPCLASSFACTORY iface,
2006 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
2008 IMoniker* pMoniker;
2009 HRESULT hr;
2011 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
2013 *ppv = NULL;
2015 if (pUnk)
2016 return CLASS_E_NOAGGREGATION;
2018 hr = CompositeMonikerImpl_Construct(&pMoniker, NULL, NULL);
2020 if (SUCCEEDED(hr))
2022 hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
2023 IMoniker_Release(pMoniker);
2026 return hr;
2029 static HRESULT WINAPI CompositeMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
2031 FIXME("(%d), stub!\n",fLock);
2032 return S_OK;
2035 static const IClassFactoryVtbl CompositeMonikerCFVtbl =
2037 CompositeMonikerCF_QueryInterface,
2038 CompositeMonikerCF_AddRef,
2039 CompositeMonikerCF_Release,
2040 CompositeMonikerCF_CreateInstance,
2041 CompositeMonikerCF_LockServer
2043 static const IClassFactoryVtbl *CompositeMonikerCF = &CompositeMonikerCFVtbl;
2045 HRESULT CompositeMonikerCF_Create(REFIID riid, LPVOID *ppv)
2047 return IClassFactory_QueryInterface((IClassFactory *)&CompositeMonikerCF, riid, ppv);