ntdll: Validate blocks in the heap pending free request list.
[wine.git] / dlls / ole32 / compositemoniker.c
blob7f0ff55627e15df5f41efeea41088bbdace48134
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 "ole2.h"
32 #include "moniker.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39 typedef struct CompositeMonikerImpl
41 IMoniker IMoniker_iface;
42 IROTData IROTData_iface;
43 IMarshal IMarshal_iface;
44 LONG ref;
46 IMoniker *left;
47 IMoniker *right;
48 unsigned int comp_count;
49 } CompositeMonikerImpl;
51 static inline CompositeMonikerImpl *impl_from_IMoniker(IMoniker *iface)
53 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMoniker_iface);
56 static const IMonikerVtbl VT_CompositeMonikerImpl;
58 static CompositeMonikerImpl *unsafe_impl_from_IMoniker(IMoniker *iface)
60 if (iface->lpVtbl != &VT_CompositeMonikerImpl)
61 return NULL;
62 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMoniker_iface);
65 static inline CompositeMonikerImpl *impl_from_IROTData(IROTData *iface)
67 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IROTData_iface);
70 static inline CompositeMonikerImpl *impl_from_IMarshal(IMarshal *iface)
72 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMarshal_iface);
75 typedef struct EnumMonikerImpl
77 IEnumMoniker IEnumMoniker_iface;
78 LONG ref;
79 IMoniker **monikers;
80 unsigned int count;
81 unsigned int pos;
82 } EnumMonikerImpl;
84 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
86 return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
89 static HRESULT create_enumerator(IMoniker **components, unsigned int count, BOOL forward, IEnumMoniker **ret);
90 static HRESULT composite_get_rightmost(CompositeMonikerImpl *composite, IMoniker **left, IMoniker **rightmost);
91 static HRESULT composite_get_leftmost(CompositeMonikerImpl *composite, IMoniker **leftmost);
93 /*******************************************************************************
94 * CompositeMoniker_QueryInterface
95 *******************************************************************************/
96 static HRESULT WINAPI
97 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
99 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
101 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
103 /* Perform a sanity check on the parameters.*/
104 if ( ppvObject==0 )
105 return E_INVALIDARG;
107 /* Initialize the return parameter */
108 *ppvObject = 0;
110 /* Compare the riid with the interface IDs implemented by this object.*/
111 if (IsEqualIID(&IID_IUnknown, riid) ||
112 IsEqualIID(&IID_IPersist, riid) ||
113 IsEqualIID(&IID_IPersistStream, riid) ||
114 IsEqualIID(&IID_IMoniker, riid)
116 *ppvObject = iface;
117 else if (IsEqualIID(&IID_IROTData, riid))
118 *ppvObject = &This->IROTData_iface;
119 else if (IsEqualIID(&IID_IMarshal, riid))
120 *ppvObject = &This->IMarshal_iface;
122 /* Check that we obtained an interface.*/
123 if ((*ppvObject)==0)
124 return E_NOINTERFACE;
126 /* Query Interface always increases the reference count by one when it is successful */
127 IMoniker_AddRef(iface);
129 return S_OK;
132 /******************************************************************************
133 * CompositeMoniker_AddRef
134 ******************************************************************************/
135 static ULONG WINAPI
136 CompositeMonikerImpl_AddRef(IMoniker* iface)
138 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
140 TRACE("(%p)\n",This);
142 return InterlockedIncrement(&This->ref);
145 static ULONG WINAPI CompositeMonikerImpl_Release(IMoniker* iface)
147 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
148 ULONG refcount = InterlockedDecrement(&moniker->ref);
150 TRACE("%p, refcount %lu\n", iface, refcount);
152 if (!refcount)
154 if (moniker->left) IMoniker_Release(moniker->left);
155 if (moniker->right) IMoniker_Release(moniker->right);
156 heap_free(moniker);
159 return refcount;
162 /******************************************************************************
163 * CompositeMoniker_GetClassID
164 ******************************************************************************/
165 static HRESULT WINAPI
166 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
168 TRACE("(%p,%p)\n",iface,pClassID);
170 if (pClassID==NULL)
171 return E_POINTER;
173 *pClassID = CLSID_CompositeMoniker;
175 return S_OK;
178 /******************************************************************************
179 * CompositeMoniker_IsDirty
180 ******************************************************************************/
181 static HRESULT WINAPI
182 CompositeMonikerImpl_IsDirty(IMoniker* iface)
184 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
185 method in the OLE-provided moniker interfaces always return S_FALSE because
186 their internal state never changes. */
188 TRACE("(%p)\n",iface);
190 return S_FALSE;
193 static HRESULT WINAPI CompositeMonikerImpl_Load(IMoniker *iface, IStream *stream)
195 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
196 IMoniker *last, *m, *c;
197 DWORD i, count;
198 HRESULT hr;
200 TRACE("%p, %p\n", iface, stream);
202 if (moniker->comp_count)
203 return E_UNEXPECTED;
205 hr = IStream_Read(stream, &count, sizeof(DWORD), NULL);
206 if (hr != S_OK)
208 WARN("Failed to read component count, hr %#lx.\n", hr);
209 return hr;
212 if (count < 2)
214 WARN("Unexpected component count %lu.\n", count);
215 return E_UNEXPECTED;
218 if (FAILED(hr = OleLoadFromStream(stream, &IID_IMoniker, (void **)&last)))
219 return hr;
221 for (i = 1; i < count - 1; ++i)
223 if (FAILED(hr = OleLoadFromStream(stream, &IID_IMoniker, (void **)&m)))
225 WARN("Failed to initialize component %lu, hr %#lx.\n", i, hr);
226 IMoniker_Release(last);
227 return hr;
229 hr = CreateGenericComposite(last, m, &c);
230 IMoniker_Release(last);
231 IMoniker_Release(m);
232 if (FAILED(hr)) return hr;
233 last = c;
236 if (FAILED(hr = OleLoadFromStream(stream, &IID_IMoniker, (void **)&m)))
238 IMoniker_Release(last);
239 return hr;
242 moniker->left = last;
243 moniker->right = m;
244 moniker->comp_count = count;
246 return hr;
249 static HRESULT composite_save_components(IMoniker *moniker, IStream *stream)
251 CompositeMonikerImpl *comp_moniker;
252 HRESULT hr;
254 if ((comp_moniker = unsafe_impl_from_IMoniker(moniker)))
256 if (SUCCEEDED(hr = composite_save_components(comp_moniker->left, stream)))
257 hr = composite_save_components(comp_moniker->right, stream);
259 else
260 hr = OleSaveToStream((IPersistStream *)moniker, stream);
262 return hr;
265 static HRESULT WINAPI CompositeMonikerImpl_Save(IMoniker *iface, IStream *stream, BOOL clear_dirty)
267 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
268 HRESULT hr;
270 TRACE("%p, %p, %d\n", iface, stream, clear_dirty);
272 if (!moniker->comp_count)
273 return E_UNEXPECTED;
275 hr = IStream_Write(stream, &moniker->comp_count, sizeof(moniker->comp_count), NULL);
276 if (FAILED(hr)) return hr;
278 return composite_save_components(iface, stream);
281 /******************************************************************************
282 * CompositeMoniker_GetSizeMax
283 ******************************************************************************/
284 static HRESULT WINAPI
285 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
287 IEnumMoniker *enumMk;
288 IMoniker *pmk;
289 ULARGE_INTEGER ptmpSize;
291 /* The sizeMax of this object is calculated by calling GetSizeMax on
292 * each moniker within this object then summing all returned values
295 TRACE("(%p,%p)\n",iface,pcbSize);
297 if (!pcbSize)
298 return E_POINTER;
300 pcbSize->QuadPart = sizeof(DWORD);
302 IMoniker_Enum(iface,TRUE,&enumMk);
304 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
306 IMoniker_GetSizeMax(pmk,&ptmpSize);
308 IMoniker_Release(pmk);
310 pcbSize->QuadPart += ptmpSize.QuadPart + sizeof(CLSID);
313 IEnumMoniker_Release(enumMk);
315 return S_OK;
318 static HRESULT compose_with(IMoniker *left, IMoniker *right, IMoniker **c)
320 HRESULT hr = IMoniker_ComposeWith(left, right, TRUE, c);
321 if (FAILED(hr) && hr != MK_E_NEEDGENERIC) return hr;
322 return CreateGenericComposite(left, right, c);
325 static HRESULT WINAPI CompositeMonikerImpl_BindToObject(IMoniker *iface, IBindCtx *pbc,
326 IMoniker *toleft, REFIID riid, void **result)
328 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
329 IMoniker *left, *rightmost, *c;
330 IRunningObjectTable *rot;
331 IUnknown *object;
332 HRESULT hr;
334 TRACE("%p, %p, %p, %s, %p.\n", iface, pbc, toleft, debugstr_guid(riid), result);
336 if (!result)
337 return E_POINTER;
339 *result = NULL;
341 if (!toleft)
343 hr = IBindCtx_GetRunningObjectTable(pbc, &rot);
344 if (SUCCEEDED(hr))
346 hr = IRunningObjectTable_GetObject(rot, iface, &object);
347 IRunningObjectTable_Release(rot);
348 if (FAILED(hr)) return E_INVALIDARG;
350 hr = IUnknown_QueryInterface(object, riid, result);
351 IUnknown_Release(object);
354 return hr;
357 /* Try to bind rightmost component with (toleft, composite->left) composite at its left side */
358 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
359 return hr;
361 hr = compose_with(toleft, left, &c);
362 IMoniker_Release(left);
364 if (SUCCEEDED(hr))
366 hr = IMoniker_BindToObject(rightmost, pbc, c, riid, result);
367 IMoniker_Release(c);
370 IMoniker_Release(rightmost);
372 return hr;
375 static HRESULT WINAPI CompositeMonikerImpl_BindToStorage(IMoniker *iface, IBindCtx *pbc,
376 IMoniker *toleft, REFIID riid, void **result)
378 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
379 IMoniker *left, *rightmost, *composed_left;
380 HRESULT hr;
382 TRACE("%p, %p, %p, %s, %p.\n", iface, pbc, toleft, debugstr_guid(riid), result);
384 *result = NULL;
386 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
387 return hr;
389 if (toleft)
391 hr = compose_with(toleft, left, &composed_left);
393 else
395 composed_left = left;
396 IMoniker_AddRef(composed_left);
399 if (SUCCEEDED(hr))
401 hr = IMoniker_BindToStorage(rightmost, pbc, composed_left, riid, result);
402 IMoniker_Release(composed_left);
405 IMoniker_Release(rightmost);
406 IMoniker_Release(left);
408 return hr;
411 static HRESULT WINAPI CompositeMonikerImpl_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD howfar,
412 IMoniker **toleft, IMoniker **reduced)
414 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
415 IMoniker *m, *reduced_left, *reduced_right;
416 BOOL was_reduced;
417 HRESULT hr;
419 TRACE("%p, %p, %ld, %p, %p.\n", iface, pbc, howfar, toleft, reduced);
421 if (!pbc || !reduced)
422 return E_INVALIDARG;
424 if (FAILED(hr = IMoniker_Reduce(moniker->left, pbc, howfar, NULL, &reduced_left)))
425 return hr;
427 m = moniker->left;
428 if (FAILED(hr = IMoniker_Reduce(moniker->right, pbc, howfar, &m, &reduced_right)))
430 IMoniker_Release(reduced_left);
431 return hr;
434 if ((was_reduced = (reduced_left != moniker->left || reduced_right != moniker->right)))
436 hr = CreateGenericComposite(reduced_left, reduced_right, reduced);
438 else
440 *reduced = iface;
441 IMoniker_AddRef(*reduced);
444 IMoniker_Release(reduced_left);
445 IMoniker_Release(reduced_right);
447 return was_reduced ? hr : MK_S_REDUCED_TO_SELF;
450 static HRESULT WINAPI CompositeMonikerImpl_ComposeWith(IMoniker *iface, IMoniker *right,
451 BOOL only_if_not_generic, IMoniker **composite)
453 TRACE("%p, %p, %d, %p.\n", iface, right, only_if_not_generic, composite);
455 *composite = NULL;
457 return only_if_not_generic ? MK_E_NEEDGENERIC : CreateGenericComposite(iface, right, composite);
460 static void composite_get_components(IMoniker *moniker, IMoniker **components, unsigned int *index)
462 CompositeMonikerImpl *comp_moniker;
464 if ((comp_moniker = unsafe_impl_from_IMoniker(moniker)))
466 composite_get_components(comp_moniker->left, components, index);
467 composite_get_components(comp_moniker->right, components, index);
469 else
471 components[*index] = moniker;
472 (*index)++;
476 static HRESULT composite_get_components_alloc(IMoniker *iface, unsigned int *count, IMoniker ***components)
478 CompositeMonikerImpl *moniker;
479 unsigned int index;
481 if ((moniker = unsafe_impl_from_IMoniker(iface)))
482 *count = moniker->comp_count;
483 else
484 *count = 1;
486 if (!(*components = heap_alloc(*count * sizeof(**components))))
487 return E_OUTOFMEMORY;
489 index = 0;
490 composite_get_components(iface, *components, &index);
492 return S_OK;
495 static HRESULT WINAPI CompositeMonikerImpl_Enum(IMoniker *iface, BOOL forward, IEnumMoniker **ret_enum)
497 IMoniker **monikers;
498 unsigned int count;
499 HRESULT hr;
501 TRACE("%p, %d, %p\n", iface, forward, ret_enum);
503 if (!ret_enum)
504 return E_INVALIDARG;
506 if (FAILED(hr = composite_get_components_alloc(iface, &count, &monikers)))
507 return hr;
509 hr = create_enumerator(monikers, count, forward, ret_enum);
510 heap_free(monikers);
512 return hr;
515 static HRESULT WINAPI CompositeMonikerImpl_IsEqual(IMoniker *iface, IMoniker *other)
517 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface), *other_moniker;
518 IMoniker **components, **other_components;
519 unsigned int i, count;
520 HRESULT hr;
522 TRACE("%p, %p.\n", iface, other);
524 if (!other)
525 return E_INVALIDARG;
527 if (!(other_moniker = unsafe_impl_from_IMoniker(other)))
528 return S_FALSE;
530 if (moniker->comp_count != other_moniker->comp_count)
531 return S_FALSE;
533 if (FAILED(hr = composite_get_components_alloc(iface, &count, &components))) return hr;
534 if (FAILED(hr = composite_get_components_alloc(other, &count, &other_components)))
536 heap_free(components);
537 return hr;
540 for (i = 0; i < moniker->comp_count; ++i)
542 if ((hr = IMoniker_IsEqual(components[i], other_components[i]) != S_OK))
543 break;
546 heap_free(other_components);
547 heap_free(components);
549 return hr;
552 static HRESULT WINAPI CompositeMonikerImpl_Hash(IMoniker *iface, DWORD *hash)
554 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
555 DWORD left_hash, right_hash;
556 HRESULT hr;
558 TRACE("%p, %p\n", iface, hash);
560 if (!hash)
561 return E_POINTER;
563 if (!moniker->comp_count)
564 return E_UNEXPECTED;
566 *hash = 0;
568 if (FAILED(hr = IMoniker_Hash(moniker->left, &left_hash))) return hr;
569 if (FAILED(hr = IMoniker_Hash(moniker->right, &right_hash))) return hr;
571 *hash = left_hash ^ right_hash;
573 return hr;
576 static HRESULT WINAPI CompositeMonikerImpl_IsRunning(IMoniker *iface, IBindCtx *pbc,
577 IMoniker *toleft, IMoniker *newly_running)
579 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
580 IMoniker *c, *left, *rightmost;
581 IRunningObjectTable *rot;
582 HRESULT hr;
584 TRACE("%p, %p, %p, %p.\n", iface, pbc, toleft, newly_running);
586 if (!pbc)
587 return E_INVALIDARG;
589 if (toleft)
591 if (SUCCEEDED(hr = CreateGenericComposite(toleft, iface, &c)))
593 hr = IMoniker_IsRunning(c, pbc, NULL, newly_running);
594 IMoniker_Release(c);
597 return hr;
600 if (newly_running)
601 return IMoniker_IsEqual(iface, newly_running);
603 if (FAILED(hr = IBindCtx_GetRunningObjectTable(pbc, &rot)))
604 return hr;
606 hr = IRunningObjectTable_IsRunning(rot, iface);
607 IRunningObjectTable_Release(rot);
608 if (hr == S_OK) return S_OK;
610 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
611 return hr;
613 hr = IMoniker_IsRunning(rightmost, pbc, left, NULL);
615 IMoniker_Release(left);
616 IMoniker_Release(rightmost);
618 return hr;
621 static HRESULT WINAPI CompositeMonikerImpl_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
622 IMoniker *toleft, FILETIME *changetime)
624 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
625 IMoniker *left, *rightmost, *composed_left = NULL, *running = NULL;
626 IRunningObjectTable *rot;
627 HRESULT hr;
629 TRACE("%p, %p, %p, %p.\n", iface, pbc, toleft, changetime);
631 if (!changetime || !pbc)
632 return E_INVALIDARG;
634 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
635 return hr;
637 if (toleft)
639 /* Compose (toleft, left) and check that against rightmost */
640 if (SUCCEEDED(hr = compose_with(toleft, left, &composed_left)) && composed_left)
641 hr = compose_with(composed_left, rightmost, &running);
643 else
645 composed_left = left;
646 IMoniker_AddRef(composed_left);
647 running = iface;
648 IMoniker_AddRef(running);
651 if (SUCCEEDED(hr))
653 if (SUCCEEDED(hr = IBindCtx_GetRunningObjectTable(pbc, &rot)))
655 if (IRunningObjectTable_GetTimeOfLastChange(rot, running, changetime) != S_OK)
656 hr = IMoniker_GetTimeOfLastChange(rightmost, pbc, composed_left, changetime);
657 IRunningObjectTable_Release(rot);
661 if (composed_left)
662 IMoniker_Release(composed_left);
663 if (running)
664 IMoniker_Release(running);
665 IMoniker_Release(rightmost);
666 IMoniker_Release(left);
668 return hr;
671 static HRESULT WINAPI CompositeMonikerImpl_Inverse(IMoniker *iface, IMoniker **inverse)
673 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
674 IMoniker *right_inverted, *left_inverted;
675 HRESULT hr;
677 TRACE("%p, %p.\n", iface, inverse);
679 if (!inverse)
680 return E_INVALIDARG;
682 *inverse = NULL;
684 if (FAILED(hr = IMoniker_Inverse(moniker->right, &right_inverted))) return hr;
685 if (FAILED(hr = IMoniker_Inverse(moniker->left, &left_inverted)))
687 IMoniker_Release(right_inverted);
688 return hr;
691 hr = CreateGenericComposite(right_inverted, left_inverted, inverse);
693 IMoniker_Release(left_inverted);
694 IMoniker_Release(right_inverted);
696 return hr;
699 static HRESULT WINAPI CompositeMonikerImpl_CommonPrefixWith(IMoniker *iface, IMoniker *other,
700 IMoniker **prefix)
702 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface), *other_moniker;
703 unsigned int i, count, prefix_len = 0;
704 IMoniker *leftmost;
705 HRESULT hr;
707 TRACE("%p, %p, %p.\n", iface, other, prefix);
709 /* If the other moniker is a composite, this method compares the components of each composite from left */
710 /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
711 /* of the leftmost components were common to both monikers. */
713 if (prefix)
714 *prefix = NULL;
716 if (!other || !prefix)
717 return E_INVALIDARG;
719 if ((other_moniker = unsafe_impl_from_IMoniker(other)))
721 IMoniker **components, **other_components, **prefix_components;
722 IMoniker *last, *c;
724 if (FAILED(hr = composite_get_components_alloc(iface, &count, &components))) return hr;
725 if (FAILED(hr = composite_get_components_alloc(other, &count, &other_components)))
727 heap_free(components);
728 return hr;
731 count = min(moniker->comp_count, other_moniker->comp_count);
732 if (!(prefix_components = heap_calloc(count, sizeof(*prefix_components))))
734 heap_free(components);
735 heap_free(other_components);
736 return E_OUTOFMEMORY;
739 /* Collect prefix components */
740 for (i = 0; i < count; ++i)
742 IMoniker *p;
744 if (FAILED(hr = IMoniker_CommonPrefixWith(components[i], other_components[i], &p)))
745 break;
746 prefix_components[prefix_len++] = p;
747 /* S_OK means that prefix was found and is neither of tested monikers */
748 if (hr == S_OK) break;
751 heap_free(components);
752 heap_free(other_components);
754 if (!prefix_len)
756 heap_free(prefix_components);
757 return MK_E_NOPREFIX;
760 last = prefix_components[0];
761 for (i = 1; i < prefix_len; ++i)
763 hr = CreateGenericComposite(last, prefix_components[i], &c);
764 IMoniker_Release(last);
765 IMoniker_Release(prefix_components[i]);
766 if (FAILED(hr)) break;
767 last = c;
769 heap_free(prefix_components);
771 if (SUCCEEDED(hr))
773 *prefix = last;
774 if (IMoniker_IsEqual(iface, *prefix) == S_OK)
775 hr = MK_S_US;
776 else if (prefix_len < count)
777 hr = S_OK;
778 else
779 hr = prefix_len == moniker->comp_count ? MK_S_ME : MK_S_HIM;
782 return hr;
785 /* For non-composite, compare to leftmost component */
786 if (SUCCEEDED(hr = composite_get_leftmost(moniker, &leftmost)))
788 if ((hr = IMoniker_IsEqual(leftmost, other)) == S_OK)
790 *prefix = leftmost;
791 IMoniker_AddRef(*prefix);
794 hr = hr == S_OK ? MK_S_HIM : MK_E_NOPREFIX;
795 IMoniker_Release(leftmost);
798 return hr;
801 static HRESULT composite_compose_components(IMoniker **comp, unsigned int count, IMoniker **ret)
803 IMoniker *last, *c;
804 HRESULT hr = S_OK;
805 unsigned int i;
807 last = comp[0];
808 IMoniker_AddRef(last);
810 for (i = 1; i < count; ++i)
812 hr = CreateGenericComposite(last, comp[i], &c);
813 IMoniker_Release(last);
814 if (FAILED(hr)) break;
815 last = c;
818 *ret = SUCCEEDED(hr) ? last : NULL;
820 return hr;
823 static HRESULT WINAPI CompositeMonikerImpl_RelativePathTo(IMoniker *iface, IMoniker *other,
824 IMoniker **relpath)
826 unsigned int count, this_count, other_count, prefix_len = 0;
827 IMoniker *inv, *tail = NULL, *other_tail = NULL, *rel = NULL;
828 IMoniker **components, **other_components;
829 unsigned int start = 0, other_start = 0;
830 HRESULT hr;
832 TRACE("%p, %p, %p.\n", iface, other, relpath);
834 if (!relpath)
835 return E_INVALIDARG;
837 *relpath = NULL;
839 if (FAILED(hr = composite_get_components_alloc(iface, &this_count, &components))) return hr;
840 if (FAILED(hr = composite_get_components_alloc(other, &other_count, &other_components)))
842 heap_free(components);
843 return hr;
846 /* Skip common prefix of equal components */
847 count = min(other_count, this_count);
848 while (IMoniker_IsEqual(components[prefix_len], other_components[prefix_len]) == S_OK)
850 if (++prefix_len == count) break;
853 if (prefix_len)
855 this_count -= prefix_len;
856 other_count -= prefix_len;
857 other_start += prefix_len;
858 start += prefix_len;
860 else
862 /* Replace first component of the other tail with relative path */
863 if (SUCCEEDED(hr = IMoniker_RelativePathTo(*components, *other_components, &rel)))
864 *other_components = rel;
866 this_count--;
867 start++;
870 /* Invert left side tail */
871 if (this_count && SUCCEEDED(hr))
873 if (SUCCEEDED(hr = composite_compose_components(&components[start], this_count, &tail)))
875 hr = IMoniker_Inverse(tail, &inv);
876 IMoniker_Release(tail);
877 tail = inv;
881 if (other_count && SUCCEEDED(hr))
882 hr = composite_compose_components(&other_components[other_start], other_count, &other_tail);
884 if (tail || other_tail)
885 hr = CreateGenericComposite(tail, other_tail, relpath);
886 else if (SUCCEEDED(hr))
888 *relpath = other;
889 IMoniker_AddRef(*relpath);
890 hr = MK_S_HIM;
893 if (rel)
894 IMoniker_Release(rel);
895 if (tail)
896 IMoniker_Release(tail);
897 if (other_tail)
898 IMoniker_Release(other_tail);
900 heap_free(other_components);
901 heap_free(components);
903 return hr;
906 static HRESULT WINAPI CompositeMonikerImpl_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
907 IMoniker *pmkToLeft, LPOLESTR *displayname)
909 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
910 WCHAR *left_name = NULL, *right_name = NULL;
911 HRESULT hr;
913 TRACE("%p, %p, %p, %p\n", iface, pbc, pmkToLeft, displayname);
915 if (!pbc || !displayname || !moniker->comp_count)
916 return E_INVALIDARG;
918 if (FAILED(hr = IMoniker_GetDisplayName(moniker->left, pbc, NULL, &left_name))) return hr;
919 if (FAILED(hr = IMoniker_GetDisplayName(moniker->right, pbc, NULL, &right_name)))
921 CoTaskMemFree(left_name);
922 return hr;
925 if (!(*displayname = CoTaskMemAlloc((lstrlenW(left_name) + lstrlenW(right_name) + 1) * sizeof(WCHAR))))
927 CoTaskMemFree(left_name);
928 CoTaskMemFree(right_name);
929 return E_OUTOFMEMORY;
932 lstrcpyW(*displayname, left_name);
933 lstrcatW(*displayname, right_name);
935 CoTaskMemFree(left_name);
936 CoTaskMemFree(right_name);
938 return S_OK;
941 static HRESULT WINAPI CompositeMonikerImpl_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
942 IMoniker *pmkToLeft, LPOLESTR name, ULONG *eaten, IMoniker **result)
944 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
945 IMoniker *left, *rightmost;
946 HRESULT hr;
948 TRACE("%p, %p, %p, %s, %p, %p.\n", iface, pbc, pmkToLeft, debugstr_w(name), eaten, result);
950 if (!pbc)
951 return E_INVALIDARG;
953 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
954 return hr;
956 /* Let rightmost component parse the name, using what's left of the composite as a left side. */
957 hr = IMoniker_ParseDisplayName(rightmost, pbc, left, name, eaten, result);
959 IMoniker_Release(left);
960 IMoniker_Release(rightmost);
962 return hr;
965 /******************************************************************************
966 * CompositeMoniker_IsSystemMoniker
967 ******************************************************************************/
968 static HRESULT WINAPI
969 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
971 TRACE("(%p,%p)\n",iface,pwdMksys);
973 if (!pwdMksys)
974 return E_POINTER;
976 (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
978 return S_OK;
981 /*******************************************************************************
982 * CompositeMonikerIROTData_QueryInterface
983 *******************************************************************************/
984 static HRESULT WINAPI
985 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
986 VOID** ppvObject)
988 CompositeMonikerImpl *This = impl_from_IROTData(iface);
990 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject);
992 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
995 /***********************************************************************
996 * CompositeMonikerIROTData_AddRef
998 static ULONG WINAPI
999 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
1001 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1003 TRACE("(%p)\n",iface);
1005 return IMoniker_AddRef(&This->IMoniker_iface);
1008 /***********************************************************************
1009 * CompositeMonikerIROTData_Release
1011 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1013 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1015 TRACE("(%p)\n",iface);
1017 return IMoniker_Release(&This->IMoniker_iface);
1020 static HRESULT composite_get_moniker_comparison_data(IMoniker *moniker,
1021 BYTE *data, ULONG max_len, ULONG *ret_len)
1023 IROTData *rot_data;
1024 HRESULT hr;
1026 if (FAILED(hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rot_data)))
1028 WARN("Failed to get IROTData for component moniker, hr %#lx.\n", hr);
1029 return hr;
1032 hr = IROTData_GetComparisonData(rot_data, data, max_len, ret_len);
1033 IROTData_Release(rot_data);
1035 return hr;
1038 static HRESULT WINAPI CompositeMonikerROTDataImpl_GetComparisonData(IROTData *iface,
1039 BYTE *data, ULONG max_len, ULONG *ret_len)
1041 CompositeMonikerImpl *moniker = impl_from_IROTData(iface);
1042 HRESULT hr;
1043 ULONG len;
1045 TRACE("%p, %p, %lu, %p\n", iface, data, max_len, ret_len);
1047 if (!moniker->comp_count)
1048 return E_UNEXPECTED;
1050 /* Get required size first */
1051 *ret_len = sizeof(CLSID);
1053 len = 0;
1054 hr = composite_get_moniker_comparison_data(moniker->left, NULL, 0, &len);
1055 if (SUCCEEDED(hr) || hr == E_OUTOFMEMORY)
1056 *ret_len += len;
1057 else
1059 WARN("Failed to get comparison data length for left component, hr %#lx.\n", hr);
1060 return hr;
1063 len = 0;
1064 hr = composite_get_moniker_comparison_data(moniker->right, NULL, 0, &len);
1065 if (SUCCEEDED(hr) || hr == E_OUTOFMEMORY)
1066 *ret_len += len;
1067 else
1069 WARN("Failed to get comparison data length for right component, hr %#lx.\n", hr);
1070 return hr;
1073 if (max_len < *ret_len)
1074 return E_OUTOFMEMORY;
1076 memcpy(data, &CLSID_CompositeMoniker, sizeof(CLSID));
1077 data += sizeof(CLSID);
1078 max_len -= sizeof(CLSID);
1079 if (FAILED(hr = composite_get_moniker_comparison_data(moniker->left, data, max_len, &len)))
1081 WARN("Failed to get comparison data for left component, hr %#lx.\n", hr);
1082 return hr;
1084 data += len;
1085 max_len -= len;
1086 if (FAILED(hr = composite_get_moniker_comparison_data(moniker->right, data, max_len, &len)))
1088 WARN("Failed to get comparison data for right component, hr %#lx.\n", hr);
1089 return hr;
1092 return S_OK;
1095 static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1097 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1099 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);
1101 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppv);
1104 static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
1106 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1108 TRACE("(%p)\n",iface);
1110 return CompositeMonikerImpl_AddRef(&This->IMoniker_iface);
1113 static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
1115 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1117 TRACE("(%p)\n",iface);
1119 return CompositeMonikerImpl_Release(&This->IMoniker_iface);
1122 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
1123 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1124 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1126 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1128 TRACE("%s, %p, %lx, %p, %lx, %p.\n", debugstr_guid(riid), pv,
1129 dwDestContext, pvDestContext, mshlflags, pCid);
1131 return IMoniker_GetClassID(&This->IMoniker_iface, pCid);
1134 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
1135 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1136 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1138 CompositeMonikerImpl *moniker = impl_from_IMarshal(iface);
1139 HRESULT hr;
1140 ULONG size;
1142 TRACE("%s, %p, %lx, %p, %lx, %p.\n", debugstr_guid(riid), pv,
1143 dwDestContext, pvDestContext, mshlflags, pSize);
1145 if (!moniker->comp_count)
1146 return E_UNEXPECTED;
1148 *pSize = 0x10; /* to match native */
1150 if (FAILED(hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)moniker->left, dwDestContext,
1151 pvDestContext, mshlflags)))
1153 return hr;
1155 *pSize += size;
1157 if (FAILED(hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)moniker->right, dwDestContext,
1158 pvDestContext, mshlflags)))
1160 return hr;
1162 *pSize += size;
1164 return hr;
1167 static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(IMarshal *iface, IStream *stream,
1168 REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD flags)
1170 CompositeMonikerImpl *moniker = impl_from_IMarshal(iface);
1171 HRESULT hr;
1173 TRACE("%p, %p, %s, %p, %lx, %p, %#lx\n", iface, stream, debugstr_guid(riid), pv, dwDestContext, pvDestContext, flags);
1175 if (!moniker->comp_count)
1176 return E_UNEXPECTED;
1178 if (FAILED(hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker->left, dwDestContext, pvDestContext, flags)))
1180 WARN("Failed to marshal left component, hr %#lx.\n", hr);
1181 return hr;
1184 if (FAILED(hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker->right, dwDestContext, pvDestContext, flags)))
1185 WARN("Failed to marshal right component, hr %#lx.\n", hr);
1187 return hr;
1190 static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *stream,
1191 REFIID riid, void **ppv)
1193 CompositeMonikerImpl *moniker = impl_from_IMarshal(iface);
1194 HRESULT hr;
1196 TRACE("%p, %p, %s, %p\n", iface, stream, debugstr_guid(riid), ppv);
1198 if (moniker->left)
1200 IMoniker_Release(moniker->left);
1201 moniker->left = NULL;
1204 if (moniker->right)
1206 IMoniker_Release(moniker->right);
1207 moniker->right = NULL;
1210 if (FAILED(hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker->left)))
1212 WARN("Failed to unmarshal left moniker, hr %#lx.\n", hr);
1213 return hr;
1216 if (FAILED(hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker->right)))
1218 WARN("Failed to unmarshal right moniker, hr %#lx.\n", hr);
1219 return hr;
1222 return IMoniker_QueryInterface(&moniker->IMoniker_iface, riid, ppv);
1225 static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1227 TRACE("(%p)\n", pStm);
1228 /* can't release a state-based marshal as nothing on server side to
1229 * release */
1230 return S_OK;
1233 static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(IMarshal *iface,
1234 DWORD dwReserved)
1236 TRACE("%#lx\n", dwReserved);
1237 /* can't disconnect a state-based marshal as nothing on server side to
1238 * disconnect from */
1239 return S_OK;
1242 /******************************************************************************
1243 * EnumMonikerImpl_QueryInterface
1244 ******************************************************************************/
1245 static HRESULT WINAPI
1246 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1248 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1250 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1252 /* Perform a sanity check on the parameters.*/
1253 if ( ppvObject==0 )
1254 return E_INVALIDARG;
1256 /* Initialize the return parameter */
1257 *ppvObject = 0;
1259 /* Compare the riid with the interface IDs implemented by this object.*/
1260 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
1261 *ppvObject = iface;
1263 /* Check that we obtained an interface.*/
1264 if ((*ppvObject)==0)
1265 return E_NOINTERFACE;
1267 /* Query Interface always increases the reference count by one when it is successful */
1268 IEnumMoniker_AddRef(iface);
1270 return S_OK;
1273 /******************************************************************************
1274 * EnumMonikerImpl_AddRef
1275 ******************************************************************************/
1276 static ULONG WINAPI
1277 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1279 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1281 TRACE("(%p)\n",This);
1283 return InterlockedIncrement(&This->ref);
1287 static ULONG WINAPI EnumMonikerImpl_Release(IEnumMoniker *iface)
1289 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1290 ULONG refcount = InterlockedDecrement(&e->ref);
1291 unsigned int i;
1293 TRACE("%p, refcount %lu.\n", iface, refcount);
1295 if (!refcount)
1297 for (i = 0; i < e->count; ++i)
1298 IMoniker_Release(e->monikers[i]);
1299 heap_free(e->monikers);
1300 heap_free(e);
1303 return refcount;
1306 static HRESULT WINAPI EnumMonikerImpl_Next(IEnumMoniker *iface, ULONG count,
1307 IMoniker **m, ULONG *fetched)
1309 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1310 unsigned int i;
1312 TRACE("%p, %lu, %p, %p.\n", iface, count, m, fetched);
1314 if (!m)
1315 return E_INVALIDARG;
1317 *m = NULL;
1319 /* retrieve the requested number of moniker from the current position */
1320 for (i = 0; (e->pos < e->count) && (i < count); ++i)
1322 m[i] = e->monikers[e->pos++];
1323 IMoniker_AddRef(m[i]);
1326 if (fetched)
1327 *fetched = i;
1329 return i == count ? S_OK : S_FALSE;
1332 static HRESULT WINAPI EnumMonikerImpl_Skip(IEnumMoniker *iface, ULONG count)
1334 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1336 TRACE("%p, %lu.\n", iface, count);
1338 if (!count)
1339 return S_OK;
1341 if ((e->pos + count) >= e->count)
1342 return S_FALSE;
1344 e->pos += count;
1346 return S_OK;
1349 static HRESULT WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface)
1351 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1353 TRACE("%p.\n", iface);
1355 e->pos = 0;
1357 return S_OK;
1360 static HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker *iface, IEnumMoniker **ret)
1362 TRACE("%p, %p.\n", iface, ret);
1364 if (!ret)
1365 return E_INVALIDARG;
1367 *ret = NULL;
1369 return E_NOTIMPL;
1372 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1374 EnumMonikerImpl_QueryInterface,
1375 EnumMonikerImpl_AddRef,
1376 EnumMonikerImpl_Release,
1377 EnumMonikerImpl_Next,
1378 EnumMonikerImpl_Skip,
1379 EnumMonikerImpl_Reset,
1380 EnumMonikerImpl_Clone
1383 static HRESULT create_enumerator(IMoniker **components, unsigned int count, BOOL forward, IEnumMoniker **ret)
1385 EnumMonikerImpl *object;
1386 unsigned int i;
1388 if (!(object = heap_alloc_zero(sizeof(*object))))
1389 return E_OUTOFMEMORY;
1391 object->IEnumMoniker_iface.lpVtbl = &VT_EnumMonikerImpl;
1392 object->ref = 1;
1393 object->count = count;
1395 if (!(object->monikers = heap_calloc(count, sizeof(*object->monikers))))
1397 heap_free(object);
1398 return E_OUTOFMEMORY;
1401 for (i = 0; i < count; ++i)
1403 object->monikers[i] = forward ? components[i] : components[count - i - 1];
1404 IMoniker_AddRef(object->monikers[i]);
1407 *ret = &object->IEnumMoniker_iface;
1409 return S_OK;
1412 static const IMonikerVtbl VT_CompositeMonikerImpl =
1414 CompositeMonikerImpl_QueryInterface,
1415 CompositeMonikerImpl_AddRef,
1416 CompositeMonikerImpl_Release,
1417 CompositeMonikerImpl_GetClassID,
1418 CompositeMonikerImpl_IsDirty,
1419 CompositeMonikerImpl_Load,
1420 CompositeMonikerImpl_Save,
1421 CompositeMonikerImpl_GetSizeMax,
1422 CompositeMonikerImpl_BindToObject,
1423 CompositeMonikerImpl_BindToStorage,
1424 CompositeMonikerImpl_Reduce,
1425 CompositeMonikerImpl_ComposeWith,
1426 CompositeMonikerImpl_Enum,
1427 CompositeMonikerImpl_IsEqual,
1428 CompositeMonikerImpl_Hash,
1429 CompositeMonikerImpl_IsRunning,
1430 CompositeMonikerImpl_GetTimeOfLastChange,
1431 CompositeMonikerImpl_Inverse,
1432 CompositeMonikerImpl_CommonPrefixWith,
1433 CompositeMonikerImpl_RelativePathTo,
1434 CompositeMonikerImpl_GetDisplayName,
1435 CompositeMonikerImpl_ParseDisplayName,
1436 CompositeMonikerImpl_IsSystemMoniker
1439 /********************************************************************************/
1440 /* Virtual function table for the IROTData class. */
1441 static const IROTDataVtbl VT_ROTDataImpl =
1443 CompositeMonikerROTDataImpl_QueryInterface,
1444 CompositeMonikerROTDataImpl_AddRef,
1445 CompositeMonikerROTDataImpl_Release,
1446 CompositeMonikerROTDataImpl_GetComparisonData
1449 static const IMarshalVtbl VT_MarshalImpl =
1451 CompositeMonikerMarshalImpl_QueryInterface,
1452 CompositeMonikerMarshalImpl_AddRef,
1453 CompositeMonikerMarshalImpl_Release,
1454 CompositeMonikerMarshalImpl_GetUnmarshalClass,
1455 CompositeMonikerMarshalImpl_GetMarshalSizeMax,
1456 CompositeMonikerMarshalImpl_MarshalInterface,
1457 CompositeMonikerMarshalImpl_UnmarshalInterface,
1458 CompositeMonikerMarshalImpl_ReleaseMarshalData,
1459 CompositeMonikerMarshalImpl_DisconnectObject
1462 struct comp_node
1464 IMoniker *moniker;
1465 struct comp_node *parent;
1466 struct comp_node *left;
1467 struct comp_node *right;
1470 static HRESULT moniker_get_tree_representation(IMoniker *moniker, struct comp_node *parent,
1471 struct comp_node **ret)
1473 CompositeMonikerImpl *comp_moniker;
1474 struct comp_node *node;
1476 if (!(node = heap_alloc_zero(sizeof(*node))))
1477 return E_OUTOFMEMORY;
1478 node->parent = parent;
1480 if ((comp_moniker = unsafe_impl_from_IMoniker(moniker)))
1482 moniker_get_tree_representation(comp_moniker->left, node, &node->left);
1483 moniker_get_tree_representation(comp_moniker->right, node, &node->right);
1485 else
1487 node->moniker = moniker;
1488 IMoniker_AddRef(node->moniker);
1491 *ret = node;
1493 return S_OK;
1496 static struct comp_node *moniker_tree_get_rightmost(struct comp_node *root)
1498 if (!root->left && !root->right) return root->moniker ? root : NULL;
1499 while (root->right) root = root->right;
1500 return root;
1503 static struct comp_node *moniker_tree_get_leftmost(struct comp_node *root)
1505 if (!root->left && !root->right) return root->moniker ? root : NULL;
1506 while (root->left) root = root->left;
1507 return root;
1510 static void moniker_tree_node_release(struct comp_node *node)
1512 if (node->moniker)
1513 IMoniker_Release(node->moniker);
1514 heap_free(node);
1517 static void moniker_tree_release(struct comp_node *node)
1519 if (node->left)
1520 moniker_tree_node_release(node->left);
1521 if (node->right)
1522 moniker_tree_node_release(node->right);
1523 moniker_tree_node_release(node);
1526 static void moniker_tree_replace_node(struct comp_node *node, struct comp_node *replace_with)
1528 if (node->parent)
1530 if (node->parent->left == node) node->parent->left = replace_with;
1531 else node->parent->right = replace_with;
1532 replace_with->parent = node->parent;
1534 else if (replace_with->moniker)
1536 /* Replacing root with non-composite */
1537 node->moniker = replace_with->moniker;
1538 IMoniker_AddRef(node->moniker);
1539 node->left = node->right = NULL;
1540 moniker_tree_node_release(replace_with);
1542 else
1544 /* Attaching composite branches to the root */
1545 node->left = replace_with->left;
1546 node->right = replace_with->right;
1547 moniker_tree_node_release(replace_with);
1551 static void moniker_tree_discard(struct comp_node *node, BOOL left)
1553 if (node->parent)
1555 moniker_tree_replace_node(node->parent, left ? node->parent->left : node->parent->right);
1556 moniker_tree_node_release(node);
1558 else
1560 IMoniker_Release(node->moniker);
1561 node->moniker = NULL;
1565 static HRESULT moniker_create_from_tree(const struct comp_node *root, unsigned int *count, IMoniker **moniker)
1567 IMoniker *left_moniker, *right_moniker;
1568 HRESULT hr;
1570 *moniker = NULL;
1572 /* Non-composite node */
1573 if (!root->left && !root->right)
1575 (*count)++;
1576 *moniker = root->moniker;
1577 if (*moniker) IMoniker_AddRef(*moniker);
1578 return S_OK;
1581 if (FAILED(hr = moniker_create_from_tree(root->left, count, &left_moniker))) return hr;
1582 if (FAILED(hr = moniker_create_from_tree(root->right, count, &right_moniker)))
1584 IMoniker_Release(left_moniker);
1585 return hr;
1588 hr = CreateGenericComposite(left_moniker, right_moniker, moniker);
1589 IMoniker_Release(left_moniker);
1590 IMoniker_Release(right_moniker);
1591 return hr;
1594 static void moniker_get_tree_comp_count(const struct comp_node *root, unsigned int *count)
1596 if (!root->left && !root->right)
1598 (*count)++;
1599 return;
1602 moniker_get_tree_comp_count(root->left, count);
1603 moniker_get_tree_comp_count(root->right, count);
1606 static HRESULT composite_get_rightmost(CompositeMonikerImpl *composite, IMoniker **left, IMoniker **rightmost)
1608 struct comp_node *root, *node;
1609 unsigned int count;
1610 HRESULT hr;
1612 /* Shortcut for trivial case when right component is non-composite */
1613 if (!unsafe_impl_from_IMoniker(composite->right))
1615 *left = composite->left;
1616 IMoniker_AddRef(*left);
1617 *rightmost = composite->right;
1618 IMoniker_AddRef(*rightmost);
1619 return S_OK;
1622 *left = *rightmost = NULL;
1624 if (FAILED(hr = moniker_get_tree_representation(&composite->IMoniker_iface, NULL, &root)))
1625 return hr;
1627 if (!(node = moniker_tree_get_rightmost(root)))
1629 WARN("Couldn't get right most component.\n");
1630 moniker_tree_release(root);
1631 return E_FAIL;
1634 *rightmost = node->moniker;
1635 IMoniker_AddRef(*rightmost);
1636 moniker_tree_discard(node, TRUE);
1638 hr = moniker_create_from_tree(root, &count, left);
1639 moniker_tree_release(root);
1640 if (FAILED(hr))
1642 IMoniker_Release(*rightmost);
1643 *rightmost = NULL;
1646 return hr;
1649 static HRESULT composite_get_leftmost(CompositeMonikerImpl *composite, IMoniker **leftmost)
1651 struct comp_node *root, *node;
1652 HRESULT hr;
1654 if (!unsafe_impl_from_IMoniker(composite->left))
1656 *leftmost = composite->left;
1657 IMoniker_AddRef(*leftmost);
1658 return S_OK;
1661 if (FAILED(hr = moniker_get_tree_representation(&composite->IMoniker_iface, NULL, &root)))
1662 return hr;
1664 if (!(node = moniker_tree_get_leftmost(root)))
1666 WARN("Couldn't get left most component.\n");
1667 moniker_tree_release(root);
1668 return E_FAIL;
1671 *leftmost = node->moniker;
1672 IMoniker_AddRef(*leftmost);
1674 moniker_tree_release(root);
1676 return S_OK;
1679 static HRESULT moniker_simplify_composition(IMoniker *left, IMoniker *right,
1680 unsigned int *count, IMoniker **new_left, IMoniker **new_right)
1682 struct comp_node *left_tree, *right_tree;
1683 unsigned int modified = 0;
1684 HRESULT hr = S_OK;
1685 IMoniker *c;
1687 *count = 0;
1689 moniker_get_tree_representation(left, NULL, &left_tree);
1690 moniker_get_tree_representation(right, NULL, &right_tree);
1692 /* Simplify by composing trees together, in a non-generic way. */
1693 for (;;)
1695 struct comp_node *l, *r;
1697 if (!(l = moniker_tree_get_rightmost(left_tree))) break;
1698 if (!(r = moniker_tree_get_leftmost(right_tree))) break;
1700 c = NULL;
1701 if (FAILED(IMoniker_ComposeWith(l->moniker, r->moniker, TRUE, &c))) break;
1702 modified++;
1704 if (c)
1706 /* Replace with composed moniker on the left side */
1707 IMoniker_Release(l->moniker);
1708 l->moniker = c;
1710 else
1711 moniker_tree_discard(l, TRUE);
1712 moniker_tree_discard(r, FALSE);
1715 if (!modified)
1717 *new_left = left;
1718 IMoniker_AddRef(*new_left);
1719 *new_right = right;
1720 IMoniker_AddRef(*new_right);
1722 moniker_get_tree_comp_count(left_tree, count);
1723 moniker_get_tree_comp_count(right_tree, count);
1725 else
1727 hr = moniker_create_from_tree(left_tree, count, new_left);
1728 if (SUCCEEDED(hr))
1729 hr = moniker_create_from_tree(right_tree, count, new_right);
1732 moniker_tree_release(left_tree);
1733 moniker_tree_release(right_tree);
1735 if (FAILED(hr))
1737 if (*new_left) IMoniker_Release(*new_left);
1738 if (*new_right) IMoniker_Release(*new_right);
1739 *new_left = *new_right = NULL;
1742 return hr;
1745 static HRESULT create_composite(IMoniker *left, IMoniker *right, IMoniker **moniker)
1747 IMoniker *new_left, *new_right;
1748 CompositeMonikerImpl *object;
1749 HRESULT hr;
1751 *moniker = NULL;
1753 if (!(object = heap_alloc_zero(sizeof(*object))))
1754 return E_OUTOFMEMORY;
1756 object->IMoniker_iface.lpVtbl = &VT_CompositeMonikerImpl;
1757 object->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
1758 object->IMarshal_iface.lpVtbl = &VT_MarshalImpl;
1759 object->ref = 1;
1761 /* Uninitialized moniker created by object activation */
1762 if (!left && !right)
1764 *moniker = &object->IMoniker_iface;
1765 return S_OK;
1768 if (FAILED(hr = moniker_simplify_composition(left, right, &object->comp_count, &new_left, &new_right)))
1770 IMoniker_Release(&object->IMoniker_iface);
1771 return hr;
1774 if (!new_left || !new_right)
1776 *moniker = new_left ? new_left : new_right;
1777 IMoniker_Release(&object->IMoniker_iface);
1778 return S_OK;
1781 object->left = new_left;
1782 object->right = new_right;
1784 *moniker = &object->IMoniker_iface;
1786 return S_OK;
1789 /******************************************************************************
1790 * CreateGenericComposite [OLE32.@]
1791 ******************************************************************************/
1792 HRESULT WINAPI CreateGenericComposite(IMoniker *left, IMoniker *right, IMoniker **composite)
1794 TRACE("%p, %p, %p\n", left, right, composite);
1796 if (!composite)
1797 return E_POINTER;
1799 if (!left && right)
1801 *composite = right;
1802 IMoniker_AddRef(*composite);
1803 return S_OK;
1805 else if (left && !right)
1807 *composite = left;
1808 IMoniker_AddRef(*composite);
1809 return S_OK;
1811 else if (!left && !right)
1812 return S_OK;
1814 return create_composite(left, right, composite);
1817 /******************************************************************************
1818 * MonikerCommonPrefixWith [OLE32.@]
1819 ******************************************************************************/
1820 HRESULT WINAPI
1821 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1823 FIXME("(),stub!\n");
1824 return E_NOTIMPL;
1827 HRESULT WINAPI CompositeMoniker_CreateInstance(IClassFactory *iface,
1828 IUnknown *pUnk, REFIID riid, void **ppv)
1830 IMoniker* pMoniker;
1831 HRESULT hr;
1833 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
1835 *ppv = NULL;
1837 if (pUnk)
1838 return CLASS_E_NOAGGREGATION;
1840 hr = create_composite(NULL, NULL, &pMoniker);
1842 if (SUCCEEDED(hr))
1844 hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
1845 IMoniker_Release(pMoniker);
1848 return hr;