1 /*
2 * CompositeMonikers implementation
3 *
4 * Copyright 1999 Noomen Hamza
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include <assert.h>
22 #include <stdarg.h>
23 #include <string.h>
24
25 #define COBJMACROS
26 #define NONAMELESSUNION
27 #define NONAMELESSSTRUCT
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "winerror.h"
33 #include "wine/debug.h"
34 #include "wine/unicode.h"
35 #include "ole2.h"
36 #include "moniker.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39
40 #define BLOCK_TAB_SIZE 5 /* represent the first size table and it's increment block size */
41
42 /* CompositeMoniker data structure */
43 typedef struct CompositeMonikerImpl{
44
45 const IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/
46
47 /* The ROT (RunningObjectTable implementation) uses the IROTData
48 * interface to test whether two monikers are equal. That's why IROTData
49 * interface is implemented by monikers.
50 */
51 const IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/
52
53 const IMarshalVtbl* lpvtblMarshal; /* VTable relative to the IMarshal interface.*/
54
55 LONG ref; /* reference counter for this object */
56
57 IMoniker** tabMoniker; /* dynamic table containing all components (monikers) of this composite moniker */
58
59 ULONG tabSize; /* size of tabMoniker */
60
61 ULONG tabLastIndex; /* first free index in tabMoniker */
62
63 } CompositeMonikerImpl;
64
65
66 /* EnumMoniker data structure */
67 typedef struct EnumMonikerImpl{
68
69 const IEnumMonikerVtbl *lpVtbl; /* VTable relative to the IEnumMoniker interface.*/
70
71 LONG ref; /* reference counter for this object */
72
73 IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
74
75 ULONG tabSize; /* size of tabMoniker */
76
77 ULONG currentPos; /* index pointer on the current moniker */
78
79 } EnumMonikerImpl;
80
81 static inline IMoniker *impl_from_IROTData( IROTData *iface )
82 {
83 return (IMoniker *)((char*)iface - FIELD_OFFSET(CompositeMonikerImpl, lpvtbl2));
84 }
85
86 static inline IMoniker *impl_from_IMarshal( IMarshal *iface )
87 {
88 return (IMoniker *)((char*)iface - FIELD_OFFSET(CompositeMonikerImpl, lpvtblMarshal));
89 }
90
91 static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk);
92
93 /*******************************************************************************
94 * CompositeMoniker_QueryInterface
95 *******************************************************************************/
96 static HRESULT WINAPI
97 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
98 {
99 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
100
101 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
102
103 /* Perform a sanity check on the parameters.*/
104 if ( (This==0) || (ppvObject==0) )
105 return E_INVALIDARG;
106
107 /* Initialize the return parameter */
108 *ppvObject = 0;
109
110 /* Compare the riid with the interface IDs implemented by this object.*/
111 if (IsEqualIID(&IID_IUnknown, riid) ||
112 IsEqualIID(&IID_IPersist, riid) ||
113 IsEqualIID(&IID_IPersistStream, riid) ||
114 IsEqualIID(&IID_IMoniker, riid)
115 )
116 *ppvObject = iface;
117 else if (IsEqualIID(&IID_IROTData, riid))
118 *ppvObject = (IROTData*)&(This->lpvtbl2);
119 else if (IsEqualIID(&IID_IMarshal, riid))
120 *ppvObject = (IROTData*)&(This->lpvtblMarshal);
121
122 /* Check that we obtained an interface.*/
123 if ((*ppvObject)==0)
124 return E_NOINTERFACE;
125
126 /* Query Interface always increases the reference count by one when it is successful */
127 IMoniker_AddRef(iface);
128
129 return S_OK;
130 }
131
132 /******************************************************************************
133 * CompositeMoniker_AddRef
134 ******************************************************************************/
135 static ULONG WINAPI
136 CompositeMonikerImpl_AddRef(IMoniker* iface)
137 {
138 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
139
140 TRACE("(%p)\n",This);
141
142 return InterlockedIncrement(&This->ref);
143 }
144
145 static void CompositeMonikerImpl_ReleaseMonikersInTable(CompositeMonikerImpl *This)
146 {
147 ULONG i;
148
149 for (i = 0; i < This->tabLastIndex; i++)
150 IMoniker_Release(This->tabMoniker[i]);
151
152 This->tabLastIndex = 0;
153 }
154
155 /******************************************************************************
156 * CompositeMoniker_Release
157 ******************************************************************************/
158 static ULONG WINAPI
159 CompositeMonikerImpl_Release(IMoniker* iface)
160 {
161 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
162 ULONG ref;
163
164 TRACE("(%p)\n",This);
165
166 ref = InterlockedDecrement(&This->ref);
167
168 /* destroy the object if there's no more reference on it */
169 if (ref == 0){
170
171 /* release all the components before destroying this object */
172 CompositeMonikerImpl_ReleaseMonikersInTable(This);
173
174 HeapFree(GetProcessHeap(),0,This->tabMoniker);
175 HeapFree(GetProcessHeap(),0,This);
176 }
177 return ref;
178 }
179
180 /******************************************************************************
181 * CompositeMoniker_GetClassID
182 ******************************************************************************/
183 static HRESULT WINAPI
184 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
185 {
186 TRACE("(%p,%p)\n",iface,pClassID);
187
188 if (pClassID==NULL)
189 return E_POINTER;
190
191 *pClassID = CLSID_CompositeMoniker;
192
193 return S_OK;
194 }
195
196 /******************************************************************************
197 * CompositeMoniker_IsDirty
198 ******************************************************************************/
199 static HRESULT WINAPI
200 CompositeMonikerImpl_IsDirty(IMoniker* iface)
201 {
202 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
203 method in the OLE-provided moniker interfaces always return S_FALSE because
204 their internal state never changes. */
205
206 TRACE("(%p)\n",iface);
207
208 return S_FALSE;
209 }
210
211 /******************************************************************************
212 * CompositeMoniker_Load
213 ******************************************************************************/
214 static HRESULT WINAPI
215 CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
216 {
217 HRESULT res;
218 DWORD moniker_count;
219 DWORD i;
220
221 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
222
223 TRACE("(%p,%p)\n",iface,pStm);
224
225 /* this function call OleLoadFromStream function for each moniker within this object */
226
227 res=IStream_Read(pStm,&moniker_count,sizeof(DWORD),NULL);
228 if (res != S_OK)
229 {
230 ERR("couldn't reading moniker count from stream\n");
231 return E_FAIL;
232 }
233
234 CompositeMonikerImpl_ReleaseMonikersInTable(This);
235
236 for (i = 0; i < moniker_count; i++)
237 {
238 res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
239 if (FAILED(res))
240 {
241 ERR("couldn't load moniker from stream, res = 0x%08x\n", res);
242 break;
243 }
244
245 /* resize the table if needed */
246 if (++This->tabLastIndex==This->tabSize){
247
248 This->tabSize+=BLOCK_TAB_SIZE;
249 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
250
251 if (This->tabMoniker==NULL)
252 return E_OUTOFMEMORY;
253 }
254 }
255
256 return res;
257 }
258
259 /******************************************************************************
260 * CompositeMoniker_Save
261 ******************************************************************************/
262 static HRESULT WINAPI
263 CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
264 {
265 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
266 HRESULT res;
267 IEnumMoniker *enumMk;
268 IMoniker *pmk;
269 DWORD moniker_count = This->tabLastIndex;
270
271 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
272
273 /* This function calls OleSaveToStream function for each moniker within
274 * this object.
275 * When I tested this function in windows, I usually found this constant
276 * at the beginning of the stream. I don't known why (there's no
277 * indication in the specification) !
278 */
279 res=IStream_Write(pStm,&moniker_count,sizeof(moniker_count),NULL);
280 if (FAILED(res)) return res;
281
282 IMoniker_Enum(iface,TRUE,&enumMk);
283
284 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
285
286 res=OleSaveToStream((IPersistStream*)pmk,pStm);
287
288 IMoniker_Release(pmk);
289
290 if (FAILED(res)){
291
292 IEnumMoniker_Release(enumMk);
293 return res;
294 }
295 }
296
297 IEnumMoniker_Release(enumMk);
298
299 return S_OK;
300 }
301
302 /******************************************************************************
303 * CompositeMoniker_GetSizeMax
304 ******************************************************************************/
305 static HRESULT WINAPI
306 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
307 {
308 IEnumMoniker *enumMk;
309 IMoniker *pmk;
310 ULARGE_INTEGER ptmpSize;
311
312 /* The sizeMax of this object is calculated by calling GetSizeMax on
313 * each moniker within this object then summing all returned values
314 */
315
316 TRACE("(%p,%p)\n",iface,pcbSize);
317
318 if (!pcbSize)
319 return E_POINTER;
320
321 pcbSize->QuadPart = sizeof(DWORD);
322
323 IMoniker_Enum(iface,TRUE,&enumMk);
324
325 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
326
327 IMoniker_GetSizeMax(pmk,&ptmpSize);
328
329 IMoniker_Release(pmk);
330
331 pcbSize->QuadPart = ptmpSize.QuadPart + sizeof(CLSID);
332 }
333
334 IEnumMoniker_Release(enumMk);
335
336 return S_OK;
337 }
338
339 /******************************************************************************
340 * CompositeMoniker_BindToObject
341 ******************************************************************************/
342 static HRESULT WINAPI
343 CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,
344 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
345 {
346 HRESULT res;
347 IRunningObjectTable *prot;
348 IMoniker *tempMk,*antiMk,*mostRigthMk;
349 IEnumMoniker *enumMoniker;
350
351 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
352
353 if (ppvResult==NULL)
354 return E_POINTER;
355
356 *ppvResult=0;
357 /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
358 /* object for the requested interface pointer. */
359 if(pmkToLeft==NULL){
360
361 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
362
363 if (SUCCEEDED(res)){
364
365 /* if the requested class was loaded before ! we don't need to reload it */
366 res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
367
368 if (res==S_OK)
369 return res;
370 }
371 }
372 else{
373 /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
374 /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
375
376 IMoniker_Enum(iface,FALSE,&enumMoniker);
377 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
378 IEnumMoniker_Release(enumMoniker);
379
380 res=CreateAntiMoniker(&antiMk);
381 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
382 IMoniker_Release(antiMk);
383
384 res=IMoniker_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult);
385
386 IMoniker_Release(tempMk);
387 IMoniker_Release(mostRigthMk);
388 }
389
390 return res;
391 }
392
393 /******************************************************************************
394 * CompositeMoniker_BindToStorage
395 ******************************************************************************/
396 static HRESULT WINAPI
397 CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
398 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
399 {
400 HRESULT res;
401 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk;
402 IEnumMoniker *enumMoniker;
403
404 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
405
406 *ppvResult=0;
407
408 /* This method recursively calls BindToStorage on the rightmost component of the composite, */
409 /* passing the rest of the composite as the pmkToLeft parameter for that call. */
410
411 if (pmkToLeft)
412 {
413 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
414 if (FAILED(res)) return res;
415 }
416 else
417 leftMk = iface;
418
419 IMoniker_Enum(iface, FALSE, &enumMoniker);
420 IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL);
421 IEnumMoniker_Release(enumMoniker);
422
423 res = CreateAntiMoniker(&antiMk);
424 if (FAILED(res)) return res;
425 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
426 if (FAILED(res)) return res;
427 IMoniker_Release(antiMk);
428
429 res = IMoniker_BindToStorage(mostRigthMk, pbc, tempMk, riid, ppvResult);
430
431 IMoniker_Release(tempMk);
432
433 IMoniker_Release(mostRigthMk);
434
435 if (pmkToLeft)
436 IMoniker_Release(leftMk);
437
438 return res;
439 }
440
441 /******************************************************************************
442 * CompositeMoniker_Reduce
443 ******************************************************************************/
444 static HRESULT WINAPI
445 CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
446 IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
447 {
448 HRESULT res;
449 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk;
450 IEnumMoniker *enumMoniker;
451
452 TRACE("(%p,%p,%d,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
453
454 if (ppmkReduced==NULL)
455 return E_POINTER;
456
457 /* This method recursively calls Reduce for each of its component monikers. */
458
459 if (ppmkToLeft==NULL){
460
461 IMoniker_Enum(iface,FALSE,&enumMoniker);
462 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
463 IEnumMoniker_Release(enumMoniker);
464
465 res=CreateAntiMoniker(&antiMk);
466 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
467 IMoniker_Release(antiMk);
468
469 return IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
470 }
471 else if (*ppmkToLeft==NULL)
472
473 return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);
474
475 else{
476
477 /* separate the composite moniker in to left and right moniker */
478 IMoniker_Enum(iface,FALSE,&enumMoniker);
479 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
480 IEnumMoniker_Release(enumMoniker);
481
482 res=CreateAntiMoniker(&antiMk);
483 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
484 IMoniker_Release(antiMk);
485
486 /* If any of the components reduces itself, the method returns S_OK and passes back a composite */
487 /* of the reduced components */
488 if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) &&
489 IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk)
490 )
491
492 return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced);
493
494 else{
495 /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
496
497 IMoniker_AddRef(iface);
498
499 *ppmkReduced=iface;
500
501 return MK_S_REDUCED_TO_SELF;
502 }
503 }
504 }
505
506 /******************************************************************************
507 * CompositeMoniker_ComposeWith
508 ******************************************************************************/
509 static HRESULT WINAPI
510 CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
511 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
512 {
513 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
514
515 if ((ppmkComposite==NULL)||(pmkRight==NULL))
516 return E_POINTER;
517
518 *ppmkComposite=0;
519
520 /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */
521 /* otherwise, the method returns the result of combining the two monikers by calling the */
522 /* CreateGenericComposite function */
523
524 if (fOnlyIfNotGeneric)
525 return MK_E_NEEDGENERIC;
526
527 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
528 }
529
530 /******************************************************************************
531 * CompositeMoniker_Enum
532 ******************************************************************************/
533 static HRESULT WINAPI
534 CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
535 {
536 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
537
538 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
539
540 if (ppenumMoniker == NULL)
541 return E_POINTER;
542
543 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);
544 }
545
546 /******************************************************************************
547 * CompositeMoniker_IsEqual
548 ******************************************************************************/
549 static HRESULT WINAPI
550 CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
551 {
552 IEnumMoniker *enumMoniker1,*enumMoniker2;
553 IMoniker *tempMk1,*tempMk2;
554 HRESULT res1,res2,res;
555
556 TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
557
558 if (pmkOtherMoniker==NULL)
559 return S_FALSE;
560
561 /* This method returns S_OK if the components of both monikers are equal when compared in the */
562 /* left-to-right order.*/
563 IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);
564
565 if (enumMoniker1==NULL)
566 return S_FALSE;
567
568 IMoniker_Enum(iface,TRUE,&enumMoniker2);
569
570 while(1){
571
572 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
573 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
574
575 if((res1==S_OK)&&(res2==S_OK)){
576
577 if(IMoniker_IsEqual(tempMk1,tempMk2)==S_FALSE){
578 res= S_FALSE;
579 break;
580 }
581 else
582 continue;
583 }
584 else if ( (res1==S_FALSE) && (res2==S_FALSE) ){
585 res = S_OK;
586 break;
587 }
588 else{
589 res = S_FALSE;
590 break;
591 }
592
593 if (res1==S_OK)
594 IMoniker_Release(tempMk1);
595
596 if (res2==S_OK)
597 IMoniker_Release(tempMk2);
598 }
599
600 IEnumMoniker_Release(enumMoniker1);
601 IEnumMoniker_Release(enumMoniker2);
602
603 return res;
604 }
605 /******************************************************************************
606 * CompositeMoniker_Hash
607 ******************************************************************************/
608 static HRESULT WINAPI
609 CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
610 {
611 IEnumMoniker *enumMoniker;
612 IMoniker *tempMk;
613 HRESULT res;
614 DWORD tempHash;
615
616 TRACE("(%p,%p)\n",iface,pdwHash);
617
618 if (pdwHash==NULL)
619 return E_POINTER;
620
621 res = IMoniker_Enum(iface,TRUE,&enumMoniker);
622 if(FAILED(res))
623 return res;
624
625 *pdwHash = 0;
626
627 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
628 res = IMoniker_Hash(tempMk, &tempHash);
629 if(FAILED(res))
630 break;
631 *pdwHash = *pdwHash ^ tempHash;
632
633 IMoniker_Release(tempMk);
634 }
635
636 IEnumMoniker_Release(enumMoniker);
637
638 return res;
639 }
640
641 /******************************************************************************
642 * CompositeMoniker_IsRunning
643 ******************************************************************************/
644 static HRESULT WINAPI
645 CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc,
646 IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
647 {
648 IRunningObjectTable* rot;
649 HRESULT res;
650 IMoniker *tempMk,*antiMk,*mostRigthMk;
651 IEnumMoniker *enumMoniker;
652
653 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
654
655 /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/
656 if (pmkToLeft!=NULL){
657
658 CreateGenericComposite(pmkToLeft,iface,&tempMk);
659
660 res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);
661
662 IMoniker_Release(tempMk);
663
664 return res;
665 }
666 else
667 /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */
668 /* to this moniker */
669
670 if (pmkNewlyRunning!=NULL)
671
672 if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)
673 return S_OK;
674
675 else
676 return S_FALSE;
677
678 else{
679
680 if (pbc==NULL)
681 return E_POINTER;
682
683 /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */
684 /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */
685 /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */
686 /* the composite as the pmkToLeft parameter for that call. */
687
688 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
689
690 if (FAILED(res))
691 return res;
692
693 res = IRunningObjectTable_IsRunning(rot,iface);
694 IRunningObjectTable_Release(rot);
695
696 if(res==S_OK)
697 return S_OK;
698
699 else{
700
701 IMoniker_Enum(iface,FALSE,&enumMoniker);
702 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
703 IEnumMoniker_Release(enumMoniker);
704
705 res=CreateAntiMoniker(&antiMk);
706 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
707 IMoniker_Release(antiMk);
708
709 res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning);
710
711 IMoniker_Release(tempMk);
712 IMoniker_Release(mostRigthMk);
713
714 return res;
715 }
716 }
717 }
718
719 /******************************************************************************
720 * CompositeMoniker_GetTimeOfLastChange
721 ******************************************************************************/
722 static HRESULT WINAPI
723 CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
724 IMoniker* pmkToLeft, FILETIME* pCompositeTime)
725 {
726 HRESULT res;
727 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftMk;
728 IEnumMoniker *enumMoniker;
729
730 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);
731
732 if (pCompositeTime==NULL)
733 return E_INVALIDARG;
734
735 /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to */
736 /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */
737 /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */
738 /* of the composite as the pmkToLeft parameter for that call. */
739 if (pmkToLeft)
740 {
741 IRunningObjectTable* rot;
742
743 res = IMoniker_ComposeWith(pmkToLeft, iface, FALSE, &leftMk);
744
745 res = IBindCtx_GetRunningObjectTable(pbc,&rot);
746 if (FAILED(res))
747 {
748 IMoniker_Release(leftMk);
749 return res;
750 }
751
752 if (IRunningObjectTable_GetTimeOfLastChange(rot,leftMk,pCompositeTime)==S_OK)
753 {
754 IMoniker_Release(leftMk);
755 return res;
756 }
757 }
758 else
759 leftMk = iface;
760
761 IMoniker_Enum(iface, FALSE, &enumMoniker);
762 IEnumMoniker_Next(enumMoniker, 1, &mostRigthMk, NULL);
763 IEnumMoniker_Release(enumMoniker);
764
765 res = CreateAntiMoniker(&antiMk);
766 res = IMoniker_ComposeWith(leftMk, antiMk, 0, &tempMk);
767 IMoniker_Release(antiMk);
768
769 res = IMoniker_GetTimeOfLastChange(mostRigthMk, pbc, tempMk, pCompositeTime);
770
771 IMoniker_Release(tempMk);
772 IMoniker_Release(mostRigthMk);
773
774 if (pmkToLeft)
775 IMoniker_Release(leftMk);
776
777 return res;
778 }
779
780 /******************************************************************************
781 * CompositeMoniker_Inverse
782 ******************************************************************************/
783 static HRESULT WINAPI
784 CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
785 {
786 HRESULT res;
787 IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk;
788 IEnumMoniker *enumMoniker;
789
790 TRACE("(%p,%p)\n",iface,ppmk);
791
792 if (ppmk==NULL)
793 return E_POINTER;
794
795 /* This method returns a composite moniker that consists of the inverses of each of the components */
796 /* of the original composite, stored in reverse order */
797
798 res=CreateAntiMoniker(&antiMk);
799 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
800 IMoniker_Release(antiMk);
801
802 if (tempMk==NULL)
803
804 return IMoniker_Inverse(iface,ppmk);
805
806 else{
807
808 IMoniker_Enum(iface,FALSE,&enumMoniker);
809 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
810 IEnumMoniker_Release(enumMoniker);
811
812 IMoniker_Inverse(mostRigthMk,&mostRigthInvMk);
813 CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);
814
815 res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk);
816
817 IMoniker_Release(tempMk);
818 IMoniker_Release(mostRigthMk);
819 IMoniker_Release(tempInvMk);
820 IMoniker_Release(mostRigthInvMk);
821
822 return res;
823 }
824 }
825
826 /******************************************************************************
827 * CompositeMoniker_CommonPrefixWith
828 ******************************************************************************/
829 static HRESULT WINAPI
830 CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,
831 IMoniker** ppmkPrefix)
832 {
833 DWORD mkSys;
834 HRESULT res1,res2;
835 IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
836 IEnumMoniker *enumMoniker1,*enumMoniker2;
837 ULONG i,nbCommonMk=0;
838
839 /* If the other moniker is a composite, this method compares the components of each composite from left */
840 /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
841 /* of the leftmost components were common to both monikers. */
842
843 if (ppmkPrefix==NULL)
844 return E_POINTER;
845
846 *ppmkPrefix=0;
847
848 if (pmkOther==NULL)
849 return MK_E_NOPREFIX;
850
851 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
852
853 if((mkSys==MKSYS_GENERICCOMPOSITE)){
854
855 IMoniker_Enum(iface,TRUE,&enumMoniker1);
856 IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
857
858 while(1){
859
860 res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
861 res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
862
863 if ((res1==S_FALSE) && (res2==S_FALSE)){
864
865 /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
866 *ppmkPrefix=iface;
867 IMoniker_AddRef(iface);
868 return MK_S_US;
869 }
870 else if ((res1==S_OK) && (res2==S_OK)){
871
872 if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
873
874 nbCommonMk++;
875
876 else
877 break;
878
879 }
880 else if (res1==S_OK){
881
882 /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
883 /* ppmkPrefix to the other moniker. */
884 *ppmkPrefix=pmkOther;
885 return MK_S_HIM;
886 }
887 else{
888 /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
889 /* to this moniker. */
890 *ppmkPrefix=iface;
891 return MK_S_ME;
892 }
893 }
894
895 IEnumMoniker_Release(enumMoniker1);
896 IEnumMoniker_Release(enumMoniker2);
897
898 /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
899 if (nbCommonMk==0)
900 return MK_E_NOPREFIX;
901
902 IEnumMoniker_Reset(enumMoniker1);
903
904 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
905
906 /* if we have more than one common moniker the result will be a composite moniker */
907 if (nbCommonMk>1){
908
909 /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
910 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
911 CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
912 IMoniker_Release(tempMk1);
913 IMoniker_Release(tempMk2);
914
915 /* compose all common monikers in a composite moniker */
916 for(i=0;i<nbCommonMk;i++){
917
918 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
919
920 CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
921
922 IMoniker_Release(*ppmkPrefix);
923
924 IMoniker_Release(tempMk1);
925
926 *ppmkPrefix=tempMk2;
927 }
928 return S_OK;
929 }
930 else{
931 /* if we have only one common moniker the result will be a simple moniker which is the most-left one*/
932 *ppmkPrefix=tempMk1;
933
934 return