ntdll: Fix race in NtRead/WriteFile.
[wine/testsucceed.git] / dlls / ole32 / compositemoniker.c
blob275d875362bb161613af12adfc1e1e3b82ba2343
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 it's increment block size */
42 /* CompositeMoniker data structure */
43 typedef struct CompositeMonikerImpl{
45 const IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/
47 /* The ROT (RunningObjectTable implementation) uses the IROTData
48 * interface to test whether two monikers are equal. That's why IROTData
49 * interface is implemented by monikers.
51 const IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/
53 const IMarshalVtbl* lpvtblMarshal; /* VTable relative to the IMarshal interface.*/
55 LONG ref; /* reference counter for this object */
57 IMoniker** tabMoniker; /* dynamic table containing all components (monikers) of this composite moniker */
59 ULONG tabSize; /* size of tabMoniker */
61 ULONG tabLastIndex; /* first free index in tabMoniker */
63 } CompositeMonikerImpl;
66 /* EnumMoniker data structure */
67 typedef struct EnumMonikerImpl{
69 const IEnumMonikerVtbl *lpVtbl; /* VTable relative to the IEnumMoniker interface.*/
71 LONG ref; /* reference counter for this object */
73 IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
75 ULONG tabSize; /* size of tabMoniker */
77 ULONG currentPos; /* index pointer on the current moniker */
79 } EnumMonikerImpl;
81 static inline IMoniker *impl_from_IROTData( IROTData *iface )
83 return (IMoniker *)((char*)iface - FIELD_OFFSET(CompositeMonikerImpl, lpvtbl2));
86 static inline IMoniker *impl_from_IMarshal( IMarshal *iface )
88 return (IMoniker *)((char*)iface - FIELD_OFFSET(CompositeMonikerImpl, lpvtblMarshal));
91 static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk);
93 /*******************************************************************************
94 * CompositeMoniker_QueryInterface
95 *******************************************************************************/
96 static HRESULT WINAPI
97 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
99 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
101 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
103 /* Perform a sanity check on the parameters.*/
104 if ( (This==0) || (ppvObject==0) )
105 return E_INVALIDARG;
107 /* Initialize the return parameter */
108 *ppvObject = 0;
110 /* Compare the riid with the interface IDs implemented by this object.*/
111 if (IsEqualIID(&IID_IUnknown, riid) ||
112 IsEqualIID(&IID_IPersist, riid) ||
113 IsEqualIID(&IID_IPersistStream, riid) ||
114 IsEqualIID(&IID_IMoniker, riid)
116 *ppvObject = iface;
117 else if (IsEqualIID(&IID_IROTData, riid))
118 *ppvObject = &This->lpvtbl2;
119 else if (IsEqualIID(&IID_IMarshal, riid))
120 *ppvObject = &This->lpvtblMarshal;
122 /* Check that we obtained an interface.*/
123 if ((*ppvObject)==0)
124 return E_NOINTERFACE;
126 /* Query Interface always increases the reference count by one when it is successful */
127 IMoniker_AddRef(iface);
129 return S_OK;
132 /******************************************************************************
133 * CompositeMoniker_AddRef
134 ******************************************************************************/
135 static ULONG WINAPI
136 CompositeMonikerImpl_AddRef(IMoniker* iface)
138 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
140 TRACE("(%p)\n",This);
142 return InterlockedIncrement(&This->ref);
145 static void CompositeMonikerImpl_ReleaseMonikersInTable(CompositeMonikerImpl *This)
147 ULONG i;
149 for (i = 0; i < This->tabLastIndex; i++)
150 IMoniker_Release(This->tabMoniker[i]);
152 This->tabLastIndex = 0;
155 /******************************************************************************
156 * CompositeMoniker_Release
157 ******************************************************************************/
158 static ULONG WINAPI
159 CompositeMonikerImpl_Release(IMoniker* iface)
161 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
162 ULONG ref;
164 TRACE("(%p)\n",This);
166 ref = InterlockedDecrement(&This->ref);
168 /* destroy the object if there's no more reference on it */
169 if (ref == 0){
171 /* release all the components before destroying this object */
172 CompositeMonikerImpl_ReleaseMonikersInTable(This);
174 HeapFree(GetProcessHeap(),0,This->tabMoniker);
175 HeapFree(GetProcessHeap(),0,This);
177 return ref;
180 /******************************************************************************
181 * CompositeMoniker_GetClassID
182 ******************************************************************************/
183 static HRESULT WINAPI
184 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
186 TRACE("(%p,%p)\n",iface,pClassID);
188 if (pClassID==NULL)
189 return E_POINTER;
191 *pClassID = CLSID_CompositeMoniker;
193 return S_OK;
196 /******************************************************************************
197 * CompositeMoniker_IsDirty
198 ******************************************************************************/
199 static HRESULT WINAPI
200 CompositeMonikerImpl_IsDirty(IMoniker* iface)
202 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
203 method in the OLE-provided moniker interfaces always return S_FALSE because
204 their internal state never changes. */
206 TRACE("(%p)\n",iface);
208 return S_FALSE;
211 /******************************************************************************
212 * CompositeMoniker_Load
213 ******************************************************************************/
214 static HRESULT WINAPI
215 CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
217 HRESULT res;
218 DWORD moniker_count;
219 DWORD i;
221 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
223 TRACE("(%p,%p)\n",iface,pStm);
225 /* this function call OleLoadFromStream function for each moniker within this object */
227 res=IStream_Read(pStm,&moniker_count,sizeof(DWORD),NULL);
228 if (res != S_OK)
230 ERR("couldn't reading moniker count from stream\n");
231 return E_FAIL;
234 CompositeMonikerImpl_ReleaseMonikersInTable(This);
236 for (i = 0; i < moniker_count; i++)
238 res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
239 if (FAILED(res))
241 ERR("couldn't load moniker from stream, res = 0x%08x\n", res);
242 break;
245 /* resize the table if needed */
246 if (++This->tabLastIndex==This->tabSize){
248 This->tabSize+=BLOCK_TAB_SIZE;
249 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
251 if (This->tabMoniker==NULL)
252 return E_OUTOFMEMORY;
256 return res;
259 /******************************************************************************
260 * CompositeMoniker_Save
261 ******************************************************************************/
262 static HRESULT WINAPI
263 CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
265 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
266 HRESULT res;
267 IEnumMoniker *enumMk;
268 IMoniker *pmk;
269 DWORD moniker_count = This->tabLastIndex;
271 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
273 /* This function calls OleSaveToStream function for each moniker within
274 * this object.
275 * When I tested this function in windows, I usually found this constant
276 * at the beginning of the stream. I don't known why (there's no
277 * indication in the specification) !
279 res=IStream_Write(pStm,&moniker_count,sizeof(moniker_count),NULL);
280 if (FAILED(res)) return res;
282 IMoniker_Enum(iface,TRUE,&enumMk);
284 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
286 res=OleSaveToStream((IPersistStream*)pmk,pStm);
288 IMoniker_Release(pmk);
290 if (FAILED(res)){
292 IEnumMoniker_Release(enumMk);
293 return res;
297 IEnumMoniker_Release(enumMk);
299 return S_OK;
302 /******************************************************************************
303 * CompositeMoniker_GetSizeMax
304 ******************************************************************************/
305 static HRESULT WINAPI
306 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
308 IEnumMoniker *enumMk;
309 IMoniker *pmk;
310 ULARGE_INTEGER ptmpSize;
312 /* The sizeMax of this object is calculated by calling GetSizeMax on
313 * each moniker within this object then summing all returned values
316 TRACE("(%p,%p)\n",iface,pcbSize);
318 if (!pcbSize)
319 return E_POINTER;
321 pcbSize->QuadPart = sizeof(DWORD);
323 IMoniker_Enum(iface,TRUE,&enumMk);
325 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
327 IMoniker_GetSizeMax(pmk,&ptmpSize);
329 IMoniker_Release(pmk);
331 pcbSize->QuadPart = ptmpSize.QuadPart + sizeof(CLSID);
334 IEnumMoniker_Release(enumMk);
336 return S_OK;
339 /******************************************************************************
340 * CompositeMoniker_BindToObject
341 ******************************************************************************/
342 static HRESULT WINAPI
343 CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,
344 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
346 HRESULT res;
347 IRunningObjectTable *prot;
348 IMoniker *tempMk,*antiMk,*mostRigthMk;
349 IEnumMoniker *enumMoniker;
351 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
353 if (ppvResult==NULL)
354 return E_POINTER;
356 *ppvResult=0;
357 /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
358 /* object for the requested interface pointer. */
359 if(pmkToLeft==NULL){
361 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
363 if (SUCCEEDED(res)){
365 /* if the requested class was loaded before ! we don't need to reload it */
366 res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
368 if (res==S_OK)
369 return res;
372 else{
373 /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
374 /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
376 IMoniker_Enum(iface,FALSE,&enumMoniker);
377 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
378 IEnumMoniker_Release(enumMoniker);
380 res=CreateAntiMoniker(&antiMk);
381 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
382 IMoniker_Release(antiMk);
384 res=IMoniker_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult);
386 IMoniker_Release(tempMk);
387 IMoniker_Release(mostRigthMk);
390 return res;
393 /******************************************************************************
394 * CompositeMoniker_BindToStorage
395 ******************************************************************************/
396 static HRESULT WINAPI
397 CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
398 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
400 HRESULT res;
401 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk;
402 IEnumMoniker *enumMoniker;
404 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
406 *ppvResult=0;
408 /* This method recursively calls BindToStorage on the rightmost component of the composite, */
409 /* passing the rest of the composite as the pmkToLeft parameter for that call. */
411 if (pmkToLeft)
413 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
414 if (FAILED(res)) return res;
416 else
417 leftMk = iface;
419 IMoniker_Enum(iface, FALSE, &enumMoniker);
420 IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL);
421 IEnumMoniker_Release(enumMoniker);
423 res = CreateAntiMoniker(&antiMk);
424 if (FAILED(res)) return res;
425 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
426 if (FAILED(res)) return res;
427 IMoniker_Release(antiMk);
429 res = IMoniker_BindToStorage(mostRigthMk, pbc, tempMk, riid, ppvResult);
431 IMoniker_Release(tempMk);
433 IMoniker_Release(mostRigthMk);
435 if (pmkToLeft)
436 IMoniker_Release(leftMk);
438 return res;
441 /******************************************************************************
442 * CompositeMoniker_Reduce
443 ******************************************************************************/
444 static HRESULT WINAPI
445 CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
446 IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
448 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk;
449 IEnumMoniker *enumMoniker;
451 TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
453 if (ppmkReduced==NULL)
454 return E_POINTER;
456 /* This method recursively calls Reduce for each of its component monikers. */
458 if (ppmkToLeft==NULL){
460 IMoniker_Enum(iface,FALSE,&enumMoniker);
461 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
462 IEnumMoniker_Release(enumMoniker);
464 CreateAntiMoniker(&antiMk);
465 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
466 IMoniker_Release(antiMk);
468 return IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
470 else if (*ppmkToLeft==NULL)
472 return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);
474 else{
476 /* separate the composite moniker in to left and right moniker */
477 IMoniker_Enum(iface,FALSE,&enumMoniker);
478 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
479 IEnumMoniker_Release(enumMoniker);
481 CreateAntiMoniker(&antiMk);
482 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
483 IMoniker_Release(antiMk);
485 /* If any of the components reduces itself, the method returns S_OK and passes back a composite */
486 /* of the reduced components */
487 if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) &&
488 IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk)
491 return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced);
493 else{
494 /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
496 IMoniker_AddRef(iface);
498 *ppmkReduced=iface;
500 return MK_S_REDUCED_TO_SELF;
505 /******************************************************************************
506 * CompositeMoniker_ComposeWith
507 ******************************************************************************/
508 static HRESULT WINAPI
509 CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
510 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
512 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
514 if ((ppmkComposite==NULL)||(pmkRight==NULL))
515 return E_POINTER;
517 *ppmkComposite=0;
519 /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */
520 /* otherwise, the method returns the result of combining the two monikers by calling the */
521 /* CreateGenericComposite function */
523 if (fOnlyIfNotGeneric)
524 return MK_E_NEEDGENERIC;
526 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
529 /******************************************************************************
530 * CompositeMoniker_Enum
531 ******************************************************************************/
532 static HRESULT WINAPI
533 CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
535 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
537 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
539 if (ppenumMoniker == NULL)
540 return E_POINTER;
542 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);
545 /******************************************************************************
546 * CompositeMoniker_IsEqual
547 ******************************************************************************/
548 static HRESULT WINAPI
549 CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
551 IEnumMoniker *enumMoniker1,*enumMoniker2;
552 IMoniker *tempMk1,*tempMk2;
553 HRESULT res1,res2,res;
554 BOOL done;
556 TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
558 if (pmkOtherMoniker==NULL)
559 return S_FALSE;
561 /* This method returns S_OK if the components of both monikers are equal when compared in the */
562 /* left-to-right order.*/
563 IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);
565 if (enumMoniker1==NULL)
566 return S_FALSE;
568 IMoniker_Enum(iface,TRUE,&enumMoniker2);
570 do {
572 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
573 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
575 if((res1==S_OK)&&(res2==S_OK)){
576 done = (res = IMoniker_IsEqual(tempMk1,tempMk2)) == S_FALSE;
578 else
580 res = (res1==S_FALSE) && (res2==S_FALSE);
581 done = TRUE;
584 if (res1==S_OK)
585 IMoniker_Release(tempMk1);
587 if (res2==S_OK)
588 IMoniker_Release(tempMk2);
589 } while (!done);
591 IEnumMoniker_Release(enumMoniker1);
592 IEnumMoniker_Release(enumMoniker2);
594 return res;
596 /******************************************************************************
597 * CompositeMoniker_Hash
598 ******************************************************************************/
599 static HRESULT WINAPI
600 CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
602 IEnumMoniker *enumMoniker;
603 IMoniker *tempMk;
604 HRESULT res;
605 DWORD tempHash;
607 TRACE("(%p,%p)\n",iface,pdwHash);
609 if (pdwHash==NULL)
610 return E_POINTER;
612 res = IMoniker_Enum(iface,TRUE,&enumMoniker);
613 if(FAILED(res))
614 return res;
616 *pdwHash = 0;
618 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
619 res = IMoniker_Hash(tempMk, &tempHash);
620 if(FAILED(res))
621 break;
622 *pdwHash = *pdwHash ^ tempHash;
624 IMoniker_Release(tempMk);
627 IEnumMoniker_Release(enumMoniker);
629 return res;
632 /******************************************************************************
633 * CompositeMoniker_IsRunning
634 ******************************************************************************/
635 static HRESULT WINAPI
636 CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc,
637 IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
639 IRunningObjectTable* rot;
640 HRESULT res;
641 IMoniker *tempMk,*antiMk,*mostRigthMk;
642 IEnumMoniker *enumMoniker;
644 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
646 /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/
647 if (pmkToLeft!=NULL){
649 CreateGenericComposite(pmkToLeft,iface,&tempMk);
651 res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);
653 IMoniker_Release(tempMk);
655 return res;
657 else
658 /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */
659 /* to this moniker */
661 if (pmkNewlyRunning!=NULL)
663 if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)
664 return S_OK;
666 else
667 return S_FALSE;
669 else{
671 if (pbc==NULL)
672 return E_INVALIDARG;
674 /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */
675 /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */
676 /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */
677 /* the composite as the pmkToLeft parameter for that call. */
679 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
681 if (FAILED(res))
682 return res;
684 res = IRunningObjectTable_IsRunning(rot,iface);
685 IRunningObjectTable_Release(rot);
687 if(res==S_OK)
688 return S_OK;
690 else{
692 IMoniker_Enum(iface,FALSE,&enumMoniker);
693 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
694 IEnumMoniker_Release(enumMoniker);
696 res=CreateAntiMoniker(&antiMk);
697 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
698 IMoniker_Release(antiMk);
700 res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning);
702 IMoniker_Release(tempMk);
703 IMoniker_Release(mostRigthMk);
705 return res;
710 /******************************************************************************
711 * CompositeMoniker_GetTimeOfLastChange
712 ******************************************************************************/
713 static HRESULT WINAPI
714 CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
715 IMoniker* pmkToLeft, FILETIME* pCompositeTime)
717 HRESULT res;
718 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk;
719 IEnumMoniker *enumMoniker;
721 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);
723 if (pCompositeTime==NULL)
724 return E_INVALIDARG;
726 /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to */
727 /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */
728 /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */
729 /* of the composite as the pmkToLeft parameter for that call. */
730 if (pmkToLeft)
732 IRunningObjectTable* rot;
734 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
736 res = IBindCtx_GetRunningObjectTable(pbc,&rot);
737 if (FAILED(res))
739 IMoniker_Release(leftMk);
740 return res;
743 if (IRunningObjectTable_GetTimeOfLastChange(rot,leftMk,pCompositeTime)==S_OK)
745 IMoniker_Release(leftMk);
746 return res;
749 else
750 leftMk = iface;
752 IMoniker_Enum(iface, FALSE, &enumMoniker);
753 IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL);
754 IEnumMoniker_Release(enumMoniker);
756 res = CreateAntiMoniker(&antiMk);
757 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
758 IMoniker_Release(antiMk);
760 res = IMoniker_GetTimeOfLastChange(mostRigthMk, pbc, tempMk, pCompositeTime);
762 IMoniker_Release(tempMk);
763 IMoniker_Release(mostRigthMk);
765 if (pmkToLeft)
766 IMoniker_Release(leftMk);
768 return res;
771 /******************************************************************************
772 * CompositeMoniker_Inverse
773 ******************************************************************************/
774 static HRESULT WINAPI
775 CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
777 HRESULT res;
778 IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk;
779 IEnumMoniker *enumMoniker;
781 TRACE("(%p,%p)\n",iface,ppmk);
783 if (ppmk==NULL)
784 return E_POINTER;
786 /* This method returns a composite moniker that consists of the inverses of each of the components */
787 /* of the original composite, stored in reverse order */
789 res=CreateAntiMoniker(&antiMk);
790 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
791 IMoniker_Release(antiMk);
793 if (tempMk==NULL)
795 return IMoniker_Inverse(iface,ppmk);
797 else{
799 IMoniker_Enum(iface,FALSE,&enumMoniker);
800 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
801 IEnumMoniker_Release(enumMoniker);
803 IMoniker_Inverse(mostRigthMk,&mostRigthInvMk);
804 CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);
806 res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk);
808 IMoniker_Release(tempMk);
809 IMoniker_Release(mostRigthMk);
810 IMoniker_Release(tempInvMk);
811 IMoniker_Release(mostRigthInvMk);
813 return res;
817 /******************************************************************************
818 * CompositeMoniker_CommonPrefixWith
819 ******************************************************************************/
820 static HRESULT WINAPI
821 CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,
822 IMoniker** ppmkPrefix)
824 DWORD mkSys;
825 HRESULT res1,res2;
826 IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
827 IEnumMoniker *enumMoniker1,*enumMoniker2;
828 ULONG i,nbCommonMk=0;
830 /* If the other moniker is a composite, this method compares the components of each composite from left */
831 /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
832 /* of the leftmost components were common to both monikers. */
834 if (ppmkPrefix==NULL)
835 return E_POINTER;
837 *ppmkPrefix=0;
839 if (pmkOther==NULL)
840 return MK_E_NOPREFIX;
842 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
844 if((mkSys==MKSYS_GENERICCOMPOSITE)){
846 IMoniker_Enum(iface,TRUE,&enumMoniker1);
847 IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
849 while(1){
851 res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
852 res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
854 if ((res1==S_FALSE) && (res2==S_FALSE)){
856 /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
857 *ppmkPrefix=iface;
858 IMoniker_AddRef(iface);
859 return MK_S_US;
861 else if ((res1==S_OK) && (res2==S_OK)){
863 if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
865 nbCommonMk++;
867 else
868 break;
871 else if (res1==S_OK){
873 /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
874 /* ppmkPrefix to the other moniker. */
875 *ppmkPrefix=pmkOther;
876 return MK_S_HIM;
878 else{
879 /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
880 /* to this moniker. */
881 *ppmkPrefix=iface;
882 return MK_S_ME;
886 IEnumMoniker_Release(enumMoniker1);
887 IEnumMoniker_Release(enumMoniker2);
889 /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
890 if (nbCommonMk==0)
891 return MK_E_NOPREFIX;
893 IEnumMoniker_Reset(enumMoniker1);
895 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
897 /* if we have more than one common moniker the result will be a composite moniker */
898 if (nbCommonMk>1){
900 /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
901 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
902 CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
903 IMoniker_Release(tempMk1);
904 IMoniker_Release(tempMk2);
906 /* compose all common monikers in a composite moniker */
907 for(i=0;i<nbCommonMk;i++){
909 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
911 CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
913 IMoniker_Release(*ppmkPrefix);
915 IMoniker_Release(tempMk1);
917 *ppmkPrefix=tempMk2;
919 return S_OK;
921 else{
922 /* if we have only one common moniker the result will be a simple moniker which is the most-left one*/
923 *ppmkPrefix=tempMk1;
925 return S_OK;
928 else{
929 /* If the other moniker is not a composite, the method simply compares it to the leftmost component
930 of this moniker.*/
932 IMoniker_Enum(iface,TRUE,&enumMoniker1);
934 IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
936 if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){
938 *ppmkPrefix=pmkOther;
940 return MK_S_HIM;
942 else
943 return MK_E_NOPREFIX;
947 /***************************************************************************************************
948 * GetAfterCommonPrefix (local function)
949 * This function returns a moniker that consist of the remainder when the common prefix is removed
950 ***************************************************************************************************/
951 static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk)
953 IMoniker *tempMk,*tempMk1,*tempMk2;
954 IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3;
955 ULONG nbRestMk=0;
956 DWORD mkSys;
957 HRESULT res1,res2;
959 *restMk=0;
961 /* to create an enumerator for pGenMk with current position pointed on the first element after common */
962 /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop */
963 /* on the first difference. */
964 IMoniker_Enum(pGenMk,TRUE,&enumMoniker1);
966 IMoniker_IsSystemMoniker(commonMk,&mkSys);
968 if (mkSys==MKSYS_GENERICCOMPOSITE){
970 IMoniker_Enum(commonMk,TRUE,&enumMoniker2);
971 while(1){
973 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
974 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
976 if ((res1==S_FALSE)||(res2==S_FALSE)){
978 if (res1==S_OK)
980 nbRestMk++;
982 IMoniker_Release(tempMk1);
983 IMoniker_Release(tempMk2);
985 break;
987 IMoniker_Release(tempMk1);
988 IMoniker_Release(tempMk2);
991 else{
992 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
993 IMoniker_Release(tempMk1);
996 /* count the number of elements in the enumerator after the common prefix */
997 IEnumMoniker_Clone(enumMoniker1,&enumMoniker3);
999 for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++)
1001 IMoniker_Release(tempMk);
1003 if (nbRestMk==0)
1004 return;
1006 /* create a generic composite moniker with monikers located after the common prefix */
1007 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
1009 if (nbRestMk==1){
1011 *restMk= tempMk1;
1012 return;
1014 else {
1016 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
1018 CreateGenericComposite(tempMk1,tempMk2,restMk);
1020 IMoniker_Release(tempMk1);
1022 IMoniker_Release(tempMk2);
1024 while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){
1026 CreateGenericComposite(*restMk,tempMk1,&tempMk2);
1028 IMoniker_Release(tempMk1);
1030 IMoniker_Release(*restMk);
1032 *restMk=tempMk2;
1037 /******************************************************************************
1038 * CompositeMoniker_RelativePathTo
1039 ******************************************************************************/
1040 static HRESULT WINAPI
1041 CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther,
1042 IMoniker** ppmkRelPath)
1044 HRESULT res;
1045 IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0;
1047 TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath);
1049 if (ppmkRelPath==NULL)
1050 return E_POINTER;
1052 *ppmkRelPath=0;
1054 /* This method finds the common prefix of the two monikers and creates two monikers that consist */
1055 /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */
1056 /* of this moniker and composes the remainder of the other moniker on the right of it. */
1058 /* finds the common prefix of the two monikers */
1059 res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk);
1061 /* if there's no common prefix or the two moniker are equal the relative is the other moniker */
1062 if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){
1064 *ppmkRelPath=pmkOther;
1065 IMoniker_AddRef(pmkOther);
1066 return MK_S_HIM;
1069 GetAfterCommonPrefix(iface,commonMk,&restThisMk);
1070 GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk);
1072 /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */
1073 /* moniker when the common prefix is removed */
1074 if (res==MK_S_HIM){
1076 IMoniker_Inverse(restThisMk,ppmkRelPath);
1077 IMoniker_Release(restThisMk);
1079 /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */
1080 /* when the common prefix is removed */
1081 else if (res==MK_S_ME){
1083 *ppmkRelPath=restOtherMk;
1084 IMoniker_AddRef(restOtherMk);
1086 /* the relative path is the inverse for the remainder of this moniker and the remainder of the other */
1087 /* moniker on the right of it. */
1088 else if (res==S_OK){
1090 IMoniker_Inverse(restThisMk,&invRestThisMk);
1091 IMoniker_Release(restThisMk);
1092 CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath);
1093 IMoniker_Release(invRestThisMk);
1094 IMoniker_Release(restOtherMk);
1096 return S_OK;
1099 /******************************************************************************
1100 * CompositeMoniker_GetDisplayName
1101 ******************************************************************************/
1102 static HRESULT WINAPI
1103 CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1104 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1106 ULONG lengthStr=1;
1107 IEnumMoniker *enumMoniker;
1108 IMoniker* tempMk;
1109 LPOLESTR tempStr;
1111 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1113 if (ppszDisplayName==NULL)
1114 return E_POINTER;
1116 *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR));
1118 if (*ppszDisplayName==NULL)
1119 return E_OUTOFMEMORY;
1121 /* This method returns the concatenation of the display names returned by each component moniker of */
1122 /* the composite */
1124 **ppszDisplayName=0;
1126 IMoniker_Enum(iface,TRUE,&enumMoniker);
1128 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
1130 IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr);
1132 lengthStr+=lstrlenW(tempStr);
1134 *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));
1136 if (*ppszDisplayName==NULL)
1137 return E_OUTOFMEMORY;
1139 strcatW(*ppszDisplayName,tempStr);
1141 CoTaskMemFree(tempStr);
1142 IMoniker_Release(tempMk);
1145 IEnumMoniker_Release(enumMoniker);
1147 return S_OK;
1150 /******************************************************************************
1151 * CompositeMoniker_ParseDisplayName
1152 ******************************************************************************/
1153 static HRESULT WINAPI
1154 CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc,
1155 IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten,
1156 IMoniker** ppmkOut)
1158 IEnumMoniker *enumMoniker;
1159 IMoniker *tempMk,*mostRigthMk,*antiMk;
1160 /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/
1161 /* passing everything else as the pmkToLeft parameter for that call. */
1163 /* get the most right moniker */
1164 IMoniker_Enum(iface,FALSE,&enumMoniker);
1165 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
1166 IEnumMoniker_Release(enumMoniker);
1168 /* get the left moniker */
1169 CreateAntiMoniker(&antiMk);
1170 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
1171 IMoniker_Release(antiMk);
1173 return IMoniker_ParseDisplayName(mostRigthMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut);
1176 /******************************************************************************
1177 * CompositeMoniker_IsSystemMoniker
1178 ******************************************************************************/
1179 static HRESULT WINAPI
1180 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1182 TRACE("(%p,%p)\n",iface,pwdMksys);
1184 if (!pwdMksys)
1185 return E_POINTER;
1187 (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
1189 return S_OK;
1192 /*******************************************************************************
1193 * CompositeMonikerIROTData_QueryInterface
1194 *******************************************************************************/
1195 static HRESULT WINAPI
1196 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
1197 VOID** ppvObject)
1200 IMoniker *This = impl_from_IROTData(iface);
1202 TRACE("(%p,%p,%p)\n",iface,riid,ppvObject);
1204 return CompositeMonikerImpl_QueryInterface(This, riid, ppvObject);
1207 /***********************************************************************
1208 * CompositeMonikerIROTData_AddRef
1210 static ULONG WINAPI
1211 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
1213 IMoniker *This = impl_from_IROTData(iface);
1215 TRACE("(%p)\n",iface);
1217 return IMoniker_AddRef(This);
1220 /***********************************************************************
1221 * CompositeMonikerIROTData_Release
1223 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1225 IMoniker *This = impl_from_IROTData(iface);
1227 TRACE("(%p)\n",iface);
1229 return IMoniker_Release(This);
1232 /******************************************************************************
1233 * CompositeMonikerIROTData_GetComparisonData
1234 ******************************************************************************/
1235 static HRESULT WINAPI
1236 CompositeMonikerROTDataImpl_GetComparisonData(IROTData* iface,
1237 BYTE* pbData, ULONG cbMax, ULONG* pcbData)
1239 IMoniker *This = impl_from_IROTData(iface);
1240 IEnumMoniker *pEnumMk;
1241 IMoniker *pmk;
1242 HRESULT hr;
1244 TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
1246 *pcbData = sizeof(CLSID);
1248 hr = IMoniker_Enum(This, TRUE, &pEnumMk);
1249 if (FAILED(hr)) return hr;
1251 while(IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1253 IROTData *pROTData;
1254 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1255 if (FAILED(hr))
1256 ERR("moniker doesn't support IROTData interface\n");
1258 if (SUCCEEDED(hr))
1260 ULONG cbData;
1261 hr = IROTData_GetComparisonData(pROTData, NULL, 0, &cbData);
1262 IROTData_Release(pROTData);
1263 if (SUCCEEDED(hr) || (hr == E_OUTOFMEMORY))
1265 *pcbData += cbData;
1266 hr = S_OK;
1268 else
1269 ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
1272 IMoniker_Release(pmk);
1274 if (FAILED(hr))
1276 IEnumMoniker_Release(pEnumMk);
1277 return hr;
1280 if (cbMax < *pcbData)
1281 return E_OUTOFMEMORY;
1283 IEnumMoniker_Reset(pEnumMk);
1285 memcpy(pbData, &CLSID_CompositeMoniker, sizeof(CLSID));
1286 pbData += sizeof(CLSID);
1287 cbMax -= sizeof(CLSID);
1289 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1291 IROTData *pROTData;
1292 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1293 if (FAILED(hr))
1294 ERR("moniker doesn't support IROTData interface\n");
1296 if (SUCCEEDED(hr))
1298 ULONG cbData;
1299 hr = IROTData_GetComparisonData(pROTData, pbData, cbMax, &cbData);
1300 IROTData_Release(pROTData);
1301 if (SUCCEEDED(hr))
1303 pbData += cbData;
1304 cbMax -= cbData;
1306 else
1307 ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
1310 IMoniker_Release(pmk);
1312 if (FAILED(hr))
1314 IEnumMoniker_Release(pEnumMk);
1315 return hr;
1319 IEnumMoniker_Release(pEnumMk);
1321 return S_OK;
1324 static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1326 IMoniker *This = impl_from_IMarshal(iface);
1328 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);
1330 return CompositeMonikerImpl_QueryInterface(This, riid, ppv);
1333 static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
1335 IMoniker *This = impl_from_IMarshal(iface);
1337 TRACE("(%p)\n",iface);
1339 return CompositeMonikerImpl_AddRef(This);
1342 static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
1344 IMoniker *This = impl_from_IMarshal(iface);
1346 TRACE("(%p)\n",iface);
1348 return CompositeMonikerImpl_Release(This);
1351 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
1352 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1353 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1355 IMoniker *This = impl_from_IMarshal(iface);
1357 TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1358 dwDestContext, pvDestContext, mshlflags, pCid);
1360 return IMoniker_GetClassID(This, pCid);
1363 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
1364 LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext,
1365 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1367 IMoniker *This = impl_from_IMarshal(iface);
1368 IEnumMoniker *pEnumMk;
1369 IMoniker *pmk;
1370 HRESULT hr;
1371 ULARGE_INTEGER size;
1373 TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1374 dwDestContext, pvDestContext, mshlflags, pSize);
1376 *pSize = 0x10; /* to match native */
1378 hr = IMoniker_Enum(This, TRUE, &pEnumMk);
1379 if (FAILED(hr)) return hr;
1381 hr = IMoniker_GetSizeMax(This, &size);
1383 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1385 ULONG size;
1387 hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1388 if (SUCCEEDED(hr))
1389 *pSize += size;
1391 IMoniker_Release(pmk);
1393 if (FAILED(hr))
1395 IEnumMoniker_Release(pEnumMk);
1396 return hr;
1400 IEnumMoniker_Release(pEnumMk);
1402 return S_OK;
1405 static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(LPMARSHAL iface, IStream *pStm,
1406 REFIID riid, void* pv, DWORD dwDestContext,
1407 void* pvDestContext, DWORD mshlflags)
1409 IMoniker *This = impl_from_IMarshal(iface);
1410 IEnumMoniker *pEnumMk;
1411 IMoniker *pmk;
1412 HRESULT hr;
1413 ULONG i = 0;
1415 TRACE("(%p, %s, %p, %x, %p, %x)\n", pStm, debugstr_guid(riid), pv,
1416 dwDestContext, pvDestContext, mshlflags);
1418 hr = IMoniker_Enum(This, TRUE, &pEnumMk);
1419 if (FAILED(hr)) return hr;
1421 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1423 hr = CoMarshalInterface(pStm, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1425 IMoniker_Release(pmk);
1427 if (FAILED(hr))
1429 IEnumMoniker_Release(pEnumMk);
1430 return hr;
1432 i++;
1435 if (i != 2)
1436 FIXME("moniker count of %d not supported\n", i);
1438 IEnumMoniker_Release(pEnumMk);
1440 return S_OK;
1443 static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv)
1445 CompositeMonikerImpl *This = (CompositeMonikerImpl *)impl_from_IMarshal(iface);
1446 HRESULT hr;
1448 TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1450 CompositeMonikerImpl_ReleaseMonikersInTable(This);
1452 /* resize the table if needed */
1453 if (This->tabLastIndex + 2 > This->tabSize)
1455 This->tabSize += max(BLOCK_TAB_SIZE, 2);
1456 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1458 if (This->tabMoniker==NULL)
1459 return E_OUTOFMEMORY;
1462 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1463 if (FAILED(hr))
1465 ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
1466 return hr;
1468 This->tabLastIndex++;
1469 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1470 if (FAILED(hr))
1472 ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
1473 return hr;
1475 This->tabLastIndex++;
1477 return IMoniker_QueryInterface((IMoniker *)&This->lpvtbl1, riid, ppv);
1480 static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
1482 TRACE("(%p)\n", pStm);
1483 /* can't release a state-based marshal as nothing on server side to
1484 * release */
1485 return S_OK;
1488 static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved)
1490 TRACE("(0x%x)\n", dwReserved);
1491 /* can't disconnect a state-based marshal as nothing on server side to
1492 * disconnect from */
1493 return S_OK;
1496 /******************************************************************************
1497 * EnumMonikerImpl_QueryInterface
1498 ******************************************************************************/
1499 static HRESULT WINAPI
1500 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1502 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1504 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
1506 /* Perform a sanity check on the parameters.*/
1507 if ( (This==0) || (ppvObject==0) )
1508 return E_INVALIDARG;
1510 /* Initialize the return parameter */
1511 *ppvObject = 0;
1513 /* Compare the riid with the interface IDs implemented by this object.*/
1514 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
1515 *ppvObject = iface;
1517 /* Check that we obtained an interface.*/
1518 if ((*ppvObject)==0)
1519 return E_NOINTERFACE;
1521 /* Query Interface always increases the reference count by one when it is successful */
1522 IEnumMoniker_AddRef(iface);
1524 return S_OK;
1527 /******************************************************************************
1528 * EnumMonikerImpl_AddRef
1529 ******************************************************************************/
1530 static ULONG WINAPI
1531 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1533 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1535 TRACE("(%p)\n",This);
1537 return InterlockedIncrement(&This->ref);
1541 /******************************************************************************
1542 * EnumMonikerImpl_Release
1543 ******************************************************************************/
1544 static ULONG WINAPI
1545 EnumMonikerImpl_Release(IEnumMoniker* iface)
1547 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1548 ULONG i;
1549 ULONG ref;
1550 TRACE("(%p)\n",This);
1552 ref = InterlockedDecrement(&This->ref);
1554 /* destroy the object if there's no more reference on it */
1555 if (ref == 0) {
1557 for(i=0;i<This->tabSize;i++)
1558 IMoniker_Release(This->tabMoniker[i]);
1560 HeapFree(GetProcessHeap(),0,This->tabMoniker);
1561 HeapFree(GetProcessHeap(),0,This);
1563 return ref;
1566 /******************************************************************************
1567 * EnumMonikerImpl_Next
1568 ******************************************************************************/
1569 static HRESULT WINAPI
1570 EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt,
1571 ULONG* pceltFethed)
1573 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1574 ULONG i;
1576 /* retrieve the requested number of moniker from the current position */
1577 for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++)
1579 rgelt[i]=This->tabMoniker[This->currentPos++];
1580 IMoniker_AddRef(rgelt[i]);
1583 if (pceltFethed!=NULL)
1584 *pceltFethed= i;
1586 if (i==celt)
1587 return S_OK;
1588 else
1589 return S_FALSE;
1592 /******************************************************************************
1593 * EnumMonikerImpl_Skip
1594 ******************************************************************************/
1595 static HRESULT WINAPI
1596 EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt)
1598 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1600 if ((This->currentPos+celt) >= This->tabSize)
1601 return S_FALSE;
1603 This->currentPos+=celt;
1605 return S_OK;
1608 /******************************************************************************
1609 * EnumMonikerImpl_Reset
1610 ******************************************************************************/
1611 static HRESULT WINAPI
1612 EnumMonikerImpl_Reset(IEnumMoniker* iface)
1615 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1617 This->currentPos=0;
1619 return S_OK;
1622 /******************************************************************************
1623 * EnumMonikerImpl_Clone
1624 ******************************************************************************/
1625 static HRESULT WINAPI
1626 EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)
1628 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1630 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
1633 /********************************************************************************/
1634 /* Virtual function table for the IROTData class */
1635 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1637 EnumMonikerImpl_QueryInterface,
1638 EnumMonikerImpl_AddRef,
1639 EnumMonikerImpl_Release,
1640 EnumMonikerImpl_Next,
1641 EnumMonikerImpl_Skip,
1642 EnumMonikerImpl_Reset,
1643 EnumMonikerImpl_Clone
1646 /******************************************************************************
1647 * EnumMonikerImpl_CreateEnumMoniker
1648 ******************************************************************************/
1649 static HRESULT
1650 EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize,
1651 ULONG currentPos, BOOL leftToRigth, IEnumMoniker ** ppmk)
1653 EnumMonikerImpl* newEnumMoniker;
1654 int i;
1656 if (currentPos > tabSize)
1657 return E_INVALIDARG;
1659 newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
1661 if (newEnumMoniker == 0)
1662 return STG_E_INSUFFICIENTMEMORY;
1664 /* Initialize the virtual function table. */
1665 newEnumMoniker->lpVtbl = &VT_EnumMonikerImpl;
1666 newEnumMoniker->ref = 1;
1668 newEnumMoniker->tabSize=tabSize;
1669 newEnumMoniker->currentPos=currentPos;
1671 newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(IMoniker));
1673 if (newEnumMoniker->tabMoniker==NULL) {
1674 HeapFree(GetProcessHeap(), 0, newEnumMoniker);
1675 return E_OUTOFMEMORY;
1678 if (leftToRigth)
1679 for (i=0;i<tabSize;i++){
1681 newEnumMoniker->tabMoniker[i]=tabMoniker[i];
1682 IMoniker_AddRef(tabMoniker[i]);
1684 else
1685 for (i=tabSize-1;i>=0;i--){
1687 newEnumMoniker->tabMoniker[tabSize-i-1]=tabMoniker[i];
1688 IMoniker_AddRef(tabMoniker[i]);
1691 *ppmk=(IEnumMoniker*)newEnumMoniker;
1693 return S_OK;
1696 /********************************************************************************/
1697 /* Virtual function table for the CompositeMonikerImpl class which includes */
1698 /* IPersist, IPersistStream and IMoniker functions. */
1700 static const IMonikerVtbl VT_CompositeMonikerImpl =
1702 CompositeMonikerImpl_QueryInterface,
1703 CompositeMonikerImpl_AddRef,
1704 CompositeMonikerImpl_Release,
1705 CompositeMonikerImpl_GetClassID,
1706 CompositeMonikerImpl_IsDirty,
1707 CompositeMonikerImpl_Load,
1708 CompositeMonikerImpl_Save,
1709 CompositeMonikerImpl_GetSizeMax,
1710 CompositeMonikerImpl_BindToObject,
1711 CompositeMonikerImpl_BindToStorage,
1712 CompositeMonikerImpl_Reduce,
1713 CompositeMonikerImpl_ComposeWith,
1714 CompositeMonikerImpl_Enum,
1715 CompositeMonikerImpl_IsEqual,
1716 CompositeMonikerImpl_Hash,
1717 CompositeMonikerImpl_IsRunning,
1718 CompositeMonikerImpl_GetTimeOfLastChange,
1719 CompositeMonikerImpl_Inverse,
1720 CompositeMonikerImpl_CommonPrefixWith,
1721 CompositeMonikerImpl_RelativePathTo,
1722 CompositeMonikerImpl_GetDisplayName,
1723 CompositeMonikerImpl_ParseDisplayName,
1724 CompositeMonikerImpl_IsSystemMoniker
1727 /********************************************************************************/
1728 /* Virtual function table for the IROTData class. */
1729 static const IROTDataVtbl VT_ROTDataImpl =
1731 CompositeMonikerROTDataImpl_QueryInterface,
1732 CompositeMonikerROTDataImpl_AddRef,
1733 CompositeMonikerROTDataImpl_Release,
1734 CompositeMonikerROTDataImpl_GetComparisonData
1737 static const IMarshalVtbl VT_MarshalImpl =
1739 CompositeMonikerMarshalImpl_QueryInterface,
1740 CompositeMonikerMarshalImpl_AddRef,
1741 CompositeMonikerMarshalImpl_Release,
1742 CompositeMonikerMarshalImpl_GetUnmarshalClass,
1743 CompositeMonikerMarshalImpl_GetMarshalSizeMax,
1744 CompositeMonikerMarshalImpl_MarshalInterface,
1745 CompositeMonikerMarshalImpl_UnmarshalInterface,
1746 CompositeMonikerMarshalImpl_ReleaseMarshalData,
1747 CompositeMonikerMarshalImpl_DisconnectObject
1750 /******************************************************************************
1751 * Composite-Moniker_Construct (local function)
1752 *******************************************************************************/
1753 static HRESULT
1754 CompositeMonikerImpl_Construct(IMoniker** ppMoniker,
1755 LPMONIKER pmkFirst, LPMONIKER pmkRest)
1757 DWORD mkSys;
1758 IEnumMoniker *enumMoniker;
1759 IMoniker *tempMk;
1760 HRESULT res;
1761 CompositeMonikerImpl *This;
1763 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1765 if (!This)
1766 return E_OUTOFMEMORY;
1768 TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);
1770 /* Initialize the virtual function table. */
1771 This->lpvtbl1 = &VT_CompositeMonikerImpl;
1772 This->lpvtbl2 = &VT_ROTDataImpl;
1773 This->lpvtblMarshal= &VT_MarshalImpl;
1774 This->ref = 1;
1776 This->tabSize=BLOCK_TAB_SIZE;
1777 This->tabLastIndex=0;
1779 This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(IMoniker));
1780 if (This->tabMoniker==NULL) {
1781 HeapFree(GetProcessHeap(), 0, This);
1782 return E_OUTOFMEMORY;
1785 if (!pmkFirst && !pmkRest)
1787 *ppMoniker = (IMoniker *)This;
1788 return S_OK;
1791 IMoniker_IsSystemMoniker(pmkFirst,&mkSys);
1793 /* put the first moniker contents in the beginning of the table */
1794 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1796 This->tabMoniker[(This->tabLastIndex)++]=pmkFirst;
1797 IMoniker_AddRef(pmkFirst);
1799 else{
1801 IMoniker_Enum(pmkFirst,TRUE,&enumMoniker);
1803 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1806 if (++This->tabLastIndex==This->tabSize){
1807 LPVOID tab_moniker = This->tabMoniker;
1809 This->tabSize+=BLOCK_TAB_SIZE;
1810 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1812 if (This->tabMoniker==NULL){
1813 HeapFree(GetProcessHeap(), 0, tab_moniker);
1814 HeapFree(GetProcessHeap(), 0, This);
1815 return E_OUTOFMEMORY;
1820 IEnumMoniker_Release(enumMoniker);
1823 /* put the rest moniker contents after the first one and make simplification if needed */
1825 IMoniker_IsSystemMoniker(pmkRest,&mkSys);
1827 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1829 /* add a simple moniker to the moniker table */
1831 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk);
1833 if (res==MK_E_NEEDGENERIC){
1835 /* there's no simplification in this case */
1836 This->tabMoniker[This->tabLastIndex]=pmkRest;
1838 This->tabLastIndex++;
1840 IMoniker_AddRef(pmkRest);
1842 else if (tempMk==NULL){
1844 /* we have an antimoniker after a simple moniker so we can make a simplification in this case */
1845 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1847 This->tabLastIndex--;
1849 else if (SUCCEEDED(res)){
1851 /* the non-generic composition was successful so we can make a simplification in this case */
1852 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1854 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1855 } else
1856 return res;
1858 /* resize tabMoniker if needed */
1859 if (This->tabLastIndex==This->tabSize){
1860 LPVOID tab_moniker = This->tabMoniker;
1862 This->tabSize+=BLOCK_TAB_SIZE;
1864 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1866 if (This->tabMoniker==NULL){
1867 HeapFree(GetProcessHeap(), 0, tab_moniker);
1868 HeapFree(GetProcessHeap(), 0, This);
1869 return E_OUTOFMEMORY;
1873 else{
1875 /* add a composite moniker to the moniker table (do the same thing
1876 * for each moniker within the composite moniker as a simple moniker
1877 * (see above for how to add a simple moniker case) )
1879 IMoniker_Enum(pmkRest,TRUE,&enumMoniker);
1881 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1883 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk);
1885 if (res==MK_E_NEEDGENERIC){
1887 This->tabLastIndex++;
1889 else if (tempMk==NULL){
1891 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1892 IMoniker_Release(This->tabMoniker[This->tabLastIndex]);
1893 This->tabLastIndex--;
1895 else{
1897 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1899 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1902 if (This->tabLastIndex==This->tabSize){
1903 LPVOID tab_moniker = This->tabMoniker;
1905 This->tabSize+=BLOCK_TAB_SIZE;
1907 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1909 if (This->tabMoniker==NULL){
1910 HeapFree(GetProcessHeap(), 0, tab_moniker);
1911 HeapFree(GetProcessHeap(), 0, This);
1912 return E_OUTOFMEMORY;
1917 IEnumMoniker_Release(enumMoniker);
1920 /* only one moniker, then just return it */
1921 if (This->tabLastIndex == 1)
1923 *ppMoniker = This->tabMoniker[0];
1924 IMoniker_AddRef(*ppMoniker);
1925 IMoniker_Release((IMoniker *)This);
1927 else
1928 *ppMoniker = (IMoniker *)This;
1930 return S_OK;
1933 /******************************************************************************
1934 * CreateGenericComposite [OLE32.@]
1935 ******************************************************************************/
1936 HRESULT WINAPI
1937 CreateGenericComposite(LPMONIKER pmkFirst, LPMONIKER pmkRest,
1938 LPMONIKER* ppmkComposite)
1940 IMoniker* moniker = 0;
1941 HRESULT hr = S_OK;
1943 TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite);
1945 if (ppmkComposite==NULL)
1946 return E_POINTER;
1948 *ppmkComposite=0;
1950 if (pmkFirst==NULL && pmkRest!=NULL){
1952 *ppmkComposite=pmkRest;
1953 return S_OK;
1955 else if (pmkFirst!=NULL && pmkRest==NULL){
1956 *ppmkComposite=pmkFirst;
1957 return S_OK;
1959 else if (pmkFirst==NULL && pmkRest==NULL)
1960 return S_OK;
1962 hr = CompositeMonikerImpl_Construct(&moniker,pmkFirst,pmkRest);
1964 if (FAILED(hr))
1965 return hr;
1967 hr = IMoniker_QueryInterface(moniker,&IID_IMoniker,(void**)ppmkComposite);
1968 IMoniker_Release(moniker);
1970 return hr;
1973 /******************************************************************************
1974 * MonikerCommonPrefixWith [OLE32.@]
1975 ******************************************************************************/
1976 HRESULT WINAPI
1977 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1979 FIXME("(),stub!\n");
1980 return E_NOTIMPL;
1983 static HRESULT WINAPI CompositeMonikerCF_QueryInterface(LPCLASSFACTORY iface,
1984 REFIID riid, LPVOID *ppv)
1986 *ppv = NULL;
1987 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory))
1989 *ppv = iface;
1990 IUnknown_AddRef(iface);
1991 return S_OK;
1993 return E_NOINTERFACE;
1996 static ULONG WINAPI CompositeMonikerCF_AddRef(LPCLASSFACTORY iface)
1998 return 2; /* non-heap based object */
2001 static ULONG WINAPI CompositeMonikerCF_Release(LPCLASSFACTORY iface)
2003 return 1; /* non-heap based object */
2006 static HRESULT WINAPI CompositeMonikerCF_CreateInstance(LPCLASSFACTORY iface,
2007 LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv)
2009 IMoniker* pMoniker;
2010 HRESULT hr;
2012 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
2014 *ppv = NULL;
2016 if (pUnk)
2017 return CLASS_E_NOAGGREGATION;
2019 hr = CompositeMonikerImpl_Construct(&pMoniker, NULL, NULL);
2021 if (SUCCEEDED(hr))
2023 hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
2024 IMoniker_Release(pMoniker);
2027 return hr;
2030 static HRESULT WINAPI CompositeMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock)
2032 FIXME("(%d), stub!\n",fLock);
2033 return S_OK;
2036 static const IClassFactoryVtbl CompositeMonikerCFVtbl =
2038 CompositeMonikerCF_QueryInterface,
2039 CompositeMonikerCF_AddRef,
2040 CompositeMonikerCF_Release,
2041 CompositeMonikerCF_CreateInstance,
2042 CompositeMonikerCF_LockServer
2044 static const IClassFactoryVtbl *CompositeMonikerCF = &CompositeMonikerCFVtbl;
2046 HRESULT CompositeMonikerCF_Create(REFIID riid, LPVOID *ppv)
2048 return IClassFactory_QueryInterface((IClassFactory *)&CompositeMonikerCF, riid, ppv);