mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / ole32 / compositemoniker.c
blob5914008fe39f01be2146e183557592f8cb4580e3
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
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winerror.h"
31 #include "wine/debug.h"
32 #include "ole2.h"
33 #include "moniker.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(ole);
37 #define BLOCK_TAB_SIZE 5 /* represent the first size table and its increment block size */
39 /* CompositeMoniker data structure */
40 typedef struct CompositeMonikerImpl{
41 IMoniker IMoniker_iface;
42 IROTData IROTData_iface;
43 IMarshal IMarshal_iface;
44 LONG ref;
45 IMoniker** tabMoniker; /* dynamic table containing all components (monikers) of this composite moniker */
46 ULONG tabSize; /* size of tabMoniker */
47 ULONG tabLastIndex; /* first free index in tabMoniker */
48 } CompositeMonikerImpl;
50 static inline CompositeMonikerImpl *impl_from_IMoniker(IMoniker *iface)
52 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMoniker_iface);
55 static inline CompositeMonikerImpl *impl_from_IROTData(IROTData *iface)
57 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IROTData_iface);
60 static inline CompositeMonikerImpl *impl_from_IMarshal(IMarshal *iface)
62 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMarshal_iface);
65 /* EnumMoniker data structure */
66 typedef struct EnumMonikerImpl{
67 IEnumMoniker IEnumMoniker_iface;
68 LONG ref;
69 IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
70 ULONG tabSize; /* size of tabMoniker */
71 ULONG currentPos; /* index pointer on the current moniker */
72 } EnumMonikerImpl;
74 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
76 return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
79 static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRight,IEnumMoniker ** ppmk);
81 /*******************************************************************************
82 * CompositeMoniker_QueryInterface
83 *******************************************************************************/
84 static HRESULT WINAPI
85 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
87 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
89 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
91 /* Perform a sanity check on the parameters.*/
92 if ( ppvObject==0 )
93 return E_INVALIDARG;
95 /* Initialize the return parameter */
96 *ppvObject = 0;
98 /* Compare the riid with the interface IDs implemented by this object.*/
99 if (IsEqualIID(&IID_IUnknown, riid) ||
100 IsEqualIID(&IID_IPersist, riid) ||
101 IsEqualIID(&IID_IPersistStream, riid) ||
102 IsEqualIID(&IID_IMoniker, riid)
104 *ppvObject = iface;
105 else if (IsEqualIID(&IID_IROTData, riid))
106 *ppvObject = &This->IROTData_iface;
107 else if (IsEqualIID(&IID_IMarshal, riid))
108 *ppvObject = &This->IMarshal_iface;
110 /* Check that we obtained an interface.*/
111 if ((*ppvObject)==0)
112 return E_NOINTERFACE;
114 /* Query Interface always increases the reference count by one when it is successful */
115 IMoniker_AddRef(iface);
117 return S_OK;
120 /******************************************************************************
121 * CompositeMoniker_AddRef
122 ******************************************************************************/
123 static ULONG WINAPI
124 CompositeMonikerImpl_AddRef(IMoniker* iface)
126 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
128 TRACE("(%p)\n",This);
130 return InterlockedIncrement(&This->ref);
133 static void CompositeMonikerImpl_ReleaseMonikersInTable(CompositeMonikerImpl *This)
135 ULONG i;
137 for (i = 0; i < This->tabLastIndex; i++)
138 IMoniker_Release(This->tabMoniker[i]);
140 This->tabLastIndex = 0;
143 /******************************************************************************
144 * CompositeMoniker_Release
145 ******************************************************************************/
146 static ULONG WINAPI
147 CompositeMonikerImpl_Release(IMoniker* iface)
149 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
150 ULONG ref;
152 TRACE("(%p)\n",This);
154 ref = InterlockedDecrement(&This->ref);
156 /* destroy the object if there are no more references to it */
157 if (ref == 0){
159 /* release all the components before destroying this object */
160 CompositeMonikerImpl_ReleaseMonikersInTable(This);
162 HeapFree(GetProcessHeap(),0,This->tabMoniker);
163 HeapFree(GetProcessHeap(),0,This);
165 return ref;
168 /******************************************************************************
169 * CompositeMoniker_GetClassID
170 ******************************************************************************/
171 static HRESULT WINAPI
172 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
174 TRACE("(%p,%p)\n",iface,pClassID);
176 if (pClassID==NULL)
177 return E_POINTER;
179 *pClassID = CLSID_CompositeMoniker;
181 return S_OK;
184 /******************************************************************************
185 * CompositeMoniker_IsDirty
186 ******************************************************************************/
187 static HRESULT WINAPI
188 CompositeMonikerImpl_IsDirty(IMoniker* iface)
190 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
191 method in the OLE-provided moniker interfaces always return S_FALSE because
192 their internal state never changes. */
194 TRACE("(%p)\n",iface);
196 return S_FALSE;
199 /******************************************************************************
200 * CompositeMoniker_Load
201 ******************************************************************************/
202 static HRESULT WINAPI
203 CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
205 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
206 HRESULT res;
207 DWORD moniker_count;
208 DWORD i;
210 TRACE("(%p,%p)\n",iface,pStm);
212 /* this function call OleLoadFromStream function for each moniker within this object */
214 res=IStream_Read(pStm,&moniker_count,sizeof(DWORD),NULL);
215 if (res != S_OK)
217 ERR("couldn't reading moniker count from stream\n");
218 return E_FAIL;
221 CompositeMonikerImpl_ReleaseMonikersInTable(This);
223 for (i = 0; i < moniker_count; i++)
225 res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
226 if (FAILED(res))
228 ERR("couldn't load moniker from stream, res = 0x%08x\n", res);
229 break;
232 /* resize the table if needed */
233 if (++This->tabLastIndex==This->tabSize){
235 This->tabSize+=BLOCK_TAB_SIZE;
236 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
238 if (This->tabMoniker==NULL)
239 return E_OUTOFMEMORY;
243 return res;
246 /******************************************************************************
247 * CompositeMoniker_Save
248 ******************************************************************************/
249 static HRESULT WINAPI
250 CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
252 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
253 HRESULT res;
254 IEnumMoniker *enumMk;
255 IMoniker *pmk;
256 DWORD moniker_count = This->tabLastIndex;
258 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
260 /* This function calls OleSaveToStream function for each moniker within
261 * this object.
262 * When I tested this function in windows, I usually found this constant
263 * at the beginning of the stream. I don't known why (there's no
264 * indication in the specification) !
266 res=IStream_Write(pStm,&moniker_count,sizeof(moniker_count),NULL);
267 if (FAILED(res)) return res;
269 IMoniker_Enum(iface,TRUE,&enumMk);
271 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
273 res=OleSaveToStream((IPersistStream*)pmk,pStm);
275 IMoniker_Release(pmk);
277 if (FAILED(res)){
279 IEnumMoniker_Release(enumMk);
280 return res;
284 IEnumMoniker_Release(enumMk);
286 return S_OK;
289 /******************************************************************************
290 * CompositeMoniker_GetSizeMax
291 ******************************************************************************/
292 static HRESULT WINAPI
293 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
295 IEnumMoniker *enumMk;
296 IMoniker *pmk;
297 ULARGE_INTEGER ptmpSize;
299 /* The sizeMax of this object is calculated by calling GetSizeMax on
300 * each moniker within this object then summing all returned values
303 TRACE("(%p,%p)\n",iface,pcbSize);
305 if (!pcbSize)
306 return E_POINTER;
308 pcbSize->QuadPart = sizeof(DWORD);
310 IMoniker_Enum(iface,TRUE,&enumMk);
312 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
314 IMoniker_GetSizeMax(pmk,&ptmpSize);
316 IMoniker_Release(pmk);
318 pcbSize->QuadPart += ptmpSize.QuadPart + sizeof(CLSID);
321 IEnumMoniker_Release(enumMk);
323 return S_OK;
326 /******************************************************************************
327 * CompositeMoniker_BindToObject
328 ******************************************************************************/
329 static HRESULT WINAPI
330 CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,
331 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
333 HRESULT res;
334 IRunningObjectTable *prot;
335 IMoniker *tempMk,*antiMk,*rightMostMk;
336 IEnumMoniker *enumMoniker;
338 TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
340 if (ppvResult==NULL)
341 return E_POINTER;
343 *ppvResult=0;
344 /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
345 /* object for the requested interface pointer. */
346 if(pmkToLeft==NULL){
348 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
350 if (SUCCEEDED(res)){
352 /* if the requested class was loaded before ! we don't need to reload it */
353 res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
355 if (res==S_OK)
356 return res;
359 else{
360 /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
361 /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
363 IMoniker_Enum(iface,FALSE,&enumMoniker);
364 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
365 IEnumMoniker_Release(enumMoniker);
367 res=CreateAntiMoniker(&antiMk);
368 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
369 IMoniker_Release(antiMk);
371 res=IMoniker_BindToObject(rightMostMk,pbc,tempMk,riid,ppvResult);
373 IMoniker_Release(tempMk);
374 IMoniker_Release(rightMostMk);
377 return res;
380 /******************************************************************************
381 * CompositeMoniker_BindToStorage
382 ******************************************************************************/
383 static HRESULT WINAPI
384 CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
385 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
387 HRESULT res;
388 IMoniker *tempMk,*antiMk,*rightMostMk,*leftMk;
389 IEnumMoniker *enumMoniker;
391 TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
393 *ppvResult=0;
395 /* This method recursively calls BindToStorage on the rightmost component of the composite, */
396 /* passing the rest of the composite as the pmkToLeft parameter for that call. */
398 if (pmkToLeft)
400 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
401 if (FAILED(res)) return res;
403 else
404 leftMk = iface;
406 IMoniker_Enum(iface, FALSE, &enumMoniker);
407 IEnumMoniker_Next(enumMoniker, 1, &rightMostMk, NULL);
408 IEnumMoniker_Release(enumMoniker);
410 res = CreateAntiMoniker(&antiMk);
411 if (FAILED(res)) return res;
412 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
413 if (FAILED(res)) return res;
414 IMoniker_Release(antiMk);
416 res = IMoniker_BindToStorage(rightMostMk, pbc, tempMk, riid, ppvResult);
418 IMoniker_Release(tempMk);
420 IMoniker_Release(rightMostMk);
422 if (pmkToLeft)
423 IMoniker_Release(leftMk);
425 return res;
428 /******************************************************************************
429 * CompositeMoniker_Reduce
430 ******************************************************************************/
431 static HRESULT WINAPI
432 CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
433 IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
435 HRESULT res;
436 IMoniker *tempMk,*antiMk,*rightMostMk,*leftReducedComposedMk,*rightMostReducedMk;
437 IEnumMoniker *enumMoniker;
439 TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
441 if (ppmkReduced==NULL)
442 return E_POINTER;
444 /* This method recursively calls Reduce for each of its component monikers. */
446 if (ppmkToLeft==NULL){
448 IMoniker_Enum(iface,FALSE,&enumMoniker);
449 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
450 IEnumMoniker_Release(enumMoniker);
452 CreateAntiMoniker(&antiMk);
453 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
454 IMoniker_Release(antiMk);
456 res = IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
457 IMoniker_Release(tempMk);
458 IMoniker_Release(rightMostMk);
460 return res;
462 else if (*ppmkToLeft==NULL)
464 return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);
466 else{
468 /* separate the composite moniker in to left and right moniker */
469 IMoniker_Enum(iface,FALSE,&enumMoniker);
470 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
471 IEnumMoniker_Release(enumMoniker);
473 CreateAntiMoniker(&antiMk);
474 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
475 IMoniker_Release(antiMk);
477 /* If any of the components reduces itself, the method returns S_OK and passes back a composite */
478 /* of the reduced components */
479 if (IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,NULL,&rightMostReducedMk) &&
480 IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk) ){
481 IMoniker_Release(tempMk);
482 IMoniker_Release(rightMostMk);
484 return CreateGenericComposite(leftReducedComposedMk,rightMostReducedMk,ppmkReduced);
486 else{
487 /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
488 IMoniker_Release(tempMk);
489 IMoniker_Release(rightMostMk);
491 IMoniker_AddRef(iface);
493 *ppmkReduced=iface;
495 return MK_S_REDUCED_TO_SELF;
500 /******************************************************************************
501 * CompositeMoniker_ComposeWith
502 ******************************************************************************/
503 static HRESULT WINAPI
504 CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
505 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
507 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
509 if ((ppmkComposite==NULL)||(pmkRight==NULL))
510 return E_POINTER;
512 *ppmkComposite=0;
514 /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */
515 /* otherwise, the method returns the result of combining the two monikers by calling the */
516 /* CreateGenericComposite function */
518 if (fOnlyIfNotGeneric)
519 return MK_E_NEEDGENERIC;
521 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
524 /******************************************************************************
525 * CompositeMoniker_Enum
526 ******************************************************************************/
527 static HRESULT WINAPI
528 CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
530 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
532 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
534 if (ppenumMoniker == NULL)
535 return E_POINTER;
537 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);
540 /******************************************************************************
541 * CompositeMoniker_IsEqual
542 ******************************************************************************/
543 static HRESULT WINAPI
544 CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
546 IEnumMoniker *enumMoniker1,*enumMoniker2;
547 IMoniker *tempMk1,*tempMk2;
548 HRESULT res1,res2,res;
549 BOOL done;
551 TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
553 if (pmkOtherMoniker==NULL)
554 return S_FALSE;
556 /* This method returns S_OK if the components of both monikers are equal when compared in the */
557 /* left-to-right order.*/
558 IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);
560 if (enumMoniker1==NULL)
561 return S_FALSE;
563 IMoniker_Enum(iface,TRUE,&enumMoniker2);
565 do {
567 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
568 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
570 if((res1==S_OK)&&(res2==S_OK)){
571 done = (res = IMoniker_IsEqual(tempMk1,tempMk2)) == S_FALSE;
573 else
575 res = (res1==S_FALSE) && (res2==S_FALSE);
576 done = TRUE;
579 if (res1==S_OK)
580 IMoniker_Release(tempMk1);
582 if (res2==S_OK)
583 IMoniker_Release(tempMk2);
584 } while (!done);
586 IEnumMoniker_Release(enumMoniker1);
587 IEnumMoniker_Release(enumMoniker2);
589 return res;
591 /******************************************************************************
592 * CompositeMoniker_Hash
593 ******************************************************************************/
594 static HRESULT WINAPI
595 CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
597 IEnumMoniker *enumMoniker;
598 IMoniker *tempMk;
599 HRESULT res;
600 DWORD tempHash;
602 TRACE("(%p,%p)\n",iface,pdwHash);
604 if (pdwHash==NULL)
605 return E_POINTER;
607 res = IMoniker_Enum(iface,TRUE,&enumMoniker);
608 if(FAILED(res))
609 return res;
611 *pdwHash = 0;
613 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
614 res = IMoniker_Hash(tempMk, &tempHash);
615 if(FAILED(res))
616 break;
617 *pdwHash = *pdwHash ^ tempHash;
619 IMoniker_Release(tempMk);
622 IEnumMoniker_Release(enumMoniker);
624 return res;
627 /******************************************************************************
628 * CompositeMoniker_IsRunning
629 ******************************************************************************/
630 static HRESULT WINAPI
631 CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc,
632 IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
634 IRunningObjectTable* rot;
635 HRESULT res;
636 IMoniker *tempMk,*antiMk,*rightMostMk;
637 IEnumMoniker *enumMoniker;
639 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
641 /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/
642 if (pmkToLeft!=NULL){
644 CreateGenericComposite(pmkToLeft,iface,&tempMk);
646 res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);
648 IMoniker_Release(tempMk);
650 return res;
652 else
653 /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */
654 /* to this moniker */
656 if (pmkNewlyRunning!=NULL)
658 if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)
659 return S_OK;
661 else
662 return S_FALSE;
664 else{
666 if (pbc==NULL)
667 return E_INVALIDARG;
669 /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */
670 /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */
671 /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */
672 /* the composite as the pmkToLeft parameter for that call. */
674 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
676 if (FAILED(res))
677 return res;
679 res = IRunningObjectTable_IsRunning(rot,iface);
680 IRunningObjectTable_Release(rot);
682 if(res==S_OK)
683 return S_OK;
685 else{
687 IMoniker_Enum(iface,FALSE,&enumMoniker);
688 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
689 IEnumMoniker_Release(enumMoniker);
691 res=CreateAntiMoniker(&antiMk);
692 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
693 IMoniker_Release(antiMk);
695 res=IMoniker_IsRunning(rightMostMk,pbc,tempMk,pmkNewlyRunning);
697 IMoniker_Release(tempMk);
698 IMoniker_Release(rightMostMk);
700 return res;
705 /******************************************************************************
706 * CompositeMoniker_GetTimeOfLastChange
707 ******************************************************************************/
708 static HRESULT WINAPI
709 CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
710 IMoniker* pmkToLeft, FILETIME* pCompositeTime)
712 HRESULT res;
713 IMoniker *tempMk,*antiMk,*rightMostMk,*leftMk;
714 IEnumMoniker *enumMoniker;
716 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);
718 if (pCompositeTime==NULL)
719 return E_INVALIDARG;
721 /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to */
722 /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */
723 /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */
724 /* of the composite as the pmkToLeft parameter for that call. */
725 if (pmkToLeft)
727 IRunningObjectTable* rot;
729 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
730 if (FAILED(res))
731 return res;
733 res = IBindCtx_GetRunningObjectTable(pbc,&rot);
734 if (FAILED(res))
736 IMoniker_Release(leftMk);
737 return res;
740 if (IRunningObjectTable_GetTimeOfLastChange(rot,leftMk,pCompositeTime)==S_OK)
742 IMoniker_Release(leftMk);
743 return res;
746 else
747 leftMk = iface;
749 IMoniker_Enum(iface, FALSE, &enumMoniker);
750 IEnumMoniker_Next(enumMoniker, 1, &rightMostMk, NULL);
751 IEnumMoniker_Release(enumMoniker);
753 res = CreateAntiMoniker(&antiMk);
754 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
755 IMoniker_Release(antiMk);
757 res = IMoniker_GetTimeOfLastChange(rightMostMk, pbc, tempMk, pCompositeTime);
759 IMoniker_Release(tempMk);
760 IMoniker_Release(rightMostMk);
762 if (pmkToLeft)
763 IMoniker_Release(leftMk);
765 return res;
768 /******************************************************************************
769 * CompositeMoniker_Inverse
770 ******************************************************************************/
771 static HRESULT WINAPI
772 CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
774 HRESULT res;
775 IMoniker *tempMk,*antiMk,*rightMostMk,*tempInvMk,*rightMostInvMk;
776 IEnumMoniker *enumMoniker;
778 TRACE("(%p,%p)\n",iface,ppmk);
780 if (ppmk==NULL)
781 return E_POINTER;
783 /* This method returns a composite moniker that consists of the inverses of each of the components */
784 /* of the original composite, stored in reverse order */
786 *ppmk = NULL;
788 res=CreateAntiMoniker(&antiMk);
789 if (FAILED(res))
790 return res;
792 res=IMoniker_ComposeWith(iface,antiMk,FALSE,&tempMk);
793 IMoniker_Release(antiMk);
794 if (FAILED(res))
795 return res;
797 if (tempMk==NULL)
799 return IMoniker_Inverse(iface,ppmk);
801 else{
803 IMoniker_Enum(iface,FALSE,&enumMoniker);
804 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
805 IEnumMoniker_Release(enumMoniker);
807 IMoniker_Inverse(rightMostMk,&rightMostInvMk);
808 CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);
810 res=CreateGenericComposite(rightMostInvMk,tempInvMk,ppmk);
812 IMoniker_Release(tempMk);
813 IMoniker_Release(rightMostMk);
814 IMoniker_Release(tempInvMk);
815 IMoniker_Release(rightMostInvMk);
817 return res;
821 /******************************************************************************
822 * CompositeMoniker_CommonPrefixWith
823 ******************************************************************************/
824 static HRESULT WINAPI
825 CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,
826 IMoniker** ppmkPrefix)
828 DWORD mkSys;
829 HRESULT res1,res2;
830 IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
831 IEnumMoniker *enumMoniker1,*enumMoniker2;
832 ULONG i,nbCommonMk=0;
834 /* If the other moniker is a composite, this method compares the components of each composite from left */
835 /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
836 /* of the leftmost components were common to both monikers. */
838 if (ppmkPrefix==NULL)
839 return E_POINTER;
841 *ppmkPrefix=0;
843 if (pmkOther==NULL)
844 return MK_E_NOPREFIX;
846 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
848 if(mkSys==MKSYS_GENERICCOMPOSITE){
850 IMoniker_Enum(iface,TRUE,&enumMoniker1);
851 IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
853 while(1){
855 res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
856 res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
858 if ((res1==S_FALSE) && (res2==S_FALSE)){
860 /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
861 *ppmkPrefix=iface;
862 IMoniker_AddRef(iface);
863 return MK_S_US;
865 else if ((res1==S_OK) && (res2==S_OK)){
867 if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
869 nbCommonMk++;
871 else
872 break;
875 else if (res1==S_OK){
877 /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
878 /* ppmkPrefix to the other moniker. */
879 *ppmkPrefix=pmkOther;
880 return MK_S_HIM;
882 else{
883 /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
884 /* to this moniker. */
885 *ppmkPrefix=iface;
886 return MK_S_ME;
890 IEnumMoniker_Release(enumMoniker1);
891 IEnumMoniker_Release(enumMoniker2);
893 /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
894 if (nbCommonMk==0)
895 return MK_E_NOPREFIX;
897 IEnumMoniker_Reset(enumMoniker1);
899 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
901 /* if we have more than one common moniker the result will be a composite moniker */
902 if (nbCommonMk>1){
904 /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
905 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
906 CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
907 IMoniker_Release(tempMk1);
908 IMoniker_Release(tempMk2);
910 /* compose all common monikers in a composite moniker */
911 for(i=0;i<nbCommonMk;i++){
913 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
915 CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
917 IMoniker_Release(*ppmkPrefix);
919 IMoniker_Release(tempMk1);
921 *ppmkPrefix=tempMk2;
923 return S_OK;
925 else{
926 /* if we have only one common moniker the result will be a simple moniker which is the most-left one*/
927 *ppmkPrefix=tempMk1;
929 return S_OK;
932 else{
933 /* If the other moniker is not a composite, the method simply compares it to the leftmost component
934 of this moniker.*/
936 IMoniker_Enum(iface,TRUE,&enumMoniker1);
938 IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
940 if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){
942 *ppmkPrefix=pmkOther;
944 return MK_S_HIM;
946 else
947 return MK_E_NOPREFIX;
951 /***************************************************************************************************
952 * GetAfterCommonPrefix (local function)
953 * This function returns a moniker that consist of the remainder when the common prefix is removed
954 ***************************************************************************************************/
955 static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk)
957 IMoniker *tempMk,*tempMk1,*tempMk2;
958 IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3;
959 ULONG nbRestMk=0;
960 DWORD mkSys;
961 HRESULT res1,res2;
963 *restMk=0;
965 /* to create an enumerator for pGenMk with current position pointed on the first element after common */
966 /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop */
967 /* on the first difference. */
968 IMoniker_Enum(pGenMk,TRUE,&enumMoniker1);
970 IMoniker_IsSystemMoniker(commonMk,&mkSys);
972 if (mkSys==MKSYS_GENERICCOMPOSITE){
974 IMoniker_Enum(commonMk,TRUE,&enumMoniker2);
975 while(1){
977 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
978 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
980 if ((res1==S_FALSE)||(res2==S_FALSE)){
982 if (res1==S_OK)
984 nbRestMk++;
986 IMoniker_Release(tempMk1);
987 IMoniker_Release(tempMk2);
989 break;
991 IMoniker_Release(tempMk1);
992 IMoniker_Release(tempMk2);
995 else{
996 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
997 IMoniker_Release(tempMk1);
1000 /* count the number of elements in the enumerator after the common prefix */
1001 IEnumMoniker_Clone(enumMoniker1,&enumMoniker3);
1003 for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++)
1005 IMoniker_Release(tempMk);
1007 if (nbRestMk==0)
1008 return;
1010 /* create a generic composite moniker with monikers located after the common prefix */
1011 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
1013 if (nbRestMk==1){
1015 *restMk= tempMk1;
1016 return;
1018 else {
1020 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
1022 CreateGenericComposite(tempMk1,tempMk2,restMk);
1024 IMoniker_Release(tempMk1);
1026 IMoniker_Release(tempMk2);
1028 while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){
1030 CreateGenericComposite(*restMk,tempMk1,&tempMk2);
1032 IMoniker_Release(tempMk1);
1034 IMoniker_Release(*restMk);
1036 *restMk=tempMk2;
1041 /******************************************************************************
1042 * CompositeMoniker_RelativePathTo
1043 ******************************************************************************/
1044 static HRESULT WINAPI
1045 CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther,
1046 IMoniker** ppmkRelPath)
1048 HRESULT res;
1049 IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0;
1051 TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath);
1053 if (ppmkRelPath==NULL)
1054 return E_POINTER;
1056 *ppmkRelPath=0;
1058 /* This method finds the common prefix of the two monikers and creates two monikers that consist */
1059 /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */
1060 /* of this moniker and composes the remainder of the other moniker on the right of it. */
1062 /* finds the common prefix of the two monikers */
1063 res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk);
1065 /* if there's no common prefix or the two moniker are equal the relative is the other moniker */
1066 if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){
1068 *ppmkRelPath=pmkOther;
1069 IMoniker_AddRef(pmkOther);
1070 return MK_S_HIM;
1073 GetAfterCommonPrefix(iface,commonMk,&restThisMk);
1074 GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk);
1076 /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */
1077 /* moniker when the common prefix is removed */
1078 if (res==MK_S_HIM){
1080 IMoniker_Inverse(restThisMk,ppmkRelPath);
1081 IMoniker_Release(restThisMk);
1083 /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */
1084 /* when the common prefix is removed */
1085 else if (res==MK_S_ME){
1087 *ppmkRelPath=restOtherMk;
1088 IMoniker_AddRef(restOtherMk);
1090 /* the relative path is the inverse for the remainder of this moniker and the remainder of the other */
1091 /* moniker on the right of it. */
1092 else if (res==S_OK){
1094 IMoniker_Inverse(restThisMk,&invRestThisMk);
1095 IMoniker_Release(restThisMk);
1096 CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath);
1097 IMoniker_Release(invRestThisMk);
1098 IMoniker_Release(restOtherMk);
1100 return S_OK;
1103 /******************************************************************************
1104 * CompositeMoniker_GetDisplayName
1105 ******************************************************************************/
1106 static HRESULT WINAPI
1107 CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1108 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1110 ULONG lengthStr=1;
1111 IEnumMoniker *enumMoniker;
1112 IMoniker* tempMk;
1113 LPOLESTR tempStr;
1115 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1117 if (ppszDisplayName==NULL)
1118 return E_POINTER;
1120 *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR));
1122 if (*ppszDisplayName==NULL)
1123 return E_OUTOFMEMORY;
1125 /* This method returns the concatenation of the display names returned by each component moniker of */
1126 /* the composite */
1128 **ppszDisplayName=0;
1130 IMoniker_Enum(iface,TRUE,&enumMoniker);
1132 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
1134 IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr);
1136 lengthStr+=lstrlenW(tempStr);
1138 *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));
1140 if (*ppszDisplayName==NULL)
1141 return E_OUTOFMEMORY;
1143 lstrcatW(*ppszDisplayName,tempStr);
1145 CoTaskMemFree(tempStr);
1146 IMoniker_Release(tempMk);
1149 IEnumMoniker_Release(enumMoniker);
1151 return S_OK;
1154 /******************************************************************************
1155 * CompositeMoniker_ParseDisplayName
1156 ******************************************************************************/
1157 static HRESULT WINAPI
1158 CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc,
1159 IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten,
1160 IMoniker** ppmkOut)
1162 IEnumMoniker *enumMoniker;
1163 IMoniker *tempMk,*rightMostMk,*antiMk;
1164 /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/
1165 /* passing everything else as the pmkToLeft parameter for that call. */
1167 /* get the most right moniker */
1168 IMoniker_Enum(iface,FALSE,&enumMoniker);
1169 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
1170 IEnumMoniker_Release(enumMoniker);
1172 /* get the left moniker */
1173 CreateAntiMoniker(&antiMk);
1174 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
1175 IMoniker_Release(antiMk);
1177 return IMoniker_ParseDisplayName(rightMostMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut);
1180 /******************************************************************************
1181 * CompositeMoniker_IsSystemMoniker
1182 ******************************************************************************/
1183 static HRESULT WINAPI
1184 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1186 TRACE("(%p,%p)\n",iface,pwdMksys);
1188 if (!pwdMksys)
1189 return E_POINTER;
1191 (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
1193 return S_OK;
1196 /*******************************************************************************
1197 * CompositeMonikerIROTData_QueryInterface
1198 *******************************************************************************/
1199 static HRESULT WINAPI
1200 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
1201 VOID** ppvObject)
1203 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1205 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject);
1207 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
1210 /***********************************************************************
1211 * CompositeMonikerIROTData_AddRef
1213 static ULONG WINAPI
1214 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
1216 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1218 TRACE("(%p)\n",iface);
1220 return IMoniker_AddRef(&This->IMoniker_iface);
1223 /***********************************************************************
1224 * CompositeMonikerIROTData_Release
1226 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1228 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1230 TRACE("(%p)\n",iface);
1232 return IMoniker_Release(&This->IMoniker_iface);
1235 /******************************************************************************
1236 * CompositeMonikerIROTData_GetComparisonData
1237 ******************************************************************************/
1238 static HRESULT WINAPI
1239 CompositeMonikerROTDataImpl_GetComparisonData(IROTData* iface,
1240 BYTE* pbData, ULONG cbMax, ULONG* pcbData)
1242 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1243 IEnumMoniker *pEnumMk;
1244 IMoniker *pmk;
1245 HRESULT hr;
1247 TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
1249 *pcbData = sizeof(CLSID);
1251 hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1252 if (FAILED(hr)) return hr;
1254 while(IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1256 IROTData *pROTData;
1257 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1258 if (FAILED(hr))
1259 ERR("moniker doesn't support IROTData interface\n");
1261 if (SUCCEEDED(hr))
1263 ULONG cbData;
1264 hr = IROTData_GetComparisonData(pROTData, NULL, 0, &cbData);
1265 IROTData_Release(pROTData);
1266 if (SUCCEEDED(hr) || (hr == E_OUTOFMEMORY))
1268 *pcbData += cbData;
1269 hr = S_OK;
1271 else
1272 ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
1275 IMoniker_Release(pmk);
1277 if (FAILED(hr))
1279 IEnumMoniker_Release(pEnumMk);
1280 return hr;
1283 if (cbMax < *pcbData)
1284 return E_OUTOFMEMORY;
1286 IEnumMoniker_Reset(pEnumMk);
1288 memcpy(pbData, &CLSID_CompositeMoniker, sizeof(CLSID));
1289 pbData += sizeof(CLSID);
1290 cbMax -= sizeof(CLSID);
1292 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1294 IROTData *pROTData;
1295 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1296 if (FAILED(hr))
1297 ERR("moniker doesn't support IROTData interface\n");
1299 if (SUCCEEDED(hr))
1301 ULONG cbData;
1302 hr = IROTData_GetComparisonData(pROTData, pbData, cbMax, &cbData);
1303 IROTData_Release(pROTData);
1304 if (SUCCEEDED(hr))
1306 pbData += cbData;
1307 cbMax -= cbData;
1309 else
1310 ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
1313 IMoniker_Release(pmk);
1315 if (FAILED(hr))
1317 IEnumMoniker_Release(pEnumMk);
1318 return hr;
1322 IEnumMoniker_Release(pEnumMk);
1324 return S_OK;
1327 static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1329 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1331 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);
1333 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppv);
1336 static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
1338 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1340 TRACE("(%p)\n",iface);
1342 return CompositeMonikerImpl_AddRef(&This->IMoniker_iface);
1345 static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
1347 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1349 TRACE("(%p)\n",iface);
1351 return CompositeMonikerImpl_Release(&This->IMoniker_iface);
1354 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
1355 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1356 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1358 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1360 TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1361 dwDestContext, pvDestContext, mshlflags, pCid);
1363 return IMoniker_GetClassID(&This->IMoniker_iface, pCid);
1366 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
1367 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1368 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1370 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1371 IEnumMoniker *pEnumMk;
1372 IMoniker *pmk;
1373 HRESULT hr;
1374 ULARGE_INTEGER size;
1376 TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1377 dwDestContext, pvDestContext, mshlflags, pSize);
1379 *pSize = 0x10; /* to match native */
1381 hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1382 if (FAILED(hr)) return hr;
1384 hr = IMoniker_GetSizeMax(&This->IMoniker_iface, &size);
1386 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1388 ULONG size;
1390 hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1391 if (SUCCEEDED(hr))
1392 *pSize += size;
1394 IMoniker_Release(pmk);
1396 if (FAILED(hr))
1398 IEnumMoniker_Release(pEnumMk);
1399 return hr;
1403 IEnumMoniker_Release(pEnumMk);
1405 return S_OK;
1408 static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(IMarshal *iface, IStream *pStm,
1409 REFIID riid, void* pv, DWORD dwDestContext,
1410 void* pvDestContext, DWORD mshlflags)
1412 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1413 IEnumMoniker *pEnumMk;
1414 IMoniker *pmk;
1415 HRESULT hr;
1416 ULONG i = 0;
1418 TRACE("(%p, %s, %p, %x, %p, %x)\n", pStm, debugstr_guid(riid), pv,
1419 dwDestContext, pvDestContext, mshlflags);
1421 hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1422 if (FAILED(hr)) return hr;
1424 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1426 hr = CoMarshalInterface(pStm, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1428 IMoniker_Release(pmk);
1430 if (FAILED(hr))
1432 IEnumMoniker_Release(pEnumMk);
1433 return hr;
1435 i++;
1438 if (i != 2)
1439 FIXME("moniker count of %d not supported\n", i);
1441 IEnumMoniker_Release(pEnumMk);
1443 return S_OK;
1446 static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm,
1447 REFIID riid, void **ppv)
1449 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1450 HRESULT hr;
1452 TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1454 CompositeMonikerImpl_ReleaseMonikersInTable(This);
1456 /* resize the table if needed */
1457 if (This->tabLastIndex + 2 > This->tabSize)
1459 This->tabSize += max(BLOCK_TAB_SIZE, 2);
1460 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1462 if (This->tabMoniker==NULL)
1463 return E_OUTOFMEMORY;
1466 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1467 if (FAILED(hr))
1469 ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
1470 return hr;
1472 This->tabLastIndex++;
1473 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1474 if (FAILED(hr))
1476 ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
1477 return hr;
1479 This->tabLastIndex++;
1481 return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppv);
1484 static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1486 TRACE("(%p)\n", pStm);
1487 /* can't release a state-based marshal as nothing on server side to
1488 * release */
1489 return S_OK;
1492 static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(IMarshal *iface,
1493 DWORD dwReserved)
1495 TRACE("(0x%x)\n", dwReserved);
1496 /* can't disconnect a state-based marshal as nothing on server side to
1497 * disconnect from */
1498 return S_OK;
1501 /******************************************************************************
1502 * EnumMonikerImpl_QueryInterface
1503 ******************************************************************************/
1504 static HRESULT WINAPI
1505 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1507 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1509 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1511 /* Perform a sanity check on the parameters.*/
1512 if ( ppvObject==0 )
1513 return E_INVALIDARG;
1515 /* Initialize the return parameter */
1516 *ppvObject = 0;
1518 /* Compare the riid with the interface IDs implemented by this object.*/
1519 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
1520 *ppvObject = iface;
1522 /* Check that we obtained an interface.*/
1523 if ((*ppvObject)==0)
1524 return E_NOINTERFACE;
1526 /* Query Interface always increases the reference count by one when it is successful */
1527 IEnumMoniker_AddRef(iface);
1529 return S_OK;
1532 /******************************************************************************
1533 * EnumMonikerImpl_AddRef
1534 ******************************************************************************/
1535 static ULONG WINAPI
1536 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1538 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1540 TRACE("(%p)\n",This);
1542 return InterlockedIncrement(&This->ref);
1546 /******************************************************************************
1547 * EnumMonikerImpl_Release
1548 ******************************************************************************/
1549 static ULONG WINAPI
1550 EnumMonikerImpl_Release(IEnumMoniker* iface)
1552 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1553 ULONG i;
1554 ULONG ref;
1555 TRACE("(%p)\n",This);
1557 ref = InterlockedDecrement(&This->ref);
1559 /* destroy the object if there are no more references to it */
1560 if (ref == 0) {
1562 for(i=0;i<This->tabSize;i++)
1563 IMoniker_Release(This->tabMoniker[i]);
1565 HeapFree(GetProcessHeap(),0,This->tabMoniker);
1566 HeapFree(GetProcessHeap(),0,This);
1568 return ref;
1571 /******************************************************************************
1572 * EnumMonikerImpl_Next
1573 ******************************************************************************/
1574 static HRESULT WINAPI
1575 EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt,
1576 ULONG* pceltFethed)
1578 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1579 ULONG i;
1581 /* retrieve the requested number of moniker from the current position */
1582 for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++)
1584 rgelt[i]=This->tabMoniker[This->currentPos++];
1585 IMoniker_AddRef(rgelt[i]);
1588 if (pceltFethed!=NULL)
1589 *pceltFethed= i;
1591 if (i==celt)
1592 return S_OK;
1593 else
1594 return S_FALSE;
1597 /******************************************************************************
1598 * EnumMonikerImpl_Skip
1599 ******************************************************************************/
1600 static HRESULT WINAPI
1601 EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt)
1603 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1605 if ((This->currentPos+celt) >= This->tabSize)
1606 return S_FALSE;
1608 This->currentPos+=celt;
1610 return S_OK;
1613 /******************************************************************************
1614 * EnumMonikerImpl_Reset
1615 ******************************************************************************/
1616 static HRESULT WINAPI
1617 EnumMonikerImpl_Reset(IEnumMoniker* iface)
1619 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1621 This->currentPos=0;
1623 return S_OK;
1626 /******************************************************************************
1627 * EnumMonikerImpl_Clone
1628 ******************************************************************************/
1629 static HRESULT WINAPI
1630 EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)
1632 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1634 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
1637 /********************************************************************************/
1638 /* Virtual function table for the IROTData class */
1639 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1641 EnumMonikerImpl_QueryInterface,
1642 EnumMonikerImpl_AddRef,
1643 EnumMonikerImpl_Release,
1644 EnumMonikerImpl_Next,
1645 EnumMonikerImpl_Skip,
1646 EnumMonikerImpl_Reset,
1647 EnumMonikerImpl_Clone
1650 /******************************************************************************
1651 * EnumMonikerImpl_CreateEnumMoniker
1652 ******************************************************************************/
1653 static HRESULT
1654 EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize,
1655 ULONG currentPos, BOOL leftToRight, IEnumMoniker ** ppmk)
1657 EnumMonikerImpl* newEnumMoniker;
1658 ULONG i;
1660 if (currentPos > tabSize)
1661 return E_INVALIDARG;
1663 newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
1665 if (newEnumMoniker == 0)
1666 return STG_E_INSUFFICIENTMEMORY;
1668 /* Initialize the virtual function table. */
1669 newEnumMoniker->IEnumMoniker_iface.lpVtbl = &VT_EnumMonikerImpl;
1670 newEnumMoniker->ref = 1;
1672 newEnumMoniker->tabSize=tabSize;
1673 newEnumMoniker->currentPos=currentPos;
1675 newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(newEnumMoniker->tabMoniker[0]));
1677 if (newEnumMoniker->tabMoniker==NULL) {
1678 HeapFree(GetProcessHeap(), 0, newEnumMoniker);
1679 return E_OUTOFMEMORY;
1682 if (leftToRight)
1683 for (i=0;i<tabSize;i++){
1685 newEnumMoniker->tabMoniker[i]=tabMoniker[i];
1686 IMoniker_AddRef(tabMoniker[i]);
1688 else
1689 for (i = tabSize; i > 0; i--){
1691 newEnumMoniker->tabMoniker[tabSize-i]=tabMoniker[i - 1];
1692 IMoniker_AddRef(tabMoniker[i - 1]);
1695 *ppmk=&newEnumMoniker->IEnumMoniker_iface;
1697 return S_OK;
1700 /********************************************************************************/
1701 /* Virtual function table for the CompositeMonikerImpl class which includes */
1702 /* IPersist, IPersistStream and IMoniker functions. */
1704 static const IMonikerVtbl VT_CompositeMonikerImpl =
1706 CompositeMonikerImpl_QueryInterface,
1707 CompositeMonikerImpl_AddRef,
1708 CompositeMonikerImpl_Release,
1709 CompositeMonikerImpl_GetClassID,
1710 CompositeMonikerImpl_IsDirty,
1711 CompositeMonikerImpl_Load,
1712 CompositeMonikerImpl_Save,
1713 CompositeMonikerImpl_GetSizeMax,
1714 CompositeMonikerImpl_BindToObject,
1715 CompositeMonikerImpl_BindToStorage,
1716 CompositeMonikerImpl_Reduce,
1717 CompositeMonikerImpl_ComposeWith,
1718 CompositeMonikerImpl_Enum,
1719 CompositeMonikerImpl_IsEqual,
1720 CompositeMonikerImpl_Hash,
1721 CompositeMonikerImpl_IsRunning,
1722 CompositeMonikerImpl_GetTimeOfLastChange,
1723 CompositeMonikerImpl_Inverse,
1724 CompositeMonikerImpl_CommonPrefixWith,
1725 CompositeMonikerImpl_RelativePathTo,
1726 CompositeMonikerImpl_GetDisplayName,
1727 CompositeMonikerImpl_ParseDisplayName,
1728 CompositeMonikerImpl_IsSystemMoniker
1731 /********************************************************************************/
1732 /* Virtual function table for the IROTData class. */
1733 static const IROTDataVtbl VT_ROTDataImpl =
1735 CompositeMonikerROTDataImpl_QueryInterface,
1736 CompositeMonikerROTDataImpl_AddRef,
1737 CompositeMonikerROTDataImpl_Release,
1738 CompositeMonikerROTDataImpl_GetComparisonData
1741 static const IMarshalVtbl VT_MarshalImpl =
1743 CompositeMonikerMarshalImpl_QueryInterface,
1744 CompositeMonikerMarshalImpl_AddRef,
1745 CompositeMonikerMarshalImpl_Release,
1746 CompositeMonikerMarshalImpl_GetUnmarshalClass,
1747 CompositeMonikerMarshalImpl_GetMarshalSizeMax,
1748 CompositeMonikerMarshalImpl_MarshalInterface,
1749 CompositeMonikerMarshalImpl_UnmarshalInterface,
1750 CompositeMonikerMarshalImpl_ReleaseMarshalData,
1751 CompositeMonikerMarshalImpl_DisconnectObject
1754 /******************************************************************************
1755 * Composite-Moniker_Construct (local function)
1756 *******************************************************************************/
1757 static HRESULT
1758 CompositeMonikerImpl_Construct(IMoniker **ppMoniker, IMoniker *pmkFirst, IMoniker *pmkRest)
1760 DWORD mkSys;
1761 IEnumMoniker *enumMoniker;
1762 IMoniker *tempMk;
1763 HRESULT res;
1764 CompositeMonikerImpl *This;
1765 int i;
1767 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1769 if (!This)
1770 return E_OUTOFMEMORY;
1772 TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);
1774 /* Initialize the virtual function table. */
1775 This->IMoniker_iface.lpVtbl = &VT_CompositeMonikerImpl;
1776 This->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
1777 This->IMarshal_iface.lpVtbl = &VT_MarshalImpl;
1778 This->ref = 1;
1780 This->tabSize=BLOCK_TAB_SIZE;
1781 This->tabLastIndex=0;
1783 This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(This->tabMoniker[0]));
1784 if (This->tabMoniker==NULL) {
1785 HeapFree(GetProcessHeap(), 0, This);
1786 return E_OUTOFMEMORY;
1789 if (!pmkFirst && !pmkRest)
1791 *ppMoniker = &This->IMoniker_iface;
1792 return S_OK;
1795 IMoniker_IsSystemMoniker(pmkFirst,&mkSys);
1797 /* put the first moniker contents in the beginning of the table */
1798 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1800 This->tabMoniker[(This->tabLastIndex)++]=pmkFirst;
1801 IMoniker_AddRef(pmkFirst);
1803 else{
1805 IMoniker_Enum(pmkFirst,TRUE,&enumMoniker);
1807 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1810 if (++This->tabLastIndex==This->tabSize){
1811 IMoniker **tab_moniker = This->tabMoniker;
1813 This->tabSize+=BLOCK_TAB_SIZE;
1814 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1816 if (This->tabMoniker==NULL){
1817 for (i = 0; i < This->tabLastIndex; i++)
1818 IMoniker_Release(tab_moniker[i]);
1819 HeapFree(GetProcessHeap(), 0, tab_moniker);
1820 HeapFree(GetProcessHeap(), 0, This);
1821 return E_OUTOFMEMORY;
1826 IEnumMoniker_Release(enumMoniker);
1829 /* put the rest moniker contents after the first one and make simplification if needed */
1831 IMoniker_IsSystemMoniker(pmkRest,&mkSys);
1833 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1835 /* add a simple moniker to the moniker table */
1837 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk);
1839 if (res==MK_E_NEEDGENERIC){
1841 /* there's no simplification in this case */
1842 This->tabMoniker[This->tabLastIndex]=pmkRest;
1844 This->tabLastIndex++;
1846 IMoniker_AddRef(pmkRest);
1848 else if (tempMk==NULL){
1850 /* we have an antimoniker after a simple moniker so we can make a simplification in this case */
1851 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1853 This->tabLastIndex--;
1855 else if (SUCCEEDED(res)){
1857 /* the non-generic composition was successful so we can make a simplification in this case */
1858 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1860 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1861 } else{
1862 for (i = 0; i < This->tabLastIndex; i++)
1863 IMoniker_Release(This->tabMoniker[i]);
1864 HeapFree(GetProcessHeap(), 0, This->tabMoniker);
1865 HeapFree(GetProcessHeap(), 0, This);
1866 return res;
1869 /* resize tabMoniker if needed */
1870 if (This->tabLastIndex==This->tabSize){
1871 IMoniker **tab_moniker = This->tabMoniker;
1873 This->tabSize+=BLOCK_TAB_SIZE;
1875 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1877 if (This->tabMoniker==NULL){
1878 for (i = 0; i < This->tabLastIndex; i++)
1879 IMoniker_Release(tab_moniker[i]);
1880 HeapFree(GetProcessHeap(), 0, tab_moniker);
1881 HeapFree(GetProcessHeap(), 0, This);
1882 return E_OUTOFMEMORY;
1886 else{
1888 /* add a composite moniker to the moniker table (do the same thing
1889 * for each moniker within the composite moniker as a simple moniker
1890 * (see above for how to add a simple moniker case) )
1892 IMoniker_Enum(pmkRest,TRUE,&enumMoniker);
1894 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1896 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk);
1898 if (res==MK_E_NEEDGENERIC){
1900 This->tabLastIndex++;
1902 else if (tempMk==NULL){
1904 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1905 IMoniker_Release(This->tabMoniker[This->tabLastIndex]);
1906 This->tabLastIndex--;
1908 else{
1910 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1912 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1915 if (This->tabLastIndex==This->tabSize){
1916 IMoniker **tab_moniker = This->tabMoniker;
1918 This->tabSize+=BLOCK_TAB_SIZE;
1920 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1922 if (This->tabMoniker==NULL){
1923 for (i = 0; i < This->tabLastIndex; i++)
1924 IMoniker_Release(tab_moniker[i]);
1925 HeapFree(GetProcessHeap(), 0, tab_moniker);
1926 HeapFree(GetProcessHeap(), 0, This);
1927 return E_OUTOFMEMORY;
1932 IEnumMoniker_Release(enumMoniker);
1935 /* only one moniker, then just return it */
1936 if (This->tabLastIndex == 1)
1938 *ppMoniker = This->tabMoniker[0];
1939 IMoniker_AddRef(*ppMoniker);
1940 IMoniker_Release(&This->IMoniker_iface);
1942 else
1943 *ppMoniker = &This->IMoniker_iface;
1945 return S_OK;
1948 /******************************************************************************
1949 * CreateGenericComposite [OLE32.@]
1950 ******************************************************************************/
1951 HRESULT WINAPI
1952 CreateGenericComposite(IMoniker *pmkFirst, IMoniker *pmkRest, IMoniker **ppmkComposite)
1954 IMoniker* moniker = 0;
1955 HRESULT hr = S_OK;
1957 TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite);
1959 if (ppmkComposite==NULL)
1960 return E_POINTER;
1962 *ppmkComposite=0;
1964 if (pmkFirst==NULL && pmkRest!=NULL){
1966 *ppmkComposite=pmkRest;
1967 IMoniker_AddRef(pmkRest);
1968 return S_OK;
1970 else if (pmkFirst!=NULL && pmkRest==NULL){
1971 *ppmkComposite=pmkFirst;
1972 IMoniker_AddRef(pmkFirst);
1973 return S_OK;
1975 else if (pmkFirst==NULL && pmkRest==NULL)
1976 return S_OK;
1978 hr = CompositeMonikerImpl_Construct(&moniker,pmkFirst,pmkRest);
1980 if (FAILED(hr))
1981 return hr;
1983 hr = IMoniker_QueryInterface(moniker,&IID_IMoniker,(void**)ppmkComposite);
1984 IMoniker_Release(moniker);
1986 return hr;
1989 /******************************************************************************
1990 * MonikerCommonPrefixWith [OLE32.@]
1991 ******************************************************************************/
1992 HRESULT WINAPI
1993 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1995 FIXME("(),stub!\n");
1996 return E_NOTIMPL;
1999 HRESULT WINAPI CompositeMoniker_CreateInstance(IClassFactory *iface,
2000 IUnknown *pUnk, REFIID riid, void **ppv)
2002 IMoniker* pMoniker;
2003 HRESULT hr;
2005 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
2007 *ppv = NULL;
2009 if (pUnk)
2010 return CLASS_E_NOAGGREGATION;
2012 hr = CompositeMonikerImpl_Construct(&pMoniker, NULL, NULL);
2014 if (SUCCEEDED(hr))
2016 hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
2017 IMoniker_Release(pMoniker);
2020 return hr;