1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
6 /*============================================================
9 ** Purpose: part of ComEventHelpers APIs which allow binding
10 ** managed delegates to COM's connection point based events.
15 using System.Diagnostics;
17 namespace System.Runtime.InteropServices
19 // see code:ComEventsHelper#ComEventsArchitecture
20 internal class ComEventsSink : ICustomQueryInterface
22 #region private fields
24 private Guid _iidSourceItf;
25 private ComTypes.IConnectionPoint _connectionPoint;
27 private ComEventsMethod _methods;
28 private ComEventsSink _next;
35 internal ComEventsSink(object rcw, Guid iid)
44 #region static members
46 internal static ComEventsSink Find(ComEventsSink sinks, ref Guid iid)
48 ComEventsSink sink = sinks;
49 while (sink != null && sink._iidSourceItf != iid)
57 internal static ComEventsSink Add(ComEventsSink sinks, ComEventsSink sink)
63 internal static ComEventsSink RemoveAll(ComEventsSink sinks)
74 internal static ComEventsSink Remove(ComEventsSink sinks, ComEventsSink sink)
76 Debug.Assert(sinks != null, "removing event sink from empty sinks collection");
77 Debug.Assert(sink != null, "specify event sink is null");
85 ComEventsSink current = sinks;
86 while (current != null && current._next != sink)
87 current = current._next;
91 current._next = sink._next;
103 #region public methods
105 public ComEventsMethod RemoveMethod(ComEventsMethod method)
107 _methods = ComEventsMethod.Remove(_methods, method);
111 public ComEventsMethod FindMethod(int dispid)
113 return ComEventsMethod.Find(_methods, dispid);
116 public ComEventsMethod AddMethod(int dispid)
118 ComEventsMethod method = new ComEventsMethod(dispid);
119 _methods = ComEventsMethod.Add(_methods, method);
125 private static Guid IID_IManagedObject = new Guid("{C3FCC19E-A970-11D2-8B5A-00A0C9B7C9C4}");
127 CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out IntPtr ppv)
130 if (iid == _iidSourceItf || iid == typeof(IDispatch).GUID)
132 ppv = Marshal.GetComInterfaceForObject(this, typeof(IDispatch), CustomQueryInterfaceMode.Ignore);
133 return CustomQueryInterfaceResult.Handled;
135 else if (iid == IID_IManagedObject)
137 return CustomQueryInterfaceResult.Failed;
140 return CustomQueryInterfaceResult.NotHandled;
143 #region private methods
146 private void Advise(object rcw)
148 Debug.Assert(_connectionPoint == null, "comevent sink is already advised");
150 ComTypes.IConnectionPointContainer cpc = (ComTypes.IConnectionPointContainer)rcw;
151 ComTypes.IConnectionPoint cp;
152 cpc.FindConnectionPoint(ref _iidSourceItf, out cp);
154 object sinkObject = this;
156 cp.Advise(sinkObject, out _cookie);
158 _connectionPoint = cp;
161 private void Unadvise()
163 Debug.Assert(_connectionPoint != null, "can not unadvise from empty connection point");
167 _connectionPoint.Unadvise(_cookie);
168 Marshal.ReleaseComObject(_connectionPoint);
170 catch (System.Exception)
172 // swallow all exceptions on unadvise
173 // the host may not be available at this point
177 _connectionPoint = null;