ComEventsSink.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Runtime / InteropServices / ComEventsSink.cs / 1305376 / ComEventsSink.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

/*============================================================ 
** 
** Class:  ComEventsSink
** 
** Purpose: part of ComEventHelpers APIs which allow binding
** managed delegates to COM's connection point based events.
**
** Date:  April 2008 
**/
 
#if FEATURE_COMINTEROP 

namespace System.Runtime.InteropServices { 
    using System;
    using System.Diagnostics;

    // see code:ComEventsHelper#ComEventsArchitecture 
    [System.Security.SecurityCritical]
    internal class ComEventsSink : NativeMethods.IDispatch, ICustomQueryInterface 
    { 
#region private fields
 
        private Guid _iidSourceItf;
        private ComTypes.IConnectionPoint _connectionPoint;
        private int _cookie;
        private ComEventsMethod _methods; 
        private ComEventsSink _next;
 
#endregion 

 
#region ctor

        internal ComEventsSink(object rcw, Guid iid) {
            _iidSourceItf = iid; 
            this.Advise(rcw);
        } 
 
#endregion
 

#region static members

        internal static ComEventsSink Find(ComEventsSink sinks, ref Guid iid) { 

            ComEventsSink sink = sinks; 
            while (sink != null && sink._iidSourceItf != iid) { 
                sink = sink._next;
            } 

            return sink;
        }
 
        internal static ComEventsSink Add(ComEventsSink sinks, ComEventsSink sink) {
            sink._next = sinks; 
            return sink; 
        }
 
        [System.Security.SecurityCritical]
        internal static ComEventsSink RemoveAll(ComEventsSink sinks) {
            while (sinks != null) {
                sinks.Unadvise(); 
                sinks = sinks._next;
            } 
 
            return null;
        } 

        [System.Security.SecurityCritical]
        internal static ComEventsSink Remove(ComEventsSink sinks, ComEventsSink sink) {
            BCLDebug.Assert(sinks != null, "removing event sink from empty sinks collection"); 
            BCLDebug.Assert(sink != null, "specify event sink is null");
 
            if (sink == sinks) { 
                sinks = sinks._next;
            } else { 
                ComEventsSink current = sinks;
                while (current != null && current._next != sink)
                    current = current._next;
 
                if (current != null) {
                    current._next = sink._next; 
                } 
            }
 
            sink.Unadvise();

            return sinks;
        } 

#endregion 
 

#region public methods 

        public ComEventsMethod RemoveMethod(ComEventsMethod method) {
            _methods = ComEventsMethod.Remove(_methods, method);
            return _methods; 
        }
 
        public ComEventsMethod FindMethod(int dispid) { 
            return ComEventsMethod.Find(_methods, dispid);
        } 

        public ComEventsMethod AddMethod(int dispid) {
            ComEventsMethod method = new ComEventsMethod(dispid);
            _methods = ComEventsMethod.Add(_methods, method); 
            return method;
        } 
 
#endregion
 

#region IDispatch Members

        [System.Security.SecurityCritical] 
        void NativeMethods.IDispatch.GetTypeInfoCount(out uint pctinfo) {
            pctinfo = 0; 
        } 

        [System.Security.SecurityCritical] 
        void NativeMethods.IDispatch.GetTypeInfo(uint iTInfo, int lcid, out IntPtr info) {
            throw new NotImplementedException();
        }
 
        [System.Security.SecurityCritical]
        void NativeMethods.IDispatch.GetIDsOfNames(ref Guid iid, string[] names, uint cNames, int lcid, int[] rgDispId) { 
            throw new NotImplementedException(); 
        }
 
        [System.Security.SecurityCritical]
        unsafe void NativeMethods.IDispatch.Invoke(
            int dispid,
            ref Guid riid, 
            int lcid,
            ComTypes.INVOKEKIND wFlags, 
            ref ComTypes.DISPPARAMS pDispParams, 
            IntPtr pvarResult,
            IntPtr pExcepInfo, 
            IntPtr puArgErr) {

            ComEventsMethod method = FindMethod(dispid);
            if (method == null) 
                return;
 
            // notice the unsafe pointers we are using. This is to avoid unnecessary 
            // arguments marshalling. see code:ComEventsHelper#ComEventsArgsMarshalling
 
            object [] args = new object[pDispParams.cArgs];
            int [] byrefsMap = new int[pDispParams.cArgs];
            bool [] usedArgs = new bool[pDispParams.cArgs];
 
            Variant* pvars = (Variant*)pDispParams.rgvarg;
            int* pNamedArgs = (int*)pDispParams.rgdispidNamedArgs; 
 
            // copy the named args (positional) as specified
            int i; 
            int pos;
            for (i = 0; i < pDispParams.cNamedArgs; i++) {
                pos = pNamedArgs[i];
 
                args[pos] = pvars[i].ToObject();
                usedArgs[pos] = true; 
 
                if (pvars[i].IsByRef) {
                    byrefsMap[pos] = i; 
                } else {
                    byrefsMap[pos] = -1;
                }
            } 

            // copy the rest of the arguments in the reverse order 
            pos = 0; 
            for (; i < pDispParams.cArgs; i++) {
                // find the next unassigned argument 
                while (usedArgs[pos]) {
                    ++pos;
                }
 
                Variant* pvar = &pvars[pDispParams.cArgs - 1 - i];
                args[pos] = pvar->ToObject(); 
 
                if (pvar->IsByRef)
                    byrefsMap[pos] = pDispParams.cArgs - 1 - i; 
                else
                    byrefsMap[pos] = -1;

                pos++; 
            }
 
            // Do the actual delegate invocation 
            object result;
            result = method.Invoke(args); 

            // convert result to VARIANT
            if (pvarResult != IntPtr.Zero) {
                Marshal.GetNativeVariantForObject(result, pvarResult); 
            }
 
            // Now we need to marshal all the byrefs back 
            for (i = 0; i < pDispParams.cArgs; i++) {
                int idxToPos = byrefsMap[i]; 
                if (idxToPos == -1)
                    continue;

                pvars[idxToPos].CopyFromIndirect(args[i]); 
            }
        } 
 
#endregion
 
        static Guid IID_IManagedObject = new Guid("{C3FCC19E-A970-11D2-8B5A-00A0C9B7C9C4}");

        [System.Security.SecurityCritical]
        CustomQueryInterfaceResult ICustomQueryInterface.GetInterface(ref Guid iid, out IntPtr ppv) { 
            ppv = IntPtr.Zero;
            if (iid == this._iidSourceItf || iid == typeof(NativeMethods.IDispatch).GUID) { 
                ppv = Marshal.GetComInterfaceForObject(this, typeof(NativeMethods.IDispatch), CustomQueryInterfaceMode.Ignore); 
                return CustomQueryInterfaceResult.Handled;
            } 
            else if (iid == IID_IManagedObject)
            {
                return CustomQueryInterfaceResult.Failed;
            } 

            return CustomQueryInterfaceResult.NotHandled; 
        } 

#region private methods 


        private void Advise(object rcw) {
            BCLDebug.Assert(_connectionPoint == null, "comevent sink is already advised"); 

            ComTypes.IConnectionPointContainer cpc = (ComTypes.IConnectionPointContainer)rcw; 
            ComTypes.IConnectionPoint cp; 
            cpc.FindConnectionPoint(ref _iidSourceItf, out cp);
 
            object sinkObject = this;

            cp.Advise(sinkObject, out _cookie);
 
            _connectionPoint = cp;
        } 
 
        [System.Security.SecurityCritical]
        private void Unadvise() { 
            BCLDebug.Assert(_connectionPoint != null, "can not unadvise from empty connection point");

            try {
                _connectionPoint.Unadvise(_cookie); 
                Marshal.ReleaseComObject(_connectionPoint);
            } catch (System.Exception) { 
                // swallow all exceptions on unadvise 
                // the host may not be available at this point
            } finally { 
                _connectionPoint = null;
            }

        } 

#endregion 
    }; 
}
 
#endif

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK