kernel32/tests: Add a test to check some fields in fake dlls.
[wine.git] / dlls / ole32 / compositemoniker.c
blob94f4a723a82d8d90022fd520a1220be57dd02fea
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 "wine/unicode.h"
33 #include "ole2.h"
34 #include "moniker.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(ole);
38 #define BLOCK_TAB_SIZE 5 /* represent the first size table and its increment block size */
40 /* CompositeMoniker data structure */
41 typedef struct CompositeMonikerImpl{
42 IMoniker IMoniker_iface;
43 IROTData IROTData_iface;
44 IMarshal IMarshal_iface;
45 LONG ref;
46 IMoniker** tabMoniker; /* dynamic table containing all components (monikers) of this composite moniker */
47 ULONG tabSize; /* size of tabMoniker */
48 ULONG tabLastIndex; /* first free index in tabMoniker */
49 } CompositeMonikerImpl;
51 static inline CompositeMonikerImpl *impl_from_IMoniker(IMoniker *iface)
53 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMoniker_iface);
56 static inline CompositeMonikerImpl *impl_from_IROTData(IROTData *iface)
58 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IROTData_iface);
61 static inline CompositeMonikerImpl *impl_from_IMarshal(IMarshal *iface)
63 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMarshal_iface);
66 /* EnumMoniker data structure */
67 typedef struct EnumMonikerImpl{
68 IEnumMoniker IEnumMoniker_iface;
69 LONG ref;
70 IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
71 ULONG tabSize; /* size of tabMoniker */
72 ULONG currentPos; /* index pointer on the current moniker */
73 } EnumMonikerImpl;
75 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
77 return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
80 static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRight,IEnumMoniker ** ppmk);
82 /*******************************************************************************
83 * CompositeMoniker_QueryInterface
84 *******************************************************************************/
85 static HRESULT WINAPI
86 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
88 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
90 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
92 /* Perform a sanity check on the parameters.*/
93 if ( ppvObject==0 )
94 return E_INVALIDARG;
96 /* Initialize the return parameter */
97 *ppvObject = 0;
99 /* Compare the riid with the interface IDs implemented by this object.*/
100 if (IsEqualIID(&IID_IUnknown, riid) ||
101 IsEqualIID(&IID_IPersist, riid) ||
102 IsEqualIID(&IID_IPersistStream, riid) ||
103 IsEqualIID(&IID_IMoniker, riid)
105 *ppvObject = iface;
106 else if (IsEqualIID(&IID_IROTData, riid))
107 *ppvObject = &This->IROTData_iface;
108 else if (IsEqualIID(&IID_IMarshal, riid))
109 *ppvObject = &This->IMarshal_iface;
111 /* Check that we obtained an interface.*/
112 if ((*ppvObject)==0)
113 return E_NOINTERFACE;
115 /* Query Interface always increases the reference count by one when it is successful */
116 IMoniker_AddRef(iface);
118 return S_OK;
121 /******************************************************************************
122 * CompositeMoniker_AddRef
123 ******************************************************************************/
124 static ULONG WINAPI
125 CompositeMonikerImpl_AddRef(IMoniker* iface)
127 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
129 TRACE("(%p)\n",This);
131 return InterlockedIncrement(&This->ref);
134 static void CompositeMonikerImpl_ReleaseMonikersInTable(CompositeMonikerImpl *This)
136 ULONG i;
138 for (i = 0; i < This->tabLastIndex; i++)
139 IMoniker_Release(This->tabMoniker[i]);
141 This->tabLastIndex = 0;
144 /******************************************************************************
145 * CompositeMoniker_Release
146 ******************************************************************************/
147 static ULONG WINAPI
148 CompositeMonikerImpl_Release(IMoniker* iface)
150 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
151 ULONG ref;
153 TRACE("(%p)\n",This);
155 ref = InterlockedDecrement(&This->ref);
157 /* destroy the object if there are no more references to it */
158 if (ref == 0){
160 /* release all the components before destroying this object */
161 CompositeMonikerImpl_ReleaseMonikersInTable(This);
163 HeapFree(GetProcessHeap(),0,This->tabMoniker);
164 HeapFree(GetProcessHeap(),0,This);
166 return ref;
169 /******************************************************************************
170 * CompositeMoniker_GetClassID
171 ******************************************************************************/
172 static HRESULT WINAPI
173 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
175 TRACE("(%p,%p)\n",iface,pClassID);
177 if (pClassID==NULL)
178 return E_POINTER;
180 *pClassID = CLSID_CompositeMoniker;
182 return S_OK;
185 /******************************************************************************
186 * CompositeMoniker_IsDirty
187 ******************************************************************************/
188 static HRESULT WINAPI
189 CompositeMonikerImpl_IsDirty(IMoniker* iface)
191 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
192 method in the OLE-provided moniker interfaces always return S_FALSE because
193 their internal state never changes. */
195 TRACE("(%p)\n",iface);
197 return S_FALSE;
200 /******************************************************************************
201 * CompositeMoniker_Load
202 ******************************************************************************/
203 static HRESULT WINAPI
204 CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
206 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
207 HRESULT res;
208 DWORD moniker_count;
209 DWORD i;
211 TRACE("(%p,%p)\n",iface,pStm);
213 /* this function call OleLoadFromStream function for each moniker within this object */
215 res=IStream_Read(pStm,&moniker_count,sizeof(DWORD),NULL);
216 if (res != S_OK)
218 ERR("couldn't reading moniker count from stream\n");
219 return E_FAIL;
222 CompositeMonikerImpl_ReleaseMonikersInTable(This);
224 for (i = 0; i < moniker_count; i++)
226 res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
227 if (FAILED(res))
229 ERR("couldn't load moniker from stream, res = 0x%08x\n", res);
230 break;
233 /* resize the table if needed */
234 if (++This->tabLastIndex==This->tabSize){
236 This->tabSize+=BLOCK_TAB_SIZE;
237 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
239 if (This->tabMoniker==NULL)
240 return E_OUTOFMEMORY;
244 return res;
247 /******************************************************************************
248 * CompositeMoniker_Save
249 ******************************************************************************/
250 static HRESULT WINAPI
251 CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
253 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
254 HRESULT res;
255 IEnumMoniker *enumMk;
256 IMoniker *pmk;
257 DWORD moniker_count = This->tabLastIndex;
259 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
261 /* This function calls OleSaveToStream function for each moniker within
262 * this object.
263 * When I tested this function in windows, I usually found this constant
264 * at the beginning of the stream. I don't known why (there's no
265 * indication in the specification) !
267 res=IStream_Write(pStm,&moniker_count,sizeof(moniker_count),NULL);
268 if (FAILED(res)) return res;
270 IMoniker_Enum(iface,TRUE,&enumMk);
272 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
274 res=OleSaveToStream((IPersistStream*)pmk,pStm);
276 IMoniker_Release(pmk);
278 if (FAILED(res)){
280 IEnumMoniker_Release(enumMk);
281 return res;
285 IEnumMoniker_Release(enumMk);
287 return S_OK;
290 /******************************************************************************
291 * CompositeMoniker_GetSizeMax
292 ******************************************************************************/
293 static HRESULT WINAPI
294 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
296 IEnumMoniker *enumMk;
297 IMoniker *pmk;
298 ULARGE_INTEGER ptmpSize;
300 /* The sizeMax of this object is calculated by calling GetSizeMax on
301 * each moniker within this object then summing all returned values
304 TRACE("(%p,%p)\n",iface,pcbSize);
306 if (!pcbSize)
307 return E_POINTER;
309 pcbSize->QuadPart = sizeof(DWORD);
311 IMoniker_Enum(iface,TRUE,&enumMk);
313 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
315 IMoniker_GetSizeMax(pmk,&ptmpSize);
317 IMoniker_Release(pmk);
319 pcbSize->QuadPart = ptmpSize.QuadPart + sizeof(CLSID);
322 IEnumMoniker_Release(enumMk);
324 return S_OK;
327 /******************************************************************************
328 * CompositeMoniker_BindToObject
329 ******************************************************************************/
330 static HRESULT WINAPI
331 CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,
332 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
334 HRESULT res;
335 IRunningObjectTable *prot;
336 IMoniker *tempMk,*antiMk,*rightMostMk;
337 IEnumMoniker *enumMoniker;
339 TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
341 if (ppvResult==NULL)
342 return E_POINTER;
344 *ppvResult=0;
345 /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
346 /* object for the requested interface pointer. */
347 if(pmkToLeft==NULL){
349 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
351 if (SUCCEEDED(res)){
353 /* if the requested class was loaded before ! we don't need to reload it */
354 res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
356 if (res==S_OK)
357 return res;
360 else{
361 /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
362 /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
364 IMoniker_Enum(iface,FALSE,&enumMoniker);
365 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
366 IEnumMoniker_Release(enumMoniker);
368 res=CreateAntiMoniker(&antiMk);
369 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
370 IMoniker_Release(antiMk);
372 res=IMoniker_BindToObject(rightMostMk,pbc,tempMk,riid,ppvResult);
374 IMoniker_Release(tempMk);
375 IMoniker_Release(rightMostMk);
378 return res;
381 /******************************************************************************
382 * CompositeMoniker_BindToStorage
383 ******************************************************************************/
384 static HRESULT WINAPI
385 CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
386 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
388 HRESULT res;
389 IMoniker *tempMk,*antiMk,*rightMostMk,*leftMk;
390 IEnumMoniker *enumMoniker;
392 TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult);
394 *ppvResult=0;
396 /* This method recursively calls BindToStorage on the rightmost component of the composite, */
397 /* passing the rest of the composite as the pmkToLeft parameter for that call. */
399 if (pmkToLeft)
401 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
402 if (FAILED(res)) return res;
404 else
405 leftMk = iface;
407 IMoniker_Enum(iface, FALSE, &enumMoniker);
408 IEnumMoniker_Next(enumMoniker, 1, &rightMostMk, NULL);
409 IEnumMoniker_Release(enumMoniker);
411 res = CreateAntiMoniker(&antiMk);
412 if (FAILED(res)) return res;
413 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
414 if (FAILED(res)) return res;
415 IMoniker_Release(antiMk);
417 res = IMoniker_BindToStorage(rightMostMk, pbc, tempMk, riid, ppvResult);
419 IMoniker_Release(tempMk);
421 IMoniker_Release(rightMostMk);
423 if (pmkToLeft)
424 IMoniker_Release(leftMk);
426 return res;
429 /******************************************************************************
430 * CompositeMoniker_Reduce
431 ******************************************************************************/
432 static HRESULT WINAPI
433 CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
434 IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
436 HRESULT res;
437 IMoniker *tempMk,*antiMk,*rightMostMk,*leftReducedComposedMk,*rightMostReducedMk;
438 IEnumMoniker *enumMoniker;
440 TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
442 if (ppmkReduced==NULL)
443 return E_POINTER;
445 /* This method recursively calls Reduce for each of its component monikers. */
447 if (ppmkToLeft==NULL){
449 IMoniker_Enum(iface,FALSE,&enumMoniker);
450 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
451 IEnumMoniker_Release(enumMoniker);
453 CreateAntiMoniker(&antiMk);
454 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
455 IMoniker_Release(antiMk);
457 res = IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
458 IMoniker_Release(tempMk);
459 IMoniker_Release(rightMostMk);
461 return res;
463 else if (*ppmkToLeft==NULL)
465 return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);
467 else{
469 /* separate the composite moniker in to left and right moniker */
470 IMoniker_Enum(iface,FALSE,&enumMoniker);
471 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
472 IEnumMoniker_Release(enumMoniker);
474 CreateAntiMoniker(&antiMk);
475 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
476 IMoniker_Release(antiMk);
478 /* If any of the components reduces itself, the method returns S_OK and passes back a composite */
479 /* of the reduced components */
480 if (IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,NULL,&rightMostReducedMk) &&
481 IMoniker_Reduce(rightMostMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk) ){
482 IMoniker_Release(tempMk);
483 IMoniker_Release(rightMostMk);
485 return CreateGenericComposite(leftReducedComposedMk,rightMostReducedMk,ppmkReduced);
487 else{
488 /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
489 IMoniker_Release(tempMk);
490 IMoniker_Release(rightMostMk);
492 IMoniker_AddRef(iface);
494 *ppmkReduced=iface;
496 return MK_S_REDUCED_TO_SELF;
501 /******************************************************************************
502 * CompositeMoniker_ComposeWith
503 ******************************************************************************/
504 static HRESULT WINAPI
505 CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
506 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
508 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
510 if ((ppmkComposite==NULL)||(pmkRight==NULL))
511 return E_POINTER;
513 *ppmkComposite=0;
515 /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */
516 /* otherwise, the method returns the result of combining the two monikers by calling the */
517 /* CreateGenericComposite function */
519 if (fOnlyIfNotGeneric)
520 return MK_E_NEEDGENERIC;
522 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
525 /******************************************************************************
526 * CompositeMoniker_Enum
527 ******************************************************************************/
528 static HRESULT WINAPI
529 CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
531 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
533 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
535 if (ppenumMoniker == NULL)
536 return E_POINTER;
538 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);
541 /******************************************************************************
542 * CompositeMoniker_IsEqual
543 ******************************************************************************/
544 static HRESULT WINAPI
545 CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
547 IEnumMoniker *enumMoniker1,*enumMoniker2;
548 IMoniker *tempMk1,*tempMk2;
549 HRESULT res1,res2,res;
550 BOOL done;
552 TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
554 if (pmkOtherMoniker==NULL)
555 return S_FALSE;
557 /* This method returns S_OK if the components of both monikers are equal when compared in the */
558 /* left-to-right order.*/
559 IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);
561 if (enumMoniker1==NULL)
562 return S_FALSE;
564 IMoniker_Enum(iface,TRUE,&enumMoniker2);
566 do {
568 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
569 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
571 if((res1==S_OK)&&(res2==S_OK)){
572 done = (res = IMoniker_IsEqual(tempMk1,tempMk2)) == S_FALSE;
574 else
576 res = (res1==S_FALSE) && (res2==S_FALSE);
577 done = TRUE;
580 if (res1==S_OK)
581 IMoniker_Release(tempMk1);
583 if (res2==S_OK)
584 IMoniker_Release(tempMk2);
585 } while (!done);
587 IEnumMoniker_Release(enumMoniker1);
588 IEnumMoniker_Release(enumMoniker2);
590 return res;
592 /******************************************************************************
593 * CompositeMoniker_Hash
594 ******************************************************************************/
595 static HRESULT WINAPI
596 CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
598 IEnumMoniker *enumMoniker;
599 IMoniker *tempMk;
600 HRESULT res;
601 DWORD tempHash;
603 TRACE("(%p,%p)\n",iface,pdwHash);
605 if (pdwHash==NULL)
606 return E_POINTER;
608 res = IMoniker_Enum(iface,TRUE,&enumMoniker);
609 if(FAILED(res))
610 return res;
612 *pdwHash = 0;
614 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
615 res = IMoniker_Hash(tempMk, &tempHash);
616 if(FAILED(res))
617 break;
618 *pdwHash = *pdwHash ^ tempHash;
620 IMoniker_Release(tempMk);
623 IEnumMoniker_Release(enumMoniker);
625 return res;
628 /******************************************************************************
629 * CompositeMoniker_IsRunning
630 ******************************************************************************/
631 static HRESULT WINAPI
632 CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc,
633 IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
635 IRunningObjectTable* rot;
636 HRESULT res;
637 IMoniker *tempMk,*antiMk,*rightMostMk;
638 IEnumMoniker *enumMoniker;
640 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
642 /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/
643 if (pmkToLeft!=NULL){
645 CreateGenericComposite(pmkToLeft,iface,&tempMk);
647 res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);
649 IMoniker_Release(tempMk);
651 return res;
653 else
654 /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */
655 /* to this moniker */
657 if (pmkNewlyRunning!=NULL)
659 if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)
660 return S_OK;
662 else
663 return S_FALSE;
665 else{
667 if (pbc==NULL)
668 return E_INVALIDARG;
670 /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */
671 /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */
672 /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */
673 /* the composite as the pmkToLeft parameter for that call. */
675 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
677 if (FAILED(res))
678 return res;
680 res = IRunningObjectTable_IsRunning(rot,iface);
681 IRunningObjectTable_Release(rot);
683 if(res==S_OK)
684 return S_OK;
686 else{
688 IMoniker_Enum(iface,FALSE,&enumMoniker);
689 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
690 IEnumMoniker_Release(enumMoniker);
692 res=CreateAntiMoniker(&antiMk);
693 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
694 IMoniker_Release(antiMk);
696 res=IMoniker_IsRunning(rightMostMk,pbc,tempMk,pmkNewlyRunning);
698 IMoniker_Release(tempMk);
699 IMoniker_Release(rightMostMk);
701 return res;
706 /******************************************************************************
707 * CompositeMoniker_GetTimeOfLastChange
708 ******************************************************************************/
709 static HRESULT WINAPI
710 CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
711 IMoniker* pmkToLeft, FILETIME* pCompositeTime)
713 HRESULT res;
714 IMoniker *tempMk,*antiMk,*rightMostMk,*leftMk;
715 IEnumMoniker *enumMoniker;
717 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);
719 if (pCompositeTime==NULL)
720 return E_INVALIDARG;
722 /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to */
723 /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */
724 /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */
725 /* of the composite as the pmkToLeft parameter for that call. */
726 if (pmkToLeft)
728 IRunningObjectTable* rot;
730 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
731 if (FAILED(res))
732 return res;
734 res = IBindCtx_GetRunningObjectTable(pbc,&rot);
735 if (FAILED(res))
737 IMoniker_Release(leftMk);
738 return res;
741 if (IRunningObjectTable_GetTimeOfLastChange(rot,leftMk,pCompositeTime)==S_OK)
743 IMoniker_Release(leftMk);
744 return res;
747 else
748 leftMk = iface;
750 IMoniker_Enum(iface, FALSE, &enumMoniker);
751 IEnumMoniker_Next(enumMoniker, 1, &rightMostMk, NULL);
752 IEnumMoniker_Release(enumMoniker);
754 res = CreateAntiMoniker(&antiMk);
755 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
756 IMoniker_Release(antiMk);
758 res = IMoniker_GetTimeOfLastChange(rightMostMk, pbc, tempMk, pCompositeTime);
760 IMoniker_Release(tempMk);
761 IMoniker_Release(rightMostMk);
763 if (pmkToLeft)
764 IMoniker_Release(leftMk);
766 return res;
769 /******************************************************************************
770 * CompositeMoniker_Inverse
771 ******************************************************************************/
772 static HRESULT WINAPI
773 CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
775 HRESULT res;
776 IMoniker *tempMk,*antiMk,*rightMostMk,*tempInvMk,*rightMostInvMk;
777 IEnumMoniker *enumMoniker;
779 TRACE("(%p,%p)\n",iface,ppmk);
781 if (ppmk==NULL)
782 return E_POINTER;
784 /* This method returns a composite moniker that consists of the inverses of each of the components */
785 /* of the original composite, stored in reverse order */
787 *ppmk = NULL;
789 res=CreateAntiMoniker(&antiMk);
790 if (FAILED(res))
791 return res;
793 res=IMoniker_ComposeWith(iface,antiMk,FALSE,&tempMk);
794 IMoniker_Release(antiMk);
795 if (FAILED(res))
796 return res;
798 if (tempMk==NULL)
800 return IMoniker_Inverse(iface,ppmk);
802 else{
804 IMoniker_Enum(iface,FALSE,&enumMoniker);
805 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
806 IEnumMoniker_Release(enumMoniker);
808 IMoniker_Inverse(rightMostMk,&rightMostInvMk);
809 CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);
811 res=CreateGenericComposite(rightMostInvMk,tempInvMk,ppmk);
813 IMoniker_Release(tempMk);
814 IMoniker_Release(rightMostMk);
815 IMoniker_Release(tempInvMk);
816 IMoniker_Release(rightMostInvMk);
818 return res;
822 /******************************************************************************
823 * CompositeMoniker_CommonPrefixWith
824 ******************************************************************************/
825 static HRESULT WINAPI
826 CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,
827 IMoniker** ppmkPrefix)
829 DWORD mkSys;
830 HRESULT res1,res2;
831 IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
832 IEnumMoniker *enumMoniker1,*enumMoniker2;
833 ULONG i,nbCommonMk=0;
835 /* If the other moniker is a composite, this method compares the components of each composite from left */
836 /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
837 /* of the leftmost components were common to both monikers. */
839 if (ppmkPrefix==NULL)
840 return E_POINTER;
842 *ppmkPrefix=0;
844 if (pmkOther==NULL)
845 return MK_E_NOPREFIX;
847 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
849 if(mkSys==MKSYS_GENERICCOMPOSITE){
851 IMoniker_Enum(iface,TRUE,&enumMoniker1);
852 IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
854 while(1){
856 res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
857 res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
859 if ((res1==S_FALSE) && (res2==S_FALSE)){
861 /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
862 *ppmkPrefix=iface;
863 IMoniker_AddRef(iface);
864 return MK_S_US;
866 else if ((res1==S_OK) && (res2==S_OK)){
868 if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
870 nbCommonMk++;
872 else
873 break;
876 else if (res1==S_OK){
878 /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
879 /* ppmkPrefix to the other moniker. */
880 *ppmkPrefix=pmkOther;
881 return MK_S_HIM;
883 else{
884 /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
885 /* to this moniker. */
886 *ppmkPrefix=iface;
887 return MK_S_ME;
891 IEnumMoniker_Release(enumMoniker1);
892 IEnumMoniker_Release(enumMoniker2);
894 /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
895 if (nbCommonMk==0)
896 return MK_E_NOPREFIX;
898 IEnumMoniker_Reset(enumMoniker1);
900 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
902 /* if we have more than one common moniker the result will be a composite moniker */
903 if (nbCommonMk>1){
905 /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
906 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
907 CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
908 IMoniker_Release(tempMk1);
909 IMoniker_Release(tempMk2);
911 /* compose all common monikers in a composite moniker */
912 for(i=0;i<nbCommonMk;i++){
914 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
916 CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
918 IMoniker_Release(*ppmkPrefix);
920 IMoniker_Release(tempMk1);
922 *ppmkPrefix=tempMk2;
924 return S_OK;
926 else{
927 /* if we have only one common moniker the result will be a simple moniker which is the most-left one*/
928 *ppmkPrefix=tempMk1;
930 return S_OK;
933 else{
934 /* If the other moniker is not a composite, the method simply compares it to the leftmost component
935 of this moniker.*/
937 IMoniker_Enum(iface,TRUE,&enumMoniker1);
939 IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
941 if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){
943 *ppmkPrefix=pmkOther;
945 return MK_S_HIM;
947 else
948 return MK_E_NOPREFIX;
952 /***************************************************************************************************
953 * GetAfterCommonPrefix (local function)
954 * This function returns a moniker that consist of the remainder when the common prefix is removed
955 ***************************************************************************************************/
956 static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk)
958 IMoniker *tempMk,*tempMk1,*tempMk2;
959 IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3;
960 ULONG nbRestMk=0;
961 DWORD mkSys;
962 HRESULT res1,res2;
964 *restMk=0;
966 /* to create an enumerator for pGenMk with current position pointed on the first element after common */
967 /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop */
968 /* on the first difference. */
969 IMoniker_Enum(pGenMk,TRUE,&enumMoniker1);
971 IMoniker_IsSystemMoniker(commonMk,&mkSys);
973 if (mkSys==MKSYS_GENERICCOMPOSITE){
975 IMoniker_Enum(commonMk,TRUE,&enumMoniker2);
976 while(1){
978 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
979 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
981 if ((res1==S_FALSE)||(res2==S_FALSE)){
983 if (res1==S_OK)
985 nbRestMk++;
987 IMoniker_Release(tempMk1);
988 IMoniker_Release(tempMk2);
990 break;
992 IMoniker_Release(tempMk1);
993 IMoniker_Release(tempMk2);
996 else{
997 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
998 IMoniker_Release(tempMk1);
1001 /* count the number of elements in the enumerator after the common prefix */
1002 IEnumMoniker_Clone(enumMoniker1,&enumMoniker3);
1004 for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++)
1006 IMoniker_Release(tempMk);
1008 if (nbRestMk==0)
1009 return;
1011 /* create a generic composite moniker with monikers located after the common prefix */
1012 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
1014 if (nbRestMk==1){
1016 *restMk= tempMk1;
1017 return;
1019 else {
1021 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
1023 CreateGenericComposite(tempMk1,tempMk2,restMk);
1025 IMoniker_Release(tempMk1);
1027 IMoniker_Release(tempMk2);
1029 while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){
1031 CreateGenericComposite(*restMk,tempMk1,&tempMk2);
1033 IMoniker_Release(tempMk1);
1035 IMoniker_Release(*restMk);
1037 *restMk=tempMk2;
1042 /******************************************************************************
1043 * CompositeMoniker_RelativePathTo
1044 ******************************************************************************/
1045 static HRESULT WINAPI
1046 CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther,
1047 IMoniker** ppmkRelPath)
1049 HRESULT res;
1050 IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0;
1052 TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath);
1054 if (ppmkRelPath==NULL)
1055 return E_POINTER;
1057 *ppmkRelPath=0;
1059 /* This method finds the common prefix of the two monikers and creates two monikers that consist */
1060 /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */
1061 /* of this moniker and composes the remainder of the other moniker on the right of it. */
1063 /* finds the common prefix of the two monikers */
1064 res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk);
1066 /* if there's no common prefix or the two moniker are equal the relative is the other moniker */
1067 if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){
1069 *ppmkRelPath=pmkOther;
1070 IMoniker_AddRef(pmkOther);
1071 return MK_S_HIM;
1074 GetAfterCommonPrefix(iface,commonMk,&restThisMk);
1075 GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk);
1077 /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */
1078 /* moniker when the common prefix is removed */
1079 if (res==MK_S_HIM){
1081 IMoniker_Inverse(restThisMk,ppmkRelPath);
1082 IMoniker_Release(restThisMk);
1084 /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */
1085 /* when the common prefix is removed */
1086 else if (res==MK_S_ME){
1088 *ppmkRelPath=restOtherMk;
1089 IMoniker_AddRef(restOtherMk);
1091 /* the relative path is the inverse for the remainder of this moniker and the remainder of the other */
1092 /* moniker on the right of it. */
1093 else if (res==S_OK){
1095 IMoniker_Inverse(restThisMk,&invRestThisMk);
1096 IMoniker_Release(restThisMk);
1097 CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath);
1098 IMoniker_Release(invRestThisMk);
1099 IMoniker_Release(restOtherMk);
1101 return S_OK;
1104 /******************************************************************************
1105 * CompositeMoniker_GetDisplayName
1106 ******************************************************************************/
1107 static HRESULT WINAPI
1108 CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1109 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1111 ULONG lengthStr=1;
1112 IEnumMoniker *enumMoniker;
1113 IMoniker* tempMk;
1114 LPOLESTR tempStr;
1116 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1118 if (ppszDisplayName==NULL)
1119 return E_POINTER;
1121 *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR));
1123 if (*ppszDisplayName==NULL)
1124 return E_OUTOFMEMORY;
1126 /* This method returns the concatenation of the display names returned by each component moniker of */
1127 /* the composite */
1129 **ppszDisplayName=0;
1131 IMoniker_Enum(iface,TRUE,&enumMoniker);
1133 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
1135 IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr);
1137 lengthStr+=lstrlenW(tempStr);
1139 *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));
1141 if (*ppszDisplayName==NULL)
1142 return E_OUTOFMEMORY;
1144 strcatW(*ppszDisplayName,tempStr);
1146 CoTaskMemFree(tempStr);
1147 IMoniker_Release(tempMk);
1150 IEnumMoniker_Release(enumMoniker);
1152 return S_OK;
1155 /******************************************************************************
1156 * CompositeMoniker_ParseDisplayName
1157 ******************************************************************************/
1158 static HRESULT WINAPI
1159 CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc,
1160 IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten,
1161 IMoniker** ppmkOut)
1163 IEnumMoniker *enumMoniker;
1164 IMoniker *tempMk,*rightMostMk,*antiMk;
1165 /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/
1166 /* passing everything else as the pmkToLeft parameter for that call. */
1168 /* get the most right moniker */
1169 IMoniker_Enum(iface,FALSE,&enumMoniker);
1170 IEnumMoniker_Next(enumMoniker,1,&rightMostMk,NULL);
1171 IEnumMoniker_Release(enumMoniker);
1173 /* get the left moniker */
1174 CreateAntiMoniker(&antiMk);
1175 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
1176 IMoniker_Release(antiMk);
1178 return IMoniker_ParseDisplayName(rightMostMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut);
1181 /******************************************************************************
1182 * CompositeMoniker_IsSystemMoniker
1183 ******************************************************************************/
1184 static HRESULT WINAPI
1185 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1187 TRACE("(%p,%p)\n",iface,pwdMksys);
1189 if (!pwdMksys)
1190 return E_POINTER;
1192 (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
1194 return S_OK;
1197 /*******************************************************************************
1198 * CompositeMonikerIROTData_QueryInterface
1199 *******************************************************************************/
1200 static HRESULT WINAPI
1201 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
1202 VOID** ppvObject)
1204 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1206 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject);
1208 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
1211 /***********************************************************************
1212 * CompositeMonikerIROTData_AddRef
1214 static ULONG WINAPI
1215 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
1217 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1219 TRACE("(%p)\n",iface);
1221 return IMoniker_AddRef(&This->IMoniker_iface);
1224 /***********************************************************************
1225 * CompositeMonikerIROTData_Release
1227 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1229 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1231 TRACE("(%p)\n",iface);
1233 return IMoniker_Release(&This->IMoniker_iface);
1236 /******************************************************************************
1237 * CompositeMonikerIROTData_GetComparisonData
1238 ******************************************************************************/
1239 static HRESULT WINAPI
1240 CompositeMonikerROTDataImpl_GetComparisonData(IROTData* iface,
1241 BYTE* pbData, ULONG cbMax, ULONG* pcbData)
1243 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1244 IEnumMoniker *pEnumMk;
1245 IMoniker *pmk;
1246 HRESULT hr;
1248 TRACE("(%p, %u, %p)\n", pbData, cbMax, pcbData);
1250 *pcbData = sizeof(CLSID);
1252 hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1253 if (FAILED(hr)) return hr;
1255 while(IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1257 IROTData *pROTData;
1258 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1259 if (FAILED(hr))
1260 ERR("moniker doesn't support IROTData interface\n");
1262 if (SUCCEEDED(hr))
1264 ULONG cbData;
1265 hr = IROTData_GetComparisonData(pROTData, NULL, 0, &cbData);
1266 IROTData_Release(pROTData);
1267 if (SUCCEEDED(hr) || (hr == E_OUTOFMEMORY))
1269 *pcbData += cbData;
1270 hr = S_OK;
1272 else
1273 ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
1276 IMoniker_Release(pmk);
1278 if (FAILED(hr))
1280 IEnumMoniker_Release(pEnumMk);
1281 return hr;
1284 if (cbMax < *pcbData)
1285 return E_OUTOFMEMORY;
1287 IEnumMoniker_Reset(pEnumMk);
1289 memcpy(pbData, &CLSID_CompositeMoniker, sizeof(CLSID));
1290 pbData += sizeof(CLSID);
1291 cbMax -= sizeof(CLSID);
1293 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1295 IROTData *pROTData;
1296 hr = IMoniker_QueryInterface(pmk, &IID_IROTData, (void **)&pROTData);
1297 if (FAILED(hr))
1298 ERR("moniker doesn't support IROTData interface\n");
1300 if (SUCCEEDED(hr))
1302 ULONG cbData;
1303 hr = IROTData_GetComparisonData(pROTData, pbData, cbMax, &cbData);
1304 IROTData_Release(pROTData);
1305 if (SUCCEEDED(hr))
1307 pbData += cbData;
1308 cbMax -= cbData;
1310 else
1311 ERR("IROTData_GetComparisonData failed with error 0x%08x\n", hr);
1314 IMoniker_Release(pmk);
1316 if (FAILED(hr))
1318 IEnumMoniker_Release(pEnumMk);
1319 return hr;
1323 IEnumMoniker_Release(pEnumMk);
1325 return S_OK;
1328 static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1330 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1332 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);
1334 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppv);
1337 static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
1339 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1341 TRACE("(%p)\n",iface);
1343 return CompositeMonikerImpl_AddRef(&This->IMoniker_iface);
1346 static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
1348 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1350 TRACE("(%p)\n",iface);
1352 return CompositeMonikerImpl_Release(&This->IMoniker_iface);
1355 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
1356 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1357 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1359 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1361 TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1362 dwDestContext, pvDestContext, mshlflags, pCid);
1364 return IMoniker_GetClassID(&This->IMoniker_iface, pCid);
1367 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
1368 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1369 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1371 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1372 IEnumMoniker *pEnumMk;
1373 IMoniker *pmk;
1374 HRESULT hr;
1375 ULARGE_INTEGER size;
1377 TRACE("(%s, %p, %x, %p, %x, %p)\n", debugstr_guid(riid), pv,
1378 dwDestContext, pvDestContext, mshlflags, pSize);
1380 *pSize = 0x10; /* to match native */
1382 hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1383 if (FAILED(hr)) return hr;
1385 hr = IMoniker_GetSizeMax(&This->IMoniker_iface, &size);
1387 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1389 ULONG size;
1391 hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1392 if (SUCCEEDED(hr))
1393 *pSize += size;
1395 IMoniker_Release(pmk);
1397 if (FAILED(hr))
1399 IEnumMoniker_Release(pEnumMk);
1400 return hr;
1404 IEnumMoniker_Release(pEnumMk);
1406 return S_OK;
1409 static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(IMarshal *iface, IStream *pStm,
1410 REFIID riid, void* pv, DWORD dwDestContext,
1411 void* pvDestContext, DWORD mshlflags)
1413 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1414 IEnumMoniker *pEnumMk;
1415 IMoniker *pmk;
1416 HRESULT hr;
1417 ULONG i = 0;
1419 TRACE("(%p, %s, %p, %x, %p, %x)\n", pStm, debugstr_guid(riid), pv,
1420 dwDestContext, pvDestContext, mshlflags);
1422 hr = IMoniker_Enum(&This->IMoniker_iface, TRUE, &pEnumMk);
1423 if (FAILED(hr)) return hr;
1425 while (IEnumMoniker_Next(pEnumMk, 1, &pmk, NULL) == S_OK)
1427 hr = CoMarshalInterface(pStm, &IID_IMoniker, (IUnknown *)pmk, dwDestContext, pvDestContext, mshlflags);
1429 IMoniker_Release(pmk);
1431 if (FAILED(hr))
1433 IEnumMoniker_Release(pEnumMk);
1434 return hr;
1436 i++;
1439 if (i != 2)
1440 FIXME("moniker count of %d not supported\n", i);
1442 IEnumMoniker_Release(pEnumMk);
1444 return S_OK;
1447 static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm,
1448 REFIID riid, void **ppv)
1450 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1451 HRESULT hr;
1453 TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv);
1455 CompositeMonikerImpl_ReleaseMonikersInTable(This);
1457 /* resize the table if needed */
1458 if (This->tabLastIndex + 2 > This->tabSize)
1460 This->tabSize += max(BLOCK_TAB_SIZE, 2);
1461 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1463 if (This->tabMoniker==NULL)
1464 return E_OUTOFMEMORY;
1467 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1468 if (FAILED(hr))
1470 ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
1471 return hr;
1473 This->tabLastIndex++;
1474 hr = CoUnmarshalInterface(pStm, &IID_IMoniker, (void**)&This->tabMoniker[This->tabLastIndex]);
1475 if (FAILED(hr))
1477 ERR("couldn't unmarshal moniker, hr = 0x%08x\n", hr);
1478 return hr;
1480 This->tabLastIndex++;
1482 return IMoniker_QueryInterface(&This->IMoniker_iface, riid, ppv);
1485 static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1487 TRACE("(%p)\n", pStm);
1488 /* can't release a state-based marshal as nothing on server side to
1489 * release */
1490 return S_OK;
1493 static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(IMarshal *iface,
1494 DWORD dwReserved)
1496 TRACE("(0x%x)\n", dwReserved);
1497 /* can't disconnect a state-based marshal as nothing on server side to
1498 * disconnect from */
1499 return S_OK;
1502 /******************************************************************************
1503 * EnumMonikerImpl_QueryInterface
1504 ******************************************************************************/
1505 static HRESULT WINAPI
1506 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1508 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1510 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1512 /* Perform a sanity check on the parameters.*/
1513 if ( ppvObject==0 )
1514 return E_INVALIDARG;
1516 /* Initialize the return parameter */
1517 *ppvObject = 0;
1519 /* Compare the riid with the interface IDs implemented by this object.*/
1520 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
1521 *ppvObject = iface;
1523 /* Check that we obtained an interface.*/
1524 if ((*ppvObject)==0)
1525 return E_NOINTERFACE;
1527 /* Query Interface always increases the reference count by one when it is successful */
1528 IEnumMoniker_AddRef(iface);
1530 return S_OK;
1533 /******************************************************************************
1534 * EnumMonikerImpl_AddRef
1535 ******************************************************************************/
1536 static ULONG WINAPI
1537 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1539 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1541 TRACE("(%p)\n",This);
1543 return InterlockedIncrement(&This->ref);
1547 /******************************************************************************
1548 * EnumMonikerImpl_Release
1549 ******************************************************************************/
1550 static ULONG WINAPI
1551 EnumMonikerImpl_Release(IEnumMoniker* iface)
1553 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1554 ULONG i;
1555 ULONG ref;
1556 TRACE("(%p)\n",This);
1558 ref = InterlockedDecrement(&This->ref);
1560 /* destroy the object if there are no more references to it */
1561 if (ref == 0) {
1563 for(i=0;i<This->tabSize;i++)
1564 IMoniker_Release(This->tabMoniker[i]);
1566 HeapFree(GetProcessHeap(),0,This->tabMoniker);
1567 HeapFree(GetProcessHeap(),0,This);
1569 return ref;
1572 /******************************************************************************
1573 * EnumMonikerImpl_Next
1574 ******************************************************************************/
1575 static HRESULT WINAPI
1576 EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt,
1577 ULONG* pceltFethed)
1579 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1580 ULONG i;
1582 /* retrieve the requested number of moniker from the current position */
1583 for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++)
1585 rgelt[i]=This->tabMoniker[This->currentPos++];
1586 IMoniker_AddRef(rgelt[i]);
1589 if (pceltFethed!=NULL)
1590 *pceltFethed= i;
1592 if (i==celt)
1593 return S_OK;
1594 else
1595 return S_FALSE;
1598 /******************************************************************************
1599 * EnumMonikerImpl_Skip
1600 ******************************************************************************/
1601 static HRESULT WINAPI
1602 EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt)
1604 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1606 if ((This->currentPos+celt) >= This->tabSize)
1607 return S_FALSE;
1609 This->currentPos+=celt;
1611 return S_OK;
1614 /******************************************************************************
1615 * EnumMonikerImpl_Reset
1616 ******************************************************************************/
1617 static HRESULT WINAPI
1618 EnumMonikerImpl_Reset(IEnumMoniker* iface)
1620 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1622 This->currentPos=0;
1624 return S_OK;
1627 /******************************************************************************
1628 * EnumMonikerImpl_Clone
1629 ******************************************************************************/
1630 static HRESULT WINAPI
1631 EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)
1633 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1635 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
1638 /********************************************************************************/
1639 /* Virtual function table for the IROTData class */
1640 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1642 EnumMonikerImpl_QueryInterface,
1643 EnumMonikerImpl_AddRef,
1644 EnumMonikerImpl_Release,
1645 EnumMonikerImpl_Next,
1646 EnumMonikerImpl_Skip,
1647 EnumMonikerImpl_Reset,
1648 EnumMonikerImpl_Clone
1651 /******************************************************************************
1652 * EnumMonikerImpl_CreateEnumMoniker
1653 ******************************************************************************/
1654 static HRESULT
1655 EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize,
1656 ULONG currentPos, BOOL leftToRight, IEnumMoniker ** ppmk)
1658 EnumMonikerImpl* newEnumMoniker;
1659 ULONG i;
1661 if (currentPos > tabSize)
1662 return E_INVALIDARG;
1664 newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
1666 if (newEnumMoniker == 0)
1667 return STG_E_INSUFFICIENTMEMORY;
1669 /* Initialize the virtual function table. */
1670 newEnumMoniker->IEnumMoniker_iface.lpVtbl = &VT_EnumMonikerImpl;
1671 newEnumMoniker->ref = 1;
1673 newEnumMoniker->tabSize=tabSize;
1674 newEnumMoniker->currentPos=currentPos;
1676 newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(newEnumMoniker->tabMoniker[0]));
1678 if (newEnumMoniker->tabMoniker==NULL) {
1679 HeapFree(GetProcessHeap(), 0, newEnumMoniker);
1680 return E_OUTOFMEMORY;
1683 if (leftToRight)
1684 for (i=0;i<tabSize;i++){
1686 newEnumMoniker->tabMoniker[i]=tabMoniker[i];
1687 IMoniker_AddRef(tabMoniker[i]);
1689 else
1690 for (i = tabSize; i > 0; i--){
1692 newEnumMoniker->tabMoniker[tabSize-i]=tabMoniker[i - 1];
1693 IMoniker_AddRef(tabMoniker[i - 1]);
1696 *ppmk=&newEnumMoniker->IEnumMoniker_iface;
1698 return S_OK;
1701 /********************************************************************************/
1702 /* Virtual function table for the CompositeMonikerImpl class which includes */
1703 /* IPersist, IPersistStream and IMoniker functions. */
1705 static const IMonikerVtbl VT_CompositeMonikerImpl =
1707 CompositeMonikerImpl_QueryInterface,
1708 CompositeMonikerImpl_AddRef,
1709 CompositeMonikerImpl_Release,
1710 CompositeMonikerImpl_GetClassID,
1711 CompositeMonikerImpl_IsDirty,
1712 CompositeMonikerImpl_Load,
1713 CompositeMonikerImpl_Save,
1714 CompositeMonikerImpl_GetSizeMax,
1715 CompositeMonikerImpl_BindToObject,
1716 CompositeMonikerImpl_BindToStorage,
1717 CompositeMonikerImpl_Reduce,
1718 CompositeMonikerImpl_ComposeWith,
1719 CompositeMonikerImpl_Enum,
1720 CompositeMonikerImpl_IsEqual,
1721 CompositeMonikerImpl_Hash,
1722 CompositeMonikerImpl_IsRunning,
1723 CompositeMonikerImpl_GetTimeOfLastChange,
1724 CompositeMonikerImpl_Inverse,
1725 CompositeMonikerImpl_CommonPrefixWith,
1726 CompositeMonikerImpl_RelativePathTo,
1727 CompositeMonikerImpl_GetDisplayName,
1728 CompositeMonikerImpl_ParseDisplayName,
1729 CompositeMonikerImpl_IsSystemMoniker
1732 /********************************************************************************/
1733 /* Virtual function table for the IROTData class. */
1734 static const IROTDataVtbl VT_ROTDataImpl =
1736 CompositeMonikerROTDataImpl_QueryInterface,
1737 CompositeMonikerROTDataImpl_AddRef,
1738 CompositeMonikerROTDataImpl_Release,
1739 CompositeMonikerROTDataImpl_GetComparisonData
1742 static const IMarshalVtbl VT_MarshalImpl =
1744 CompositeMonikerMarshalImpl_QueryInterface,
1745 CompositeMonikerMarshalImpl_AddRef,
1746 CompositeMonikerMarshalImpl_Release,
1747 CompositeMonikerMarshalImpl_GetUnmarshalClass,
1748 CompositeMonikerMarshalImpl_GetMarshalSizeMax,
1749 CompositeMonikerMarshalImpl_MarshalInterface,
1750 CompositeMonikerMarshalImpl_UnmarshalInterface,
1751 CompositeMonikerMarshalImpl_ReleaseMarshalData,
1752 CompositeMonikerMarshalImpl_DisconnectObject
1755 /******************************************************************************
1756 * Composite-Moniker_Construct (local function)
1757 *******************************************************************************/
1758 static HRESULT
1759 CompositeMonikerImpl_Construct(IMoniker **ppMoniker, IMoniker *pmkFirst, IMoniker *pmkRest)
1761 DWORD mkSys;
1762 IEnumMoniker *enumMoniker;
1763 IMoniker *tempMk;
1764 HRESULT res;
1765 CompositeMonikerImpl *This;
1766 int i;
1768 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1770 if (!This)
1771 return E_OUTOFMEMORY;
1773 TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);
1775 /* Initialize the virtual function table. */
1776 This->IMoniker_iface.lpVtbl = &VT_CompositeMonikerImpl;
1777 This->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
1778 This->IMarshal_iface.lpVtbl = &VT_MarshalImpl;
1779 This->ref = 1;
1781 This->tabSize=BLOCK_TAB_SIZE;
1782 This->tabLastIndex=0;
1784 This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(This->tabMoniker[0]));
1785 if (This->tabMoniker==NULL) {
1786 HeapFree(GetProcessHeap(), 0, This);
1787 return E_OUTOFMEMORY;
1790 if (!pmkFirst && !pmkRest)
1792 *ppMoniker = &This->IMoniker_iface;
1793 return S_OK;
1796 IMoniker_IsSystemMoniker(pmkFirst,&mkSys);
1798 /* put the first moniker contents in the beginning of the table */
1799 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1801 This->tabMoniker[(This->tabLastIndex)++]=pmkFirst;
1802 IMoniker_AddRef(pmkFirst);
1804 else{
1806 IMoniker_Enum(pmkFirst,TRUE,&enumMoniker);
1808 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1811 if (++This->tabLastIndex==This->tabSize){
1812 IMoniker **tab_moniker = This->tabMoniker;
1814 This->tabSize+=BLOCK_TAB_SIZE;
1815 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1817 if (This->tabMoniker==NULL){
1818 for (i = 0; i < This->tabLastIndex; i++)
1819 IMoniker_Release(tab_moniker[i]);
1820 HeapFree(GetProcessHeap(), 0, tab_moniker);
1821 HeapFree(GetProcessHeap(), 0, This);
1822 return E_OUTOFMEMORY;
1827 IEnumMoniker_Release(enumMoniker);
1830 /* put the rest moniker contents after the first one and make simplification if needed */
1832 IMoniker_IsSystemMoniker(pmkRest,&mkSys);
1834 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1836 /* add a simple moniker to the moniker table */
1838 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk);
1840 if (res==MK_E_NEEDGENERIC){
1842 /* there's no simplification in this case */
1843 This->tabMoniker[This->tabLastIndex]=pmkRest;
1845 This->tabLastIndex++;
1847 IMoniker_AddRef(pmkRest);
1849 else if (tempMk==NULL){
1851 /* we have an antimoniker after a simple moniker so we can make a simplification in this case */
1852 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1854 This->tabLastIndex--;
1856 else if (SUCCEEDED(res)){
1858 /* the non-generic composition was successful so we can make a simplification in this case */
1859 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1861 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1862 } else{
1863 for (i = 0; i < This->tabLastIndex; i++)
1864 IMoniker_Release(This->tabMoniker[i]);
1865 HeapFree(GetProcessHeap(), 0, This->tabMoniker);
1866 HeapFree(GetProcessHeap(), 0, This);
1867 return res;
1870 /* resize tabMoniker if needed */
1871 if (This->tabLastIndex==This->tabSize){
1872 IMoniker **tab_moniker = This->tabMoniker;
1874 This->tabSize+=BLOCK_TAB_SIZE;
1876 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1878 if (This->tabMoniker==NULL){
1879 for (i = 0; i < This->tabLastIndex; i++)
1880 IMoniker_Release(tab_moniker[i]);
1881 HeapFree(GetProcessHeap(), 0, tab_moniker);
1882 HeapFree(GetProcessHeap(), 0, This);
1883 return E_OUTOFMEMORY;
1887 else{
1889 /* add a composite moniker to the moniker table (do the same thing
1890 * for each moniker within the composite moniker as a simple moniker
1891 * (see above for how to add a simple moniker case) )
1893 IMoniker_Enum(pmkRest,TRUE,&enumMoniker);
1895 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1897 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk);
1899 if (res==MK_E_NEEDGENERIC){
1901 This->tabLastIndex++;
1903 else if (tempMk==NULL){
1905 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1906 IMoniker_Release(This->tabMoniker[This->tabLastIndex]);
1907 This->tabLastIndex--;
1909 else{
1911 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1913 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1916 if (This->tabLastIndex==This->tabSize){
1917 IMoniker **tab_moniker = This->tabMoniker;
1919 This->tabSize+=BLOCK_TAB_SIZE;
1921 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(This->tabMoniker[0]));
1923 if (This->tabMoniker==NULL){
1924 for (i = 0; i < This->tabLastIndex; i++)
1925 IMoniker_Release(tab_moniker[i]);
1926 HeapFree(GetProcessHeap(), 0, tab_moniker);
1927 HeapFree(GetProcessHeap(), 0, This);
1928 return E_OUTOFMEMORY;
1933 IEnumMoniker_Release(enumMoniker);
1936 /* only one moniker, then just return it */
1937 if (This->tabLastIndex == 1)
1939 *ppMoniker = This->tabMoniker[0];
1940 IMoniker_AddRef(*ppMoniker);
1941 IMoniker_Release(&This->IMoniker_iface);
1943 else
1944 *ppMoniker = &This->IMoniker_iface;
1946 return S_OK;
1949 /******************************************************************************
1950 * CreateGenericComposite [OLE32.@]
1951 ******************************************************************************/
1952 HRESULT WINAPI
1953 CreateGenericComposite(IMoniker *pmkFirst, IMoniker *pmkRest, IMoniker **ppmkComposite)
1955 IMoniker* moniker = 0;
1956 HRESULT hr = S_OK;
1958 TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite);
1960 if (ppmkComposite==NULL)
1961 return E_POINTER;
1963 *ppmkComposite=0;
1965 if (pmkFirst==NULL && pmkRest!=NULL){
1967 *ppmkComposite=pmkRest;
1968 IMoniker_AddRef(pmkRest);
1969 return S_OK;
1971 else if (pmkFirst!=NULL && pmkRest==NULL){
1972 *ppmkComposite=pmkFirst;
1973 IMoniker_AddRef(pmkFirst);
1974 return S_OK;
1976 else if (pmkFirst==NULL && pmkRest==NULL)
1977 return S_OK;
1979 hr = CompositeMonikerImpl_Construct(&moniker,pmkFirst,pmkRest);
1981 if (FAILED(hr))
1982 return hr;
1984 hr = IMoniker_QueryInterface(moniker,&IID_IMoniker,(void**)ppmkComposite);
1985 IMoniker_Release(moniker);
1987 return hr;
1990 /******************************************************************************
1991 * MonikerCommonPrefixWith [OLE32.@]
1992 ******************************************************************************/
1993 HRESULT WINAPI
1994 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1996 FIXME("(),stub!\n");
1997 return E_NOTIMPL;
2000 HRESULT WINAPI CompositeMoniker_CreateInstance(IClassFactory *iface,
2001 IUnknown *pUnk, REFIID riid, void **ppv)
2003 IMoniker* pMoniker;
2004 HRESULT hr;
2006 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
2008 *ppv = NULL;
2010 if (pUnk)
2011 return CLASS_E_NOAGGREGATION;
2013 hr = CompositeMonikerImpl_Construct(&pMoniker, NULL, NULL);
2015 if (SUCCEEDED(hr))
2017 hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
2018 IMoniker_Release(pMoniker);
2021 return hr;