gdi32: Fix leak in GdiDeleteSpoolFileHandle.
[wine.git] / dlls / ole32 / compositemoniker.c
blobd322604adcefebc3a9d518540da1dab47c0f0a7e
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"
36 WINE_DEFAULT_DEBUG_CHANNEL(ole);
38 typedef struct CompositeMonikerImpl
40 IMoniker IMoniker_iface;
41 IROTData IROTData_iface;
42 IMarshal IMarshal_iface;
43 LONG ref;
45 IMoniker *left;
46 IMoniker *right;
47 unsigned int comp_count;
48 } CompositeMonikerImpl;
50 static inline CompositeMonikerImpl *impl_from_IMoniker(IMoniker *iface)
52 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMoniker_iface);
55 static const IMonikerVtbl VT_CompositeMonikerImpl;
57 static CompositeMonikerImpl *unsafe_impl_from_IMoniker(IMoniker *iface)
59 if (iface->lpVtbl != &VT_CompositeMonikerImpl)
60 return NULL;
61 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMoniker_iface);
64 static inline CompositeMonikerImpl *impl_from_IROTData(IROTData *iface)
66 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IROTData_iface);
69 static inline CompositeMonikerImpl *impl_from_IMarshal(IMarshal *iface)
71 return CONTAINING_RECORD(iface, CompositeMonikerImpl, IMarshal_iface);
74 typedef struct EnumMonikerImpl
76 IEnumMoniker IEnumMoniker_iface;
77 LONG ref;
78 IMoniker **monikers;
79 unsigned int count;
80 unsigned int pos;
81 } EnumMonikerImpl;
83 static inline EnumMonikerImpl *impl_from_IEnumMoniker(IEnumMoniker *iface)
85 return CONTAINING_RECORD(iface, EnumMonikerImpl, IEnumMoniker_iface);
88 static HRESULT create_enumerator(IMoniker **components, unsigned int count, BOOL forward, IEnumMoniker **ret);
89 static HRESULT composite_get_rightmost(CompositeMonikerImpl *composite, IMoniker **left, IMoniker **rightmost);
90 static HRESULT composite_get_leftmost(CompositeMonikerImpl *composite, IMoniker **leftmost);
92 /*******************************************************************************
93 * CompositeMoniker_QueryInterface
94 *******************************************************************************/
95 static HRESULT WINAPI
96 CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject)
98 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
100 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
102 /* Perform a sanity check on the parameters.*/
103 if ( ppvObject==0 )
104 return E_INVALIDARG;
106 /* Initialize the return parameter */
107 *ppvObject = 0;
109 /* Compare the riid with the interface IDs implemented by this object.*/
110 if (IsEqualIID(&IID_IUnknown, riid) ||
111 IsEqualIID(&IID_IPersist, riid) ||
112 IsEqualIID(&IID_IPersistStream, riid) ||
113 IsEqualIID(&IID_IMoniker, riid)
115 *ppvObject = iface;
116 else if (IsEqualIID(&IID_IROTData, riid))
117 *ppvObject = &This->IROTData_iface;
118 else if (IsEqualIID(&IID_IMarshal, riid))
119 *ppvObject = &This->IMarshal_iface;
121 /* Check that we obtained an interface.*/
122 if ((*ppvObject)==0)
123 return E_NOINTERFACE;
125 /* Query Interface always increases the reference count by one when it is successful */
126 IMoniker_AddRef(iface);
128 return S_OK;
131 /******************************************************************************
132 * CompositeMoniker_AddRef
133 ******************************************************************************/
134 static ULONG WINAPI
135 CompositeMonikerImpl_AddRef(IMoniker* iface)
137 CompositeMonikerImpl *This = impl_from_IMoniker(iface);
139 TRACE("(%p)\n",This);
141 return InterlockedIncrement(&This->ref);
144 static ULONG WINAPI CompositeMonikerImpl_Release(IMoniker* iface)
146 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
147 ULONG refcount = InterlockedDecrement(&moniker->ref);
149 TRACE("%p, refcount %lu\n", iface, refcount);
151 if (!refcount)
153 if (moniker->left) IMoniker_Release(moniker->left);
154 if (moniker->right) IMoniker_Release(moniker->right);
155 free(moniker);
158 return refcount;
161 /******************************************************************************
162 * CompositeMoniker_GetClassID
163 ******************************************************************************/
164 static HRESULT WINAPI
165 CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID)
167 TRACE("(%p,%p)\n",iface,pClassID);
169 if (pClassID==NULL)
170 return E_POINTER;
172 *pClassID = CLSID_CompositeMoniker;
174 return S_OK;
177 /******************************************************************************
178 * CompositeMoniker_IsDirty
179 ******************************************************************************/
180 static HRESULT WINAPI
181 CompositeMonikerImpl_IsDirty(IMoniker* iface)
183 /* Note that the OLE-provided implementations of the IPersistStream::IsDirty
184 method in the OLE-provided moniker interfaces always return S_FALSE because
185 their internal state never changes. */
187 TRACE("(%p)\n",iface);
189 return S_FALSE;
192 static HRESULT WINAPI CompositeMonikerImpl_Load(IMoniker *iface, IStream *stream)
194 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
195 IMoniker *last, *m, *c;
196 DWORD i, count;
197 HRESULT hr;
199 TRACE("%p, %p\n", iface, stream);
201 if (moniker->comp_count)
202 return E_UNEXPECTED;
204 hr = IStream_Read(stream, &count, sizeof(DWORD), NULL);
205 if (hr != S_OK)
207 WARN("Failed to read component count, hr %#lx.\n", hr);
208 return hr;
211 if (count < 2)
213 WARN("Unexpected component count %lu.\n", count);
214 return E_UNEXPECTED;
217 if (FAILED(hr = OleLoadFromStream(stream, &IID_IMoniker, (void **)&last)))
218 return hr;
220 for (i = 1; i < count - 1; ++i)
222 if (FAILED(hr = OleLoadFromStream(stream, &IID_IMoniker, (void **)&m)))
224 WARN("Failed to initialize component %lu, hr %#lx.\n", i, hr);
225 IMoniker_Release(last);
226 return hr;
228 hr = CreateGenericComposite(last, m, &c);
229 IMoniker_Release(last);
230 IMoniker_Release(m);
231 if (FAILED(hr)) return hr;
232 last = c;
235 if (FAILED(hr = OleLoadFromStream(stream, &IID_IMoniker, (void **)&m)))
237 IMoniker_Release(last);
238 return hr;
241 moniker->left = last;
242 moniker->right = m;
243 moniker->comp_count = count;
245 return hr;
248 static HRESULT composite_save_components(IMoniker *moniker, IStream *stream)
250 CompositeMonikerImpl *comp_moniker;
251 HRESULT hr;
253 if ((comp_moniker = unsafe_impl_from_IMoniker(moniker)))
255 if (SUCCEEDED(hr = composite_save_components(comp_moniker->left, stream)))
256 hr = composite_save_components(comp_moniker->right, stream);
258 else
259 hr = OleSaveToStream((IPersistStream *)moniker, stream);
261 return hr;
264 static HRESULT WINAPI CompositeMonikerImpl_Save(IMoniker *iface, IStream *stream, BOOL clear_dirty)
266 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
267 HRESULT hr;
269 TRACE("%p, %p, %d\n", iface, stream, clear_dirty);
271 if (!moniker->comp_count)
272 return E_UNEXPECTED;
274 hr = IStream_Write(stream, &moniker->comp_count, sizeof(moniker->comp_count), NULL);
275 if (FAILED(hr)) return hr;
277 return composite_save_components(iface, stream);
280 /******************************************************************************
281 * CompositeMoniker_GetSizeMax
282 ******************************************************************************/
283 static HRESULT WINAPI
284 CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize)
286 IEnumMoniker *enumMk;
287 IMoniker *pmk;
288 ULARGE_INTEGER ptmpSize;
290 /* The sizeMax of this object is calculated by calling GetSizeMax on
291 * each moniker within this object then summing all returned values
294 TRACE("(%p,%p)\n",iface,pcbSize);
296 if (!pcbSize)
297 return E_POINTER;
299 pcbSize->QuadPart = sizeof(DWORD);
301 IMoniker_Enum(iface,TRUE,&enumMk);
303 while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){
305 IMoniker_GetSizeMax(pmk,&ptmpSize);
307 IMoniker_Release(pmk);
309 pcbSize->QuadPart += ptmpSize.QuadPart + sizeof(CLSID);
312 IEnumMoniker_Release(enumMk);
314 return S_OK;
317 static HRESULT compose_with(IMoniker *left, IMoniker *right, IMoniker **c)
319 HRESULT hr = IMoniker_ComposeWith(left, right, TRUE, c);
320 if (FAILED(hr) && hr != MK_E_NEEDGENERIC) return hr;
321 return CreateGenericComposite(left, right, c);
324 static HRESULT WINAPI CompositeMonikerImpl_BindToObject(IMoniker *iface, IBindCtx *pbc,
325 IMoniker *toleft, REFIID riid, void **result)
327 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
328 IMoniker *left, *rightmost, *c;
329 IRunningObjectTable *rot;
330 IUnknown *object;
331 HRESULT hr;
333 TRACE("%p, %p, %p, %s, %p.\n", iface, pbc, toleft, debugstr_guid(riid), result);
335 if (!result)
336 return E_POINTER;
338 *result = NULL;
340 if (!toleft)
342 hr = IBindCtx_GetRunningObjectTable(pbc, &rot);
343 if (SUCCEEDED(hr))
345 hr = IRunningObjectTable_GetObject(rot, iface, &object);
346 IRunningObjectTable_Release(rot);
347 if (FAILED(hr)) return E_INVALIDARG;
349 hr = IUnknown_QueryInterface(object, riid, result);
350 IUnknown_Release(object);
353 return hr;
356 /* Try to bind rightmost component with (toleft, composite->left) composite at its left side */
357 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
358 return hr;
360 hr = compose_with(toleft, left, &c);
361 IMoniker_Release(left);
363 if (SUCCEEDED(hr))
365 hr = IMoniker_BindToObject(rightmost, pbc, c, riid, result);
366 IMoniker_Release(c);
369 IMoniker_Release(rightmost);
371 return hr;
374 static HRESULT WINAPI CompositeMonikerImpl_BindToStorage(IMoniker *iface, IBindCtx *pbc,
375 IMoniker *toleft, REFIID riid, void **result)
377 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
378 IMoniker *left, *rightmost, *composed_left;
379 HRESULT hr;
381 TRACE("%p, %p, %p, %s, %p.\n", iface, pbc, toleft, debugstr_guid(riid), result);
383 *result = NULL;
385 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
386 return hr;
388 if (toleft)
390 hr = compose_with(toleft, left, &composed_left);
392 else
394 composed_left = left;
395 IMoniker_AddRef(composed_left);
398 if (SUCCEEDED(hr))
400 hr = IMoniker_BindToStorage(rightmost, pbc, composed_left, riid, result);
401 IMoniker_Release(composed_left);
404 IMoniker_Release(rightmost);
405 IMoniker_Release(left);
407 return hr;
410 static HRESULT WINAPI CompositeMonikerImpl_Reduce(IMoniker *iface, IBindCtx *pbc, DWORD howfar,
411 IMoniker **toleft, IMoniker **reduced)
413 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
414 IMoniker *m, *reduced_left, *reduced_right;
415 BOOL was_reduced;
416 HRESULT hr;
418 TRACE("%p, %p, %ld, %p, %p.\n", iface, pbc, howfar, toleft, reduced);
420 if (!pbc || !reduced)
421 return E_INVALIDARG;
423 if (FAILED(hr = IMoniker_Reduce(moniker->left, pbc, howfar, NULL, &reduced_left)))
424 return hr;
426 m = moniker->left;
427 if (FAILED(hr = IMoniker_Reduce(moniker->right, pbc, howfar, &m, &reduced_right)))
429 IMoniker_Release(reduced_left);
430 return hr;
433 if ((was_reduced = (reduced_left != moniker->left || reduced_right != moniker->right)))
435 hr = CreateGenericComposite(reduced_left, reduced_right, reduced);
437 else
439 *reduced = iface;
440 IMoniker_AddRef(*reduced);
443 IMoniker_Release(reduced_left);
444 IMoniker_Release(reduced_right);
446 return was_reduced ? hr : MK_S_REDUCED_TO_SELF;
449 static HRESULT WINAPI CompositeMonikerImpl_ComposeWith(IMoniker *iface, IMoniker *right,
450 BOOL only_if_not_generic, IMoniker **composite)
452 TRACE("%p, %p, %d, %p.\n", iface, right, only_if_not_generic, composite);
454 *composite = NULL;
456 return only_if_not_generic ? MK_E_NEEDGENERIC : CreateGenericComposite(iface, right, composite);
459 static void composite_get_components(IMoniker *moniker, IMoniker **components, unsigned int *index)
461 CompositeMonikerImpl *comp_moniker;
463 if ((comp_moniker = unsafe_impl_from_IMoniker(moniker)))
465 composite_get_components(comp_moniker->left, components, index);
466 composite_get_components(comp_moniker->right, components, index);
468 else
470 components[*index] = moniker;
471 (*index)++;
475 static HRESULT composite_get_components_alloc(IMoniker *iface, unsigned int *count, IMoniker ***components)
477 CompositeMonikerImpl *moniker;
478 unsigned int index;
480 if ((moniker = unsafe_impl_from_IMoniker(iface)))
481 *count = moniker->comp_count;
482 else
483 *count = 1;
485 if (!(*components = malloc(*count * sizeof(**components))))
486 return E_OUTOFMEMORY;
488 index = 0;
489 composite_get_components(iface, *components, &index);
491 return S_OK;
494 static HRESULT WINAPI CompositeMonikerImpl_Enum(IMoniker *iface, BOOL forward, IEnumMoniker **ret_enum)
496 IMoniker **monikers;
497 unsigned int count;
498 HRESULT hr;
500 TRACE("%p, %d, %p\n", iface, forward, ret_enum);
502 if (!ret_enum)
503 return E_INVALIDARG;
505 if (FAILED(hr = composite_get_components_alloc(iface, &count, &monikers)))
506 return hr;
508 hr = create_enumerator(monikers, count, forward, ret_enum);
509 free(monikers);
511 return hr;
514 static HRESULT WINAPI CompositeMonikerImpl_IsEqual(IMoniker *iface, IMoniker *other)
516 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface), *other_moniker;
517 IMoniker **components, **other_components;
518 unsigned int i, count;
519 HRESULT hr;
521 TRACE("%p, %p.\n", iface, other);
523 if (!other)
524 return E_INVALIDARG;
526 if (!(other_moniker = unsafe_impl_from_IMoniker(other)))
527 return S_FALSE;
529 if (moniker->comp_count != other_moniker->comp_count)
530 return S_FALSE;
532 if (FAILED(hr = composite_get_components_alloc(iface, &count, &components))) return hr;
533 if (FAILED(hr = composite_get_components_alloc(other, &count, &other_components)))
535 free(components);
536 return hr;
539 for (i = 0; i < moniker->comp_count; ++i)
541 if ((hr = IMoniker_IsEqual(components[i], other_components[i]) != S_OK))
542 break;
545 free(other_components);
546 free(components);
548 return hr;
551 static HRESULT WINAPI CompositeMonikerImpl_Hash(IMoniker *iface, DWORD *hash)
553 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
554 DWORD left_hash, right_hash;
555 HRESULT hr;
557 TRACE("%p, %p\n", iface, hash);
559 if (!hash)
560 return E_POINTER;
562 if (!moniker->comp_count)
563 return E_UNEXPECTED;
565 *hash = 0;
567 if (FAILED(hr = IMoniker_Hash(moniker->left, &left_hash))) return hr;
568 if (FAILED(hr = IMoniker_Hash(moniker->right, &right_hash))) return hr;
570 *hash = left_hash ^ right_hash;
572 return hr;
575 static HRESULT WINAPI CompositeMonikerImpl_IsRunning(IMoniker *iface, IBindCtx *pbc,
576 IMoniker *toleft, IMoniker *newly_running)
578 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
579 IMoniker *c, *left, *rightmost;
580 IRunningObjectTable *rot;
581 HRESULT hr;
583 TRACE("%p, %p, %p, %p.\n", iface, pbc, toleft, newly_running);
585 if (!pbc)
586 return E_INVALIDARG;
588 if (toleft)
590 if (SUCCEEDED(hr = CreateGenericComposite(toleft, iface, &c)))
592 hr = IMoniker_IsRunning(c, pbc, NULL, newly_running);
593 IMoniker_Release(c);
596 return hr;
599 if (newly_running)
600 return IMoniker_IsEqual(iface, newly_running);
602 if (FAILED(hr = IBindCtx_GetRunningObjectTable(pbc, &rot)))
603 return hr;
605 hr = IRunningObjectTable_IsRunning(rot, iface);
606 IRunningObjectTable_Release(rot);
607 if (hr == S_OK) return S_OK;
609 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
610 return hr;
612 hr = IMoniker_IsRunning(rightmost, pbc, left, NULL);
614 IMoniker_Release(left);
615 IMoniker_Release(rightmost);
617 return hr;
620 static HRESULT WINAPI CompositeMonikerImpl_GetTimeOfLastChange(IMoniker *iface, IBindCtx *pbc,
621 IMoniker *toleft, FILETIME *changetime)
623 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
624 IMoniker *left, *rightmost, *composed_left = NULL, *running = NULL;
625 IRunningObjectTable *rot;
626 HRESULT hr;
628 TRACE("%p, %p, %p, %p.\n", iface, pbc, toleft, changetime);
630 if (!changetime || !pbc)
631 return E_INVALIDARG;
633 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
634 return hr;
636 if (toleft)
638 /* Compose (toleft, left) and check that against rightmost */
639 if (SUCCEEDED(hr = compose_with(toleft, left, &composed_left)) && composed_left)
640 hr = compose_with(composed_left, rightmost, &running);
642 else
644 composed_left = left;
645 IMoniker_AddRef(composed_left);
646 running = iface;
647 IMoniker_AddRef(running);
650 if (SUCCEEDED(hr))
652 if (SUCCEEDED(hr = IBindCtx_GetRunningObjectTable(pbc, &rot)))
654 if (IRunningObjectTable_GetTimeOfLastChange(rot, running, changetime) != S_OK)
655 hr = IMoniker_GetTimeOfLastChange(rightmost, pbc, composed_left, changetime);
656 IRunningObjectTable_Release(rot);
660 if (composed_left)
661 IMoniker_Release(composed_left);
662 if (running)
663 IMoniker_Release(running);
664 IMoniker_Release(rightmost);
665 IMoniker_Release(left);
667 return hr;
670 static HRESULT WINAPI CompositeMonikerImpl_Inverse(IMoniker *iface, IMoniker **inverse)
672 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
673 IMoniker *right_inverted, *left_inverted;
674 HRESULT hr;
676 TRACE("%p, %p.\n", iface, inverse);
678 if (!inverse)
679 return E_INVALIDARG;
681 *inverse = NULL;
683 if (FAILED(hr = IMoniker_Inverse(moniker->right, &right_inverted))) return hr;
684 if (FAILED(hr = IMoniker_Inverse(moniker->left, &left_inverted)))
686 IMoniker_Release(right_inverted);
687 return hr;
690 hr = CreateGenericComposite(right_inverted, left_inverted, inverse);
692 IMoniker_Release(left_inverted);
693 IMoniker_Release(right_inverted);
695 return hr;
698 static HRESULT WINAPI CompositeMonikerImpl_CommonPrefixWith(IMoniker *iface, IMoniker *other,
699 IMoniker **prefix)
701 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface), *other_moniker;
702 unsigned int i, count, prefix_len = 0;
703 IMoniker *leftmost;
704 HRESULT hr;
706 TRACE("%p, %p, %p.\n", iface, other, prefix);
708 /* If the other moniker is a composite, this method compares the components of each composite from left */
709 /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */
710 /* of the leftmost components were common to both monikers. */
712 if (prefix)
713 *prefix = NULL;
715 if (!other || !prefix)
716 return E_INVALIDARG;
718 if ((other_moniker = unsafe_impl_from_IMoniker(other)))
720 IMoniker **components, **other_components, **prefix_components;
721 IMoniker *last, *c;
723 if (FAILED(hr = composite_get_components_alloc(iface, &count, &components))) return hr;
724 if (FAILED(hr = composite_get_components_alloc(other, &count, &other_components)))
726 free(components);
727 return hr;
730 count = min(moniker->comp_count, other_moniker->comp_count);
731 if (!(prefix_components = calloc(count, sizeof(*prefix_components))))
733 free(components);
734 free(other_components);
735 return E_OUTOFMEMORY;
738 /* Collect prefix components */
739 for (i = 0; i < count; ++i)
741 IMoniker *p;
743 if (FAILED(hr = IMoniker_CommonPrefixWith(components[i], other_components[i], &p)))
744 break;
745 prefix_components[prefix_len++] = p;
746 /* S_OK means that prefix was found and is neither of tested monikers */
747 if (hr == S_OK) break;
750 free(components);
751 free(other_components);
753 if (!prefix_len)
755 free(prefix_components);
756 return MK_E_NOPREFIX;
759 last = prefix_components[0];
760 for (i = 1; i < prefix_len; ++i)
762 hr = CreateGenericComposite(last, prefix_components[i], &c);
763 IMoniker_Release(last);
764 IMoniker_Release(prefix_components[i]);
765 if (FAILED(hr)) break;
766 last = c;
768 free(prefix_components);
770 if (SUCCEEDED(hr))
772 *prefix = last;
773 if (IMoniker_IsEqual(iface, *prefix) == S_OK)
774 hr = MK_S_US;
775 else if (prefix_len < count)
776 hr = S_OK;
777 else
778 hr = prefix_len == moniker->comp_count ? MK_S_ME : MK_S_HIM;
781 return hr;
784 /* For non-composite, compare to leftmost component */
785 if (SUCCEEDED(hr = composite_get_leftmost(moniker, &leftmost)))
787 if ((hr = IMoniker_IsEqual(leftmost, other)) == S_OK)
789 *prefix = leftmost;
790 IMoniker_AddRef(*prefix);
793 hr = hr == S_OK ? MK_S_HIM : MK_E_NOPREFIX;
794 IMoniker_Release(leftmost);
797 return hr;
800 static HRESULT composite_compose_components(IMoniker **comp, unsigned int count, IMoniker **ret)
802 IMoniker *last, *c;
803 HRESULT hr = S_OK;
804 unsigned int i;
806 last = comp[0];
807 IMoniker_AddRef(last);
809 for (i = 1; i < count; ++i)
811 hr = CreateGenericComposite(last, comp[i], &c);
812 IMoniker_Release(last);
813 if (FAILED(hr)) break;
814 last = c;
817 *ret = SUCCEEDED(hr) ? last : NULL;
819 return hr;
822 static HRESULT WINAPI CompositeMonikerImpl_RelativePathTo(IMoniker *iface, IMoniker *other,
823 IMoniker **relpath)
825 unsigned int count, this_count, other_count, prefix_len = 0;
826 IMoniker *inv, *tail = NULL, *other_tail = NULL, *rel = NULL;
827 IMoniker **components, **other_components;
828 unsigned int start = 0, other_start = 0;
829 HRESULT hr;
831 TRACE("%p, %p, %p.\n", iface, other, relpath);
833 if (!relpath)
834 return E_INVALIDARG;
836 *relpath = NULL;
838 if (FAILED(hr = composite_get_components_alloc(iface, &this_count, &components))) return hr;
839 if (FAILED(hr = composite_get_components_alloc(other, &other_count, &other_components)))
841 free(components);
842 return hr;
845 /* Skip common prefix of equal components */
846 count = min(other_count, this_count);
847 while (IMoniker_IsEqual(components[prefix_len], other_components[prefix_len]) == S_OK)
849 if (++prefix_len == count) break;
852 if (prefix_len)
854 this_count -= prefix_len;
855 other_count -= prefix_len;
856 other_start += prefix_len;
857 start += prefix_len;
859 else
861 /* Replace first component of the other tail with relative path */
862 if (SUCCEEDED(hr = IMoniker_RelativePathTo(*components, *other_components, &rel)))
863 *other_components = rel;
865 this_count--;
866 start++;
869 /* Invert left side tail */
870 if (this_count && SUCCEEDED(hr))
872 if (SUCCEEDED(hr = composite_compose_components(&components[start], this_count, &tail)))
874 hr = IMoniker_Inverse(tail, &inv);
875 IMoniker_Release(tail);
876 tail = inv;
880 if (other_count && SUCCEEDED(hr))
881 hr = composite_compose_components(&other_components[other_start], other_count, &other_tail);
883 if (tail || other_tail)
884 hr = CreateGenericComposite(tail, other_tail, relpath);
885 else if (SUCCEEDED(hr))
887 *relpath = other;
888 IMoniker_AddRef(*relpath);
889 hr = MK_S_HIM;
892 if (rel)
893 IMoniker_Release(rel);
894 if (tail)
895 IMoniker_Release(tail);
896 if (other_tail)
897 IMoniker_Release(other_tail);
899 free(other_components);
900 free(components);
902 return hr;
905 static HRESULT WINAPI CompositeMonikerImpl_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
906 IMoniker *pmkToLeft, LPOLESTR *displayname)
908 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
909 WCHAR *left_name = NULL, *right_name = NULL;
910 HRESULT hr;
912 TRACE("%p, %p, %p, %p\n", iface, pbc, pmkToLeft, displayname);
914 if (!pbc || !displayname || !moniker->comp_count)
915 return E_INVALIDARG;
917 if (FAILED(hr = IMoniker_GetDisplayName(moniker->left, pbc, NULL, &left_name))) return hr;
918 if (FAILED(hr = IMoniker_GetDisplayName(moniker->right, pbc, NULL, &right_name)))
920 CoTaskMemFree(left_name);
921 return hr;
924 if (!(*displayname = CoTaskMemAlloc((lstrlenW(left_name) + lstrlenW(right_name) + 1) * sizeof(WCHAR))))
926 CoTaskMemFree(left_name);
927 CoTaskMemFree(right_name);
928 return E_OUTOFMEMORY;
931 lstrcpyW(*displayname, left_name);
932 lstrcatW(*displayname, right_name);
934 CoTaskMemFree(left_name);
935 CoTaskMemFree(right_name);
937 return S_OK;
940 static HRESULT WINAPI CompositeMonikerImpl_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
941 IMoniker *pmkToLeft, LPOLESTR name, ULONG *eaten, IMoniker **result)
943 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
944 IMoniker *left, *rightmost;
945 HRESULT hr;
947 TRACE("%p, %p, %p, %s, %p, %p.\n", iface, pbc, pmkToLeft, debugstr_w(name), eaten, result);
949 if (!pbc)
950 return E_INVALIDARG;
952 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
953 return hr;
955 /* Let rightmost component parse the name, using what's left of the composite as a left side. */
956 hr = IMoniker_ParseDisplayName(rightmost, pbc, left, name, eaten, result);
958 IMoniker_Release(left);
959 IMoniker_Release(rightmost);
961 return hr;
964 /******************************************************************************
965 * CompositeMoniker_IsSystemMoniker
966 ******************************************************************************/
967 static HRESULT WINAPI
968 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
970 TRACE("(%p,%p)\n",iface,pwdMksys);
972 if (!pwdMksys)
973 return E_POINTER;
975 (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
977 return S_OK;
980 /*******************************************************************************
981 * CompositeMonikerIROTData_QueryInterface
982 *******************************************************************************/
983 static HRESULT WINAPI
984 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
985 VOID** ppvObject)
987 CompositeMonikerImpl *This = impl_from_IROTData(iface);
989 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject);
991 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
994 /***********************************************************************
995 * CompositeMonikerIROTData_AddRef
997 static ULONG WINAPI
998 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
1000 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1002 TRACE("(%p)\n",iface);
1004 return IMoniker_AddRef(&This->IMoniker_iface);
1007 /***********************************************************************
1008 * CompositeMonikerIROTData_Release
1010 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1012 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1014 TRACE("(%p)\n",iface);
1016 return IMoniker_Release(&This->IMoniker_iface);
1019 static HRESULT composite_get_moniker_comparison_data(IMoniker *moniker,
1020 BYTE *data, ULONG max_len, ULONG *ret_len)
1022 IROTData *rot_data;
1023 HRESULT hr;
1025 if (FAILED(hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rot_data)))
1027 WARN("Failed to get IROTData for component moniker, hr %#lx.\n", hr);
1028 return hr;
1031 hr = IROTData_GetComparisonData(rot_data, data, max_len, ret_len);
1032 IROTData_Release(rot_data);
1034 return hr;
1037 static HRESULT WINAPI CompositeMonikerROTDataImpl_GetComparisonData(IROTData *iface,
1038 BYTE *data, ULONG max_len, ULONG *ret_len)
1040 CompositeMonikerImpl *moniker = impl_from_IROTData(iface);
1041 HRESULT hr;
1042 ULONG len;
1044 TRACE("%p, %p, %lu, %p\n", iface, data, max_len, ret_len);
1046 if (!moniker->comp_count)
1047 return E_UNEXPECTED;
1049 /* Get required size first */
1050 *ret_len = sizeof(CLSID);
1052 len = 0;
1053 hr = composite_get_moniker_comparison_data(moniker->left, NULL, 0, &len);
1054 if (SUCCEEDED(hr) || hr == E_OUTOFMEMORY)
1055 *ret_len += len;
1056 else
1058 WARN("Failed to get comparison data length for left component, hr %#lx.\n", hr);
1059 return hr;
1062 len = 0;
1063 hr = composite_get_moniker_comparison_data(moniker->right, NULL, 0, &len);
1064 if (SUCCEEDED(hr) || hr == E_OUTOFMEMORY)
1065 *ret_len += len;
1066 else
1068 WARN("Failed to get comparison data length for right component, hr %#lx.\n", hr);
1069 return hr;
1072 if (max_len < *ret_len)
1073 return E_OUTOFMEMORY;
1075 memcpy(data, &CLSID_CompositeMoniker, sizeof(CLSID));
1076 data += sizeof(CLSID);
1077 max_len -= sizeof(CLSID);
1078 if (FAILED(hr = composite_get_moniker_comparison_data(moniker->left, data, max_len, &len)))
1080 WARN("Failed to get comparison data for left component, hr %#lx.\n", hr);
1081 return hr;
1083 data += len;
1084 max_len -= len;
1085 if (FAILED(hr = composite_get_moniker_comparison_data(moniker->right, data, max_len, &len)))
1087 WARN("Failed to get comparison data for right component, hr %#lx.\n", hr);
1088 return hr;
1091 return S_OK;
1094 static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1096 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1098 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);
1100 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppv);
1103 static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
1105 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1107 TRACE("(%p)\n",iface);
1109 return CompositeMonikerImpl_AddRef(&This->IMoniker_iface);
1112 static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
1114 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1116 TRACE("(%p)\n",iface);
1118 return CompositeMonikerImpl_Release(&This->IMoniker_iface);
1121 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
1122 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1123 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1125 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1127 TRACE("%s, %p, %lx, %p, %lx, %p.\n", debugstr_guid(riid), pv,
1128 dwDestContext, pvDestContext, mshlflags, pCid);
1130 return IMoniker_GetClassID(&This->IMoniker_iface, pCid);
1133 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
1134 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1135 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1137 CompositeMonikerImpl *moniker = impl_from_IMarshal(iface);
1138 HRESULT hr;
1139 ULONG size;
1141 TRACE("%s, %p, %lx, %p, %lx, %p.\n", debugstr_guid(riid), pv,
1142 dwDestContext, pvDestContext, mshlflags, pSize);
1144 if (!moniker->comp_count)
1145 return E_UNEXPECTED;
1147 *pSize = 0x10; /* to match native */
1149 if (FAILED(hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)moniker->left, dwDestContext,
1150 pvDestContext, mshlflags)))
1152 return hr;
1154 *pSize += size;
1156 if (FAILED(hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)moniker->right, dwDestContext,
1157 pvDestContext, mshlflags)))
1159 return hr;
1161 *pSize += size;
1163 return hr;
1166 static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(IMarshal *iface, IStream *stream,
1167 REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD flags)
1169 CompositeMonikerImpl *moniker = impl_from_IMarshal(iface);
1170 HRESULT hr;
1172 TRACE("%p, %p, %s, %p, %lx, %p, %#lx\n", iface, stream, debugstr_guid(riid), pv, dwDestContext, pvDestContext, flags);
1174 if (!moniker->comp_count)
1175 return E_UNEXPECTED;
1177 if (FAILED(hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker->left, dwDestContext, pvDestContext, flags)))
1179 WARN("Failed to marshal left component, hr %#lx.\n", hr);
1180 return hr;
1183 if (FAILED(hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker->right, dwDestContext, pvDestContext, flags)))
1184 WARN("Failed to marshal right component, hr %#lx.\n", hr);
1186 return hr;
1189 static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *stream,
1190 REFIID riid, void **ppv)
1192 CompositeMonikerImpl *moniker = impl_from_IMarshal(iface);
1193 HRESULT hr;
1195 TRACE("%p, %p, %s, %p\n", iface, stream, debugstr_guid(riid), ppv);
1197 if (moniker->left)
1199 IMoniker_Release(moniker->left);
1200 moniker->left = NULL;
1203 if (moniker->right)
1205 IMoniker_Release(moniker->right);
1206 moniker->right = NULL;
1209 if (FAILED(hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker->left)))
1211 WARN("Failed to unmarshal left moniker, hr %#lx.\n", hr);
1212 return hr;
1215 if (FAILED(hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker->right)))
1217 WARN("Failed to unmarshal right moniker, hr %#lx.\n", hr);
1218 return hr;
1221 return IMoniker_QueryInterface(&moniker->IMoniker_iface, riid, ppv);
1224 static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1226 TRACE("(%p)\n", pStm);
1227 /* can't release a state-based marshal as nothing on server side to
1228 * release */
1229 return S_OK;
1232 static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(IMarshal *iface,
1233 DWORD dwReserved)
1235 TRACE("%#lx\n", dwReserved);
1236 /* can't disconnect a state-based marshal as nothing on server side to
1237 * disconnect from */
1238 return S_OK;
1241 /******************************************************************************
1242 * EnumMonikerImpl_QueryInterface
1243 ******************************************************************************/
1244 static HRESULT WINAPI
1245 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1247 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1249 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1251 /* Perform a sanity check on the parameters.*/
1252 if ( ppvObject==0 )
1253 return E_INVALIDARG;
1255 /* Initialize the return parameter */
1256 *ppvObject = 0;
1258 /* Compare the riid with the interface IDs implemented by this object.*/
1259 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
1260 *ppvObject = iface;
1262 /* Check that we obtained an interface.*/
1263 if ((*ppvObject)==0)
1264 return E_NOINTERFACE;
1266 /* Query Interface always increases the reference count by one when it is successful */
1267 IEnumMoniker_AddRef(iface);
1269 return S_OK;
1272 /******************************************************************************
1273 * EnumMonikerImpl_AddRef
1274 ******************************************************************************/
1275 static ULONG WINAPI
1276 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1278 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1280 TRACE("(%p)\n",This);
1282 return InterlockedIncrement(&This->ref);
1286 static ULONG WINAPI EnumMonikerImpl_Release(IEnumMoniker *iface)
1288 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1289 ULONG refcount = InterlockedDecrement(&e->ref);
1290 unsigned int i;
1292 TRACE("%p, refcount %lu.\n", iface, refcount);
1294 if (!refcount)
1296 for (i = 0; i < e->count; ++i)
1297 IMoniker_Release(e->monikers[i]);
1298 free(e->monikers);
1299 free(e);
1302 return refcount;
1305 static HRESULT WINAPI EnumMonikerImpl_Next(IEnumMoniker *iface, ULONG count,
1306 IMoniker **m, ULONG *fetched)
1308 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1309 unsigned int i;
1311 TRACE("%p, %lu, %p, %p.\n", iface, count, m, fetched);
1313 if (!m)
1314 return E_INVALIDARG;
1316 *m = NULL;
1318 /* retrieve the requested number of moniker from the current position */
1319 for (i = 0; (e->pos < e->count) && (i < count); ++i)
1321 m[i] = e->monikers[e->pos++];
1322 IMoniker_AddRef(m[i]);
1325 if (fetched)
1326 *fetched = i;
1328 return i == count ? S_OK : S_FALSE;
1331 static HRESULT WINAPI EnumMonikerImpl_Skip(IEnumMoniker *iface, ULONG count)
1333 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1335 TRACE("%p, %lu.\n", iface, count);
1337 if (!count)
1338 return S_OK;
1340 if ((e->pos + count) >= e->count)
1341 return S_FALSE;
1343 e->pos += count;
1345 return S_OK;
1348 static HRESULT WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface)
1350 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1352 TRACE("%p.\n", iface);
1354 e->pos = 0;
1356 return S_OK;
1359 static HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker *iface, IEnumMoniker **ret)
1361 TRACE("%p, %p.\n", iface, ret);
1363 if (!ret)
1364 return E_INVALIDARG;
1366 *ret = NULL;
1368 return E_NOTIMPL;
1371 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1373 EnumMonikerImpl_QueryInterface,
1374 EnumMonikerImpl_AddRef,
1375 EnumMonikerImpl_Release,
1376 EnumMonikerImpl_Next,
1377 EnumMonikerImpl_Skip,
1378 EnumMonikerImpl_Reset,
1379 EnumMonikerImpl_Clone
1382 static HRESULT create_enumerator(IMoniker **components, unsigned int count, BOOL forward, IEnumMoniker **ret)
1384 EnumMonikerImpl *object;
1385 unsigned int i;
1387 if (!(object = calloc(1, sizeof(*object))))
1388 return E_OUTOFMEMORY;
1390 object->IEnumMoniker_iface.lpVtbl = &VT_EnumMonikerImpl;
1391 object->ref = 1;
1392 object->count = count;
1394 if (!(object->monikers = calloc(count, sizeof(*object->monikers))))
1396 free(object);
1397 return E_OUTOFMEMORY;
1400 for (i = 0; i < count; ++i)
1402 object->monikers[i] = forward ? components[i] : components[count - i - 1];
1403 IMoniker_AddRef(object->monikers[i]);
1406 *ret = &object->IEnumMoniker_iface;
1408 return S_OK;
1411 static const IMonikerVtbl VT_CompositeMonikerImpl =
1413 CompositeMonikerImpl_QueryInterface,
1414 CompositeMonikerImpl_AddRef,
1415 CompositeMonikerImpl_Release,
1416 CompositeMonikerImpl_GetClassID,
1417 CompositeMonikerImpl_IsDirty,
1418 CompositeMonikerImpl_Load,
1419 CompositeMonikerImpl_Save,
1420 CompositeMonikerImpl_GetSizeMax,
1421 CompositeMonikerImpl_BindToObject,
1422 CompositeMonikerImpl_BindToStorage,
1423 CompositeMonikerImpl_Reduce,
1424 CompositeMonikerImpl_ComposeWith,
1425 CompositeMonikerImpl_Enum,
1426 CompositeMonikerImpl_IsEqual,
1427 CompositeMonikerImpl_Hash,
1428 CompositeMonikerImpl_IsRunning,
1429 CompositeMonikerImpl_GetTimeOfLastChange,
1430 CompositeMonikerImpl_Inverse,
1431 CompositeMonikerImpl_CommonPrefixWith,
1432 CompositeMonikerImpl_RelativePathTo,
1433 CompositeMonikerImpl_GetDisplayName,
1434 CompositeMonikerImpl_ParseDisplayName,
1435 CompositeMonikerImpl_IsSystemMoniker
1438 /********************************************************************************/
1439 /* Virtual function table for the IROTData class. */
1440 static const IROTDataVtbl VT_ROTDataImpl =
1442 CompositeMonikerROTDataImpl_QueryInterface,
1443 CompositeMonikerROTDataImpl_AddRef,
1444 CompositeMonikerROTDataImpl_Release,
1445 CompositeMonikerROTDataImpl_GetComparisonData
1448 static const IMarshalVtbl VT_MarshalImpl =
1450 CompositeMonikerMarshalImpl_QueryInterface,
1451 CompositeMonikerMarshalImpl_AddRef,
1452 CompositeMonikerMarshalImpl_Release,
1453 CompositeMonikerMarshalImpl_GetUnmarshalClass,
1454 CompositeMonikerMarshalImpl_GetMarshalSizeMax,
1455 CompositeMonikerMarshalImpl_MarshalInterface,
1456 CompositeMonikerMarshalImpl_UnmarshalInterface,
1457 CompositeMonikerMarshalImpl_ReleaseMarshalData,
1458 CompositeMonikerMarshalImpl_DisconnectObject
1461 struct comp_node
1463 IMoniker *moniker;
1464 struct comp_node *parent;
1465 struct comp_node *left;
1466 struct comp_node *right;
1469 static HRESULT moniker_get_tree_representation(IMoniker *moniker, struct comp_node *parent,
1470 struct comp_node **ret)
1472 CompositeMonikerImpl *comp_moniker;
1473 struct comp_node *node;
1475 if (!(node = calloc(1, sizeof(*node))))
1476 return E_OUTOFMEMORY;
1477 node->parent = parent;
1479 if ((comp_moniker = unsafe_impl_from_IMoniker(moniker)))
1481 moniker_get_tree_representation(comp_moniker->left, node, &node->left);
1482 moniker_get_tree_representation(comp_moniker->right, node, &node->right);
1484 else
1486 node->moniker = moniker;
1487 IMoniker_AddRef(node->moniker);
1490 *ret = node;
1492 return S_OK;
1495 static struct comp_node *moniker_tree_get_rightmost(struct comp_node *root)
1497 if (!root->left && !root->right) return root->moniker ? root : NULL;
1498 while (root->right) root = root->right;
1499 return root;
1502 static struct comp_node *moniker_tree_get_leftmost(struct comp_node *root)
1504 if (!root->left && !root->right) return root->moniker ? root : NULL;
1505 while (root->left) root = root->left;
1506 return root;
1509 static void moniker_tree_node_release(struct comp_node *node)
1511 if (node->moniker)
1512 IMoniker_Release(node->moniker);
1513 free(node);
1516 static void moniker_tree_release(struct comp_node *node)
1518 if (node->left)
1519 moniker_tree_node_release(node->left);
1520 if (node->right)
1521 moniker_tree_node_release(node->right);
1522 moniker_tree_node_release(node);
1525 static void moniker_tree_replace_node(struct comp_node *node, struct comp_node *replace_with)
1527 if (node->parent)
1529 if (node->parent->left == node) node->parent->left = replace_with;
1530 else node->parent->right = replace_with;
1531 replace_with->parent = node->parent;
1533 else if (replace_with->moniker)
1535 /* Replacing root with non-composite */
1536 node->moniker = replace_with->moniker;
1537 IMoniker_AddRef(node->moniker);
1538 node->left = node->right = NULL;
1539 moniker_tree_node_release(replace_with);
1541 else
1543 /* Attaching composite branches to the root */
1544 node->left = replace_with->left;
1545 node->right = replace_with->right;
1546 moniker_tree_node_release(replace_with);
1550 static void moniker_tree_discard(struct comp_node *node, BOOL left)
1552 if (node->parent)
1554 moniker_tree_replace_node(node->parent, left ? node->parent->left : node->parent->right);
1555 moniker_tree_node_release(node);
1557 else
1559 IMoniker_Release(node->moniker);
1560 node->moniker = NULL;
1564 static HRESULT moniker_create_from_tree(const struct comp_node *root, unsigned int *count, IMoniker **moniker)
1566 IMoniker *left_moniker, *right_moniker;
1567 HRESULT hr;
1569 *moniker = NULL;
1571 /* Non-composite node */
1572 if (!root->left && !root->right)
1574 (*count)++;
1575 *moniker = root->moniker;
1576 if (*moniker) IMoniker_AddRef(*moniker);
1577 return S_OK;
1580 if (FAILED(hr = moniker_create_from_tree(root->left, count, &left_moniker))) return hr;
1581 if (FAILED(hr = moniker_create_from_tree(root->right, count, &right_moniker)))
1583 IMoniker_Release(left_moniker);
1584 return hr;
1587 hr = CreateGenericComposite(left_moniker, right_moniker, moniker);
1588 IMoniker_Release(left_moniker);
1589 IMoniker_Release(right_moniker);
1590 return hr;
1593 static void moniker_get_tree_comp_count(const struct comp_node *root, unsigned int *count)
1595 if (!root->left && !root->right)
1597 (*count)++;
1598 return;
1601 moniker_get_tree_comp_count(root->left, count);
1602 moniker_get_tree_comp_count(root->right, count);
1605 static HRESULT composite_get_rightmost(CompositeMonikerImpl *composite, IMoniker **left, IMoniker **rightmost)
1607 struct comp_node *root, *node;
1608 unsigned int count;
1609 HRESULT hr;
1611 /* Shortcut for trivial case when right component is non-composite */
1612 if (!unsafe_impl_from_IMoniker(composite->right))
1614 *left = composite->left;
1615 IMoniker_AddRef(*left);
1616 *rightmost = composite->right;
1617 IMoniker_AddRef(*rightmost);
1618 return S_OK;
1621 *left = *rightmost = NULL;
1623 if (FAILED(hr = moniker_get_tree_representation(&composite->IMoniker_iface, NULL, &root)))
1624 return hr;
1626 if (!(node = moniker_tree_get_rightmost(root)))
1628 WARN("Couldn't get right most component.\n");
1629 moniker_tree_release(root);
1630 return E_FAIL;
1633 *rightmost = node->moniker;
1634 IMoniker_AddRef(*rightmost);
1635 moniker_tree_discard(node, TRUE);
1637 hr = moniker_create_from_tree(root, &count, left);
1638 moniker_tree_release(root);
1639 if (FAILED(hr))
1641 IMoniker_Release(*rightmost);
1642 *rightmost = NULL;
1645 return hr;
1648 static HRESULT composite_get_leftmost(CompositeMonikerImpl *composite, IMoniker **leftmost)
1650 struct comp_node *root, *node;
1651 HRESULT hr;
1653 if (!unsafe_impl_from_IMoniker(composite->left))
1655 *leftmost = composite->left;
1656 IMoniker_AddRef(*leftmost);
1657 return S_OK;
1660 if (FAILED(hr = moniker_get_tree_representation(&composite->IMoniker_iface, NULL, &root)))
1661 return hr;
1663 if (!(node = moniker_tree_get_leftmost(root)))
1665 WARN("Couldn't get left most component.\n");
1666 moniker_tree_release(root);
1667 return E_FAIL;
1670 *leftmost = node->moniker;
1671 IMoniker_AddRef(*leftmost);
1673 moniker_tree_release(root);
1675 return S_OK;
1678 static HRESULT moniker_simplify_composition(IMoniker *left, IMoniker *right,
1679 unsigned int *count, IMoniker **new_left, IMoniker **new_right)
1681 struct comp_node *left_tree, *right_tree;
1682 unsigned int modified = 0;
1683 HRESULT hr = S_OK;
1684 IMoniker *c;
1686 *count = 0;
1688 moniker_get_tree_representation(left, NULL, &left_tree);
1689 moniker_get_tree_representation(right, NULL, &right_tree);
1691 /* Simplify by composing trees together, in a non-generic way. */
1692 for (;;)
1694 struct comp_node *l, *r;
1696 if (!(l = moniker_tree_get_rightmost(left_tree))) break;
1697 if (!(r = moniker_tree_get_leftmost(right_tree))) break;
1699 c = NULL;
1700 if (FAILED(IMoniker_ComposeWith(l->moniker, r->moniker, TRUE, &c))) break;
1701 modified++;
1703 if (c)
1705 /* Replace with composed moniker on the left side */
1706 IMoniker_Release(l->moniker);
1707 l->moniker = c;
1709 else
1710 moniker_tree_discard(l, TRUE);
1711 moniker_tree_discard(r, FALSE);
1714 if (!modified)
1716 *new_left = left;
1717 IMoniker_AddRef(*new_left);
1718 *new_right = right;
1719 IMoniker_AddRef(*new_right);
1721 moniker_get_tree_comp_count(left_tree, count);
1722 moniker_get_tree_comp_count(right_tree, count);
1724 else
1726 hr = moniker_create_from_tree(left_tree, count, new_left);
1727 if (SUCCEEDED(hr))
1728 hr = moniker_create_from_tree(right_tree, count, new_right);
1731 moniker_tree_release(left_tree);
1732 moniker_tree_release(right_tree);
1734 if (FAILED(hr))
1736 if (*new_left) IMoniker_Release(*new_left);
1737 if (*new_right) IMoniker_Release(*new_right);
1738 *new_left = *new_right = NULL;
1741 return hr;
1744 static HRESULT create_composite(IMoniker *left, IMoniker *right, IMoniker **moniker)
1746 IMoniker *new_left, *new_right;
1747 CompositeMonikerImpl *object;
1748 HRESULT hr;
1750 *moniker = NULL;
1752 if (!(object = calloc(1, sizeof(*object))))
1753 return E_OUTOFMEMORY;
1755 object->IMoniker_iface.lpVtbl = &VT_CompositeMonikerImpl;
1756 object->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
1757 object->IMarshal_iface.lpVtbl = &VT_MarshalImpl;
1758 object->ref = 1;
1760 /* Uninitialized moniker created by object activation */
1761 if (!left && !right)
1763 *moniker = &object->IMoniker_iface;
1764 return S_OK;
1767 if (FAILED(hr = moniker_simplify_composition(left, right, &object->comp_count, &new_left, &new_right)))
1769 IMoniker_Release(&object->IMoniker_iface);
1770 return hr;
1773 if (!new_left || !new_right)
1775 *moniker = new_left ? new_left : new_right;
1776 IMoniker_Release(&object->IMoniker_iface);
1777 return S_OK;
1780 object->left = new_left;
1781 object->right = new_right;
1783 *moniker = &object->IMoniker_iface;
1785 return S_OK;
1788 /******************************************************************************
1789 * CreateGenericComposite [OLE32.@]
1790 ******************************************************************************/
1791 HRESULT WINAPI CreateGenericComposite(IMoniker *left, IMoniker *right, IMoniker **composite)
1793 TRACE("%p, %p, %p\n", left, right, composite);
1795 if (!composite)
1796 return E_POINTER;
1798 if (!left && right)
1800 *composite = right;
1801 IMoniker_AddRef(*composite);
1802 return S_OK;
1804 else if (left && !right)
1806 *composite = left;
1807 IMoniker_AddRef(*composite);
1808 return S_OK;
1810 else if (!left && !right)
1811 return S_OK;
1813 return create_composite(left, right, composite);
1816 /******************************************************************************
1817 * MonikerCommonPrefixWith [OLE32.@]
1818 ******************************************************************************/
1819 HRESULT WINAPI
1820 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1822 FIXME("(),stub!\n");
1823 return E_NOTIMPL;
1826 HRESULT WINAPI CompositeMoniker_CreateInstance(IClassFactory *iface,
1827 IUnknown *pUnk, REFIID riid, void **ppv)
1829 IMoniker* pMoniker;
1830 HRESULT hr;
1832 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
1834 *ppv = NULL;
1836 if (pUnk)
1837 return CLASS_E_NOAGGREGATION;
1839 hr = create_composite(NULL, NULL, &pMoniker);
1841 if (SUCCEEDED(hr))
1843 hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
1844 IMoniker_Release(pMoniker);
1847 return hr;