87c483ad4cea6c2dce0479572d26609ee8cc148f
[reactos.git] / reactos / lib / ole32 / compositemoniker.c
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 static const CLSID CLSID_CompositeMoniker = {
41 0x309, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}
42 };
43
44 #define BLOCK_TAB_SIZE 5 /* represent the first size table and it's increment block size */
45
46 /* CompositeMoniker data structure */
47 typedef struct CompositeMonikerImpl{
48
49 const IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/
50
51 /* The ROT (RunningObjectTable implementation) uses the IROTData
52 * interface to test whether two monikers are equal. That's why IROTData
53 * interface is implemented by monikers.
54 */
55 const IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/
56
57 LONG ref; /* reference counter for this object */
58
59 IMoniker** tabMoniker; /* dynamaic table containing all components (monikers) of this composite moniker */
60
61 ULONG tabSize; /* size of tabMoniker */
62
63 ULONG tabLastIndex; /* first free index in tabMoniker */
64
65 } CompositeMonikerImpl;
66
67
68 /* EnumMoniker data structure */
69 typedef struct EnumMonikerImpl{
70
71 const IEnumMonikerVtbl *lpVtbl; /* VTable relative to the IEnumMoniker interface.*/
72
73 LONG ref; /* reference counter for this object */
74
75 IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */
76
77 ULONG tabSize; /* size of tabMoniker */
78
79 ULONG currentPos; /* index pointer on the current moniker */
80
81 } EnumMonikerImpl;
82
83
84 static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk);
85
86 /*******************************************************************************
87 * CompositeMoniker_QueryInterface
88 *******************************************************************************/
89 static HRESULT WINAPI
90 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
91 {
92 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
93
94 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
95
96 /* Perform a sanity check on the parameters.*/
97 if ( (This==0) || (ppvObject==0) )
98 return E_INVALIDARG;
99
100 /* Initialize the return parameter */
101 *ppvObject = 0;
102
103 /* Compare the riid with the interface IDs implemented by this object.*/
104 if (IsEqualIID(&IID_IUnknown, riid) ||
105 IsEqualIID(&IID_IPersist, riid) ||
106 IsEqualIID(&IID_IPersistStream, riid) ||
107 IsEqualIID(&IID_IMoniker, riid)
108 )
109 *ppvObject = iface;
110 else if (IsEqualIID(&IID_IROTData, riid))
111 *ppvObject = (IROTData*)&(This->lpvtbl2);
112
113 /* Check that we obtained an interface.*/
114 if ((*ppvObject)==0)
115 return E_NOINTERFACE;
116
117 /* Query Interface always increases the reference count by one when it is successful */
118 IMoniker_AddRef(iface);
119
120 return S_OK;
121 }
122
123 /******************************************************************************
124 * CompositeMoniker_AddRef
125 ******************************************************************************/
126 static ULONG WINAPI
127 CompositeMonikerImpl_AddRef(IMoniker* iface)
128 {
129 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
130
131 TRACE("(%p)\n",This);
132
133 return InterlockedIncrement(&This->ref);
134 }
135
136 /******************************************************************************
137 * CompositeMoniker_Release
138 ******************************************************************************/
139 static ULONG WINAPI
140 CompositeMonikerImpl_Release(IMoniker* iface)
141 {
142 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
143 ULONG i;
144 ULONG ref;
145
146 TRACE("(%p)\n",This);
147
148 ref = InterlockedDecrement(&This->ref);
149
150 /* destroy the object if there's no more reference on it */
151 if (ref == 0){
152
153 /* release all the components before destroying this object */
154 for (i=0;i<This->tabLastIndex;i++)
155 IMoniker_Release(This->tabMoniker[i]);
156
157 HeapFree(GetProcessHeap(),0,This->tabMoniker);
158 HeapFree(GetProcessHeap(),0,This);
159 }
160 return ref;
161 }
162
163 /******************************************************************************
164 * CompositeMoniker_GetClassID
165 ******************************************************************************/
166 static HRESULT WINAPI
167 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
168 {
169 TRACE("(%p,%p),stub!\n",iface,pClassID);
170
171 if (pClassID==NULL)
172 return E_POINTER;
173
174 *pClassID = CLSID_CompositeMoniker;
175
176 return S_OK;
177 }
178
179 /******************************************************************************
180 * CompositeMoniker_IsDirty
181 ******************************************************************************/
182 static HRESULT WINAPI
183 CompositeMonikerImpl_IsDirty(IMoniker* iface)
184 {
185 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
186 method in the OLE-provided moniker interfaces always return S_FALSE because
187 their internal state never changes. */
188
189 TRACE("(%p)\n",iface);
190
191 return S_FALSE;
192 }
193
194 /******************************************************************************
195 * CompositeMoniker_Load
196 ******************************************************************************/
197 static HRESULT WINAPI
198 CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm)
199 {
200 HRESULT res;
201 DWORD constant;
202 CLSID clsid;
203 WCHAR string[1]={0};
204
205 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
206
207 TRACE("(%p,%p)\n",iface,pStm);
208
209 /* this function call OleLoadFromStream function for each moniker within this object */
210
211 /* read the a constant written by CompositeMonikerImpl_Save (see CompositeMonikerImpl_Save for more details)*/
212 res=IStream_Read(pStm,&constant,sizeof(DWORD),NULL);
213
214 if (SUCCEEDED(res)&& constant!=3)
215 return E_FAIL;
216
217 while(1){
218 #if 0
219 res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]);
220 #endif
221 res=ReadClassStm(pStm,&clsid);
222 DPRINTF("res=%ld",res);
223 if (FAILED(res))
224 break;
225
226 if (IsEqualIID(&clsid,&CLSID_FileMoniker)){
227 res=CreateFileMoniker(string,&This->tabMoniker[This->tabLastIndex]);
228 if (FAILED(res))
229 break;
230 res=IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);
231 if (FAILED(res))
232 break;
233 }
234 else if (IsEqualIID(&clsid,&CLSID_ItemMoniker)){
235 CreateItemMoniker(string,string,&This->tabMoniker[This->tabLastIndex]);
236 if (res!=S_OK)
237 break;
238 IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);
239 if (FAILED(res))
240 break;
241 }
242 else if (IsEqualIID(&clsid,&CLSID_AntiMoniker)){
243 CreateAntiMoniker(&This->tabMoniker[This->tabLastIndex]);
244 if (FAILED(res))
245 break;
246 IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm);
247 if (FAILED(res))
248 break;
249 }
250 else if (IsEqualIID(&clsid,&CLSID_CompositeMoniker))
251 return E_FAIL;
252
253 else
254 {
255 FIXME("()\n");
256 /* FIXME: To whoever wrote this code: It's either return or break. it cannot be both! */
257 break;
258 return E_NOTIMPL;
259 }
260
261 /* resize the table if needed */
262 if (++This->tabLastIndex==This->tabSize){
263
264 This->tabSize+=BLOCK_TAB_SIZE;
265 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
266
267 if (This->tabMoniker==NULL)
268 return E_OUTOFMEMORY;
269 }
270 }
271
272 return res;
273 }
274
275 /******************************************************************************
276 * CompositeMoniker_Save
277 ******************************************************************************/
278 static HRESULT WINAPI
279 CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty)
280 {
281 HRESULT res;
282 IEnumMoniker *enumMk;
283 IMoniker *pmk;
284 DWORD constant=3;
285
286 TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty);
287
288 /* This function calls OleSaveToStream function for each moniker within
289 * this object.
290 * When I tested this function in windows, I usually found this constant
291 * at the beginning of the stream. I don't known why (there's no
292 * indication in the specification) !
293 */
294 res=IStream_Write(pStm,&constant,sizeof(constant),NULL);
295
296 IMoniker_Enum(iface,TRUE,&enumMk);
297
298 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
299
300 res=OleSaveToStream((IPersistStream*)pmk,pStm);
301
302 IMoniker_Release(pmk);
303
304 if (FAILED(res)){
305
306 IEnumMoniker_Release(pmk);
307 return res;
308 }
309 }
310
311 IEnumMoniker_Release(enumMk);
312
313 return S_OK;
314 }
315
316 /******************************************************************************
317 * CompositeMoniker_GetSizeMax
318 ******************************************************************************/
319 static HRESULT WINAPI
320 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
321 {
322 IEnumMoniker *enumMk;
323 IMoniker *pmk;
324 ULARGE_INTEGER ptmpSize;
325
326 /* The sizeMax of this object is calculated by calling GetSizeMax on
327 * each moniker within this object then summing all returned values
328 */
329
330 TRACE("(%p,%p)\n",iface,pcbSize);
331
332 if (pcbSize!=NULL)
333 return E_POINTER;
334
335 pcbSize->u.LowPart =0;
336 pcbSize->u.HighPart=0;
337
338 IMoniker_Enum(iface,TRUE,&enumMk);
339
340 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)){
341
342 IMoniker_GetSizeMax(pmk,&ptmpSize);
343
344 IMoniker_Release(pmk);
345
346 pcbSize->u.LowPart +=ptmpSize.u.LowPart;
347 pcbSize->u.HighPart+=ptmpSize.u.HighPart;
348 }
349
350 IEnumMoniker_Release(enumMk);
351
352 return S_OK;
353 }
354
355 /******************************************************************************
356 * CompositeMoniker_BindToObject
357 ******************************************************************************/
358 static HRESULT WINAPI
359 CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc,
360 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
361 {
362 HRESULT res;
363 IRunningObjectTable *prot;
364 IMoniker *tempMk,*antiMk,*mostRigthMk;
365 IEnumMoniker *enumMoniker;
366
367 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
368
369 if (ppvResult==NULL)
370 return E_POINTER;
371
372 *ppvResult=0;
373 /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */
374 /* object for the requested interface pointer. */
375 if(pmkToLeft==NULL){
376
377 res=IBindCtx_GetRunningObjectTable(pbc,&prot);
378
379 if (SUCCEEDED(res)){
380
381 /* if the requested class was loaded before ! we don't need to reload it */
382 res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult);
383
384 if (res==S_OK)
385 return res;
386 }
387 }
388 else{
389 /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */
390 /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */
391
392 IMoniker_Enum(iface,FALSE,&enumMoniker);
393 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
394 IEnumMoniker_Release(enumMoniker);
395
396 res=CreateAntiMoniker(&antiMk);
397 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
398 IMoniker_Release(antiMk);
399
400 res=CompositeMonikerImpl_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult);
401
402 IMoniker_Release(tempMk);
403 IMoniker_Release(mostRigthMk);
404 }
405
406 return res;
407 }
408
409 /******************************************************************************
410 * CompositeMoniker_BindToStorage
411 ******************************************************************************/
412 static HRESULT WINAPI
413 CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc,
414 IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult)
415 {
416 HRESULT res;
417 IMoniker *tempMk,*antiMk,*mostRigthMk;
418 IEnumMoniker *enumMoniker;
419
420 TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult);
421
422 *ppvResult=0;
423
424 /* This method recursively calls BindToStorage on the rightmost component of the composite, */
425 /* passing the rest of the composite as the pmkToLeft parameter for that call. */
426
427 if (pmkToLeft!=NULL){
428
429 IMoniker_Enum(iface,FALSE,&enumMoniker);
430 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
431 IEnumMoniker_Release(enumMoniker);
432
433 res=CreateAntiMoniker(&antiMk);
434 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
435 IMoniker_Release(antiMk);
436
437 res=CompositeMonikerImpl_BindToStorage(mostRigthMk,pbc,tempMk,riid,ppvResult);
438
439 IMoniker_Release(tempMk);
440
441 IMoniker_Release(mostRigthMk);
442
443 return res;
444 }
445 else
446 return IMoniker_BindToStorage(iface,pbc,NULL,riid,ppvResult);
447 }
448
449 /******************************************************************************
450 * CompositeMoniker_Reduce
451 ******************************************************************************/
452 static HRESULT WINAPI
453 CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar,
454 IMoniker** ppmkToLeft, IMoniker** ppmkReduced)
455 {
456 HRESULT res;
457 IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk;
458 IEnumMoniker *enumMoniker;
459
460 TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced);
461
462 if (ppmkReduced==NULL)
463 return E_POINTER;
464
465 /* This method recursively calls Reduce for each of its component monikers. */
466
467 if (ppmkToLeft==NULL){
468
469 IMoniker_Enum(iface,FALSE,&enumMoniker);
470 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
471 IEnumMoniker_Release(enumMoniker);
472
473 res=CreateAntiMoniker(&antiMk);
474 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
475 IMoniker_Release(antiMk);
476
477 return CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced);
478 }
479 else if (*ppmkToLeft==NULL)
480
481 return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced);
482
483 else{
484
485 /* separate the composite moniker in to left and right moniker */
486 IMoniker_Enum(iface,FALSE,&enumMoniker);
487 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
488 IEnumMoniker_Release(enumMoniker);
489
490 res=CreateAntiMoniker(&antiMk);
491 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
492 IMoniker_Release(antiMk);
493
494 /* If any of the components reduces itself, the method returns S_OK and passes back a composite */
495 /* of the reduced components */
496 if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) &&
497 CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk)
498 )
499
500 return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced);
501
502 else{
503 /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/
504
505 IMoniker_AddRef(iface);
506
507 *ppmkReduced=iface;
508
509 return MK_S_REDUCED_TO_SELF;
510 }
511 }
512 }
513
514 /******************************************************************************
515 * CompositeMoniker_ComposeWith
516 ******************************************************************************/
517 static HRESULT WINAPI
518 CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight,
519 BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite)
520 {
521 TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite);
522
523 if ((ppmkComposite==NULL)||(pmkRight==NULL))
524 return E_POINTER;
525
526 *ppmkComposite=0;
527
528 /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */
529 /* otherwise, the method returns the result of combining the two monikers by calling the */
530 /* CreateGenericComposite function */
531
532 if (fOnlyIfNotGeneric)
533 return MK_E_NEEDGENERIC;
534
535 return CreateGenericComposite(iface,pmkRight,ppmkComposite);
536 }
537
538 /******************************************************************************
539 * CompositeMoniker_Enum
540 ******************************************************************************/
541 static HRESULT WINAPI
542 CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker)
543 {
544 CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface;
545
546 TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker);
547
548 if (ppenumMoniker == NULL)
549 return E_POINTER;
550
551 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker);
552 }
553
554 /******************************************************************************
555 * CompositeMoniker_IsEqual
556 ******************************************************************************/
557 static HRESULT WINAPI
558 CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker)
559 {
560 IEnumMoniker *enumMoniker1,*enumMoniker2;
561 IMoniker *tempMk1,*tempMk2;
562 HRESULT res1,res2,res;
563
564 TRACE("(%p,%p)\n",iface,pmkOtherMoniker);
565
566 if (pmkOtherMoniker==NULL)
567 return S_FALSE;
568
569 /* This method returns S_OK if the components of both monikers are equal when compared in the */
570 /* left-to-right order.*/
571 IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1);
572
573 if (enumMoniker1==NULL)
574 return S_FALSE;
575
576 IMoniker_Enum(iface,TRUE,&enumMoniker2);
577
578 while(1){
579
580 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
581 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
582
583 if((res1==S_OK)&&(res2==S_OK)){
584
585 if(IMoniker_IsEqual(tempMk1,tempMk2)==S_FALSE){
586 res= S_FALSE;
587 break;
588 }
589 else
590 continue;
591 }
592 else if ( (res1==S_FALSE) && (res2==S_FALSE) ){
593 res = S_OK;
594 break;
595 }
596 else{
597 res = S_FALSE;
598 break;
599 }
600
601 if (res1==S_OK)
602 IMoniker_Release(tempMk1);
603
604 if (res2==S_OK)
605 IMoniker_Release(tempMk2);
606 }
607
608 IEnumMoniker_Release(enumMoniker1);
609 IEnumMoniker_Release(enumMoniker2);
610
611 return res;
612 }
613 /******************************************************************************
614 * CompositeMoniker_Hash
615 ******************************************************************************/
616 static HRESULT WINAPI
617 CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash)
618 {
619 IEnumMoniker *enumMoniker;
620 IMoniker *tempMk;
621 HRESULT res;
622 DWORD tempHash;
623
624 TRACE("(%p,%p)\n",iface,pdwHash);
625
626 if (pdwHash==NULL)
627 return E_POINTER;
628
629 res = IMoniker_Enum(iface,TRUE,&enumMoniker);
630 if(FAILED(res))
631 return res;
632
633 while(1){
634 res=IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL);
635 if(FAILED(res))
636 break;
637
638 res = IMoniker_Hash(tempMk, &tempHash);
639 if(FAILED(res))
640 break;
641 *pdwHash = (*pdwHash * 37) + tempHash;
642
643 IMoniker_Release(tempMk);
644 }
645
646 IEnumMoniker_Release(enumMoniker);
647
648 return res;
649 }
650
651 /******************************************************************************
652 * CompositeMoniker_IsRunning
653 ******************************************************************************/
654 static HRESULT WINAPI
655 CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc,
656 IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning)
657 {
658 IRunningObjectTable* rot;
659 HRESULT res;
660 IMoniker *tempMk,*antiMk,*mostRigthMk;
661 IEnumMoniker *enumMoniker;
662
663 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning);
664
665 /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/
666 if (pmkToLeft!=NULL){
667
668 CreateGenericComposite(pmkToLeft,iface,&tempMk);
669
670 res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning);
671
672 IMoniker_Release(tempMk);
673
674 return res;
675 }
676 else
677 /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */
678 /* to this moniker */
679
680 if (pmkNewlyRunning!=NULL)
681
682 if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK)
683 return S_OK;
684
685 else
686 return S_FALSE;
687
688 else{
689
690 if (pbc==NULL)
691 return E_POINTER;
692
693 /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */
694 /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */
695 /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */
696 /* the composite as the pmkToLeft parameter for that call. */
697
698 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
699
700 if (FAILED(res))
701 return res;
702
703 res = IRunningObjectTable_IsRunning(rot,iface);
704 IRunningObjectTable_Release(rot);
705
706 if(res==S_OK)
707 return S_OK;
708
709 else{
710
711 IMoniker_Enum(iface,FALSE,&enumMoniker);
712 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
713 IEnumMoniker_Release(enumMoniker);
714
715 res=CreateAntiMoniker(&antiMk);
716 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
717 IMoniker_Release(antiMk);
718
719 res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning);
720
721 IMoniker_Release(tempMk);
722 IMoniker_Release(mostRigthMk);
723
724 return res;
725 }
726 }
727 }
728
729 /******************************************************************************
730 * CompositeMoniker_GetTimeOfLastChange
731 ******************************************************************************/
732 static HRESULT WINAPI
733 CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc,
734 IMoniker* pmkToLeft, FILETIME* pCompositeTime)
735 {
736 IRunningObjectTable* rot;
737 HRESULT res;
738 IMoniker *tempMk,*antiMk,*mostRigthMk;
739 IEnumMoniker *enumMoniker;
740
741 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime);
742
743 if (pCompositeTime==NULL)
744 return E_INVALIDARG;
745
746 /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to */
747 /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */
748 /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */
749 /* of the composite as the pmkToLeft parameter for that call. */
750 if (pmkToLeft!=NULL){
751
752 res=CreateGenericComposite(pmkToLeft,iface,&tempMk);
753
754 res=IBindCtx_GetRunningObjectTable(pbc,&rot);
755
756 if (FAILED(res))
757 return res;
758
759 if (IRunningObjectTable_GetTimeOfLastChange(rot,tempMk,pCompositeTime)==S_OK)
760 return res;
761 else
762
763 IMoniker_Enum(iface,FALSE,&enumMoniker);
764 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
765 IEnumMoniker_Release(enumMoniker);
766
767 res=CreateAntiMoniker(&antiMk);
768 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
769 IMoniker_Release(antiMk);
770
771 res=CompositeMonikerImpl_GetTimeOfLastChange(mostRigthMk,pbc,tempMk,pCompositeTime);
772
773 IMoniker_Release(tempMk);
774 IMoniker_Release(mostRigthMk);
775
776 return res;
777 }
778 else
779 return IMoniker_GetTimeOfLastChange(iface,pbc,NULL,pCompositeTime);
780 }
781
782 /******************************************************************************
783 * CompositeMoniker_Inverse
784 ******************************************************************************/
785 static HRESULT WINAPI
786 CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk)
787 {
788 HRESULT res;
789 IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk;
790 IEnumMoniker *enumMoniker;
791
792 TRACE("(%p,%p)\n",iface,ppmk);
793
794 if (ppmk==NULL)
795 return E_POINTER;
796
797 /* This method returns a composite moniker that consists of the inverses of each of the components */
798 /* of the original composite, stored in reverse order */
799
800 res=CreateAntiMoniker(&antiMk);
801 res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
802 IMoniker_Release(antiMk);
803
804 if (tempMk==NULL)
805
806 return IMoniker_Inverse(iface,ppmk);
807
808 else{
809
810 IMoniker_Enum(iface,FALSE,&enumMoniker);
811 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
812 IEnumMoniker_Release(enumMoniker);
813
814 IMoniker_Inverse(mostRigthMk,&mostRigthInvMk);
815 CompositeMonikerImpl_Inverse(tempMk,&tempInvMk);
816
817 res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk);
818
819 IMoniker_Release(tempMk);
820 IMoniker_Release(mostRigthMk);
821 IMoniker_Release(tempInvMk);
822 IMoniker_Release(mostRigthInvMk);
823
824 return res;
825 }
826 }
827
828 /******************************************************************************
829 * CompositeMoniker_CommonPrefixWith
830 ******************************************************************************/
831 static HRESULT WINAPI
832 CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther,
833 IMoniker** ppmkPrefix)
834 {
835 DWORD mkSys;
836 HRESULT res1,res2;
837 IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2;
838 IEnumMoniker *enumMoniker1,*enumMoniker2;
839 ULONG i,nbCommonMk=0;
840
841 /* If the other moniker is a composite, this method compares the components of each composite from left */
842 /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
843 /* of the leftmost components were common to both monikers. */
844
845 if (ppmkPrefix==NULL)
846 return E_POINTER;
847
848 *ppmkPrefix=0;
849
850 if (pmkOther==NULL)
851 return MK_E_NOPREFIX;
852
853 IMoniker_IsSystemMoniker(pmkOther,&mkSys);
854
855 if((mkSys==MKSYS_GENERICCOMPOSITE)){
856
857 IMoniker_Enum(iface,TRUE,&enumMoniker1);
858 IMoniker_Enum(pmkOther,TRUE,&enumMoniker2);
859
860 while(1){
861
862 res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
863 res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL);
864
865 if ((res1==S_FALSE) && (res2==S_FALSE)){
866
867 /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/
868 *ppmkPrefix=iface;
869 IMoniker_AddRef(iface);
870 return MK_S_US;
871 }
872 else if ((res1==S_OK) && (res2==S_OK)){
873
874 if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK)
875
876 nbCommonMk++;
877
878 else
879 break;
880
881 }
882 else if (res1==S_OK){
883
884 /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */
885 /* ppmkPrefix to the other moniker. */
886 *ppmkPrefix=pmkOther;
887 return MK_S_HIM;
888 }
889 else{
890 /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */
891 /* to this moniker. */
892 *ppmkPrefix=iface;
893 return MK_S_ME;
894 }
895 }
896
897 IEnumMoniker_Release(enumMoniker1);
898 IEnumMoniker_Release(enumMoniker2);
899
900 /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */
901 if (nbCommonMk==0)
902 return MK_E_NOPREFIX;
903
904 IEnumMoniker_Reset(enumMoniker1);
905
906 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
907
908 /* if we have more than one commun moniker the result will be a composite moniker */
909 if (nbCommonMk>1){
910
911 /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/
912 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
913 CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix);
914 IMoniker_Release(tempMk1);
915 IMoniker_Release(tempMk2);
916
917 /* compose all common monikers in a composite moniker */
918 for(i=0;i<nbCommonMk;i++){
919
920 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
921
922 CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2);
923
924 IMoniker_Release(*ppmkPrefix);
925
926 IMoniker_Release(tempMk1);
927
928 *ppmkPrefix=tempMk2;
929 }
930 return S_OK;
931 }
932 else{
933 /* if we have only one commun moniker the result will be a simple moniker which is the most-left one*/
934 *ppmkPrefix=tempMk1;
935
936 return S_OK;
937 }
938 }
939 else{
940 /* If the other moniker is not a composite, the method simply compares it to the leftmost component
941 of this moniker.*/
942
943 IMoniker_Enum(iface,TRUE,&enumMoniker1);
944
945 IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL);
946
947 if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){
948
949 *ppmkPrefix=pmkOther;
950
951 return MK_S_HIM;
952 }
953 else
954 return MK_E_NOPREFIX;
955 }
956 }
957
958 /***************************************************************************************************
959 * GetAfterCommonPrefix (local function)
960 * This function returns a moniker that consist of the remainder when the common prefix is removed
961 ***************************************************************************************************/
962 static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk)
963 {
964 IMoniker *tempMk,*tempMk1,*tempMk2;
965 IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3;
966 ULONG nbRestMk=0;
967 DWORD mkSys;
968 HRESULT res1,res2;
969
970 *restMk=0;
971
972 /* to create an enumerator for pGenMk with current position pointed on the first element after common */
973 /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop */
974 /* on the first difference. */
975 IMoniker_Enum(pGenMk,TRUE,&enumMoniker1);
976
977 IMoniker_IsSystemMoniker(commonMk,&mkSys);
978
979 if (mkSys==MKSYS_GENERICCOMPOSITE){
980
981 IMoniker_Enum(commonMk,TRUE,&enumMoniker2);
982 while(1){
983
984 res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
985 res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL);
986
987 if ((res1==S_FALSE)||(res2==S_FALSE)){
988
989 if (res1==S_OK)
990
991 nbRestMk++;
992
993 IMoniker_Release(tempMk1);
994 IMoniker_Release(tempMk1);
995
996 break;
997 }
998 IMoniker_Release(tempMk1);
999 IMoniker_Release(tempMk1);
1000 }
1001 }
1002 else{
1003 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
1004 IMoniker_Release(tempMk1);
1005 }
1006
1007 /* count the number of elements in the enumerator after the common prefix */
1008 IEnumMoniker_Clone(enumMoniker1,&enumMoniker3);
1009
1010 for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++)
1011
1012 IMoniker_Release(tempMk);
1013
1014 if (nbRestMk==0)
1015 return;
1016
1017 /* create a generic composite moniker with monikers located after the common prefix */
1018 IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL);
1019
1020 if (nbRestMk==1){
1021
1022 *restMk= tempMk1;
1023 return;
1024 }
1025 else {
1026
1027 IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL);
1028
1029 CreateGenericComposite(tempMk1,tempMk2,restMk);
1030
1031 IMoniker_Release(tempMk1);
1032
1033 IMoniker_Release(tempMk2);
1034
1035 while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){
1036
1037 CreateGenericComposite(*restMk,tempMk1,&tempMk2);
1038
1039 IMoniker_Release(tempMk1);
1040
1041 IMoniker_Release(*restMk);
1042
1043 *restMk=tempMk2;
1044 }
1045 }
1046 }
1047
1048 /******************************************************************************
1049 * CompositeMoniker_RelativePathTo
1050 ******************************************************************************/
1051 static HRESULT WINAPI
1052 CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther,
1053 IMoniker** ppmkRelPath)
1054 {
1055 HRESULT res;
1056 IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0;
1057
1058 TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath);
1059
1060 if (ppmkRelPath==NULL)
1061 return E_POINTER;
1062
1063 *ppmkRelPath=0;
1064
1065 /* This method finds the common prefix of the two monikers and creates two monikers that consist */
1066 /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */
1067 /* of this moniker and composes the remainder of the other moniker on the right of it. */
1068
1069 /* finds the common prefix of the two monikers */
1070 res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk);
1071
1072 /* if there's no common prefix or the two moniker are equal the relative is the other moniker */
1073 if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){
1074
1075 *ppmkRelPath=pmkOther;
1076 IMoniker_AddRef(pmkOther);
1077 return MK_S_HIM;
1078 }
1079
1080 GetAfterCommonPrefix(iface,commonMk,&restThisMk);
1081 GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk);
1082
1083 /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */
1084 /* moniker when the common prefix is removed */
1085 if (res==MK_S_HIM){
1086
1087 IMoniker_Inverse(restThisMk,ppmkRelPath);
1088 IMoniker_Release(restThisMk);
1089 }
1090 /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */
1091 /* when the common prefix is removed */
1092 else if (res==MK_S_ME){
1093
1094 *ppmkRelPath=restOtherMk;
1095 IMoniker_AddRef(restOtherMk);
1096 }
1097 /* the relative path is the inverse for the remainder of this moniker and the remainder of the other */
1098 /* moniker on the right of it. */
1099 else if (res==S_OK){
1100
1101 IMoniker_Inverse(restThisMk,&invRestThisMk);
1102 IMoniker_Release(restThisMk);
1103 CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath);
1104 IMoniker_Release(invRestThisMk);
1105 IMoniker_Release(restOtherMk);
1106 }
1107 return S_OK;
1108 }
1109
1110 /******************************************************************************
1111 * CompositeMoniker_GetDisplayName
1112 ******************************************************************************/
1113 static HRESULT WINAPI
1114 CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc,
1115 IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName)
1116 {
1117 ULONG lengthStr=1;
1118 IEnumMoniker *enumMoniker;
1119 IMoniker* tempMk;
1120 LPOLESTR tempStr;
1121
1122 TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName);
1123
1124 if (ppszDisplayName==NULL)
1125 return E_POINTER;
1126
1127 *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR));
1128
1129 if (*ppszDisplayName==NULL)
1130 return E_OUTOFMEMORY;
1131
1132 /* This method returns the concatenation of the display names returned by each component moniker of */
1133 /* the composite */
1134
1135 **ppszDisplayName=0;
1136
1137 IMoniker_Enum(iface,TRUE,&enumMoniker);
1138
1139 while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){
1140
1141 IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr);
1142
1143 lengthStr+=lstrlenW(tempStr);
1144
1145 *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR));
1146
1147 if (*ppszDisplayName==NULL)
1148 return E_OUTOFMEMORY;
1149
1150 strcatW(*ppszDisplayName,tempStr);
1151
1152 CoTaskMemFree(tempStr);
1153 IMoniker_Release(tempMk);
1154 }
1155
1156 IEnumMoniker_Release(enumMoniker);
1157
1158 return S_OK;
1159 }
1160
1161 /******************************************************************************
1162 * CompositeMoniker_ParseDisplayName
1163 ******************************************************************************/
1164 static HRESULT WINAPI
1165 CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc,
1166 IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten,
1167 IMoniker** ppmkOut)
1168 {
1169 IEnumMoniker *enumMoniker;
1170 IMoniker *tempMk,*mostRigthMk,*antiMk;
1171 /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/
1172 /* passing everything else as the pmkToLeft parameter for that call. */
1173
1174 /* get the most right moniker */
1175 IMoniker_Enum(iface,FALSE,&enumMoniker);
1176 IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL);
1177 IEnumMoniker_Release(enumMoniker);
1178
1179 /* get the left moniker */
1180 CreateAntiMoniker(&antiMk);
1181 IMoniker_ComposeWith(iface,antiMk,0,&tempMk);
1182 IMoniker_Release(antiMk);
1183
1184 return IMoniker_ParseDisplayName(mostRigthMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut);
1185 }
1186
1187 /******************************************************************************
1188 * CompositeMoniker_IsSystemMoniker
1189 ******************************************************************************/
1190 static HRESULT WINAPI
1191 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
1192 {
1193 TRACE("(%p,%p)\n",iface,pwdMksys);
1194
1195 if (!pwdMksys)
1196 return E_POINTER;
1197
1198 (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
1199
1200 return S_OK;
1201 }
1202
1203 /*******************************************************************************
1204 * CompositeMonikerIROTData_QueryInterface
1205 *******************************************************************************/
1206 static HRESULT WINAPI
1207 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
1208 VOID** ppvObject)
1209 {
1210
1211 ICOM_THIS_From_IROTData(IMoniker, iface);
1212
1213 TRACE("(%p,%p,%p)\n",iface,riid,ppvObject);
1214
1215 return CompositeMonikerImpl_QueryInterface(This, riid, ppvObject);
1216 }
1217
1218 /***********************************************************************
1219 * CompositeMonikerIROTData_AddRef
1220 */
1221 static ULONG WINAPI
1222 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
1223 {
1224 ICOM_THIS_From_IROTData(IMoniker, iface);
1225
1226 TRACE("(%p)\n",iface);
1227
1228 return IMoniker_AddRef(This);
1229 }
1230
1231 /***********************************************************************
1232 * CompositeMonikerIROTData_Release
1233 */
1234 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1235 {
1236 ICOM_THIS_From_IROTData(IMoniker, iface);
1237
1238 TRACE("(%p)\n",iface);
1239
1240 return IMoniker_Release(This);
1241 }
1242
1243 /******************************************************************************
1244 * CompositeMonikerIROTData_GetComparaisonData
1245 ******************************************************************************/
1246 static HRESULT WINAPI
1247 CompositeMonikerROTDataImpl_GetComparaisonData(IROTData* iface,
1248 BYTE* pbData, ULONG cbMax, ULONG* pcbData)
1249 {
1250 FIXME("(),stub!\n");
1251 return E_NOTIMPL;
1252 }
1253
1254 /******************************************************************************
1255 * EnumMonikerImpl_QueryInterface
1256 ******************************************************************************/
1257 static HRESULT WINAPI
1258 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1259 {
1260 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1261
1262 TRACE("(%p,%p,%p)\n",This,riid,ppvObject);
1263
1264 /* Perform a sanity check on the parameters.*/
1265 if ( (This==0) || (ppvObject==0) )
1266 return E_INVALIDARG;
1267
1268 /* Initialize the return parameter */
1269 *ppvObject = 0;
1270
1271 /* Compare the riid with the interface IDs implemented by this object.*/
1272 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
1273 *ppvObject = iface;
1274
1275 /* Check that we obtained an interface.*/
1276 if ((*ppvObject)==0)
1277 return E_NOINTERFACE;
1278
1279 /* Query Interface always increases the reference count by one when it is successful */
1280 IEnumMoniker_AddRef(iface);
1281
1282 return S_OK;
1283 }
1284
1285 /******************************************************************************
1286 * EnumMonikerImpl_AddRef
1287 ******************************************************************************/
1288 static ULONG WINAPI
1289 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1290 {
1291 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1292
1293 TRACE("(%p)\n",This);
1294
1295 return InterlockedIncrement(&This->ref);
1296
1297 }
1298
1299 /******************************************************************************
1300 * EnumMonikerImpl_Release
1301 ******************************************************************************/
1302 static ULONG WINAPI
1303 EnumMonikerImpl_Release(IEnumMoniker* iface)
1304 {
1305 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1306 ULONG i;
1307 ULONG ref;
1308 TRACE("(%p)\n",This);
1309
1310 ref = InterlockedDecrement(&This->ref);
1311
1312 /* destroy the object if there's no more reference on it */
1313 if (ref == 0) {
1314
1315 for(i=0;i<This->tabSize;i++)
1316 IMoniker_Release(This->tabMoniker[i]);
1317
1318 HeapFree(GetProcessHeap(),0,This->tabMoniker);
1319 HeapFree(GetProcessHeap(),0,This);
1320 }
1321 return ref;
1322 }
1323
1324 /******************************************************************************
1325 * EnumMonikerImpl_Next
1326 ******************************************************************************/
1327 static HRESULT WINAPI
1328 EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt,
1329 ULONG* pceltFethed)
1330 {
1331 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1332 ULONG i;
1333
1334 /* retrieve the requested number of moniker from the current position */
1335 for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++)
1336
1337 rgelt[i]=This->tabMoniker[This->currentPos++];
1338
1339 if (pceltFethed!=NULL)
1340 *pceltFethed= i;
1341
1342 if (i==celt)
1343 return S_OK;
1344 else
1345 return S_FALSE;
1346 }
1347
1348 /******************************************************************************
1349 * EnumMonikerImpl_Skip
1350 ******************************************************************************/
1351 static HRESULT WINAPI
1352 EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt)
1353 {
1354 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1355
1356 if ((This->currentPos+celt) >= This->tabSize)
1357 return S_FALSE;
1358
1359 This->currentPos+=celt;
1360
1361 return S_OK;
1362 }
1363
1364 /******************************************************************************
1365 * EnumMonikerImpl_Reset
1366 ******************************************************************************/
1367 static HRESULT WINAPI
1368 EnumMonikerImpl_Reset(IEnumMoniker* iface)
1369 {
1370
1371 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1372
1373 This->currentPos=0;
1374
1375 return S_OK;
1376 }
1377
1378 /******************************************************************************
1379 * EnumMonikerImpl_Clone
1380 ******************************************************************************/
1381 static HRESULT WINAPI
1382 EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum)
1383 {
1384 EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
1385
1386 return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum);
1387 }
1388
1389 /********************************************************************************/
1390 /* Virtual function table for the IROTData class */
1391 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1392 {
1393 EnumMonikerImpl_QueryInterface,
1394 EnumMonikerImpl_AddRef,
1395 EnumMonikerImpl_Release,
1396 EnumMonikerImpl_Next,
1397 EnumMonikerImpl_Skip,
1398 EnumMonikerImpl_Reset,
1399 EnumMonikerImpl_Clone
1400 };
1401
1402 /******************************************************************************
1403 * EnumMonikerImpl_CreateEnumMoniker
1404 ******************************************************************************/
1405 static HRESULT
1406 EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize,
1407 ULONG currentPos, BOOL leftToRigth, IEnumMoniker ** ppmk)
1408 {
1409 EnumMonikerImpl* newEnumMoniker;
1410 int i;
1411
1412 if (currentPos > tabSize)
1413 return E_INVALIDARG;
1414
1415 newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl));
1416
1417 if (newEnumMoniker == 0)
1418 return STG_E_INSUFFICIENTMEMORY;
1419
1420 /* Initialize the virtual function table. */
1421 newEnumMoniker->lpVtbl = &VT_EnumMonikerImpl;
1422 newEnumMoniker->ref = 0;
1423
1424 newEnumMoniker->tabSize=tabSize;
1425 newEnumMoniker->currentPos=currentPos;
1426
1427 newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(IMoniker));
1428
1429 if (newEnumMoniker->tabMoniker==NULL) {
1430 HeapFree(GetProcessHeap(), 0, newEnumMoniker);
1431 return E_OUTOFMEMORY;
1432 }
1433
1434 if (leftToRigth)
1435 for (i=0;i<tabSize;i++){
1436
1437 newEnumMoniker->tabMoniker[i]=tabMoniker[i];
1438 IMoniker_AddRef(tabMoniker[i]);
1439 }
1440 else
1441 for (i=tabSize-1;i>=0;i--){
1442
1443 newEnumMoniker->tabMoniker[tabSize-i-1]=tabMoniker[i];
1444 IMoniker_AddRef(tabMoniker[i]);
1445 }
1446
1447 *ppmk=(IEnumMoniker*)newEnumMoniker;
1448
1449 return S_OK;
1450 }
1451
1452 /********************************************************************************/
1453 /* Virtual function table for the CompositeMonikerImpl class which includes */
1454 /* IPersist, IPersistStream and IMoniker functions. */
1455
1456 static const IMonikerVtbl VT_CompositeMonikerImpl =
1457 {
1458 CompositeMonikerImpl_QueryInterface,
1459 CompositeMonikerImpl_AddRef,
1460 CompositeMonikerImpl_Release,
1461 CompositeMonikerImpl_GetClassID,
1462 CompositeMonikerImpl_IsDirty,
1463 CompositeMonikerImpl_Load,
1464 CompositeMonikerImpl_Save,
1465 CompositeMonikerImpl_GetSizeMax,
1466 CompositeMonikerImpl_BindToObject,
1467 CompositeMonikerImpl_BindToStorage,
1468 CompositeMonikerImpl_Reduce,
1469 CompositeMonikerImpl_ComposeWith,
1470 CompositeMonikerImpl_Enum,
1471 CompositeMonikerImpl_IsEqual,
1472 CompositeMonikerImpl_Hash,
1473 CompositeMonikerImpl_IsRunning,
1474 CompositeMonikerImpl_GetTimeOfLastChange,
1475 CompositeMonikerImpl_Inverse,
1476 CompositeMonikerImpl_CommonPrefixWith,
1477 CompositeMonikerImpl_RelativePathTo,
1478 CompositeMonikerImpl_GetDisplayName,
1479 CompositeMonikerImpl_ParseDisplayName,
1480 CompositeMonikerImpl_IsSystemMoniker
1481 };
1482
1483 /********************************************************************************/
1484 /* Virtual function table for the IROTData class. */
1485 static const IROTDataVtbl VT_ROTDataImpl =
1486 {
1487 CompositeMonikerROTDataImpl_QueryInterface,
1488 CompositeMonikerROTDataImpl_AddRef,
1489 CompositeMonikerROTDataImpl_Release,
1490 CompositeMonikerROTDataImpl_GetComparaisonData
1491 };
1492
1493 /******************************************************************************
1494 * Composite-Moniker_Construct (local function)
1495 *******************************************************************************/
1496 static HRESULT
1497 CompositeMonikerImpl_Construct(CompositeMonikerImpl* This,
1498 LPMONIKER pmkFirst, LPMONIKER pmkRest)
1499 {
1500 DWORD mkSys;
1501 IEnumMoniker *enumMoniker;
1502 IMoniker *tempMk;
1503 HRESULT res;
1504
1505 TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest);
1506
1507 /* Initialize the virtual function table. */
1508 This->lpvtbl1 = &VT_CompositeMonikerImpl;
1509 This->lpvtbl2 = &VT_ROTDataImpl;
1510 This->ref = 0;
1511
1512 This->tabSize=BLOCK_TAB_SIZE;
1513 This->tabLastIndex=0;
1514
1515 This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(IMoniker));
1516 if (This->tabMoniker==NULL)
1517 return E_OUTOFMEMORY;
1518
1519 IMoniker_IsSystemMoniker(pmkFirst,&mkSys);
1520
1521 /* put the first moniker contents in the beginning of the table */
1522 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1523
1524 This->tabMoniker[(This->tabLastIndex)++]=pmkFirst;
1525 IMoniker_AddRef(pmkFirst);
1526 }
1527 else{
1528
1529 IMoniker_Enum(pmkFirst,TRUE,&enumMoniker);
1530
1531 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1532
1533
1534 if (++This->tabLastIndex==This->tabSize){
1535
1536 This->tabSize+=BLOCK_TAB_SIZE;
1537 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1538
1539 if (This->tabMoniker==NULL)
1540 return E_OUTOFMEMORY;
1541 }
1542 }
1543
1544 IEnumMoniker_Release(enumMoniker);
1545 }
1546
1547 /* put the rest moniker contents after the first one and make simplification if needed */
1548
1549 IMoniker_IsSystemMoniker(pmkRest,&mkSys);
1550
1551 if (mkSys!=MKSYS_GENERICCOMPOSITE){
1552
1553 /* add a simple moniker to the moniker table */
1554
1555 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk);
1556
1557 if (res==MK_E_NEEDGENERIC){
1558
1559 /* there's no simplification in this case */
1560 This->tabMoniker[This->tabLastIndex]=pmkRest;
1561
1562 This->tabLastIndex++;
1563
1564 IMoniker_AddRef(pmkRest);
1565 }
1566 else if (tempMk==NULL){
1567
1568 /* we have an antimoniker after a simple moniker so we can make a simplification in this case */
1569 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1570
1571 This->tabLastIndex--;
1572 }
1573 else if (SUCCEEDED(res)){
1574
1575 /* the non-generic composition was successful so we can make a simplification in this case */
1576 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1577
1578 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1579 } else
1580 return res;
1581
1582 /* resize tabMoniker if needed */
1583 if (This->tabLastIndex==This->tabSize){
1584
1585 This->tabSize+=BLOCK_TAB_SIZE;
1586
1587 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1588
1589 if (This->tabMoniker==NULL)
1590 return E_OUTOFMEMORY;
1591 }
1592 }
1593 else{
1594
1595 /* add a composite moniker to the moniker table (do the same thing
1596 * for each moniker within the composite moniker as a simple moniker
1597 * (see above for how to add a simple moniker case) )
1598 */
1599 IMoniker_Enum(pmkRest,TRUE,&enumMoniker);
1600
1601 while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){
1602
1603 res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk);
1604
1605 if (res==MK_E_NEEDGENERIC){
1606
1607 This->tabLastIndex++;
1608 }
1609 else if (tempMk==NULL){
1610
1611 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1612 IMoniker_Release(This->tabMoniker[This->tabLastIndex]);
1613 This->tabLastIndex--;
1614 }
1615 else{
1616
1617 IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]);
1618
1619 This->tabMoniker[This->tabLastIndex-1]=tempMk;
1620 }
1621
1622 if (This->tabLastIndex==This->tabSize){
1623
1624 This->tabSize+=BLOCK_TAB_SIZE;
1625
1626 This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker));
1627
1628 if (This->tabMoniker==NULL)
1629 return E_OUTOFMEMORY;
1630 }
1631 }
1632
1633 IEnumMoniker_Release(enumMoniker);
1634 }
1635
1636 return S_OK;
1637 }
1638
1639 /******************************************************************************
1640 * CreateGenericComposite [OLE32.@]
1641 ******************************************************************************/
1642 HRESULT WINAPI
1643 CreateGenericComposite(LPMONIKER pmkFirst, LPMONIKER pmkRest,
1644 LPMONIKER* ppmkComposite)
1645 {
1646 CompositeMonikerImpl* newCompositeMoniker = 0;
1647 HRESULT hr = S_OK;
1648
1649 TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite);
1650
1651 if (ppmkComposite==NULL)
1652 return E_POINTER;
1653
1654 *ppmkComposite=0;
1655
1656 if (pmkFirst==NULL && pmkRest!=NULL){
1657
1658 *ppmkComposite=pmkRest;
1659 return S_OK;
1660 }
1661 else if (pmkFirst!=NULL && pmkRest==NULL){
1662 *ppmkComposite=pmkFirst;
1663 return S_OK;
1664 }
1665 else if (pmkFirst==NULL && pmkRest==NULL)
1666 return S_OK;
1667
1668 newCompositeMoniker = HeapAlloc(GetProcessHeap(), 0,sizeof(CompositeMonikerImpl));
1669
1670 if (newCompositeMoniker == 0)
1671 return STG_E_INSUFFICIENTMEMORY;
1672
1673 hr = CompositeMonikerImpl_Construct(newCompositeMoniker,pmkFirst,pmkRest);
1674
1675 if (FAILED(hr)){
1676
1677 HeapFree(GetProcessHeap(),0,newCompositeMoniker);
1678 return hr;
1679 }
1680 if (newCompositeMoniker->tabLastIndex==1)
1681
1682 hr = IMoniker_QueryInterface(newCompositeMoniker->tabMoniker[0],&IID_IMoniker,(void**)ppmkComposite);
1683 else
1684
1685 hr = IMoniker_QueryInterface((IMoniker*)newCompositeMoniker,&IID_IMoniker,(void**)ppmkComposite);
1686
1687 return hr;
1688 }
1689
1690 /******************************************************************************
1691 * MonikerCommonPrefixWith [OLE32.@]
1692 ******************************************************************************/
1693 HRESULT WINAPI
1694 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1695 {
1696 FIXME("(),stub!\n");
1697 return E_NOTIMPL;
1698 }