File: net\PeerToPeer\Collaboration\ContactManager.cs
Project: ndp\fx\src\SystemNet\System.Net.csproj (System.Net)
//------------------------------------------------------------------------------
// <copyright file="ContactManager.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Net.PeerToPeer.Collaboration
{
    using System;
    using System.Net.Sockets;
    using System.Collections.Specialized;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Net.Mail;
    using System.Security.Cryptography.X509Certificates;
    using System.ComponentModel;
    using System.Threading;
    using System.Diagnostics;
 
    /// <summary>
    /// This is the event args class we give back when 
    /// we have completed the createcontactasync call
    /// </summary>
    public class CreateContactCompletedEventArgs : AsyncCompletedEventArgs
    {
        private PeerContact m_peerContact;
        internal CreateContactCompletedEventArgs(   PeerContact peerContact,
                                                    Exception error,
                                                    bool cancelled,
                                                    object userToken)
            : base(error, cancelled, userToken)
        {
            m_peerContact = peerContact;
        }
 
        public PeerContact PeerContact
        {
            get{
                return m_peerContact;
            }
        }
    }
 
    /// <summary>
    /// This is the event args class we give back when 
    /// we have a subscription changed event from native 
    /// </summary>
    public class SubscriptionListChangedEventArgs : EventArgs
    {
        private PeerEndPoint m_peerEndPoint;
        private PeerContact m_peerContact;
        private PeerChangeType m_peerChangeType;
 
        internal SubscriptionListChangedEventArgs(PeerEndPoint peerEndPoint, PeerContact peerContact,
                                              PeerChangeType peerChangeType)
        {
            m_peerEndPoint = peerEndPoint;
            m_peerContact = peerContact;
            m_peerChangeType = peerChangeType;
        }
 
        public PeerEndPoint PeerEndPoint
        {
            get
            {
                return m_peerEndPoint;
            }
        }
 
        public PeerContact PeerContact
        {
            get
            {
                return m_peerContact;
            }
        }
 
        public PeerChangeType PeerChangeType
        {
            get
            {
                return m_peerChangeType;
            }
        }
 
    }
 
    /// <summary>
    /// This class handles all the operation related to contacts and thier storage in the 
    /// Windows Address Book
    /// </summary>
    public sealed class ContactManager : IDisposable
    {
        private ISynchronizeInvoke m_synchronizingObject;
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        internal ContactManager() 
        {
            CollaborationHelperFunctions.Initialize();
 
            OnCreateContactCompletedDelegate = new SendOrPostCallback(CreateContactCompletedWaitCallback);
        }
 
        //
        // Returns the peer collaboration users' contact
        //
        public static PeerContact LocalContact
        {
            // <SecurityKernel Critical="True" Ring="0">
            // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetContact(System.String,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
            // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
            // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
            // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
            // <ReferencesCritical Name="Local contact of type: SafeCollabData" Ring="1" />
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(System.Net.PeerToPeer.Collaboration.PEER_CONTACT,System.Boolean):System.Net.PeerToPeer.Collaboration.PeerContact" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            get
            {
                SafeCollabData contact = null;
                MyContact myContact; 
                PEER_CONTACT pc;
 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Get MyContact called.");
                
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                CollaborationHelperFunctions.Initialize();
 
                try{
                    //
                    // Get my contact from native with null peer name
                    //
 
                    int errorCode = UnsafeCollabNativeMethods.PeerCollabGetContact(null, out contact);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0,
                                    "PeerCollabGetContact returned with errorcode {0}", errorCode);
                        return null;
                    }
                    pc = (PEER_CONTACT)Marshal.PtrToStructure(contact.DangerousGetHandle(), typeof(PEER_CONTACT));
                    myContact = (MyContact) CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc, true);
                }
                finally{
                    if (contact != null) contact.Dispose();
                }
 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Get MyContact successful.");
 
                return myContact;
            }
        }
 
        /// <summary>
        /// Gets and set the object used to marshall event handlers calls for stand alone 
        /// events
        /// </summary>
        [Browsable(false), DefaultValue(null), Description(SR.SynchronizingObject)]
        public ISynchronizeInvoke SynchronizingObject
        {
            get
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                return m_synchronizingObject;
            }
            set
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                m_synchronizingObject = value;
            }
        }
 
        private event EventHandler<SubscriptionListChangedEventArgs> m_subscriptionListChanged;
        public event EventHandler<SubscriptionListChangedEventArgs> SubscriptionListChanged
        {
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: AddSubscriptionListChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.SubscriptionListChangedEventArgs>):Void" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            add
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                AddSubscriptionListChanged(value);
            }
            // <SecurityKernel Critical="True" Ring="2">
            // <ReferencesCritical Name="Method: RemoveSubscriptionListChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.SubscriptionListChangedEventArgs>):Void" Ring="2" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            remove
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                RemoveSubscriptionListChanged(value);
            }
        }
 
        #region Subcription list changed event variables
        private object m_lockSubLstChangedEvent;
        private object LockSubLstChangedEvent
        {
            get{
                if (m_lockSubLstChangedEvent == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref m_lockSubLstChangedEvent, o, null);
                }
                return m_lockSubLstChangedEvent;
            }
        }
 
        private RegisteredWaitHandle m_regSubLstChangedWaitHandle;
        private AutoResetEvent m_subLstChangedEvent;
        private SafeCollabEvent m_safeSubLstChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="0">
        // <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" />
        // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
        // <ReferencesCritical Name="Method: SubListChangedCallback(Object, Boolean):Void" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeSubLstChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        private void AddSubscriptionListChanged(EventHandler<SubscriptionListChangedEventArgs> callback)
        {
            //
            // Register a wait handle if one has not been registered already
            //
 
            lock (LockSubLstChangedEvent){
                if (m_subscriptionListChanged == null){
                    m_subLstChangedEvent = new AutoResetEvent(false);
 
                    //
                    // Register callback with a wait handle
                    //
                    
                    m_regSubLstChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(m_subLstChangedEvent, //Event that triggers the callback
                                            new WaitOrTimerCallback(SubListChangedCallback), //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.WatchListChanged;
                    pcer.pInstance = IntPtr.Zero;
 
                    //
                    // Register event with collab
                    //
 
                    int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
                                                                        m_subLstChangedEvent.SafeWaitHandle,
                                                                        1,
                                                                        ref pcer,
                                                                        out m_safeSubLstChangedEvent);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_SubListChangedRegFailed), errorCode);
                    }
                }
                m_subscriptionListChanged += callback;
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddSubscriptionListChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: m_safeSubLstChangedEvent" 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]
        private void RemoveSubscriptionListChanged(EventHandler<SubscriptionListChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveSubscriptionListChanged() called.");
 
            lock (LockSubLstChangedEvent){
                m_subscriptionListChanged -= callback;
                if (m_subscriptionListChanged == null){
                    CollaborationHelperFunctions.CleanEventVars(ref m_regSubLstChangedWaitHandle,
                                                                ref m_safeSubLstChangedEvent,
                                                                ref m_subLstChangedEvent);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean SubscriptionListChanged variables successful.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveSubscriptionListChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <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" />
        // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeSubLstChangedEvent" 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]
        private void SubListChangedCallback(object state, bool timedOut)
        {
            SafeCollabData eventData = null;
            int errorCode = 0;
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "SubListChangedCallback() called.");
            
            while (true){
                SubscriptionListChangedEventArgs subListChangedArgs = null;
 
                //
                // Get the event data for the fired event
                //
                try{
                    lock (LockSubLstChangedEvent){
                        if (m_safeSubLstChangedEvent.IsInvalid) return;
                        errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(m_safeSubLstChangedEvent,
                                                                                     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_GetSubListChangedDataFailed), errorCode);
                    }
 
                    PEER_COLLAB_EVENT_DATA ped = (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(eventData.DangerousGetHandle(),
                                                                            typeof(PEER_COLLAB_EVENT_DATA));
 
                    if (ped.eventType == PeerCollabEventType.WatchListChanged){
                        PEER_EVENT_WATCHLIST_CHANGED_DATA watchlistData = ped.watchListChangedData;
 
                        PeerContact peerContact = null;
 
                        if (watchlistData.pContact != IntPtr.Zero){
                            PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(watchlistData.pContact, typeof(PEER_CONTACT));
                            peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                        }
 
 
                        subListChangedArgs = new SubscriptionListChangedEventArgs(null,
                                                                                        peerContact,
                                                                                        watchlistData.changeType);
 
                    }
                }
                finally{
                    if (eventData != null) eventData.Dispose();
                }
 
                //
                // Fire the callback with the marshalled event args data
                //
 
                EventHandler<SubscriptionListChangedEventArgs> handlerCopy = m_subscriptionListChanged;
 
                if ((subListChangedArgs != null) && (handlerCopy != null)){
                    if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                        SynchronizingObject.BeginInvoke(handlerCopy, new object[] { this, subListChangedArgs });
                    else
                        handlerCopy(this, subListChangedArgs);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the subscription list changed event callback.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving SubListChangedCallback().");
        }
 
        private event EventHandler<NameChangedEventArgs> m_nameChanged;
        public event EventHandler<NameChangedEventArgs> NameChanged
        {
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: AddNameChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.NameChangedEventArgs>):Void" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            add
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                AddNameChanged(value);
            }
            // <SecurityKernel Critical="True" Ring="2">
            // <ReferencesCritical Name="Method: RemoveNameChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.NameChangedEventArgs>):Void" Ring="2" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            remove
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                RemoveNameChanged(value);
            }
        }
 
        #region Name changed event variables
        private object m_lockNameChangedEvent;
        private object LockNameChangedEvent
        {
            get{
                if (m_lockNameChangedEvent == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref m_lockNameChangedEvent, o, null);
                }
                return m_lockNameChangedEvent;
            }
        }
        private RegisteredWaitHandle m_regNameChangedWaitHandle;
        private AutoResetEvent m_nameChangedEvent;
        private SafeCollabEvent m_safeNameChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="0">
        // <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" />
        // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
        // <ReferencesCritical Name="Method: NameChangedCallback(Object, Boolean):Void" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeNameChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        private void AddNameChanged(EventHandler<NameChangedEventArgs> callback)
        {
            //
            // Register a wait handle if one has not been registered already
            //
 
            lock (LockNameChangedEvent){
                if (m_nameChanged == null){
 
                    m_nameChangedEvent = new AutoResetEvent(false);
 
                    //
                    // Register callback with a wait handle
                    //
                    
                    m_regNameChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(m_nameChangedEvent, //Event that triggers the callback
                                            new WaitOrTimerCallback(NameChangedCallback), //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.EndPointChanged;
                    pcer.pInstance = IntPtr.Zero;
 
                    //
                    // Register event with collab
                    //
 
                    int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
                                                                        m_nameChangedEvent.SafeWaitHandle,
                                                                        1,
                                                                        ref pcer,
                                                                        out m_safeNameChangedEvent);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterEvent returned with errorcode {0}", errorCode);
                        throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_NameChangedRegFailed), errorCode);
                    }
                }
                m_nameChanged += callback;
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddNameChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: m_safeNameChangedEvent" 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]
        private void RemoveNameChanged(EventHandler<NameChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveNameChanged() called.");
            lock (LockNameChangedEvent){
                m_nameChanged -= callback;
                if (m_nameChanged == null){
                    CollaborationHelperFunctions.CleanEventVars(ref m_regNameChangedWaitHandle,
                                                                ref m_safeNameChangedEvent,
                                                                ref m_nameChangedEvent);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean NameChanged variables successful.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveNameChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <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" />
        // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeNameChangedEvent" 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]
        private void NameChangedCallback(object state, bool timedOut)
        {
            SafeCollabData eventData = null;
            int errorCode = 0;
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "NameChangedCallback() called.");
            
            while (true){
                NameChangedEventArgs nameChangedArgs = null;
 
                //
                // Get the event data for the fired event
                //
                try{
                    lock (LockNameChangedEvent){
                        if (m_safeNameChangedEvent.IsInvalid) return;
                        errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(m_safeNameChangedEvent,
                                                                                     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_GetNameChangedDataFailed), errorCode);
                    }
 
                    PEER_COLLAB_EVENT_DATA ped = (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(eventData.DangerousGetHandle(),
                                                                            typeof(PEER_COLLAB_EVENT_DATA));
                    
                    if (ped.eventType == PeerCollabEventType.EndPointChanged){
                        PEER_EVENT_ENDPOINT_CHANGED_DATA endpointData = ped.endpointChangedData;
 
                        PeerContact peerContact = null;
                        PeerEndPoint peerEndPoint = null;
                        string newName = null;
 
                        if (endpointData.pContact != IntPtr.Zero){
                            PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(endpointData.pContact, typeof(PEER_CONTACT));
                            peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                        }
 
                        if (endpointData.pEndPoint != IntPtr.Zero){
                            PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(endpointData.pEndPoint, typeof(PEER_ENDPOINT));
                            peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
                            newName = peerEndPoint.Name;
                        }
 
                        nameChangedArgs = new NameChangedEventArgs(peerEndPoint,
                                                                    peerContact,
                                                                    newName);
                    }
                }
                finally{
                    if(eventData != null) eventData.Dispose();
                }
 
 
                //
                // Fire the callback with the marshalled event args data
                //
 
                EventHandler<NameChangedEventArgs> handlerCopy = m_nameChanged;
 
                if ((nameChangedArgs != null) && (handlerCopy != null)){
                    if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                        SynchronizingObject.BeginInvoke(handlerCopy, new object[] { this, nameChangedArgs });
                    else
                        handlerCopy(this, nameChangedArgs);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the name changed event callback.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving NameChangedCallback().");
        }
 
        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="2">
            // <ReferencesCritical Name="Method: RemovePresenceChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.PresenceChangedEventArgs>):Void" Ring="2" />
            // </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;
        private 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;
        private AutoResetEvent m_presenceChangedEvent;
        private SafeCollabEvent m_safePresenceChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="0">
        // <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" />
        // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
        // <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]
        private void AddPresenceChanged(EventHandler<PresenceChangedEventArgs> callback)
        {
            //
            // 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
                    //
                    
                    m_regPresenceChangedWaitHandle = 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="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]
        private void RemovePresenceChanged(EventHandler<PresenceChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemovePresenceChanged() called.");
            
            lock (LockPresenceChangedEvent){
                m_presenceChanged -= callback;
                if (m_presenceChanged == null){
                    CollaborationHelperFunctions.CleanEventVars(ref m_regPresenceChangedWaitHandle,
                                                                ref m_safePresenceChangedEvent,
                                                                ref m_presenceChangedEvent);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean PresenceChanged variables successful.");
                }
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemovePresenceChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <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" />
        // <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]
        private void PresenceChangedCallback(object state, bool timedOut)
        {
            SafeCollabData eventData = null;
            int errorCode = 0;
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "PresenceChangedCallback() called.");
 
            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;
 
                        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;
                        }
 
                        PeerContact peerContact = null;
                        PeerEndPoint peerEndPoint = null;
 
                        if (presenceData.pContact != IntPtr.Zero){
                            PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(presenceData.pContact, typeof(PEER_CONTACT));
                            peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                        }
 
                        if (presenceData.pEndPoint != IntPtr.Zero){
                            PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(presenceData.pEndPoint, typeof(PEER_ENDPOINT));
                            peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
                        }
 
                        presenceChangedArgs = new PresenceChangedEventArgs(peerEndPoint,
                                                                                        peerContact,
                                                                                        presenceData.changeType,
                                                                                        peerPresenceInfo);
                    }
                }
                finally{
                    if(eventData != null) eventData.Dispose();
                }
                
                //
                // Fire the callback with the marshalled event args data
                //
 
                EventHandler<PresenceChangedEventArgs> handlerCopy = m_presenceChanged;
 
                if ((presenceChangedArgs != null) && (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.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving PresenceChangedCallback().");
        }
 
        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="2">
            // <ReferencesCritical Name="Method: RemoveApplicationChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.ApplicationChangedEventArgs>):Void" Ring="2" />
            // </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;
        private 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;
        private AutoResetEvent m_appChangedEvent;
        private SafeCollabEvent m_safeAppChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="0">
        // <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" />
        // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
        // <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]
        private void AddApplicationChanged(EventHandler<ApplicationChangedEventArgs> callback)
        {
            //
            // Register a wait handle if one has not been registered already
            //
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddApplicationChanged() called.");
 
            lock (LockAppChangedEvent){
                if (m_applicationChanged == null){
 
                    m_appChangedEvent = new AutoResetEvent(false);
 
                    //
                    // Register callback with a wait handle
                    //
 
                    m_regAppChangedWaitHandle = 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="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]
        private void RemoveApplicationChanged(EventHandler<ApplicationChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveApplicationChanged() called.");
 
            lock (LockAppChangedEvent){
                m_applicationChanged -= callback;
                if (m_applicationChanged == null){
                    CollaborationHelperFunctions.CleanEventVars(ref m_regAppChangedWaitHandle,
                                                                ref m_safeAppChangedEvent,
                                                                ref m_appChangedEvent);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean ApplicationChanged variables successful.");
                }
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveApplicationChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <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" />
        // <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]
        private void ApplicationChangedCallback(object state, bool timedOut)
        {
            SafeCollabData eventData = null;
            int errorCode = 0;
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "ApplicationChangedCallback() called.");
 
            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;
                        PEER_APPLICATION pa = (PEER_APPLICATION)Marshal.PtrToStructure(appData.pApplication, typeof(PEER_APPLICATION));
 
                        PeerApplication peerApplication = CollaborationHelperFunctions.ConvertPEER_APPLICATIONToPeerApplication(pa); ;
 
                        PeerContact peerContact = null;
                        PeerEndPoint peerEndPoint = null;
 
                        if (appData.pContact != IntPtr.Zero){
                            PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(appData.pContact, typeof(PEER_CONTACT));
                            peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                        }
 
                        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
                //
 
                EventHandler<ApplicationChangedEventArgs> handlerCopy = m_applicationChanged;
 
                if ((appChangedArgs != null) && (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.");
                }
            }
            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="2">
            // <ReferencesCritical Name="Method: RemoveObjectChangedEvent(EventHandler`1<System.Net.PeerToPeer.Collaboration.ObjectChangedEventArgs>):Void" Ring="2" />
            // </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;
        private 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;
        private AutoResetEvent m_objChangedEvent;
        private SafeCollabEvent m_safeObjChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="0">
        // <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" />
        // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
        // <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]
        private void AddObjectChangedEvent(EventHandler<ObjectChangedEventArgs> callback)
        {
            //
            // Register a wait handle if one has not been registered already
            //
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddObjectChangedEvent() called.");
 
            lock (LockObjChangedEvent){
                if (m_objectChanged == null){
 
                    m_objChangedEvent = new AutoResetEvent(false);
 
                    //
                    // Register callback with a wait handle
                    //
                    
                    m_regObjChangedWaitHandle = 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="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]
        private void RemoveObjectChangedEvent(EventHandler<ObjectChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveObjectChangedEvent() called.");
            
            lock (LockObjChangedEvent){
                m_objectChanged -= callback;
                if (m_objectChanged == null){
                    CollaborationHelperFunctions.CleanEventVars(ref m_regObjChangedWaitHandle,
                                                                ref m_safeObjChangedEvent,
                                                                ref m_objChangedEvent);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean ObjectChanged variables successful.");
                }
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveObjectChangedEvent() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <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" />
        // <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_OBJECTToPeerObject(System.Net.PeerToPeer.Collaboration.PEER_OBJECT):System.Net.PeerToPeer.Collaboration.PeerObject" 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]
        private void ObjectChangedCallback(object state, bool timedOut)
        {
            SafeCollabData eventData = null;
            int errorCode = 0;
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "ObjectChangedCallback() called.");
 
            while (true)
            {
                ObjectChangedEventArgs objectChangedArgs = 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;
                        PEER_OBJECT po = (PEER_OBJECT)Marshal.PtrToStructure(objData.pObject, typeof(PEER_OBJECT));
 
                        PeerObject peerObject = CollaborationHelperFunctions.ConvertPEER_OBJECTToPeerObject(po);
 
                        PeerContact peerContact = null;
                        PeerEndPoint peerEndPoint = null;
 
                        if (objData.pContact != IntPtr.Zero){
                            PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(objData.pContact, typeof(PEER_CONTACT));
                            peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                        }
 
                        if (objData.pEndPoint != IntPtr.Zero){
                            PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(objData.pEndPoint, typeof(PEER_ENDPOINT));
                            peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
                        }
 
                        objectChangedArgs = new ObjectChangedEventArgs(peerEndPoint,
                                                                                                peerContact,
                                                                                                objData.changeType,
                                                                                                peerObject);
                    }
                }
                finally{
                    if(eventData != null) eventData.Dispose();
                }
 
                //
                // Fire the callback with the marshalled event args data
                //
 
                EventHandler<ObjectChangedEventArgs> handlerCopy = m_objectChanged;
 
                if ((objectChangedArgs != null) && (handlerCopy != null)){
                    if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                        SynchronizingObject.BeginInvoke(handlerCopy, new object[] { this, objectChangedArgs });
                    else
                        handlerCopy(this, objectChangedArgs);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the object changed event callback.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving ObjectChangedCallback().");
        }
 
        //
        // Grabs all the contacts from the users windows address book
        //
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabEnumContacts(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" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <UsesUnsafeCode Name="Local pContacts of type: IntPtr*" />
        // <UsesUnsafeCode Name="Method: IntPtr.op_Explicit(System.IntPtr):System.Void*" />
        // <ReferencesCritical Name="Local handlePeerEnum of type: SafeCollabEnum" Ring="1" />
        // <ReferencesCritical Name="Local contactArray of type: SafeCollabData" 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 PeerContactCollection GetContacts()
        {
            PeerContactCollection peerContactColl = new PeerContactCollection();
            SafeCollabEnum handlePeerEnum = null;
            UInt32 contactCount = 0;
            int errorCode = 0;
 
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering GetContacts()");
 
            try{
                //
                // Get contacts array from native
                //
                
                errorCode = UnsafeCollabNativeMethods.PeerCollabEnumContacts(out handlePeerEnum);
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabEnumContacts returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetContactsFailed), errorCode);
                }
 
                errorCode = UnsafeCollabNativeMethods.PeerGetItemCount(handlePeerEnum, ref contactCount);
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetItemCount returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetContactsFailed), errorCode);
                }
 
                if (contactCount == 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "No contacts found. \nLeaving GetContacts()");
                    return peerContactColl;
                }
                unsafe{
                    SafeCollabData contactArray = null;
                    try{
                        errorCode = UnsafeCollabNativeMethods.PeerGetNextItem(handlePeerEnum, ref contactCount, out contactArray);
                        if (errorCode != 0){
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetNextItem returned with errorcode {0}", errorCode);
                            throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetContactsFailed), errorCode);
                        }
 
                        //
                        // Loop through the contacts array to build PeerContact collection
                        //
 
                        IntPtr pPEER_CONTACT = contactArray.DangerousGetHandle();
                        IntPtr* pContacts = (IntPtr*)pPEER_CONTACT;
                        for (ulong i = 0; i < contactCount; i++){
                            IntPtr pContactPtr = (IntPtr)pContacts[i];
                            PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(pContactPtr, typeof(PEER_CONTACT));
 
                            PeerContact peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                            peerContactColl.Add(peerContact);
                        }
                    }
                    finally{
                        contactArray.Dispose();
                    }
                }
            }
            finally{
                handlePeerEnum.Dispose();
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, 
                "Returning collections with {0} contacts. \nLeaving GetContacts()");
 
            return peerContactColl;
        }
 
        //
        // Gets specific contact from the users windows address book
        //
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetContact(System.String,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <ReferencesCritical Name="Local safeContact of type: SafeCollabData" 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 PeerContact GetContact(PeerName peerName)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
            if (peerName == null)
                throw new ArgumentNullException("peerName");
 
            int errorCode = 0;
            SafeCollabData safeContact = null;
            PeerContact peerContact = null;
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, 
                "Entering GetContact() with peername {0}", peerName.ToString());
 
            try{
                errorCode = UnsafeCollabNativeMethods.PeerCollabGetContact(peerName.ToString(),
                                                                        out safeContact);
                if (errorCode == UnsafeCollabReturnCodes.PEER_E_CONTACT_NOT_FOUND){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "Contact not found in Contact Manager");
                    throw new PeerToPeerException(SR.GetString(SR.Collab_ContactNotFound));
                }
                else if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetContact returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetContactFailed), errorCode);
                }
 
                if (!safeContact.DangerousGetHandle().Equals(IntPtr.Zero)){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Found contact.");
                    PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(safeContact.DangerousGetHandle(), typeof(PEER_CONTACT));
                    peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                }
                else{
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "No contact found.");
                }
            }
            finally{
                safeContact.Dispose();
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving GetContact()");
 
            return peerContact;
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabQueryContactData(System.IntPtr,System.String&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabParseContact(System.String,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <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.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <SatisfiesLinkDemand Name="GCHandle.Free():System.Void" />
        // <ReferencesCritical Name="Local contact of type: SafeCollabData" 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 PeerContact CreateContact(PeerNearMe peerNearMe) 
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (peerNearMe == null)
                throw new ArgumentNullException("peerNearMe");
 
            if ((peerNearMe.PeerEndPoints == null) || (peerNearMe.PeerEndPoints.Count == 0) || (peerNearMe.PeerEndPoints[0].EndPoint == null))
                throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndpointFound));
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering CreateContact() with peernearme", peerNearMe.ToString());
 
            PeerEndPoint peerEndPoint = peerNearMe.PeerEndPoints[0];
 
            PEER_ENDPOINT pe = new PEER_ENDPOINT();
            pe.peerAddress = CollaborationHelperFunctions.ConvertIPEndpointToPEER_ADDRESS(peerEndPoint.EndPoint);
 
            //
            // Pin all the data to pass to native
            //
            GCHandle pepName = new GCHandle();
 
            if (peerEndPoint.Name != null){
                pepName = GCHandle.Alloc(peerEndPoint.Name, GCHandleType.Pinned);
                pe.pwzEndpointName = pepName.AddrOfPinnedObject();
            }
            
            GCHandle peerEP = GCHandle.Alloc(pe, GCHandleType.Pinned);
            IntPtr ptrPeerEP = peerEP.AddrOfPinnedObject();
 
            string contactData = null;
            int errorCode = 0;
            
            //
            // Refresh end point data if it not subscribed
            //
            peerNearMe.RefreshData();
 
            errorCode = UnsafeCollabNativeMethods.PeerCollabQueryContactData(ptrPeerEP, ref contactData);
            if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetContact returned with errorcode {0}", errorCode);
                throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_CreateContactFailed), errorCode);
            }
 
            SafeCollabData contact = null;
            PeerContact peerContact = null;
 
            try{
                errorCode = UnsafeCollabNativeMethods.PeerCollabParseContact(contactData, out contact);
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetContact returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_CreateContactFailed), errorCode);
                }
 
                PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(contact.DangerousGetHandle(), typeof(PEER_CONTACT));
                peerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                
                //
                // Mark it as just created and add the xml. This is used when adding the contact or getting
                // contact xml when contact is not added
                //
                peerContact.JustCreated = true;
                peerContact.ContactXml = contactData;
            }
            finally{
                if (contact != null) contact.Dispose();
                pepName.Free();
                peerEP.Free();
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving CreateContact().");
 
            return peerContact;
        }
 
        SendOrPostCallback OnCreateContactCompletedDelegate;
        object m_createContactAsyncListLock;
        object CreateContactAsyncListLock
        {
            get{
                if (m_createContactAsyncListLock == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref m_createContactAsyncListLock, o, null);
                }
                return m_createContactAsyncListLock;
            }
        }
        Dictionary<object, AsyncOperation> m_createContactAsyncList = new Dictionary<object, AsyncOperation>();
 
        private event EventHandler<CreateContactCompletedEventArgs> m_createContactCompleted;
        public event EventHandler<CreateContactCompletedEventArgs> CreateContactCompleted
        {
            add
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                m_createContactCompleted += value;
            }
            remove
            {
                if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
                
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                m_createContactCompleted -= value;
            }
        }
 
 
        //
        // Stores state to pass to the create contact async helper
        //
        private class CreateContactAsyncState
        {
            PeerNearMe m_peerNearMe;
            Object m_userToken;
            internal CreateContactAsyncState(PeerNearMe peerNearMe, Object userToken){
                m_peerNearMe = peerNearMe;
                m_userToken = userToken;
            }
            internal PeerNearMe PeerNearMe
            {
                get { return m_peerNearMe; }
            }
            internal Object UserToken
            {
                get { return m_userToken; }
            }
        }
 
        public void CreateContactAsync(PeerNearMe peerNearMe, Object userToken)
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (peerNearMe == null)
                throw new ArgumentNullException("PeerNearMe");
 
            if ((peerNearMe.PeerEndPoints == null) || (peerNearMe.PeerEndPoints.Count == 0) || (peerNearMe.PeerEndPoints[0].EndPoint == null))
                throw new PeerToPeerException(SR.GetString(SR.Collab_NoEndpointFound));
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering CreateContactAsync() with token {0} and following peernearme" , userToken);
                peerNearMe.TracePeerNearMe();
            }
 
            //
            // Add to list of usertokens 
            //
            lock (CreateContactAsyncListLock){
                if (m_createContactAsyncList.ContainsKey(userToken)){
                    throw new ArgumentException(SR.GetString(SR.DuplicateUserToken));
                }
                AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userToken);
                m_createContactAsyncList[userToken] = asyncOp;
            }
 
            ThreadPool.QueueUserWorkItem(new WaitCallback(CreateContactAsyncHelper), new CreateContactAsyncState(peerNearMe, userToken));
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving CreateContactAsync().");
 
        }
 
        //
        // Used to create a contact async'ally
        //
        private void CreateContactAsyncHelper(object state)
        {
            Exception ex = null;
            PeerContact peerContact = null;
            CreateContactAsyncState createAsyncState = state as CreateContactAsyncState;
            PeerNearMe peerNearMe = createAsyncState.PeerNearMe;
            object userToken = createAsyncState.UserToken;
 
            //
            // Call the sync version of createcontact
            //
            try{
                peerContact = CreateContact(peerNearMe);
            }
            catch (ObjectDisposedException e){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "CreateContactAsyncHelper caught error {0}", e.Message);
                ex = e;
            }
            catch (PeerToPeerException e){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "CreateContactAsyncHelper caught error {0}", e.Message);
                ex = e;
            }
 
            CreateContactCompletedEventArgs createContactCompletedArgs;
            if (ex == null){
                createContactCompletedArgs = new CreateContactCompletedEventArgs(peerContact, null, false, userToken);
            }
            else{
                createContactCompletedArgs = new CreateContactCompletedEventArgs(peerContact, ex, false, userToken);
            }
 
            PrepareToRaiseCreateContactCompletedEvent(m_createContactAsyncList[userToken], createContactCompletedArgs);
        }
 
        void OnCreateContactCompleted(CreateContactCompletedEventArgs e)
        {
            EventHandler<CreateContactCompletedEventArgs> handlerCopy = m_createContactCompleted;
            if (handlerCopy != null){
                handlerCopy(this, e);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the create contact completed event callback.");
            }
        }
 
        void CreateContactCompletedWaitCallback(object operationState)
        {
            CreateContactCompletedEventArgs args = (CreateContactCompletedEventArgs) operationState;
            //
            // Remove from usertoken list
            //
            m_createContactAsyncList.Remove(args.UserState);
 
            OnCreateContactCompleted(args);
        }
 
        internal void PrepareToRaiseCreateContactCompletedEvent(AsyncOperation asyncOP, CreateContactCompletedEventArgs args)
        {
            asyncOP.PostOperationCompleted(OnCreateContactCompletedDelegate, args);
        }
 
        //
        // Adds a contacts to the users windows address book
        //
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabAddContact(System.String,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <ReferencesCritical Name="Local contact of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public void AddContact(PeerContact peerContact) 
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (peerContact == null)
                throw new ArgumentNullException("peerContact");
 
            string contactXml = null;
 
            if (peerContact.ContactXml == null){
                try{
                    contactXml = peerContact.ToXml();
                }
                catch (PeerToPeerException e){ 
                    throw new PeerToPeerException(SR.GetString(SR.Collab_AddContactFailedNoXml), e.InnerException);
                }
            }
            else{
                contactXml = peerContact.ContactXml;
            }
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering AddContact() with following peercontact");
                peerContact.TracePeerContact();
            }
 
            SafeCollabData contact = null;
            int errorCode = 0;
 
            try{
                errorCode = UnsafeCollabNativeMethods.PeerCollabAddContact(contactXml, out contact);
            }
            finally{
                if(contact != null) contact.Dispose();
            }
 
            if (errorCode == UnsafeCollabReturnCodes.PEER_E_ALREADY_EXISTS){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabAddContact returned with errorcode {0}. Contact already exists.", errorCode);
                throw new ArgumentException(SR.GetString(SR.Collab_AddContactFailed) + " " + SR.GetString(SR.Collab_ContactExists));
            }
            else if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabAddContact returned with errorcode {0}", errorCode);
                throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_AddContactFailed), errorCode);
            }
 
            peerContact.JustCreated = false;
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                                    "Leaving AddContact() successfully.");
            
        }
 
        //
        // Deletes a contact from the users windows address book
        //
        public void DeleteContact(PeerContact peerContact) 
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                            "Entering DeleteContact().");
 
            if (peerContact == null)
                throw new ArgumentNullException("peerContact");
 
            DeleteContact(peerContact.PeerName);
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                            "Leaving DeleteContact() successfully.");
 
        }
 
        //
        // Deletes a contact from the users windows address book
        //
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabDeleteContact(System.String):System.Int32" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public void DeleteContact(PeerName peerName)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                        "Entering DeleteContact().");
 
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
            if (peerName == null)
                throw new ArgumentNullException("peerName");
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                        "Peername is {0}", peerName.ToString());
 
            int errorCode = UnsafeCollabNativeMethods.PeerCollabDeleteContact(peerName.ToString());
 
            if (errorCode == UnsafeCollabReturnCodes.PEER_E_CONTACT_NOT_FOUND){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "Contact not found in Contact Manager");
                throw new ArgumentException(SR.GetString(SR.Collab_ContactNotFound), "peerName");
            } 
            else if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabDeleteContact returned with errorcode {0}", errorCode);
                throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_DeleteContactFailed), errorCode));
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                        "Leaving DeleteContact() successfully.");
        }
 
        //
        // Updates a contact from the users windows address book
        //
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabUpdateContact(System.Net.PeerToPeer.Collaboration.PEER_CONTACT&):System.Int32" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <ReferencesCritical Name="Local safeCredentials of type: SafeCollabMemory" 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: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public void UpdateContact(PeerContact peerContact) 
        {
            if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName);
            
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
            if (peerContact == null)
                throw new ArgumentNullException("peerContact");
 
            if (peerContact.PeerName == null)
                throw new ArgumentException(SR.GetString(SR.Collab_NoPeerNameInContact));
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering UpdateContact() with following peercontact");
                peerContact.TracePeerContact();
            }
 
            SafeCollabMemory safeCredentials = null;
            int errorCode = 0;
 
            try{
                PEER_CONTACT pc = CollaborationHelperFunctions.ConvertPeerContactToPEER_CONTACT(peerContact, ref safeCredentials);
 
                errorCode = UnsafeCollabNativeMethods.PeerCollabUpdateContact(ref pc);
            }
            finally{
                if (safeCredentials != null) safeCredentials.Dispose();
            }
 
            if (errorCode == UnsafeCollabReturnCodes.PEER_E_CONTACT_NOT_FOUND){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "Contact not found in Contact Manager");
                throw new ArgumentException(SR.GetString(SR.Collab_ContactNotFound), "peerContact");
            }
            else if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabUpdateContact returned with errorcode {0}", errorCode);
                throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_UpdateContactFailed), errorCode));
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0,
                                        "Leaving UpdateContact() successfully.");
        }
 
        private bool m_Disposed;
 
        // <SecurityKernel Critical="True" Ring="2">
        // <ReferencesCritical Name="Method: Dispose(Boolean):Void" Ring="2" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: m_safeSubLstChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.CleanEventVars(System.Threading.RegisteredWaitHandle&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&,System.Threading.AutoResetEvent&):System.Void" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeNameChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Field: m_safePresenceChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeAppChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Field: m_safeObjChangedEvent" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        void Dispose(bool disposing)
        {
            if (!m_Disposed){
                CollaborationHelperFunctions.CleanEventVars(ref m_regSubLstChangedWaitHandle,
                                                            ref m_safeSubLstChangedEvent,
                                                            ref m_subLstChangedEvent);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean SubscriptionListChanged variables successful.");
                
                CollaborationHelperFunctions.CleanEventVars(ref m_regNameChangedWaitHandle,
                                                            ref m_safeNameChangedEvent,
                                                            ref m_nameChangedEvent);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean NameChanged variables successful.");
                
                CollaborationHelperFunctions.CleanEventVars(ref m_regPresenceChangedWaitHandle,
                                                            ref m_safePresenceChangedEvent,
                                                            ref m_presenceChangedEvent);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean PresenceChanged variables successful.");
 
                CollaborationHelperFunctions.CleanEventVars(ref m_regAppChangedWaitHandle,
                                                            ref m_safeAppChangedEvent,
                                                            ref m_appChangedEvent);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean ApplicationChanged variables successful.");
 
                CollaborationHelperFunctions.CleanEventVars(ref m_regObjChangedWaitHandle,
                                                            ref m_safeObjChangedEvent,
                                                            ref m_objChangedEvent);
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean ObjectChanged variables successful.");
 
                m_Disposed = true;
            }
        }
    }
}