winspool.drv: Implement OpenPrinter2.
[wine.git] / dlls / ole32 / compositemoniker.c
blob84099cee6d66356c0516df60fc98fdad9c1d8521
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) return MK_E_NOPREFIX;
756 last = prefix_components[0];
757 for (i = 1; i < prefix_len; ++i)
759 hr = CreateGenericComposite(last, prefix_components[i], &c);
760 IMoniker_Release(last);
761 IMoniker_Release(prefix_components[i]);
762 if (FAILED(hr)) break;
763 last = c;
765 heap_free(prefix_components);
767 if (SUCCEEDED(hr))
769 *prefix = last;
770 if (IMoniker_IsEqual(iface, *prefix) == S_OK)
771 hr = MK_S_US;
772 else if (prefix_len < count)
773 hr = S_OK;
774 else
775 hr = prefix_len == moniker->comp_count ? MK_S_ME : MK_S_HIM;
778 return hr;
781 /* For non-composite, compare to leftmost component */
782 if (SUCCEEDED(hr = composite_get_leftmost(moniker, &leftmost)))
784 if ((hr = IMoniker_IsEqual(leftmost, other)) == S_OK)
786 *prefix = leftmost;
787 IMoniker_AddRef(*prefix);
790 hr = hr == S_OK ? MK_S_HIM : MK_E_NOPREFIX;
791 IMoniker_Release(leftmost);
794 return hr;
797 static HRESULT composite_compose_components(IMoniker **comp, unsigned int count, IMoniker **ret)
799 IMoniker *last, *c;
800 HRESULT hr = S_OK;
801 unsigned int i;
803 last = comp[0];
804 IMoniker_AddRef(last);
806 for (i = 1; i < count; ++i)
808 hr = CreateGenericComposite(last, comp[i], &c);
809 IMoniker_Release(last);
810 if (FAILED(hr)) break;
811 last = c;
814 *ret = SUCCEEDED(hr) ? last : NULL;
816 return hr;
819 static HRESULT WINAPI CompositeMonikerImpl_RelativePathTo(IMoniker *iface, IMoniker *other,
820 IMoniker **relpath)
822 unsigned int count, this_count, other_count, prefix_len = 0;
823 IMoniker *inv, *tail = NULL, *other_tail = NULL, *rel = NULL;
824 IMoniker **components, **other_components;
825 unsigned int start = 0, other_start = 0;
826 HRESULT hr;
828 TRACE("%p, %p, %p.\n", iface, other, relpath);
830 if (!relpath)
831 return E_INVALIDARG;
833 *relpath = NULL;
835 if (FAILED(hr = composite_get_components_alloc(iface, &this_count, &components))) return hr;
836 if (FAILED(hr = composite_get_components_alloc(other, &other_count, &other_components)))
838 heap_free(components);
839 return hr;
842 /* Skip common prefix of equal components */
843 count = min(other_count, this_count);
844 while (IMoniker_IsEqual(components[prefix_len], other_components[prefix_len]) == S_OK)
846 if (++prefix_len == count) break;
849 if (prefix_len)
851 this_count -= prefix_len;
852 other_count -= prefix_len;
853 other_start += prefix_len;
854 start += prefix_len;
856 else
858 /* Replace first component of the other tail with relative path */
859 if (SUCCEEDED(hr = IMoniker_RelativePathTo(*components, *other_components, &rel)))
860 *other_components = rel;
862 this_count--;
863 start++;
866 /* Invert left side tail */
867 if (this_count && SUCCEEDED(hr))
869 if (SUCCEEDED(hr = composite_compose_components(&components[start], this_count, &tail)))
871 hr = IMoniker_Inverse(tail, &inv);
872 IMoniker_Release(tail);
873 tail = inv;
877 if (other_count && SUCCEEDED(hr))
878 hr = composite_compose_components(&other_components[other_start], other_count, &other_tail);
880 if (tail || other_tail)
881 hr = CreateGenericComposite(tail, other_tail, relpath);
882 else if (SUCCEEDED(hr))
884 *relpath = other;
885 IMoniker_AddRef(*relpath);
886 hr = MK_S_HIM;
889 if (rel)
890 IMoniker_Release(rel);
891 if (tail)
892 IMoniker_Release(tail);
893 if (other_tail)
894 IMoniker_Release(other_tail);
896 heap_free(other_components);
897 heap_free(components);
899 return hr;
902 static HRESULT WINAPI CompositeMonikerImpl_GetDisplayName(IMoniker *iface, IBindCtx *pbc,
903 IMoniker *pmkToLeft, LPOLESTR *displayname)
905 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
906 WCHAR *left_name = NULL, *right_name = NULL;
907 HRESULT hr;
909 TRACE("%p, %p, %p, %p\n", iface, pbc, pmkToLeft, displayname);
911 if (!pbc || !displayname || !moniker->comp_count)
912 return E_INVALIDARG;
914 if (FAILED(hr = IMoniker_GetDisplayName(moniker->left, pbc, NULL, &left_name))) return hr;
915 if (FAILED(hr = IMoniker_GetDisplayName(moniker->right, pbc, NULL, &right_name)))
917 CoTaskMemFree(left_name);
918 return hr;
921 if (!(*displayname = CoTaskMemAlloc((lstrlenW(left_name) + lstrlenW(right_name) + 1) * sizeof(WCHAR))))
923 CoTaskMemFree(left_name);
924 CoTaskMemFree(right_name);
925 return E_OUTOFMEMORY;
928 lstrcpyW(*displayname, left_name);
929 lstrcatW(*displayname, right_name);
931 CoTaskMemFree(left_name);
932 CoTaskMemFree(right_name);
934 return S_OK;
937 static HRESULT WINAPI CompositeMonikerImpl_ParseDisplayName(IMoniker *iface, IBindCtx *pbc,
938 IMoniker *pmkToLeft, LPOLESTR name, ULONG *eaten, IMoniker **result)
940 CompositeMonikerImpl *moniker = impl_from_IMoniker(iface);
941 IMoniker *left, *rightmost;
942 HRESULT hr;
944 TRACE("%p, %p, %p, %s, %p, %p.\n", iface, pbc, pmkToLeft, debugstr_w(name), eaten, result);
946 if (!pbc)
947 return E_INVALIDARG;
949 if (FAILED(hr = composite_get_rightmost(moniker, &left, &rightmost)))
950 return hr;
952 /* Let rightmost component parse the name, using what's left of the composite as a left side. */
953 hr = IMoniker_ParseDisplayName(rightmost, pbc, left, name, eaten, result);
955 IMoniker_Release(left);
956 IMoniker_Release(rightmost);
958 return hr;
961 /******************************************************************************
962 * CompositeMoniker_IsSystemMoniker
963 ******************************************************************************/
964 static HRESULT WINAPI
965 CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys)
967 TRACE("(%p,%p)\n",iface,pwdMksys);
969 if (!pwdMksys)
970 return E_POINTER;
972 (*pwdMksys)=MKSYS_GENERICCOMPOSITE;
974 return S_OK;
977 /*******************************************************************************
978 * CompositeMonikerIROTData_QueryInterface
979 *******************************************************************************/
980 static HRESULT WINAPI
981 CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,
982 VOID** ppvObject)
984 CompositeMonikerImpl *This = impl_from_IROTData(iface);
986 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject);
988 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppvObject);
991 /***********************************************************************
992 * CompositeMonikerIROTData_AddRef
994 static ULONG WINAPI
995 CompositeMonikerROTDataImpl_AddRef(IROTData *iface)
997 CompositeMonikerImpl *This = impl_from_IROTData(iface);
999 TRACE("(%p)\n",iface);
1001 return IMoniker_AddRef(&This->IMoniker_iface);
1004 /***********************************************************************
1005 * CompositeMonikerIROTData_Release
1007 static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface)
1009 CompositeMonikerImpl *This = impl_from_IROTData(iface);
1011 TRACE("(%p)\n",iface);
1013 return IMoniker_Release(&This->IMoniker_iface);
1016 static HRESULT composite_get_moniker_comparison_data(IMoniker *moniker,
1017 BYTE *data, ULONG max_len, ULONG *ret_len)
1019 IROTData *rot_data;
1020 HRESULT hr;
1022 if (FAILED(hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rot_data)))
1024 WARN("Failed to get IROTData for component moniker, hr %#lx.\n", hr);
1025 return hr;
1028 hr = IROTData_GetComparisonData(rot_data, data, max_len, ret_len);
1029 IROTData_Release(rot_data);
1031 return hr;
1034 static HRESULT WINAPI CompositeMonikerROTDataImpl_GetComparisonData(IROTData *iface,
1035 BYTE *data, ULONG max_len, ULONG *ret_len)
1037 CompositeMonikerImpl *moniker = impl_from_IROTData(iface);
1038 HRESULT hr;
1039 ULONG len;
1041 TRACE("%p, %p, %lu, %p\n", iface, data, max_len, ret_len);
1043 if (!moniker->comp_count)
1044 return E_UNEXPECTED;
1046 /* Get required size first */
1047 *ret_len = sizeof(CLSID);
1049 len = 0;
1050 hr = composite_get_moniker_comparison_data(moniker->left, NULL, 0, &len);
1051 if (SUCCEEDED(hr) || hr == E_OUTOFMEMORY)
1052 *ret_len += len;
1053 else
1055 WARN("Failed to get comparison data length for left component, hr %#lx.\n", hr);
1056 return hr;
1059 len = 0;
1060 hr = composite_get_moniker_comparison_data(moniker->right, NULL, 0, &len);
1061 if (SUCCEEDED(hr) || hr == E_OUTOFMEMORY)
1062 *ret_len += len;
1063 else
1065 WARN("Failed to get comparison data length for right component, hr %#lx.\n", hr);
1066 return hr;
1069 if (max_len < *ret_len)
1070 return E_OUTOFMEMORY;
1072 memcpy(data, &CLSID_CompositeMoniker, sizeof(CLSID));
1073 data += sizeof(CLSID);
1074 max_len -= sizeof(CLSID);
1075 if (FAILED(hr = composite_get_moniker_comparison_data(moniker->left, data, max_len, &len)))
1077 WARN("Failed to get comparison data for left component, hr %#lx.\n", hr);
1078 return hr;
1080 data += len;
1081 max_len -= len;
1082 if (FAILED(hr = composite_get_moniker_comparison_data(moniker->right, data, max_len, &len)))
1084 WARN("Failed to get comparison data for right component, hr %#lx.\n", hr);
1085 return hr;
1088 return S_OK;
1091 static HRESULT WINAPI CompositeMonikerMarshalImpl_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv)
1093 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1095 TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppv);
1097 return CompositeMonikerImpl_QueryInterface(&This->IMoniker_iface, riid, ppv);
1100 static ULONG WINAPI CompositeMonikerMarshalImpl_AddRef(IMarshal *iface)
1102 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1104 TRACE("(%p)\n",iface);
1106 return CompositeMonikerImpl_AddRef(&This->IMoniker_iface);
1109 static ULONG WINAPI CompositeMonikerMarshalImpl_Release(IMarshal *iface)
1111 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1113 TRACE("(%p)\n",iface);
1115 return CompositeMonikerImpl_Release(&This->IMoniker_iface);
1118 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetUnmarshalClass(
1119 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1120 void* pvDestContext, DWORD mshlflags, CLSID* pCid)
1122 CompositeMonikerImpl *This = impl_from_IMarshal(iface);
1124 TRACE("%s, %p, %lx, %p, %lx, %p.\n", debugstr_guid(riid), pv,
1125 dwDestContext, pvDestContext, mshlflags, pCid);
1127 return IMoniker_GetClassID(&This->IMoniker_iface, pCid);
1130 static HRESULT WINAPI CompositeMonikerMarshalImpl_GetMarshalSizeMax(
1131 IMarshal *iface, REFIID riid, void *pv, DWORD dwDestContext,
1132 void* pvDestContext, DWORD mshlflags, DWORD* pSize)
1134 CompositeMonikerImpl *moniker = impl_from_IMarshal(iface);
1135 HRESULT hr;
1136 ULONG size;
1138 TRACE("%s, %p, %lx, %p, %lx, %p.\n", debugstr_guid(riid), pv,
1139 dwDestContext, pvDestContext, mshlflags, pSize);
1141 if (!moniker->comp_count)
1142 return E_UNEXPECTED;
1144 *pSize = 0x10; /* to match native */
1146 if (FAILED(hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)moniker->left, dwDestContext,
1147 pvDestContext, mshlflags)))
1149 return hr;
1151 *pSize += size;
1153 if (FAILED(hr = CoGetMarshalSizeMax(&size, &IID_IMoniker, (IUnknown *)moniker->right, dwDestContext,
1154 pvDestContext, mshlflags)))
1156 return hr;
1158 *pSize += size;
1160 return hr;
1163 static HRESULT WINAPI CompositeMonikerMarshalImpl_MarshalInterface(IMarshal *iface, IStream *stream,
1164 REFIID riid, void *pv, DWORD dwDestContext, void *pvDestContext, DWORD flags)
1166 CompositeMonikerImpl *moniker = impl_from_IMarshal(iface);
1167 HRESULT hr;
1169 TRACE("%p, %p, %s, %p, %lx, %p, %#lx\n", iface, stream, debugstr_guid(riid), pv, dwDestContext, pvDestContext, flags);
1171 if (!moniker->comp_count)
1172 return E_UNEXPECTED;
1174 if (FAILED(hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker->left, dwDestContext, pvDestContext, flags)))
1176 WARN("Failed to marshal left component, hr %#lx.\n", hr);
1177 return hr;
1180 if (FAILED(hr = CoMarshalInterface(stream, &IID_IMoniker, (IUnknown *)moniker->right, dwDestContext, pvDestContext, flags)))
1181 WARN("Failed to marshal right component, hr %#lx.\n", hr);
1183 return hr;
1186 static HRESULT WINAPI CompositeMonikerMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *stream,
1187 REFIID riid, void **ppv)
1189 CompositeMonikerImpl *moniker = impl_from_IMarshal(iface);
1190 HRESULT hr;
1192 TRACE("%p, %p, %s, %p\n", iface, stream, debugstr_guid(riid), ppv);
1194 if (moniker->left)
1196 IMoniker_Release(moniker->left);
1197 moniker->left = NULL;
1200 if (moniker->right)
1202 IMoniker_Release(moniker->right);
1203 moniker->right = NULL;
1206 if (FAILED(hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker->left)))
1208 WARN("Failed to unmarshal left moniker, hr %#lx.\n", hr);
1209 return hr;
1212 if (FAILED(hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&moniker->right)))
1214 WARN("Failed to unmarshal right moniker, hr %#lx.\n", hr);
1215 return hr;
1218 return IMoniker_QueryInterface(&moniker->IMoniker_iface, riid, ppv);
1221 static HRESULT WINAPI CompositeMonikerMarshalImpl_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
1223 TRACE("(%p)\n", pStm);
1224 /* can't release a state-based marshal as nothing on server side to
1225 * release */
1226 return S_OK;
1229 static HRESULT WINAPI CompositeMonikerMarshalImpl_DisconnectObject(IMarshal *iface,
1230 DWORD dwReserved)
1232 TRACE("%#lx\n", dwReserved);
1233 /* can't disconnect a state-based marshal as nothing on server side to
1234 * disconnect from */
1235 return S_OK;
1238 /******************************************************************************
1239 * EnumMonikerImpl_QueryInterface
1240 ******************************************************************************/
1241 static HRESULT WINAPI
1242 EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject)
1244 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1246 TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject);
1248 /* Perform a sanity check on the parameters.*/
1249 if ( ppvObject==0 )
1250 return E_INVALIDARG;
1252 /* Initialize the return parameter */
1253 *ppvObject = 0;
1255 /* Compare the riid with the interface IDs implemented by this object.*/
1256 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid))
1257 *ppvObject = iface;
1259 /* Check that we obtained an interface.*/
1260 if ((*ppvObject)==0)
1261 return E_NOINTERFACE;
1263 /* Query Interface always increases the reference count by one when it is successful */
1264 IEnumMoniker_AddRef(iface);
1266 return S_OK;
1269 /******************************************************************************
1270 * EnumMonikerImpl_AddRef
1271 ******************************************************************************/
1272 static ULONG WINAPI
1273 EnumMonikerImpl_AddRef(IEnumMoniker* iface)
1275 EnumMonikerImpl *This = impl_from_IEnumMoniker(iface);
1277 TRACE("(%p)\n",This);
1279 return InterlockedIncrement(&This->ref);
1283 static ULONG WINAPI EnumMonikerImpl_Release(IEnumMoniker *iface)
1285 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1286 ULONG refcount = InterlockedDecrement(&e->ref);
1287 unsigned int i;
1289 TRACE("%p, refcount %lu.\n", iface, refcount);
1291 if (!refcount)
1293 for (i = 0; i < e->count; ++i)
1294 IMoniker_Release(e->monikers[i]);
1295 heap_free(e->monikers);
1296 heap_free(e);
1299 return refcount;
1302 static HRESULT WINAPI EnumMonikerImpl_Next(IEnumMoniker *iface, ULONG count,
1303 IMoniker **m, ULONG *fetched)
1305 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1306 unsigned int i;
1308 TRACE("%p, %lu, %p, %p.\n", iface, count, m, fetched);
1310 if (!m)
1311 return E_INVALIDARG;
1313 *m = NULL;
1315 /* retrieve the requested number of moniker from the current position */
1316 for (i = 0; (e->pos < e->count) && (i < count); ++i)
1318 m[i] = e->monikers[e->pos++];
1319 IMoniker_AddRef(m[i]);
1322 if (fetched)
1323 *fetched = i;
1325 return i == count ? S_OK : S_FALSE;
1328 static HRESULT WINAPI EnumMonikerImpl_Skip(IEnumMoniker *iface, ULONG count)
1330 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1332 TRACE("%p, %lu.\n", iface, count);
1334 if (!count)
1335 return S_OK;
1337 if ((e->pos + count) >= e->count)
1338 return S_FALSE;
1340 e->pos += count;
1342 return S_OK;
1345 static HRESULT WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface)
1347 EnumMonikerImpl *e = impl_from_IEnumMoniker(iface);
1349 TRACE("%p.\n", iface);
1351 e->pos = 0;
1353 return S_OK;
1356 static HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker *iface, IEnumMoniker **ret)
1358 TRACE("%p, %p.\n", iface, ret);
1360 if (!ret)
1361 return E_INVALIDARG;
1363 *ret = NULL;
1365 return E_NOTIMPL;
1368 static const IEnumMonikerVtbl VT_EnumMonikerImpl =
1370 EnumMonikerImpl_QueryInterface,
1371 EnumMonikerImpl_AddRef,
1372 EnumMonikerImpl_Release,
1373 EnumMonikerImpl_Next,
1374 EnumMonikerImpl_Skip,
1375 EnumMonikerImpl_Reset,
1376 EnumMonikerImpl_Clone
1379 static HRESULT create_enumerator(IMoniker **components, unsigned int count, BOOL forward, IEnumMoniker **ret)
1381 EnumMonikerImpl *object;
1382 unsigned int i;
1384 if (!(object = heap_alloc_zero(sizeof(*object))))
1385 return E_OUTOFMEMORY;
1387 object->IEnumMoniker_iface.lpVtbl = &VT_EnumMonikerImpl;
1388 object->ref = 1;
1389 object->count = count;
1391 if (!(object->monikers = heap_calloc(count, sizeof(*object->monikers))))
1393 heap_free(object);
1394 return E_OUTOFMEMORY;
1397 for (i = 0; i < count; ++i)
1399 object->monikers[i] = forward ? components[i] : components[count - i - 1];
1400 IMoniker_AddRef(object->monikers[i]);
1403 *ret = &object->IEnumMoniker_iface;
1405 return S_OK;
1408 static const IMonikerVtbl VT_CompositeMonikerImpl =
1410 CompositeMonikerImpl_QueryInterface,
1411 CompositeMonikerImpl_AddRef,
1412 CompositeMonikerImpl_Release,
1413 CompositeMonikerImpl_GetClassID,
1414 CompositeMonikerImpl_IsDirty,
1415 CompositeMonikerImpl_Load,
1416 CompositeMonikerImpl_Save,
1417 CompositeMonikerImpl_GetSizeMax,
1418 CompositeMonikerImpl_BindToObject,
1419 CompositeMonikerImpl_BindToStorage,
1420 CompositeMonikerImpl_Reduce,
1421 CompositeMonikerImpl_ComposeWith,
1422 CompositeMonikerImpl_Enum,
1423 CompositeMonikerImpl_IsEqual,
1424 CompositeMonikerImpl_Hash,
1425 CompositeMonikerImpl_IsRunning,
1426 CompositeMonikerImpl_GetTimeOfLastChange,
1427 CompositeMonikerImpl_Inverse,
1428 CompositeMonikerImpl_CommonPrefixWith,
1429 CompositeMonikerImpl_RelativePathTo,
1430 CompositeMonikerImpl_GetDisplayName,
1431 CompositeMonikerImpl_ParseDisplayName,
1432 CompositeMonikerImpl_IsSystemMoniker
1435 /********************************************************************************/
1436 /* Virtual function table for the IROTData class. */
1437 static const IROTDataVtbl VT_ROTDataImpl =
1439 CompositeMonikerROTDataImpl_QueryInterface,
1440 CompositeMonikerROTDataImpl_AddRef,
1441 CompositeMonikerROTDataImpl_Release,
1442 CompositeMonikerROTDataImpl_GetComparisonData
1445 static const IMarshalVtbl VT_MarshalImpl =
1447 CompositeMonikerMarshalImpl_QueryInterface,
1448 CompositeMonikerMarshalImpl_AddRef,
1449 CompositeMonikerMarshalImpl_Release,
1450 CompositeMonikerMarshalImpl_GetUnmarshalClass,
1451 CompositeMonikerMarshalImpl_GetMarshalSizeMax,
1452 CompositeMonikerMarshalImpl_MarshalInterface,
1453 CompositeMonikerMarshalImpl_UnmarshalInterface,
1454 CompositeMonikerMarshalImpl_ReleaseMarshalData,
1455 CompositeMonikerMarshalImpl_DisconnectObject
1458 struct comp_node
1460 IMoniker *moniker;
1461 struct comp_node *parent;
1462 struct comp_node *left;
1463 struct comp_node *right;
1466 static HRESULT moniker_get_tree_representation(IMoniker *moniker, struct comp_node *parent,
1467 struct comp_node **ret)
1469 CompositeMonikerImpl *comp_moniker;
1470 struct comp_node *node;
1472 if (!(node = heap_alloc_zero(sizeof(*node))))
1473 return E_OUTOFMEMORY;
1474 node->parent = parent;
1476 if ((comp_moniker = unsafe_impl_from_IMoniker(moniker)))
1478 moniker_get_tree_representation(comp_moniker->left, node, &node->left);
1479 moniker_get_tree_representation(comp_moniker->right, node, &node->right);
1481 else
1483 node->moniker = moniker;
1484 IMoniker_AddRef(node->moniker);
1487 *ret = node;
1489 return S_OK;
1492 static struct comp_node *moniker_tree_get_rightmost(struct comp_node *root)
1494 if (!root->left && !root->right) return root->moniker ? root : NULL;
1495 while (root->right) root = root->right;
1496 return root;
1499 static struct comp_node *moniker_tree_get_leftmost(struct comp_node *root)
1501 if (!root->left && !root->right) return root->moniker ? root : NULL;
1502 while (root->left) root = root->left;
1503 return root;
1506 static void moniker_tree_node_release(struct comp_node *node)
1508 if (node->moniker)
1509 IMoniker_Release(node->moniker);
1510 heap_free(node);
1513 static void moniker_tree_release(struct comp_node *node)
1515 if (node->left)
1516 moniker_tree_node_release(node->left);
1517 if (node->right)
1518 moniker_tree_node_release(node->right);
1519 moniker_tree_node_release(node);
1522 static void moniker_tree_replace_node(struct comp_node *node, struct comp_node *replace_with)
1524 if (node->parent)
1526 if (node->parent->left == node) node->parent->left = replace_with;
1527 else node->parent->right = replace_with;
1528 replace_with->parent = node->parent;
1530 else if (replace_with->moniker)
1532 /* Replacing root with non-composite */
1533 node->moniker = replace_with->moniker;
1534 IMoniker_AddRef(node->moniker);
1535 node->left = node->right = NULL;
1536 moniker_tree_node_release(replace_with);
1538 else
1540 /* Attaching composite branches to the root */
1541 node->left = replace_with->left;
1542 node->right = replace_with->right;
1543 moniker_tree_node_release(replace_with);
1547 static void moniker_tree_discard(struct comp_node *node, BOOL left)
1549 if (node->parent)
1551 moniker_tree_replace_node(node->parent, left ? node->parent->left : node->parent->right);
1552 moniker_tree_node_release(node);
1554 else
1556 IMoniker_Release(node->moniker);
1557 node->moniker = NULL;
1561 static HRESULT moniker_create_from_tree(const struct comp_node *root, unsigned int *count, IMoniker **moniker)
1563 IMoniker *left_moniker, *right_moniker;
1564 HRESULT hr;
1566 *moniker = NULL;
1568 /* Non-composite node */
1569 if (!root->left && !root->right)
1571 (*count)++;
1572 *moniker = root->moniker;
1573 if (*moniker) IMoniker_AddRef(*moniker);
1574 return S_OK;
1577 if (FAILED(hr = moniker_create_from_tree(root->left, count, &left_moniker))) return hr;
1578 if (FAILED(hr = moniker_create_from_tree(root->right, count, &right_moniker)))
1580 IMoniker_Release(left_moniker);
1581 return hr;
1584 hr = CreateGenericComposite(left_moniker, right_moniker, moniker);
1585 IMoniker_Release(left_moniker);
1586 IMoniker_Release(right_moniker);
1587 return hr;
1590 static void moniker_get_tree_comp_count(const struct comp_node *root, unsigned int *count)
1592 if (!root->left && !root->right)
1594 (*count)++;
1595 return;
1598 moniker_get_tree_comp_count(root->left, count);
1599 moniker_get_tree_comp_count(root->right, count);
1602 static HRESULT composite_get_rightmost(CompositeMonikerImpl *composite, IMoniker **left, IMoniker **rightmost)
1604 struct comp_node *root, *node;
1605 unsigned int count;
1606 HRESULT hr;
1608 /* Shortcut for trivial case when right component is non-composite */
1609 if (!unsafe_impl_from_IMoniker(composite->right))
1611 *left = composite->left;
1612 IMoniker_AddRef(*left);
1613 *rightmost = composite->right;
1614 IMoniker_AddRef(*rightmost);
1615 return S_OK;
1618 *left = *rightmost = NULL;
1620 if (FAILED(hr = moniker_get_tree_representation(&composite->IMoniker_iface, NULL, &root)))
1621 return hr;
1623 if (!(node = moniker_tree_get_rightmost(root)))
1625 WARN("Couldn't get right most component.\n");
1626 return E_FAIL;
1629 *rightmost = node->moniker;
1630 IMoniker_AddRef(*rightmost);
1631 moniker_tree_discard(node, TRUE);
1633 hr = moniker_create_from_tree(root, &count, left);
1634 moniker_tree_release(root);
1635 if (FAILED(hr))
1637 IMoniker_Release(*rightmost);
1638 *rightmost = NULL;
1641 return hr;
1644 static HRESULT composite_get_leftmost(CompositeMonikerImpl *composite, IMoniker **leftmost)
1646 struct comp_node *root, *node;
1647 HRESULT hr;
1649 if (!unsafe_impl_from_IMoniker(composite->left))
1651 *leftmost = composite->left;
1652 IMoniker_AddRef(*leftmost);
1653 return S_OK;
1656 if (FAILED(hr = moniker_get_tree_representation(&composite->IMoniker_iface, NULL, &root)))
1657 return hr;
1659 if (!(node = moniker_tree_get_leftmost(root)))
1661 WARN("Couldn't get right most component.\n");
1662 return E_FAIL;
1665 *leftmost = node->moniker;
1666 IMoniker_AddRef(*leftmost);
1668 moniker_tree_release(root);
1670 return S_OK;
1673 static HRESULT moniker_simplify_composition(IMoniker *left, IMoniker *right,
1674 unsigned int *count, IMoniker **new_left, IMoniker **new_right)
1676 struct comp_node *left_tree, *right_tree;
1677 unsigned int modified = 0;
1678 HRESULT hr = S_OK;
1679 IMoniker *c;
1681 *count = 0;
1683 moniker_get_tree_representation(left, NULL, &left_tree);
1684 moniker_get_tree_representation(right, NULL, &right_tree);
1686 /* Simplify by composing trees together, in a non-generic way. */
1687 for (;;)
1689 struct comp_node *l, *r;
1691 if (!(l = moniker_tree_get_rightmost(left_tree))) break;
1692 if (!(r = moniker_tree_get_leftmost(right_tree))) break;
1694 c = NULL;
1695 if (FAILED(IMoniker_ComposeWith(l->moniker, r->moniker, TRUE, &c))) break;
1696 modified++;
1698 if (c)
1700 /* Replace with composed moniker on the left side */
1701 IMoniker_Release(l->moniker);
1702 l->moniker = c;
1704 else
1705 moniker_tree_discard(l, TRUE);
1706 moniker_tree_discard(r, FALSE);
1709 if (!modified)
1711 *new_left = left;
1712 IMoniker_AddRef(*new_left);
1713 *new_right = right;
1714 IMoniker_AddRef(*new_right);
1716 moniker_get_tree_comp_count(left_tree, count);
1717 moniker_get_tree_comp_count(right_tree, count);
1719 else
1721 hr = moniker_create_from_tree(left_tree, count, new_left);
1722 if (SUCCEEDED(hr))
1723 hr = moniker_create_from_tree(right_tree, count, new_right);
1726 moniker_tree_release(left_tree);
1727 moniker_tree_release(right_tree);
1729 if (FAILED(hr))
1731 if (*new_left) IMoniker_Release(*new_left);
1732 if (*new_right) IMoniker_Release(*new_right);
1733 *new_left = *new_right = NULL;
1736 return hr;
1739 static HRESULT create_composite(IMoniker *left, IMoniker *right, IMoniker **moniker)
1741 IMoniker *new_left, *new_right;
1742 CompositeMonikerImpl *object;
1743 HRESULT hr;
1745 *moniker = NULL;
1747 if (!(object = heap_alloc_zero(sizeof(*object))))
1748 return E_OUTOFMEMORY;
1750 object->IMoniker_iface.lpVtbl = &VT_CompositeMonikerImpl;
1751 object->IROTData_iface.lpVtbl = &VT_ROTDataImpl;
1752 object->IMarshal_iface.lpVtbl = &VT_MarshalImpl;
1753 object->ref = 1;
1755 /* Uninitialized moniker created by object activation */
1756 if (!left && !right)
1758 *moniker = &object->IMoniker_iface;
1759 return S_OK;
1762 if (FAILED(hr = moniker_simplify_composition(left, right, &object->comp_count, &new_left, &new_right)))
1764 IMoniker_Release(&object->IMoniker_iface);
1765 return hr;
1768 if (!new_left || !new_right)
1770 *moniker = new_left ? new_left : new_right;
1771 IMoniker_Release(&object->IMoniker_iface);
1772 return S_OK;
1775 object->left = new_left;
1776 object->right = new_right;
1778 *moniker = &object->IMoniker_iface;
1780 return S_OK;
1783 /******************************************************************************
1784 * CreateGenericComposite [OLE32.@]
1785 ******************************************************************************/
1786 HRESULT WINAPI CreateGenericComposite(IMoniker *left, IMoniker *right, IMoniker **composite)
1788 TRACE("%p, %p, %p\n", left, right, composite);
1790 if (!composite)
1791 return E_POINTER;
1793 if (!left && right)
1795 *composite = right;
1796 IMoniker_AddRef(*composite);
1797 return S_OK;
1799 else if (left && !right)
1801 *composite = left;
1802 IMoniker_AddRef(*composite);
1803 return S_OK;
1805 else if (!left && !right)
1806 return S_OK;
1808 return create_composite(left, right, composite);
1811 /******************************************************************************
1812 * MonikerCommonPrefixWith [OLE32.@]
1813 ******************************************************************************/
1814 HRESULT WINAPI
1815 MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon)
1817 FIXME("(),stub!\n");
1818 return E_NOTIMPL;
1821 HRESULT WINAPI CompositeMoniker_CreateInstance(IClassFactory *iface,
1822 IUnknown *pUnk, REFIID riid, void **ppv)
1824 IMoniker* pMoniker;
1825 HRESULT hr;
1827 TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv);
1829 *ppv = NULL;
1831 if (pUnk)
1832 return CLASS_E_NOAGGREGATION;
1834 hr = create_composite(NULL, NULL, &pMoniker);
1836 if (SUCCEEDED(hr))
1838 hr = IMoniker_QueryInterface(pMoniker, riid, ppv);
1839 IMoniker_Release(pMoniker);
1842 return hr;