using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices.ComTypes;
using Microsoft.Win32.SafeHandles;

namespace Standard
{
    internal sealed class SafeConnectionPointCookie : SafeHandleZeroOrMinusOneIsInvalid
    {
        [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IConnectionPoint")]
        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        public SafeConnectionPointCookie(IConnectionPointContainer target, object sink, Guid eventId) : base(true)
        {
            Verify.IsNotNull<IConnectionPointContainer>(target, "target");
            Verify.IsNotNull<object>(sink, "sink");
            Verify.IsNotDefault<Guid>(eventId, "eventId");
            this.handle = IntPtr.Zero;
            IConnectionPoint connectionPoint = null;
            try
            {
                target.FindConnectionPoint(ref eventId, out connectionPoint);
                int num;
                connectionPoint.Advise(sink, out num);
                if (num == 0)
                {
                    throw new InvalidOperationException("IConnectionPoint::Advise returned an invalid cookie.");
                }
                this.handle = new IntPtr(num);
                this._cp = connectionPoint;
                connectionPoint = null;
            }
            finally
            {
                Utility.SafeRelease<IConnectionPoint>(ref connectionPoint);
            }
        }

        [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        public void Disconnect()
        {
            this.ReleaseHandle();
        }

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        protected override bool ReleaseHandle()
        {
            bool result;
            try
            {
                if (!this.IsInvalid)
                {
                    int dwCookie = this.handle.ToInt32();
                    this.handle = IntPtr.Zero;
                    try
                    {
                        this._cp.Unadvise(dwCookie);
                    }
                    finally
                    {
                        Utility.SafeRelease<IConnectionPoint>(ref this._cp);
                    }
                }
                result = true;
            }
            catch
            {
                result = false;
            }
            return result;
        }

        private IConnectionPoint _cp;
    }
}
