File: net\PeerToPeer\Collaboration\PeerContact.cs
Project: ndp\fx\src\SystemNet\System.Net.csproj (System.Net)
//------------------------------------------------------------------------------
// <copyright file="Peer.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
namespace System.Net.PeerToPeer.Collaboration
{
    using System.Net.Mail;
    using System.Security.Cryptography.X509Certificates;
    using System.Runtime.InteropServices;
    using System.Net.PeerToPeer;
    using System.Text;
    using System.ComponentModel;
    using System.Threading;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
 
    /// <summary>
    /// This is the event args class we give back when 
    /// we have an application change event triggered by native
    /// </summary>
    public class ApplicationChangedEventArgs : EventArgs
    {
        private PeerEndPoint m_peerEndPoint;
        private PeerContact m_peerContact;
        private PeerChangeType m_peerChangeType;
        private PeerApplication m_peerApplication;
 
        internal ApplicationChangedEventArgs(PeerEndPoint peerEndPoint, PeerContact peerContact,
                                        PeerChangeType peerChangeType, PeerApplication peerApplication)
        {
            m_peerEndPoint = peerEndPoint;
            m_peerContact = peerContact;
            m_peerChangeType = peerChangeType;
            m_peerApplication = peerApplication;
        }
 
        public PeerEndPoint PeerEndPoint
        {
            get
            {
                return m_peerEndPoint;
            }
        }
 
        public PeerContact PeerContact
        {
            get
            {
                return m_peerContact;
            }
        }
 
        public PeerChangeType PeerChangeType
        {
            get
            {
                return m_peerChangeType;
            }
        }
 
        public PeerApplication PeerApplication
        {
            get
            {
                return m_peerApplication;
            }
        }
    }
 
    /// <summary>
    /// This class incorporates the contact functions of a peer collaboration
    /// contact
    /// </summary>
    [Serializable]
    public class PeerContact : Peer, IEquatable<PeerContact>, ISerializable
    {
        private PeerName m_peerName;
        private string m_nickname;
        private string m_displayName;
        private MailAddress m_emailAddress;
        private SubscriptionType m_subscribeAllowed;
        private bool m_isSubscribed;
        private X509Certificate2 m_credentials;
        private string m_contactXml;
        private bool m_justCreated; 
 
        public PeerName PeerName
        {
            get {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                return m_peerName; 
            }
            internal set {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                m_peerName = value; 
            }
        }
 
        public string Nickname
        {
            get {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                return m_nickname; 
            }
            set {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                m_nickname = value; 
            }
        }
        
        public string DisplayName
        {
            get {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                return m_displayName; 
            }
            set {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                m_displayName = value; 
            }
        }
 
        public MailAddress EmailAddress
        {
            get {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                return m_emailAddress; 
            }
            set {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                m_emailAddress = value;
            }
        }
 
        public SubscriptionType SubscribeAllowed
        {
            get {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                return InternalSubscribeAllowedGet();
            }
            set{
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                InternalSubscribeAllowedSet(value);
            }
        }
 
        internal virtual SubscriptionType InternalSubscribeAllowedGet()
        {
            return m_subscribeAllowed;
        }
 
        internal virtual void InternalSubscribeAllowedSet(SubscriptionType value)
        {
            m_subscribeAllowed = value;
        }
 
        public bool IsSubscribed
        {
            get
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                return InternalIsSubscribed();
            }
            internal set { m_isSubscribed = value; }
        }
 
        internal virtual bool InternalIsSubscribed()
        {
            lock (IsSubscribeLock)
                return m_isSubscribed;
        }
 
        private object m_isSubscribeLock;
        internal object IsSubscribeLock
        {
            get
            {
                if (m_isSubscribeLock == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref m_isSubscribeLock, o, null);
                }
                return m_isSubscribeLock;
            }
        }
 
        public X509Certificate2 Credentials
        {
            get {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                
                return m_credentials;
            }
            internal set {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                m_credentials = value;
            }
 
        }
 
        internal bool JustCreated
        {
            get { return m_justCreated; }
            set { m_justCreated = value; }
        }
 
        internal string ContactXml
        {
            get { return m_contactXml; }
            set { m_contactXml = value; }
        }
 
        public override PeerEndPointCollection PeerEndPoints
        {
            // <SecurityKernel Critical="True" Ring="0">
            // <UsesUnsafeCode Name="Local pEndPoints of type: IntPtr*" />
            // <UsesUnsafeCode Name="Method: IntPtr.op_Explicit(System.IntPtr):System.Void*" />
            // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
            // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
            // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
            // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabEnumEndpoints(System.Net.PeerToPeer.Collaboration.PEER_CONTACT&,System.Net.PeerToPeer.Collaboration.SafeCollabEnum&):System.Int32" />
            // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerGetItemCount(System.Net.PeerToPeer.Collaboration.SafeCollabEnum,System.UInt32&):System.Int32" />
            // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerGetNextItem(System.Net.PeerToPeer.Collaboration.SafeCollabEnum,System.UInt32&,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
            // <ReferencesCritical Name="Local handlePeerEnum of type: SafeCollabEnum" Ring="1" />
            // <ReferencesCritical Name="Local safeCredentials of type: SafeCollabMemory" Ring="1" />
            // <ReferencesCritical Name="Local epArray of type: SafeCollabData" Ring="1" />
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPeerContactToPEER_CONTACT(System.Net.PeerToPeer.Collaboration.PeerContact,System.Net.PeerToPeer.Collaboration.SafeCollabMemory&):System.Net.PeerToPeer.Collaboration.PEER_CONTACT" Ring="1" />
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(System.Net.PeerToPeer.Collaboration.PEER_ENDPOINT):System.Net.PeerToPeer.Collaboration.PeerEndPoint" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            get
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Get PeerEndPoints called.");
 
                PeerEndPointCollection peerEndPoints = new PeerEndPointCollection();
 
                SafeCollabEnum handlePeerEnum = null;
                UInt32 pepCount = 0;
                int errorCode = 0;
 
                try{
                    SafeCollabMemory safeCredentials = null;
                    try{
                        //
                        // Get the Endpoint enumeration from native
                        //
                        PEER_CONTACT pc = CollaborationHelperFunctions.ConvertPeerContactToPEER_CONTACT(this, ref safeCredentials);
 
                        errorCode = UnsafeCollabNativeMethods.PeerCollabEnumEndpoints(ref pc, out handlePeerEnum);
                    }
                    finally{
                        if (safeCredentials != null) safeCredentials.Dispose();
                    }
 
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabEnumEndpoints returned with errorcode {0}", errorCode);
                        return peerEndPoints;
                    }
 
                    errorCode = UnsafeCollabNativeMethods.PeerGetItemCount(handlePeerEnum, ref pepCount);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetItemCount returned with errorcode {0}", errorCode);
                        return peerEndPoints;
                    }
 
                    if (pepCount == 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "No endpoints. Get PeerEndPoints returning.");
                        return peerEndPoints;
                    }
 
                    unsafe{
                        SafeCollabData epArray;
                        errorCode = UnsafeCollabNativeMethods.PeerGetNextItem(handlePeerEnum, ref pepCount, out epArray);
 
                        IntPtr pPEER_ENDPOINT = epArray.DangerousGetHandle();
                        IntPtr* pEndPoints = (IntPtr*)pPEER_ENDPOINT;
 
                        //
                        // Loop throught all the endpoints from native
                        //
                        for (ulong i = 0; i < pepCount; i++)
                        {
                            IntPtr pEndPointPtr = (IntPtr)pEndPoints[i];
                            PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(pEndPointPtr, typeof(PEER_ENDPOINT));
 
                            PeerEndPoint peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
                            peerEndPoints.Add(peerEndPoint);
                        }
                    }
                }
                finally{
                    if (handlePeerEnum != null) handlePeerEnum.Dispose();
                }
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving Get PeerEndPoints with {0} endpoints.", peerEndPoints.Count);
                return peerEndPoints;
            }
        }
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        static PeerContact()
        {
            CollaborationHelperFunctions.Initialize();
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal PeerContact() {
            OnSubscribeCompletedDelegate = new SendOrPostCallback(SubscribeCompletedWaitCallback);
        }
 
        /// <summary>
        /// Constructor to enable serialization 
        /// </summary>
        [System.Security.SecurityCritical]
        protected PeerContact(SerializationInfo serializationInfo, StreamingContext streamingContext):this()
        {
            m_peerName = (PeerName) serializationInfo.GetValue("_PeerName", typeof(PeerName));
            m_nickname = serializationInfo.GetString("_NickName");
            m_displayName = serializationInfo.GetString("_DisplayName");
 
            try{
                m_emailAddress = new MailAddress(serializationInfo.GetString("_EmailAddress"));
            }
            catch (SerializationException) { }
 
            m_subscribeAllowed = (SubscriptionType)serializationInfo.GetValue("_SubscribeAllowed", typeof(SubscriptionType));
            
            byte [] rawData = (byte[]) serializationInfo.GetValue("_Credentials", typeof(byte[]));
            m_credentials = new X509Certificate2(rawData); ;
 
            m_contactXml = serializationInfo.GetString("_ContactXml");
            m_justCreated = serializationInfo.GetBoolean("_JustCreated");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabExportContact(System.String,System.String&):System.Int32" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public string ToXml()
        {
            string xmlContact = null;
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering ToXml().");
 
            if (JustCreated)
                return ContactXml;
 
            int errorCode = UnsafeCollabNativeMethods.PeerCollabExportContact(PeerName.ToString(), ref xmlContact);
            if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabExportContact returned with errorcode {0}.", errorCode);
                throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_ContactToXmlFailed), errorCode);
 
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving ToXml() with XML string: {0}", xmlContact);
            return xmlContact;
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabParseContact(System.String,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetContact(System.String,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local contact of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(System.Net.PeerToPeer.Collaboration.PEER_CONTACT):System.Net.PeerToPeer.Collaboration.PeerContact" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static PeerContact FromXml(string peerContactXml)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering FromXml() with XML string: {0}", peerContactXml);
            
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
            CollaborationHelperFunctions.Initialize();
 
            if (peerContactXml == null)
                throw new ArgumentNullException("peerContactXml");
            
            SafeCollabData contact = null;
            PeerContact peerContact = null;
            int errorCode;
 
            try{
                errorCode = UnsafeCollabNativeMethods.PeerCollabParseContact(peerContactXml, out contact);
 
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabParseContact returned with errorcode {0}. Contact already exists.", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_ContactFromXmlFailed), errorCode);
                }
 
                PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(contact.DangerousGetHandle(), typeof(PEER_CONTACT));
                peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
            }
            finally{
                if (contact != null) contact.Dispose();
            }
 
            //
            // Check to see if this already in the contact manager else we can set the just created field
            // and set this xml since you cannot get XML for a contact not in the contact manager
            //
 
            try{
                contact = null;
                errorCode = UnsafeCollabNativeMethods.PeerCollabGetContact(peerContact.PeerName.ToString(),
                                                                                        out contact);
            }
            finally{
                if (contact != null) contact.Dispose();
            }
 
            if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, 
                    "Error or contact not found in Contact Manager. ErrorCode {0}", errorCode);
 
                //
                // Mark it as just created and add the xml. This is used when adding the contact or getting
                // contact xml when contact is not in Contact manager
                //
 
                peerContact.JustCreated = true;
                peerContact.ContactXml = peerContactXml;
            }
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving FromXml() with following peercontact");
                peerContact.TracePeerContact();
            }
            return peerContact;
        }
 
        //
        // Updates the fwatch in native contact to indicate that we want to watch this 
        // Contact
        //
        public virtual void Subscribe()
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering Subscribe().");
            
            if (IsSubscribed){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Already subscribed. Leaving Subscribe().");
                return;
            }
 
            InternalSubscribe(false);
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving Subscribe().");
        }
 
        //
        // Handles Subscribe to a contact
        //
        private void InternalSubscribe(object isAsyncObj)
        {
            //
            // Updates the IsSubscribed of the contact in the address book
            //
            
            bool isAsync = (bool)isAsyncObj;
            Exception ex = null;
 
            lock (IsSubscribeLock){
                IsSubscribed = true;
                try{
                    PeerCollaboration.ContactManager.UpdateContact(this);
                }
                catch (Exception e){
                    IsSubscribed = false;
                    if (!isAsync)
                        throw;
                    ex = e;
                }
            }
 
            if (isAsync){
                SubscribeCompletedEventArgs subscribeArgs;
                if (ex == null){
                    subscribeArgs = new SubscribeCompletedEventArgs(null, this, null, false, AsyncOp.UserSuppliedState);
                }
                else{
                    subscribeArgs = new SubscribeCompletedEventArgs(null, null, ex, false, AsyncOp.UserSuppliedState);
                }
                this.PrepareToRaiseSubscribeCompletedEvent(AsyncOp, subscribeArgs);
            }
 
        }
 
        #region Subscribe Async variables
        private AsyncOperation m_AsyncOp;
        internal AsyncOperation AsyncOp
        {
            get{
                return m_AsyncOp;
            }
            set{
                m_AsyncOp = value;
            }
        }
 
        private object m_asyncOpLock;
        internal object AsyncLock
        {
            get{
                if (m_asyncOpLock == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref m_asyncOpLock, o, null);
                }
                return m_asyncOpLock;
            }
        }
 
        private SendOrPostCallback OnSubscribeCompletedDelegate;
        #endregion
 
        private event EventHandler<SubscribeCompletedEventArgs> m_subscribeCompleted;
        public event EventHandler<SubscribeCompletedEventArgs> SubscribeCompleted
        {
            add
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                
                m_subscribeCompleted += value;
            }
            remove
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                
                m_subscribeCompleted -= value; 
            }
        }
 
        //
        // Updates the fwatch in native contact to indicate that we want to watch this 
        // Contact
        //
        public virtual void SubscribeAsync(Object userToken)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            
            if (userToken == null)
                throw new ArgumentNullException("userToken");
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering SubscribeAsync() with user token {0}.", userToken);
            
            lock (AsyncLock){
                if (AsyncOp != null)
                    throw new PeerToPeerException(SR.GetString(SR.Collab_DuplicateSubscribeAsync));
 
                AsyncOp = AsyncOperationManager.CreateOperation(userToken);
            }
 
            ThreadPool.QueueUserWorkItem(new WaitCallback(InternalSubscribe), true);
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving SubscribeAsync().");
        }
 
        protected void OnSubscribeCompleted(SubscribeCompletedEventArgs e)
        {
            EventHandler<SubscribeCompletedEventArgs> handlerCopy = m_subscribeCompleted;
 
            if (handlerCopy != null){
                handlerCopy(this, e);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the subscribe completed event callback.");
            }
        }
 
        void SubscribeCompletedWaitCallback(object operationState)
        {
            AsyncOp = null;
            OnSubscribeCompleted((SubscribeCompletedEventArgs)operationState);
        }
 
        internal void PrepareToRaiseSubscribeCompletedEvent(AsyncOperation asyncOP, SubscribeCompletedEventArgs args)
        {
            asyncOP.PostOperationCompleted(OnSubscribeCompletedDelegate, args);
        }
 
        //
        // Unsubscribe from getting events from this contact
        //
        public virtual void Unsubscribe()
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            
            if (!IsSubscribed)
                return;
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering UnSubscribe().");
 
            lock (IsSubscribeLock){
                IsSubscribed = false;
                
                try{
                    PeerCollaboration.ContactManager.UpdateContact(this);
                }
                catch (Exception){
                    IsSubscribed = true;
                    throw;
                }
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Laaving UnSubscribe().");
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: Peer.get_CurrentApplicationGuid():System.Guid" Ring="1" />
        // <ReferencesCritical Name="Method: InternalInviteAllEndPoints(PeerEndPointCollection, String, Byte[], Guid):PeerInvitationResponse" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public override PeerInvitationResponse Invite()
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            Guid appGuid = CurrentApplicationGuid;
 
            if (appGuid.Equals(Guid.Empty))
                throw new PeerToPeerException(SR.GetString(SR.Collab_NoGuidForCurrApp));
 
            //
            // We need at least one endpoint to send invitation to
            //
            return InternalInviteAllEndPoints(PeerEndPoints, null, null, appGuid); 
        }
 
        // <SecurityKernel Critical="True" Ring="2">
        // <ReferencesCritical Name="Method: InternalInviteAllEndPoints(PeerEndPointCollection, String, Byte[], Guid):PeerInvitationResponse" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public override PeerInvitationResponse Invite(  PeerApplication applicationToInvite, string message,
                                                        byte[] invitationData)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
            if (applicationToInvite == null)
                throw new ArgumentNullException("applicationToInvite");
            if (applicationToInvite.Id == Guid.Empty)
                throw new PeerToPeerException(SR.GetString(SR.Collab_EmptyGuidError));
 
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
            //
            // We need at least one endpoint to send invitation to
            //
            return InternalInviteAllEndPoints(PeerEndPoints, message, invitationData, applicationToInvite.Id); 
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: Peer.InternalInviteEndPoint(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPoint,System.Net.PeerToPeer.Collaboration.PeerContact):System.Net.PeerToPeer.Collaboration.PeerInvitationResponse" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        private PeerInvitationResponse InternalInviteAllEndPoints(  PeerEndPointCollection peerEndPoints,
                                                                    string message, byte[] invitationData,
                                                                    Guid applicationId)
        {
            if ((peerEndPoints == null) || (peerEndPoints.Count == 0))
                throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndpointFound));
 
            bool foundDeclined = false;
            bool foundExpired = false;
 
            //
            // Call for each endpoint. Return first accepted or last declined.
            //
            foreach (PeerEndPoint peerEndPoint in peerEndPoints){
                PeerInvitationResponse endPointResponse = InternalInviteEndPoint(applicationId,
                                                            message, invitationData, peerEndPoint, this);
 
                if (endPointResponse.PeerInvitationResponseType == PeerInvitationResponseType.Accepted)
                    return endPointResponse;
                else if (endPointResponse.PeerInvitationResponseType == PeerInvitationResponseType.Declined)
                    foundDeclined = true;
 
                else if (endPointResponse.PeerInvitationResponseType == PeerInvitationResponseType.Expired)
                    foundExpired = true;
            }
 
            if (foundDeclined)
                return new PeerInvitationResponse(PeerInvitationResponseType.Declined);
            else if (foundExpired)
                return new PeerInvitationResponse(PeerInvitationResponseType.Expired);
            else
                throw new PeerToPeerException(SR.GetString(SR.Collab_InviteFailed));
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: Peer.get_CurrentApplicationGuid():System.Guid" Ring="1" />
        // <ReferencesCritical Name="Method: Peer.InternalInviteEndPoint(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPoint,System.Net.PeerToPeer.Collaboration.PeerContact):System.Net.PeerToPeer.Collaboration.PeerInvitationResponse" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public PeerInvitationResponse Invite(PeerEndPoint peerEndPoint)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            //
            // We need at least one endpoint to send invitation to
            //
            if (peerEndPoint == null)
                throw new ArgumentNullException("peerEndPoint");
            if (peerEndPoint.EndPoint == null)
                throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndPointInPeerEndPoint));
 
            Guid appGuid = CurrentApplicationGuid;
 
            if (appGuid.Equals(Guid.Empty))
                throw new PeerToPeerException(SR.GetString(SR.Collab_NoGuidForCurrApp));
 
            PeerInvitationResponse response = InternalInviteEndPoint(appGuid, null, null, peerEndPoint, this);
 
            // throw an exception if the response type is ERROR
            CollaborationHelperFunctions.ThrowIfInvitationResponseInvalid(response);
            return response;
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: Peer.InternalInviteEndPoint(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPoint,System.Net.PeerToPeer.Collaboration.PeerContact):System.Net.PeerToPeer.Collaboration.PeerInvitationResponse" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public PeerInvitationResponse Invite(PeerEndPoint peerEndPoint, PeerApplication applicationToInvite, 
                                             string message, byte [] invitationData)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (applicationToInvite == null)
                throw new ArgumentNullException("applicationToInvite");
            if (applicationToInvite.Id == Guid.Empty)
                throw new PeerToPeerException(SR.GetString(SR.Collab_EmptyGuidError));
            
            //
            // We need at least one endpoint to send invitation to
            //
            if (peerEndPoint == null)
                throw new ArgumentNullException("peerEndPoint");
            if (peerEndPoint.EndPoint == null)
                throw new ArgumentException(SR.GetString(SR.Collab_NoEndPointInPeerEndPoint));
 
            PeerInvitationResponse response = InternalInviteEndPoint(applicationToInvite.Id, message, invitationData,
                                                                     peerEndPoint, this);
 
            // throw an exception if the response type is ERROR
            CollaborationHelperFunctions.ThrowIfInvitationResponseInvalid(response);
            return response;
        }
 
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: Peer.get_CurrentApplicationGuid():System.Guid" Ring="1" />
        // <ReferencesCritical Name="Method: Peer.InternalInviteAsync(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPointCollection,System.Net.PeerToPeer.Collaboration.PeerContact,System.Object):System.Void" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public override void InviteAsync(Object userToken)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (userToken == null)
                throw new ArgumentException(SR.GetString(SR.NullUserToken));
 
            Guid appGuid = CurrentApplicationGuid;
 
            if (appGuid.Equals(Guid.Empty))
                throw new PeerToPeerException(SR.GetString(SR.Collab_NoGuidForCurrApp));
 
            //
            // We need at least one endpoint to send invitation to
            //
            PeerEndPointCollection peerEndPoints = PeerEndPoints;
 
            if ((peerEndPoints == null) || (peerEndPoints.Count == 0))
                throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndpointFound));
 
 
            //
            // Call internal async invite
            //
            InternalInviteAsync(appGuid, null, null, peerEndPoints, this, userToken);
 
        }
 
        // <SecurityKernel Critical="True" Ring="2">
        // <ReferencesCritical Name="Method: Peer.InternalInviteAsync(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPointCollection,System.Net.PeerToPeer.Collaboration.PeerContact,System.Object):System.Void" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public override void InviteAsync(   PeerApplication applicationToInvite, string message,
                                            byte[] invitationData, Object userToken)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (userToken == null)
                throw new ArgumentException(SR.GetString(SR.NullUserToken));
            if (applicationToInvite == null)
                throw new ArgumentNullException("applicationToInvite");
            if (applicationToInvite.Id == Guid.Empty)
                throw new PeerToPeerException(SR.GetString(SR.Collab_EmptyGuidError));
 
            //
            // We need at least one endpoint to send invitation to
            //
            PeerEndPointCollection peerEndPoints = PeerEndPoints;
 
            if ((peerEndPoints == null) || (peerEndPoints.Count == 0))
                throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndpointFound));
 
            //
            // Call internal async invite
            //
            InternalInviteAsync(applicationToInvite.Id, null, null, peerEndPoints, this, userToken);
        }
 
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: Peer.get_CurrentApplicationGuid():System.Guid" Ring="1" />
        // <ReferencesCritical Name="Method: Peer.InternalInviteAsync(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPointCollection,System.Net.PeerToPeer.Collaboration.PeerContact,System.Object):System.Void" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public void InviteAsync(PeerEndPoint peerEndPoint, Object userToken)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (userToken == null)
                throw new ArgumentException(SR.GetString(SR.NullUserToken));
 
            Guid appGuid = CurrentApplicationGuid;
 
            if (appGuid.Equals(Guid.Empty))
                throw new PeerToPeerException(SR.GetString(SR.Collab_NoGuidForCurrApp));
            //
            // We need at least one endpoint to send invitation to
            //
            if (peerEndPoint == null)
                throw new ArgumentNullException("peerEndPoint");
            if (peerEndPoint.EndPoint == null)
                throw new ArgumentException(SR.GetString(SR.Collab_NoEndPointInPeerEndPoint));
 
            PeerEndPointCollection peerEndPoints = new PeerEndPointCollection();
            peerEndPoints.Add(peerEndPoint);
            //
            // Call internal async invite
            //
            InternalInviteAsync(appGuid, null, null, peerEndPoints, this, userToken);
        }
 
        // <SecurityKernel Critical="True" Ring="2">
        // <ReferencesCritical Name="Method: Peer.InternalInviteAsync(System.Guid,System.String,System.Byte[],System.Net.PeerToPeer.Collaboration.PeerEndPointCollection,System.Net.PeerToPeer.Collaboration.PeerContact,System.Object):System.Void" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public void InviteAsync(PeerEndPoint peerEndPoint, string message,
                                byte [] invitationData, PeerApplication applicationToInvite,
                                Object userToken)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (userToken == null)
                throw new ArgumentException(SR.GetString(SR.NullUserToken));
            if (applicationToInvite == null)
                throw new ArgumentNullException("applicationToInvite");
            if (applicationToInvite.Id == Guid.Empty)
                throw new PeerToPeerException(SR.GetString(SR.Collab_EmptyGuidError));
 
            //
            // We need at least one endpoint to send invitation to
            //
            if (peerEndPoint == null)
                throw new ArgumentNullException("peerEndPoint");
            if (peerEndPoint.EndPoint == null)
                throw new ArgumentException(SR.GetString(SR.Collab_NoEndPointInPeerEndPoint));
 
            PeerEndPointCollection peerEndPoints = new PeerEndPointCollection();
            peerEndPoints.Add(peerEndPoint);
            //
            // Call internal async invite
            //
            InternalInviteAsync(applicationToInvite.Id, message, invitationData, peerEndPoints, this, userToken);
        }
 
        //
        // Gets all applications for all endpoints for this contact
        //
        // <SecurityKernel Critical="True" Ring="2">
        // <ReferencesCritical Name="Method: InternalGetAllApplications(Guid, Boolean):PeerApplicationCollection" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public PeerApplicationCollection GetApplications()
        {
            return InternalGetAllApplications(Guid.Empty, false);
        }
 
        //
        // Gets specfic application for all endpoints for this contact
        //
        // <SecurityKernel Critical="True" Ring="2">
        // <ReferencesCritical Name="Method: InternalGetAllApplications(Guid, Boolean):PeerApplicationCollection" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public PeerApplicationCollection GetApplications(Guid applicationId)
        {
            return InternalGetAllApplications(applicationId, true);
        }
 
        //
        // Gets all applications for specific endpoint for this contact
        //
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: InternalGetApplications(Guid, Boolean, PeerEndPoint):PeerApplicationCollection" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public PeerApplicationCollection GetApplications(PeerEndPoint peerEndPoint)
        {
            if (peerEndPoint == null)
                throw new ArgumentNullException("peerEndPoint");
 
            return InternalGetApplications(Guid.Empty, false, peerEndPoint);
        }
 
        //
        // Gets specific application for specific endpoint for this contact
        //
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: InternalGetApplications(Guid, Boolean, PeerEndPoint):PeerApplicationCollection" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public PeerApplicationCollection GetApplications(PeerEndPoint peerEndPoint, Guid applicationId)
        {
            if (peerEndPoint == null)
                throw new ArgumentNullException("peerEndPoint");
 
            return InternalGetApplications(applicationId, true, peerEndPoint);
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: InternalGetApplications(Guid, Boolean, PeerEndPoint):PeerApplicationCollection" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        private PeerApplicationCollection InternalGetAllApplications(Guid applicationId, bool guidSupplied)
        {
            Dictionary<Guid, PeerApplication> mergedApplications = new Dictionary<Guid, PeerApplication>();
            PeerApplicationCollection peerApplicationCollection;
 
            PeerEndPointCollection peerEndPoints = PeerEndPoints;
 
            foreach (PeerEndPoint peerEndPoint in peerEndPoints)
            {
                peerApplicationCollection = InternalGetApplications(applicationId, guidSupplied, peerEndPoint);
 
                foreach (PeerApplication peerApplication in peerApplicationCollection)
                {
                    mergedApplications[peerApplication.Id] = peerApplication;
                }
            }
 
            //
            // Return the application collection from the dictionary
            //
 
            Dictionary<Guid, PeerApplication>.ValueCollection applications = mergedApplications.Values;
            peerApplicationCollection = new PeerApplicationCollection();
            foreach (PeerApplication peerApplication in applications)
            {
                peerApplicationCollection.Add(peerApplication);
            }
 
            return peerApplicationCollection;
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <UsesUnsafeCode Name="Local pApps of type: IntPtr*" />
        // <UsesUnsafeCode Name="Local pPeerApp of type: PEER_APPLICATION*" />
        // <UsesUnsafeCode Name="Method: IntPtr.op_Explicit(System.IntPtr):System.Void*" />
        // <SatisfiesLinkDemand Name="GCHandle.Alloc(System.Object,System.Runtime.InteropServices.GCHandleType):System.Runtime.InteropServices.GCHandle" />
        // <SatisfiesLinkDemand Name="GCHandle.AddrOfPinnedObject():System.IntPtr" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
        // <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
        // <SatisfiesLinkDemand Name="GCHandle.Free():System.Void" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabEnumApplications(System.IntPtr,System.IntPtr,System.Net.PeerToPeer.Collaboration.SafeCollabEnum&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerGetItemCount(System.Net.PeerToPeer.Collaboration.SafeCollabEnum,System.UInt32&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerGetNextItem(System.Net.PeerToPeer.Collaboration.SafeCollabEnum,System.UInt32&,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local handlePeerEnum of type: SafeCollabEnum" Ring="1" />
        // <ReferencesCritical Name="Local appArray of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        private static PeerApplicationCollection InternalGetApplications(Guid applicationId, bool guidSupplied, PeerEndPoint peerEndPoint)
        {
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering InternalGetApplications() with the following PeerEndPoint");
                peerEndPoint.TracePeerEndPoint();
            }
 
            PeerApplicationCollection peerAppColl = new PeerApplicationCollection();
            SafeCollabEnum handlePeerEnum = null;
            UInt32 appCount = 0;
            int errorCode = 0;
 
            GCHandle guidHandle = new GCHandle();
            IntPtr guidPtr = IntPtr.Zero;
 
            if (guidSupplied){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Guid supplied is {0}.", applicationId.ToString());
                GUID guid = CollaborationHelperFunctions.ConvertGuidToGUID(applicationId);
                guidHandle = GCHandle.Alloc(guid, GCHandleType.Pinned);
                guidPtr = guidHandle.AddrOfPinnedObject();
            }
 
            PEER_ENDPOINT pep = new PEER_ENDPOINT();
            pep.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint);
 
            //
            // Pin data to pass to native
            //
 
            GCHandle pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned);
            pep.pwzEndpointName = pepName.AddrOfPinnedObject();
 
            GCHandle peerEP = GCHandle.Alloc(pep, GCHandleType.Pinned);
            IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject();
 
            try
            {
                //
                // Enumerate through the applications for the endpoint
                //
                errorCode = UnsafeCollabNativeMethods.PeerCollabEnumApplications(ptrPeerEP, guidPtr, out handlePeerEnum);
 
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabEnumApplications returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetAppsFailed), errorCode);
                }
 
                errorCode = UnsafeCollabNativeMethods.PeerGetItemCount(handlePeerEnum, ref appCount);
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetItemCount returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetAppsFailed), errorCode);
                }
 
                if (appCount == 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "No PeerApplications found.");
                    return peerAppColl;
                }
 
                unsafe
                {
                    SafeCollabData appArray;
                    errorCode = UnsafeCollabNativeMethods.PeerGetNextItem(handlePeerEnum, ref appCount, out appArray);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetAppsFailed), errorCode);
                    }
 
                    IntPtr pPEER_APLICATION = appArray.DangerousGetHandle();
                    IntPtr* pApps = (IntPtr*)pPEER_APLICATION;
 
                    //
                    // Loop through the applications array from native
                    //
                    for (ulong i = 0; i < appCount; i++){
                        PEER_APPLICATION* pPeerApp = (PEER_APPLICATION*)pApps[i];
                        string description = Marshal.PtrToStringUni(pPeerApp->pwzDescription);
                        byte[] data = null;
 
                        if (pPeerApp->data.cbData != 0)
                        {
                            data = new byte[pPeerApp->data.cbData];
                            Marshal.Copy(pPeerApp->data.pbData, data, 0, (int)pPeerApp->data.cbData);
                        }
 
                        PeerApplication peerApp = new PeerApplication(CollaborationHelperFunctions.ConvertGUIDToGuid(pPeerApp->guid), description, data, null, null, PeerScope.None);
 
                        if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Retrieved following Application");
                            peerApp.TracePeerApplication();
                        }
 
                        peerAppColl.Add(peerApp);
                    }
                }
            }
            finally{
                if (guidHandle.IsAllocated) guidHandle.Free();
                if (pepName.IsAllocated) pepName.Free();
                if (peerEP.IsAllocated) peerEP.Free();
                if (handlePeerEnum != null) handlePeerEnum.Dispose();
            }
 
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving InternalGetApplications(). " + 
                "Returning collection with {0} applications.", peerAppColl.Count);
            return peerAppColl;
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: Peer.InternalGetObjects(System.Guid,System.Boolean,System.Net.PeerToPeer.Collaboration.PeerEndPoint):System.Net.PeerToPeer.Collaboration.PeerObjectCollection" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public PeerObjectCollection GetObjects(PeerEndPoint peerEndPoint)
        {
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
            
            if (peerEndPoint == null)
                throw new ArgumentNullException("peerEndPoint");
 
            return InternalGetObjects(Guid.Empty, false, peerEndPoint);
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: Peer.InternalGetObjects(System.Guid,System.Boolean,System.Net.PeerToPeer.Collaboration.PeerEndPoint):System.Net.PeerToPeer.Collaboration.PeerObjectCollection" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public PeerObjectCollection GetObjects(PeerEndPoint peerEndPoint, Guid objectId)
        {
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
            
            if (peerEndPoint == null)
                throw new ArgumentNullException("peerEndPoint");
 
            return InternalGetObjects(objectId, true, peerEndPoint);
        }
 
        internal override void RefreshIfNeeded()
        { }
 
        private event EventHandler<ApplicationChangedEventArgs> m_applicationChanged;
        public event EventHandler<ApplicationChangedEventArgs> ApplicationChanged
        {
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: AddApplicationChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.ApplicationChangedEventArgs>):Void" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            add
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                AddApplicationChanged(value);
            }
            // <SecurityKernel Critical="True" Ring="3">
            // <ReferencesCritical Name="Method: RemoveApplicationChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.ApplicationChangedEventArgs>):Void" Ring="3" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            remove
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                RemoveApplicationChanged(value);
            }
        }
 
        #region Application changed event variables
        private object m_lockAppChangedEvent;
        internal object LockAppChangedEvent
        {
            get{
                if (m_lockAppChangedEvent == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref m_lockAppChangedEvent, o, null);
                }
                return m_lockAppChangedEvent;
            }
        }
 
        private RegisteredWaitHandle m_regAppChangedWaitHandle;
        internal RegisteredWaitHandle AppChangedWaitHandle
        {
            set{
                m_regAppChangedWaitHandle = value;
            }
        }
 
        private AutoResetEvent m_appChangedEvent;
        internal AutoResetEvent AppChangedEvent
        {
            get{
                return m_appChangedEvent;
            }
            set{
                m_appChangedEvent = value;
            }
        }
 
        internal SafeCollabEvent m_safeAppChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabRegisterEvent(Microsoft.Win32.SafeHandles.SafeWaitHandle,System.UInt32,System.Net.PeerToPeer.Collaboration.PEER_COLLAB_EVENT_REGISTRATION&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&):System.Int32" />
        // <ReferencesCritical Name="Method: ApplicationChangedCallback(Object, Boolean):Void" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeAppChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal virtual void AddApplicationChanged(EventHandler<ApplicationChangedEventArgs> callback)
        {
            //
            // Register a wait handle if one has not been registered already
            //
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering AddApplicationChanged().");
 
            lock (LockAppChangedEvent)
            {
                if (m_applicationChanged == null){
 
                    m_appChangedEvent = new AutoResetEvent(false);
                    
                    //
                    // Register callback with a wait handle
                    //
 
                    AppChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(m_appChangedEvent, //Event that triggers the callback
                                            new WaitOrTimerCallback(ApplicationChangedCallback), //callback to be called 
                                            null, //state to be passed
                                            -1,   //Timeout - aplicable only for timers
                                            false //call us everytime the event is set
                                            );
                    PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
                    pcer.eventType = PeerCollabEventType.EndPointApplicationChanged;
                    pcer.pInstance = IntPtr.Zero;
 
                    //
                    // Register event with collab
                    //
                    
                    int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
                                                                        m_appChangedEvent.SafeWaitHandle,
                                                                        1,
                                                                        ref pcer,
                                                                        out m_safeAppChangedEvent);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_ApplicationChangedRegFailed), errorCode);
                    }
                }
                m_applicationChanged += callback;
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddApplicationChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="2">
        // <ReferencesCritical Name="Method: CleanContactAppEventVars():Void" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal virtual void RemoveApplicationChanged(EventHandler<ApplicationChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveApplicationChanged() called.");
            lock (LockAppChangedEvent){
                m_applicationChanged -= callback;
                if (m_applicationChanged == null){
                    CleanContactAppEventVars();
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveApplicationChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: m_safeAppChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.CleanEventVars(System.Threading.RegisteredWaitHandle&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&,System.Threading.AutoResetEvent&):System.Void" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal void CleanContactAppEventVars()
        {
            CollaborationHelperFunctions.CleanEventVars(ref m_regAppChangedWaitHandle,
                                                        ref m_safeAppChangedEvent,
                                                        ref m_appChangedEvent);
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean ApplicationChanged variables successful.");
        }
 
        protected virtual void OnApplicationChanged(ApplicationChangedEventArgs appChangedArgs)
        {
            EventHandler<ApplicationChangedEventArgs> handlerCopy = m_applicationChanged;
 
            if (handlerCopy != null){
                if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                    SynchronizingObject.BeginInvoke(handlerCopy, new object[] { this, appChangedArgs });
                else
                    handlerCopy(this, appChangedArgs);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the application changed event callback.");
            } 
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeAppChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_APPLICATIONToPeerApplication(System.Net.PeerToPeer.Collaboration.PEER_APPLICATION):System.Net.PeerToPeer.Collaboration.PeerApplication" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(System.Net.PeerToPeer.Collaboration.PEER_ENDPOINT):System.Net.PeerToPeer.Collaboration.PeerEndPoint" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(System.Net.PeerToPeer.Collaboration.PEER_CONTACT):System.Net.PeerToPeer.Collaboration.PeerContact" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal virtual void ApplicationChangedCallback(object state, bool timedOut)
        {
            SafeCollabData eventData = null;
            int errorCode = 0;
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "ApplicationChangedCallback() called.");
 
            if (m_Disposed) return;
            
            while (true)
            {
                ApplicationChangedEventArgs appChangedArgs = null;
 
                //
                // Get the event data for the fired event
                //
 
                try{
                    lock (LockAppChangedEvent){
                        if (m_safeAppChangedEvent.IsInvalid) return;
                        errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(m_safeAppChangedEvent,
                                                                                     out eventData);
                    }
 
                    if (errorCode == UnsafeCollabReturnCodes.PEER_S_NO_EVENT_DATA)
                        break;
                    else if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetEventData returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetApplicationChangedDataFailed), errorCode);
                    }
 
                    PEER_COLLAB_EVENT_DATA ped = (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(eventData.DangerousGetHandle(),
                                                                                                typeof(PEER_COLLAB_EVENT_DATA));
                    if (ped.eventType == PeerCollabEventType.EndPointApplicationChanged){
                        PEER_EVENT_APPLICATION_CHANGED_DATA appData = ped.applicationChangedData;
 
                        PeerContact peerContact = null;
 
                        if (appData.pContact != IntPtr.Zero){
                            PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(appData.pContact, typeof(PEER_CONTACT));
                            peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                        }
 
                        if (peerContact != null && Equals(peerContact)){
                            PEER_APPLICATION pa = (PEER_APPLICATION)Marshal.PtrToStructure(appData.pApplication, typeof(PEER_APPLICATION));
 
                            PeerApplication peerApplication = CollaborationHelperFunctions.ConvertPEER_APPLICATIONToPeerApplication(pa); ;
 
                            PeerEndPoint peerEndPoint = null;
 
                            if (appData.pEndPoint != IntPtr.Zero){
                                PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(appData.pEndPoint, typeof(PEER_ENDPOINT));
                                peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
                            }
 
                            appChangedArgs = new ApplicationChangedEventArgs(   peerEndPoint,
                                                                                peerContact,
                                                                                appData.changeType,
                                                                                peerApplication);
                        }
                    }
                }
                finally{
                    if (eventData != null) eventData.Dispose();
                }
 
                //
                // Fire the callback with the marshalled event args data
                //
                if(appChangedArgs != null)
                    OnApplicationChanged(appChangedArgs);
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving ApplicationChangedCallback().");
        }
 
        private event EventHandler<ObjectChangedEventArgs> m_objectChanged;
        public event EventHandler<ObjectChangedEventArgs> ObjectChanged
        {
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: AddObjectChangedEvent(EventHandler`1<System.Net.PeerToPeer.Collaboration.ObjectChangedEventArgs>):Void" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            add
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                AddObjectChangedEvent(value);
            }
            // <SecurityKernel Critical="True" Ring="3">
            // <ReferencesCritical Name="Method: RemoveObjectChangedEvent(EventHandler`1<System.Net.PeerToPeer.Collaboration.ObjectChangedEventArgs>):Void" Ring="3" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            remove
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                RemoveObjectChangedEvent(value);
            }
        }
 
        #region Object changed event variables
        private object m_lockObjChangedEvent;
        internal object LockObjChangedEvent
        {
            get
            {
                if (m_lockObjChangedEvent == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref m_lockObjChangedEvent, o, null);
                }
                return m_lockObjChangedEvent;
            }
        }
 
        private RegisteredWaitHandle m_regObjChangedWaitHandle;
        internal RegisteredWaitHandle ObjChangedWaitHandle
        {
            set{
                m_regObjChangedWaitHandle = value;
            }
        }
 
        private AutoResetEvent m_objChangedEvent;
        internal AutoResetEvent ObjChangedEvent
        {
            get{
                return m_objChangedEvent;
            }
            set{
                m_objChangedEvent = value;
            }
        }
 
        internal SafeCollabEvent m_safeObjChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabRegisterEvent(Microsoft.Win32.SafeHandles.SafeWaitHandle,System.UInt32,System.Net.PeerToPeer.Collaboration.PEER_COLLAB_EVENT_REGISTRATION&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&):System.Int32" />
        // <ReferencesCritical Name="Method: ObjectChangedCallback(Object, Boolean):Void" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeObjChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal virtual void AddObjectChangedEvent(EventHandler<ObjectChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering AddObjectChangedEvent().");
 
            //
            // Register a wait handle if one has not been registered already
            //
            lock (LockObjChangedEvent){
                if (m_objectChanged == null){
 
                    m_objChangedEvent = new AutoResetEvent(false);
 
                    //
                    // Register callback with a wait handle
                    //
 
                    ObjChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(m_objChangedEvent, //Event that triggers the callback
                                            new WaitOrTimerCallback(ObjectChangedCallback), //callback to be called 
                                            null, //state to be passed
                                            -1,   //Timeout - aplicable only for timers
                                            false //call us everytime the event is set
                                            );
                    PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
                    pcer.eventType = PeerCollabEventType.EndPointObjectChanged;
                    pcer.pInstance = IntPtr.Zero;
 
                    //
                    // Register event with collab
                    //
 
                    int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
                                                                        m_objChangedEvent.SafeWaitHandle,
                                                                        1,
                                                                        ref pcer,
                                                                        out m_safeObjChangedEvent);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_ObjectChangedRegFailed), errorCode);
                    }
                }
                m_objectChanged += callback;
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddObjectChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="2">
        // <ReferencesCritical Name="Method: CleanContactObjEventVars():Void" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal virtual void RemoveObjectChangedEvent(EventHandler<ObjectChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveObjectChangedEvent() called.");
 
            lock (LockObjChangedEvent){
                m_objectChanged -= callback;
                if (m_objectChanged == null){
                    CleanContactObjEventVars();
                }
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveObjectChangedEvent() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: m_safeObjChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.CleanEventVars(System.Threading.RegisteredWaitHandle&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&,System.Threading.AutoResetEvent&):System.Void" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal void CleanContactObjEventVars()
        {
            CollaborationHelperFunctions.CleanEventVars(ref m_regObjChangedWaitHandle,
                                                        ref m_safeObjChangedEvent,
                                                        ref m_objChangedEvent);
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean ObjectChangedEvent variables successful.");
        }
 
        protected virtual void OnObjectChanged(ObjectChangedEventArgs objChangedArgs)
        {
            EventHandler<ObjectChangedEventArgs> handlerCopy = m_objectChanged;
 
            if (handlerCopy != null){
                if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                    SynchronizingObject.BeginInvoke(handlerCopy, new object[] { this, objChangedArgs });
                else
                    handlerCopy(this, objChangedArgs);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the object changed event callback.");
            }
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeObjChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(System.Net.PeerToPeer.Collaboration.PEER_ENDPOINT):System.Net.PeerToPeer.Collaboration.PeerEndPoint" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_OBJECTToPeerObject(System.Net.PeerToPeer.Collaboration.PEER_OBJECT):System.Net.PeerToPeer.Collaboration.PeerObject" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(System.Net.PeerToPeer.Collaboration.PEER_CONTACT):System.Net.PeerToPeer.Collaboration.PeerContact" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal virtual void ObjectChangedCallback(object state, bool timedOut)
        {
            SafeCollabData eventData = null;
            int errorCode = 0;
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "ObjectChangedCallback() called.");
 
            if (m_Disposed) return;
 
            while (true){
                ObjectChangedEventArgs objChangedArgs = null;
 
                //
                // Get the event data for the fired event
                //
 
                try{
                    lock (LockObjChangedEvent){
                        if (m_safeObjChangedEvent.IsInvalid) return;
                        errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(m_safeObjChangedEvent,
                                                                                        out eventData);
                    }
 
                    if (errorCode == UnsafeCollabReturnCodes.PEER_S_NO_EVENT_DATA)
                        break;
                    else if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetEventData returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetObjectChangedDataFailed), errorCode);
                    }
 
                    PEER_COLLAB_EVENT_DATA ped = (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(eventData.DangerousGetHandle(),
                                                                                                typeof(PEER_COLLAB_EVENT_DATA));
                    if (ped.eventType == PeerCollabEventType.EndPointObjectChanged){
                        PEER_EVENT_OBJECT_CHANGED_DATA objData = ped.objectChangedData;
 
                        PeerContact peerContact = null;
 
                        if (objData.pContact != IntPtr.Zero){
                            PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(objData.pContact, typeof(PEER_CONTACT));
                            peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                        }
 
                        if (peerContact != null && Equals(peerContact)){
                            PeerEndPoint peerEndPoint = null;
 
                            if (objData.pEndPoint != IntPtr.Zero)
                            {
                                PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(objData.pEndPoint, typeof(PEER_ENDPOINT));
                                peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
                            }
 
                            PEER_OBJECT po = (PEER_OBJECT)Marshal.PtrToStructure(objData.pObject, typeof(PEER_OBJECT));
 
                            PeerObject peerObject = CollaborationHelperFunctions.ConvertPEER_OBJECTToPeerObject(po); ;
 
 
 
                            objChangedArgs = new ObjectChangedEventArgs(peerEndPoint,
                                                                                                peerContact,
                                                                                                objData.changeType,
                                                                                                peerObject);
                        }
                    }
                }
                finally{
                    if (eventData != null) eventData.Dispose();
                }
 
                //
                // Fire the callback with the marshalled event args data
                //
                if(objChangedArgs != null)
                    OnObjectChanged(objChangedArgs);
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving ObjectChangedCallback().");
        }
 
        private event EventHandler<PresenceChangedEventArgs> m_presenceChanged;
        public event EventHandler<PresenceChangedEventArgs> PresenceChanged
        {
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: AddPresenceChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.PresenceChangedEventArgs>):Void" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            add
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                AddPresenceChanged(value);
            }
            // <SecurityKernel Critical="True" Ring="3">
            // <ReferencesCritical Name="Method: RemovePresenceChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.PresenceChangedEventArgs>):Void" Ring="3" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            remove
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                RemovePresenceChanged(value);
            }
        }
 
        #region Presence changed event variables
        private object m_lockPresenceChangedEvent;
        internal object LockPresenceChangedEvent
        {
            get
            {
                if (m_lockPresenceChangedEvent == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref m_lockPresenceChangedEvent, o, null);
                }
                return m_lockPresenceChangedEvent;
            }
        }
 
        private RegisteredWaitHandle m_regPresenceChangedWaitHandle;
        internal RegisteredWaitHandle PresenceChangedWaitHandle
        {
            set{
                m_regPresenceChangedWaitHandle = value;
            }
        }
 
        private AutoResetEvent m_presenceChangedEvent;
        internal AutoResetEvent PresenceChangedEvent
        {
            get{
                return m_presenceChangedEvent;
            }
            set{
                m_presenceChangedEvent = value;
            }
        }
 
        internal SafeCollabEvent m_safePresenceChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabRegisterEvent(Microsoft.Win32.SafeHandles.SafeWaitHandle,System.UInt32,System.Net.PeerToPeer.Collaboration.PEER_COLLAB_EVENT_REGISTRATION&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&):System.Int32" />
        // <ReferencesCritical Name="Method: PresenceChangedCallback(Object, Boolean):Void" Ring="1" />
        // <ReferencesCritical Name="Field: m_safePresenceChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal virtual void AddPresenceChanged(EventHandler<PresenceChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering AddPresenceChanged().");
 
            //
            // Register a wait handle if one has not been registered already
            //
            lock (LockPresenceChangedEvent){
                if (m_presenceChanged == null){
 
                    m_presenceChangedEvent = new AutoResetEvent(false);
 
                    //
                    // Register callback with a wait handle
                    //
 
                    PresenceChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(m_presenceChangedEvent, //Event that triggers the callback
                                            new WaitOrTimerCallback(PresenceChangedCallback), //callback to be called 
                                            null, //state to be passed
                                            -1,   //Timeout - aplicable only for timers
                                            false //call us everytime the event is set
                                            );
                    PEER_COLLAB_EVENT_REGISTRATION pcer = new PEER_COLLAB_EVENT_REGISTRATION();
                    pcer.eventType = PeerCollabEventType.EndPointPresenceChanged;
                    pcer.pInstance = IntPtr.Zero;
 
                    //
                    // Register event with collab
                    //
 
                    int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
                                                                        m_presenceChangedEvent.SafeWaitHandle,
                                                                        1,
                                                                        ref pcer,
                                                                        out m_safePresenceChangedEvent);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_PresenceChangedRegFailed), errorCode);
                    }
                }
                m_presenceChanged += callback;
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddPresenceChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="2">
        // <ReferencesCritical Name="Method: CleanContactPresenceEventVars():Void" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal virtual void RemovePresenceChanged(EventHandler<PresenceChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemovePresenceChanged() called.");
 
            lock (LockPresenceChangedEvent){
                m_presenceChanged -= callback;
                if (m_presenceChanged == null){
                    CleanContactPresenceEventVars();
                }
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemovePresenceChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: m_safePresenceChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.CleanEventVars(System.Threading.RegisteredWaitHandle&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&,System.Threading.AutoResetEvent&):System.Void" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal void CleanContactPresenceEventVars()
        {
            CollaborationHelperFunctions.CleanEventVars(ref m_regPresenceChangedWaitHandle,
                                                        ref m_safePresenceChangedEvent,
                                                        ref m_presenceChangedEvent);
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean PresenceChanged variables successful.");
        }
 
        protected virtual void OnPresenceChanged(PresenceChangedEventArgs presenceChangedArgs)
        {
            EventHandler<PresenceChangedEventArgs> handlerCopy = m_presenceChanged;
 
            if (handlerCopy != null){
                if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                    SynchronizingObject.BeginInvoke(handlerCopy, new object[] { this, presenceChangedArgs });
                else
                    handlerCopy(this, presenceChangedArgs);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the presence changed event callback.");
            }
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Field: m_safePresenceChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(System.Net.PeerToPeer.Collaboration.PEER_ENDPOINT):System.Net.PeerToPeer.Collaboration.PeerEndPoint" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(System.Net.PeerToPeer.Collaboration.PEER_CONTACT):System.Net.PeerToPeer.Collaboration.PeerContact" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal virtual void PresenceChangedCallback(object state, bool timedOut)
        {
            SafeCollabData eventData = null;
            int errorCode = 0;
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "PresenceChangedCallback() called.");
 
            if (m_Disposed) return;
 
            while (true){
                PresenceChangedEventArgs presenceChangedArgs = null;
 
                //
                // Get the event data for the fired event
                //
                try{
                    lock (LockPresenceChangedEvent){
                        if (m_safePresenceChangedEvent.IsInvalid) return;
                        errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(m_safePresenceChangedEvent,
                                                                                     out eventData);
                    }
 
                    if (errorCode == UnsafeCollabReturnCodes.PEER_S_NO_EVENT_DATA)
                        break;
                    else if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetEventData returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetPresenceChangedDataFailed), errorCode);
                    }
                    PEER_COLLAB_EVENT_DATA ped = (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(eventData.DangerousGetHandle(),
                                                                                                typeof(PEER_COLLAB_EVENT_DATA));
                    if (ped.eventType == PeerCollabEventType.EndPointPresenceChanged){
 
                        PEER_EVENT_PRESENCE_CHANGED_DATA presenceData = ped.presenceChangedData;
                        PeerContact peerContact = null;
 
                        if (presenceData.pContact != IntPtr.Zero){
                            PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(presenceData.pContact, typeof(PEER_CONTACT));
                            peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                        }
 
                        if ((peerContact != null) && Equals(peerContact)){
                            PeerEndPoint peerEndPoint = null;
 
                            if (presenceData.pEndPoint != IntPtr.Zero){
 
                                PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(presenceData.pEndPoint, typeof(PEER_ENDPOINT));
                                peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
                            }                            
                            
                            PeerPresenceInfo peerPresenceInfo = null;
 
                            if (presenceData.pPresenceInfo != IntPtr.Zero){
                                PEER_PRESENCE_INFO ppi = (PEER_PRESENCE_INFO)Marshal.PtrToStructure(presenceData.pPresenceInfo, typeof(PEER_PRESENCE_INFO));
                                peerPresenceInfo = new PeerPresenceInfo();
                                peerPresenceInfo.PresenceStatus = ppi.status;
                                peerPresenceInfo.DescriptiveText = ppi.descText;
                            }
 
                            presenceChangedArgs = new PresenceChangedEventArgs(peerEndPoint,
                                                                                peerContact,
                                                                                presenceData.changeType,
                                                                                peerPresenceInfo);
                        }
                    }
                }
                finally{
                    if (eventData != null) eventData.Dispose();
                }
 
                //
                // Fire the callback with the marshalled event args data
                //
                if (presenceChangedArgs != null)
                    OnPresenceChanged(presenceChangedArgs);
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving PresenceChangedCallback().");
        }
 
        public bool Equals(PeerContact other)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
            if (other != null){
                if (other.PeerName != null){
                    return other.PeerName.Equals(PeerName);
                }
                else if (PeerName == null)
                    return true;
            }
            return false;
 
        }
 
        public override bool Equals(object obj)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
            PeerContact comparandPeerContact = obj as PeerContact;
            if (comparandPeerContact != null){
                return Equals(comparandPeerContact);
            }
            return false;
        }
 
        public new static bool Equals(object objA, object objB)
        {
            PeerContact comparandPeerContact1 = objA as PeerContact;
            PeerContact comparandPeerContact2 = objB as PeerContact;
 
            if ((comparandPeerContact1 != null) && (comparandPeerContact2 != null))
            {
                if (comparandPeerContact1.PeerName != null){
                    return comparandPeerContact1.PeerName.Equals(comparandPeerContact2.PeerName);
                }
                else if (comparandPeerContact2.PeerName == null)
                    return true;
            }
 
            return false;
        }
 
        public override int GetHashCode()
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
 
            return ((PeerName == null) ? 0 : PeerName.GetHashCode());
        }
 
        public override string ToString()
        {
            return m_displayName;
        }
 
        private bool m_Disposed;
 
        // <SecurityKernel Critical="True" Ring="2">
        // <ReferencesCritical Name="Method: CleanContactAppEventVars():Void" Ring="2" />
        // <ReferencesCritical Name="Method: CleanContactObjEventVars():Void" Ring="2" />
        // <ReferencesCritical Name="Method: CleanContactPresenceEventVars():Void" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        protected override void Dispose(bool disposing)
        {
            if (!m_Disposed){
                try{
                    CleanContactAppEventVars();
                    CleanContactObjEventVars();
                    CleanContactPresenceEventVars();
                    m_Disposed = true;
                }
                finally{
                    base.Dispose(disposing);
                }
            }
        }
        
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="Peer.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext):System.Void" />
        // </SecurityKernel>
        [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.Net.dll is still using pre-v4 security model and needs this demand")]
        [System.Security.SecurityCritical]
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter, SerializationFormatter = true)]
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            GetObjectData(info, context);
        }
 
        /// <summary>
        /// This is made virtual so that derived types can be implemented correctly
        /// </summary>
        [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
        protected override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("_PeerName", m_peerName);
            info.AddValue("_NickName", m_nickname);
            info.AddValue("_DisplayName", m_displayName);
            if(m_emailAddress != null)
                info.AddValue("_EmailAddress", m_emailAddress.ToString());
            info.AddValue("_SubscribeAllowed", m_subscribeAllowed);
            info.AddValue("_Credentials", m_credentials.RawData);
            info.AddValue("_ContactXml", m_contactXml);
            info.AddValue("_JustCreated", m_justCreated);
        }
 
        //
        // Tracing information for Peer Contact
        //
        internal void TracePeerContact()
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Contents of the PeerContact");
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tPeerName: {0}", PeerName);
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tNickname: {0}", Nickname);
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tEmailAddress: {0}", EmailAddress.ToString());
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tSubscribeAllowed: {0}", SubscribeAllowed);
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tCredentials FriendlyName: {0}", Credentials.FriendlyName);
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Verbose)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tCredentials raw data:");
                Logging.DumpData(Logging.P2PTraceSource, TraceEventType.Verbose, Logging.P2PTraceSource.MaxDataSize, Credentials.RawData, 0, Credentials.RawData.Length);
            }
            else{
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "\tCredentials raw data length {0}", Credentials.RawData.Length);
            }
        }
    }
 
    //
    // Manages collection of peer contacts
    //
    [Serializable]
    public class PeerContactCollection : Collection<PeerContact>
    {
        internal PeerContactCollection() { }
 
        protected override void SetItem(int index, PeerContact item)
        {
            // nulls not allowed
            if (item == null){
                throw new ArgumentNullException("item");
            }
            base.SetItem(index, item);
        }
 
        protected override void InsertItem(int index, PeerContact item)
        {
            // nulls not allowed
            if (item == null){
                throw new ArgumentNullException("item");
            }
            base.InsertItem(index, item);
        }
 
        public override string ToString()
        {
            bool first = true;
            StringBuilder builder = new StringBuilder();
 
            foreach (PeerContact peerContact in this)
            {
                if (!first){
                    builder.Append(", ");
                }
                else{
                    first = false;
                }
                builder.Append(peerContact.ToString());
            }
            return builder.ToString();
        }
    }
 
}