File: net\PeerToPeer\Collaboration\PeerCollaboration.cs
Project: ndp\fx\src\SystemNet\System.Net.csproj (System.Net)
//------------------------------------------------------------------------------
// <copyright file="PeerCollaboration.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Net.PeerToPeer.Collaboration
{
    using System;
    using System.Collections.ObjectModel;
    using System.Runtime.InteropServices;
    using System.Net.Mail;
    using System.Security.Cryptography.X509Certificates;
    using System.Diagnostics;
    using System.Threading;
    using System.ComponentModel;
 
    /// <summary>
    /// This class handles all the collaboration platform functions
    /// </summary>
    public static class PeerCollaboration
    {
        public static PeerPresenceInfo LocalPresenceInfo
        {
            // <SecurityKernel Critical="True" Ring="0">
            // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
            // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
            // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
            // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetPresenceInfo(System.IntPtr,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
            // <ReferencesCritical Name="Local safePresenceInfo of type: SafeCollabData" Ring="1" />
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            get
            {
                SafeCollabData safePresenceInfo = null;
                PeerPresenceInfo peerPresenceInfo = null;
 
                try{
                    CollaborationHelperFunctions.Initialize();
 
                    int errorCode = UnsafeCollabNativeMethods.PeerCollabGetPresenceInfo(IntPtr.Zero, out safePresenceInfo);
 
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetPresenceInfo returned with errorcode {0}", errorCode);
                        return null;
                    }
 
                    IntPtr ptrPeerPresenceInfo = safePresenceInfo.DangerousGetHandle();
                    PEER_PRESENCE_INFO ppi = (PEER_PRESENCE_INFO)Marshal.PtrToStructure(ptrPeerPresenceInfo, 
                                                                                        typeof(PEER_PRESENCE_INFO));
 
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Retrieved a PeerPresenceInfo with PresenceStatus {0}, Desc {1}", ppi.status, ppi.descText);
 
                    peerPresenceInfo = new PeerPresenceInfo();
                    peerPresenceInfo.PresenceStatus = ppi.status;
                    peerPresenceInfo.DescriptiveText = ppi.descText;
                }
                catch (Exception e){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetPresenceInfo had exception {0}", e.Message);
                    throw;
                }
                finally{
                    if(safePresenceInfo != null) safePresenceInfo.Dispose();
                }
                return peerPresenceInfo;
            }
            // <SecurityKernel Critical="True" Ring="0">
            // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabSetPresenceInfo(System.Net.PeerToPeer.Collaboration.PEER_PRESENCE_INFO&):System.Int32" />
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            set
            {
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                CollaborationHelperFunctions.Initialize();
 
                if (value == null)
                    throw new ArgumentNullException("value");
 
                if (value.PresenceStatus == PeerPresenceStatus.Offline)
                    throw new PeerToPeerException(SR.GetString(SR.Collab_SetPresenceOffline));
 
                PEER_PRESENCE_INFO ppi;
                ppi.status = value.PresenceStatus;
                ppi.descText = value.DescriptiveText;
 
                int errorCode = UnsafeCollabNativeMethods.PeerCollabSetPresenceInfo(ref ppi);
 
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabSetPresenceInfo returned with errorcode {0}", errorCode);
                    throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_SetLocalPresenceFailed), errorCode));
                }
 
            }
        }
 
        public static string LocalEndPointName
        {
            // <SecurityKernel Critical="True" Ring="0">
            // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEndpointName(System.String&):System.Int32" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            get
            {
                string localEndPointName = null;
 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "LocalEndPointName get called.");
                //
                // Call native to get users endpoint name
                //
 
                try{
                    int errorCode = UnsafeCollabNativeMethods.PeerCollabGetEndpointName(ref localEndPointName);
                    if (errorCode != 0){
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetEndpointName returned with errorcode {0}", errorCode);
                    }
                }
                catch (Exception e){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "LocalEndPointName threw exception {0}", e.ToString());
                    throw;
                }
 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "LocalEndPointName get returning {0}.",
                                                                                        localEndPointName);
 
                return localEndPointName;
            }
 
            // <SecurityKernel Critical="True" Ring="0">
            // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabSetEndpointName(System.String):System.Int32" />
            // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            set
            {
                //
                // Call native to set users endpoint name
                //
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "LocalEndPointName set called with {0}.",
                                                                                    value);
                
                int errorCode = UnsafeCollabNativeMethods.PeerCollabSetEndpointName(value);
                
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabSetEndpointName returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_SetLocalEndPointNameFailed), errorCode);
                }
 
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving LocalEndPointName set.");
            }
        }
 
        public static PeerScope SignInScope
        {
            // <SecurityKernel Critical="True" Ring="0">
            // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetSigninOptions(System.Net.PeerToPeer.Collaboration.PeerScope&):System.Int32" />
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            get
            {
                PeerScope peerScope = PeerScope.None;
 
                CollaborationHelperFunctions.Initialize();
                int errorCode = UnsafeCollabNativeMethods.PeerCollabGetSigninOptions(ref peerScope);
 
                if(errorCode != 0)
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetSigninOptions returned with errorcode {0}", errorCode);
 
                return peerScope;
            }
        }
 
        //
        // Lock to ensure only one Contact Manager is instantiated
        //
        static object s_contactManagerSyncObject;
        internal static object ContactManagerSyncObject
        {
            get{
                if (s_contactManagerSyncObject == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref s_contactManagerSyncObject, o, null);
                }
                return s_contactManagerSyncObject;
            }
        }
 
        static volatile ContactManager s_contactManager;
        //
        // Returns the contact manager instance. Only one is created.
        //
        public static ContactManager ContactManager
        {
            // <SecurityKernel Critical="True" Ring="2">
            // <ReferencesCritical Name="Method: ContactManager..ctor()" Ring="2" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            get{
                if (s_contactManager == null){
                    lock (ContactManagerSyncObject){
                        if (s_contactManager == null){
                            s_contactManager = new ContactManager();
                        }
                    }
                }
                return s_contactManager;
            }
        }
        
        public static PeerApplicationLaunchInfo ApplicationLaunchInfo
        {
            // <SecurityKernel Critical="True" Ring="0">
            // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
            // <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
            // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetAppLaunchInfo(System.Net.PeerToPeer.Collaboration.PEER_APP_LAUNCH_INFO&):System.Int32" />
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" 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]
            get
            {
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering GetApplicationLaunchInfo.");
 
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
                CollaborationHelperFunctions.Initialize();
 
                PeerApplicationLaunchInfo peerAppLaunchInfo = null;
                SafeCollabData appLaunchInfoData = null;
 
                int errorCode = UnsafeCollabNativeMethods.PeerCollabGetAppLaunchInfo(out appLaunchInfoData);
 
                //
                // Special case. No Data found, return null.
                //
                if (errorCode == UnsafeCollabReturnCodes.PEER_E_NOT_FOUND){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "No Application launch info available.");
                    return peerAppLaunchInfo;
                }
 
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetAppLaunchInfo returned with errorcode {0}", errorCode);
                    return peerAppLaunchInfo;
                }
 
                //
                // Marshal individual Launch info elements
                //
 
                try{
                    PEER_APP_LAUNCH_INFO pali = (PEER_APP_LAUNCH_INFO)Marshal.PtrToStructure(appLaunchInfoData.DangerousGetHandle(),
                                                            typeof(PEER_APP_LAUNCH_INFO));
 
                    peerAppLaunchInfo = new PeerApplicationLaunchInfo();
 
                    if (pali.pContact != IntPtr.Zero){
                        PEER_CONTACT pc = (PEER_CONTACT)Marshal.PtrToStructure(pali.pContact, typeof(PEER_CONTACT));
                        peerAppLaunchInfo.PeerContact = CollaborationHelperFunctions.ConvertPEER_CONTACTToPeerContact(pc);
                    }
 
                    PEER_INVITATION pi = (PEER_INVITATION)Marshal.PtrToStructure(pali.pInvitation, typeof(PEER_INVITATION));
                    peerAppLaunchInfo.PeerApplication = new PeerApplication(CollaborationHelperFunctions.ConvertGUIDToGuid(pi.applicationId),
                                                                            null, null, null, null, PeerScope.None);
                    peerAppLaunchInfo.Message = pi.pwzMessage;
                    byte[] data = null;
 
                    if (pi.applicationData.cbData != 0){
                        data = new byte[pi.applicationData.cbData];
                        Marshal.Copy(pi.applicationData.pbData, data, 0, (int)pi.applicationData.cbData);
                    }
 
                    peerAppLaunchInfo.Data = data;
 
                    PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(pali.pEndpoint, typeof(PEER_ENDPOINT));
                    peerAppLaunchInfo.PeerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
 
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "GetApplicationLaunchInfo successful.");
                }
                catch (Exception e){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "GetApplicationLaunchInfo threw error {0}.", e.ToString());
                    throw;
                }
                finally{
                    if (appLaunchInfoData != null) appLaunchInfoData.Dispose();
                }
                
                return peerAppLaunchInfo;
            }
        }
 
        static volatile ISynchronizeInvoke s_synchronizingObject;
        /// <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 static ISynchronizeInvoke SynchronizingObject
        {
            get{
                return s_synchronizingObject;
            }
            set{
                s_synchronizingObject = value;
            }
        }
 
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabSignin(System.IntPtr,System.Net.PeerToPeer.Collaboration.PeerScope):System.Int32" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static void SignIn(PeerScope peerScope)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering SignIn with peerscope {0}.", peerScope);
 
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if ((peerScope < PeerScope.None) || (peerScope > PeerScope.All))
                throw new ArgumentOutOfRangeException("peerScope");
            
            if (peerScope == PeerScope.None)
                throw new ArgumentException(SR.GetString(SR.Collab_SignInWithNone), "peerScope");
 
            CollaborationHelperFunctions.Initialize();
 
            int errorCode = UnsafeCollabNativeMethods.PeerCollabSignin(IntPtr.Zero, peerScope);
 
            if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabSignin returned with errorcode {0}", errorCode);
                throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_SignInFailed), errorCode));
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Signed into {0}.", peerScope);
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabSignout(System.Net.PeerToPeer.Collaboration.PeerScope):System.Int32" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static void SignOut(PeerScope peerScope)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering SignOut with peerscope {0}.", peerScope);
            
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            CollaborationHelperFunctions.Initialize();
 
            if ((peerScope < PeerScope.None) || (peerScope > PeerScope.All))
                throw new ArgumentOutOfRangeException("peerScope");
 
            if (peerScope != PeerScope.None){
                int errorCode = UnsafeCollabNativeMethods.PeerCollabSignout(peerScope);
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabSignout returned with errorcode {0}", errorCode);
                    throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_SignOutFailed), errorCode));
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Signed out of {0}.", peerScope);
        }
 
        //
        // Gives you all the peers on the same subnet as you
        //
        // <SecurityKernel Critical="True" Ring="0">
        // <UsesUnsafeCode Name="Local pPeersNearMe of type: IntPtr*" />
        // <UsesUnsafeCode Name="Method: IntPtr.op_Explicit(System.IntPtr):System.Void*" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabEnumPeopleNearMe(System.Net.PeerToPeer.Collaboration.SafeCollabEnum&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerGetItemCount(System.Net.PeerToPeer.Collaboration.SafeCollabEnum,System.UInt32&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerGetNextItem(System.Net.PeerToPeer.Collaboration.SafeCollabEnum,System.UInt32&,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local handlePeerEnum of type: SafeCollabEnum" Ring="1" />
        // <ReferencesCritical Name="Local appArray of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(System.Net.PeerToPeer.Collaboration.PEER_ENDPOINT):System.Net.PeerToPeer.Collaboration.PeerEndPoint" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static PeerNearMeCollection GetPeersNearMe()
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering GetPeersNearMeGetPeersNearMe.");
            CollaborationHelperFunctions.Initialize();
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            PeerNearMeCollection pnmc = new PeerNearMeCollection();
 
            SafeCollabEnum handlePeerEnum = null;
            UInt32 pnmCount = 0;
            int errorCode = 0;
 
            try{
                //
                // Call native to get the enumeration of peers near
                //
                errorCode = UnsafeCollabNativeMethods.PeerCollabEnumPeopleNearMe(out handlePeerEnum);
 
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabEnumPeopleNearMe returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetPeersNearMeFailed), errorCode);
                }
 
                errorCode = UnsafeCollabNativeMethods.PeerGetItemCount(handlePeerEnum, ref pnmCount);
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetItemCount returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetPeersNearMeFailed), errorCode);
                }
 
                if (pnmCount == 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "No peers found. \nLeaving GetPeersNearMe()");
                    return pnmc;
                }
 
                unsafe{
                    SafeCollabData appArray;
                    errorCode = UnsafeCollabNativeMethods.PeerGetNextItem(handlePeerEnum, ref pnmCount, out appArray);
 
                    IntPtr pPEER_PEOPLE_NEAR_ME = appArray.DangerousGetHandle();
                    IntPtr* pPeersNearMe = (IntPtr*)pPEER_PEOPLE_NEAR_ME;
 
                    //
                    // Loops through individual native structures and makes peers from them 
                    //
                    for (ulong i = 0; i < pnmCount; i++){
                        IntPtr pContactPtr = (IntPtr)pPeersNearMe[i];
                        PEER_PEOPLE_NEAR_ME pnm = (PEER_PEOPLE_NEAR_ME)Marshal.PtrToStructure(pContactPtr, typeof(PEER_PEOPLE_NEAR_ME));
 
                        PeerNearMe peerNearMe = new PeerNearMe();
                        peerNearMe.Id = CollaborationHelperFunctions.ConvertGUIDToGuid(pnm.id);
                        peerNearMe.Nickname = Marshal.PtrToStringUni(pnm.pwzNickname); ;
 
                        PEER_ENDPOINT pe = pnm.endpoint;
                        peerNearMe.PeerEndPoints.Add(CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe));
 
                        pnmc.Add(peerNearMe);
                    }
                }
            }
            finally{
                if (handlePeerEnum != null) handlePeerEnum.Dispose();
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving GetPeersNearMeGetPeersNearMe with {0} peers.", pnmc.Count);
 
            return pnmc;
        }
        
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.Copy(System.Byte[],System.Int32,System.IntPtr,System.Int32):System.Void" />
        // <SatisfiesLinkDemand Name="GCHandle.Alloc(System.Object,System.Runtime.InteropServices.GCHandleType):System.Runtime.InteropServices.GCHandle" />
        // <SatisfiesLinkDemand Name="GCHandle.AddrOfPinnedObject():System.IntPtr" />
        // <SatisfiesLinkDemand Name="GCHandle.Free():System.Void" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabRegisterApplication(System.Net.PeerToPeer.Collaboration.PEER_APPLICATION_REGISTRATION_INFO&,System.Net.PeerToPeer.Collaboration.PeerApplicationRegistrationType):System.Int32" />
        // <ReferencesCritical Name="Local data of type: SafeCollabMemory" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // <ReferencesCritical Name="Method: SafeCollabMemory..ctor(System.Int32)" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static void RegisterApplication(PeerApplication application, PeerApplicationRegistrationType type)
        {
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (application == null){
                throw new ArgumentNullException("application");
            }
            
            if (application.Path == null){
                throw new ArgumentException(SR.GetString(SR.Collab_AppRegNoPathError));
            }
 
            if ((type < PeerApplicationRegistrationType.CurrentUser) || (type > PeerApplicationRegistrationType.AllUsers)){
                throw new ArgumentOutOfRangeException("type");
            }
 
            CollaborationHelperFunctions.Initialize();
 
            int errorCode = 0;
 
            //
            // Convert PeerApplication.Guid into native GUID struct
            //
 
            PEER_APPLICATION_REGISTRATION_INFO appRegInfo = new PEER_APPLICATION_REGISTRATION_INFO();
            appRegInfo.application.guid = CollaborationHelperFunctions.ConvertGuidToGUID(application.Id);
 
            appRegInfo.pwzApplicationArguments = application.CommandLineArgs;
            appRegInfo.pwzApplicationToLaunch = application.Path;
            appRegInfo.dwPublicationScope = (uint)application.PeerScope;
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RegisterApplication() is called with the following Info");
                application.TracePeerApplication();
            }
 
            unsafe{
 
                SafeCollabMemory data = null;
                appRegInfo.application.data.cbData =    (application.Data!=null) ? 
                                                        (UInt32)application.Data.Length : 0;
                GCHandle descHandle = new GCHandle();
 
                try{
                    //
                    // Marshal any data to send to native call
                    //
 
                    if ((application.Data!=null) && (application.Data.Length > 0))
                    {
                        data = new SafeCollabMemory(application.Data.Length);
                        appRegInfo.application.data.pbData = data.DangerousGetHandle();
                        Marshal.Copy(application.Data, 0, appRegInfo.application.data.pbData, application.Data.Length);
                    }
                    else
                        appRegInfo.application.data.pbData = IntPtr.Zero;
 
                    descHandle = GCHandle.Alloc(application.Description, GCHandleType.Pinned);
                    appRegInfo.application.pwzDescription = descHandle.AddrOfPinnedObject();
 
                    errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterApplication(ref appRegInfo, type);
 
                }
                finally{
                    if (descHandle.IsAllocated) descHandle.Free();
                    if (data != null) data.Dispose();
                }
            }
            if (errorCode == UnsafeCollabReturnCodes.PEER_E_ALREADY_EXISTS){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterApplication returned with errorcode {0}. Application already registered.", errorCode);
                throw new ArgumentException(SR.GetString(SR.Collab_AppRegFailed) + " " + SR.GetString(SR.Collab_AppExists));
            }
            else if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabRegisterApplication returned with errorcode {0}", errorCode);
                throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_AppRegFailed), errorCode));
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "RegisterApplication successful");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabUnregisterApplication(System.Net.PeerToPeer.Collaboration.GUID&,System.Net.PeerToPeer.Collaboration.PeerApplicationRegistrationType):System.Int32" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static void UnregisterApplication(PeerApplication application, PeerApplicationRegistrationType type)
        {
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (application == null){
                throw new ArgumentNullException("application");
            }
 
            if (application.Id.Equals(Guid.Empty)){
                throw new ArgumentException(SR.GetString(SR.Collab_EmptyGuidError));
            }
 
            if ((type < PeerApplicationRegistrationType.CurrentUser) || (type > PeerApplicationRegistrationType.AllUsers)){
                throw new ArgumentOutOfRangeException("type");
            }
 
            CollaborationHelperFunctions.Initialize();
 
            //
            // Convert PeerApplication.Guid into native GUID struct
            //
 
            GUID guid = CollaborationHelperFunctions.ConvertGuidToGUID(application.Id);
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information))
            {
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "UnregisterApplication() is called with the following Info");
                application.TracePeerApplication();
            }
 
            int errorCode = UnsafeCollabNativeMethods.PeerCollabUnregisterApplication(ref guid, type);
 
            if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabUnregisterApplication returned with errorcode {0}", errorCode);
                throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_AppUnregFailed), errorCode));
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "UnregisterApplication successful");
        }
 
        //
        // Gets all applications registered to collab on this machine
        //
        public static PeerApplicationCollection GetLocalRegisteredApplications()
        {
            PeerApplicationCollection allUsersColl = GetLocalRegisteredApplications(PeerApplicationRegistrationType.AllUsers);
            PeerApplicationCollection localUsersColl = GetLocalRegisteredApplications(PeerApplicationRegistrationType.CurrentUser);
 
            if ((allUsersColl == null) || (allUsersColl.Count == 0)){ 
                return localUsersColl; 
            }
            else if ((localUsersColl == null) || (localUsersColl.Count == 0)){ 
                return allUsersColl; 
            }
            else{
                //
                // Merge the two to remove dupes
                //
 
                foreach (PeerApplication peerApplicationLocal in localUsersColl){
                    PeerApplication peerAppToRemove = null;
 
                    foreach (PeerApplication peerApplicationAll in allUsersColl){
                        if (peerApplicationAll.Id.Equals(peerApplicationLocal.Id)){
                            peerAppToRemove = peerApplicationAll;
                        }
                    }
                    if (peerAppToRemove != null)
                        allUsersColl.Remove(peerAppToRemove);
                }
 
                foreach (PeerApplication peerApplicationAll in allUsersColl){
                    localUsersColl.Add(peerApplicationAll);
                }
                return localUsersColl;
            }
        }
 
        //
        // Gets all applications registered to collab for specific user on this machine
        //
        // <SecurityKernel Critical="True" Ring="0">
        // <UsesUnsafeCode Name="Local pApps of type: IntPtr*" />
        // <UsesUnsafeCode Name="Local pPeerApp of type: PEER_APPLICATION*" />
        // <UsesUnsafeCode Name="Method: IntPtr.op_Explicit(System.IntPtr):System.Void*" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStringUni(System.IntPtr):System.String" />
        // <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabEnumApplications(System.IntPtr,System.IntPtr,System.Net.PeerToPeer.Collaboration.SafeCollabEnum&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerGetItemCount(System.Net.PeerToPeer.Collaboration.SafeCollabEnum,System.UInt32&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerGetNextItem(System.Net.PeerToPeer.Collaboration.SafeCollabEnum,System.UInt32&,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetApplicationRegistrationInfo(System.Net.PeerToPeer.Collaboration.GUID&,System.Net.PeerToPeer.Collaboration.PeerApplicationRegistrationType,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local handlePeerEnum of type: SafeCollabEnum" Ring="1" />
        // <ReferencesCritical Name="Local appArray of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Local safeAppRegInfo of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // <ReferencesCritical Name="Method: SafeCollabEnum..ctor()" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // <ReferencesCritical Name="Method: SafeCollabData..ctor()" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static PeerApplicationCollection GetLocalRegisteredApplications(PeerApplicationRegistrationType type)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering GetLocalRegisteredApplications.");
            
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if ((type < PeerApplicationRegistrationType.CurrentUser) || (type > PeerApplicationRegistrationType.AllUsers)){
                throw new ArgumentOutOfRangeException("type");
            }
 
            CollaborationHelperFunctions.Initialize();
 
            PeerApplicationCollection peerAppColl = new PeerApplicationCollection();
            SafeCollabEnum handlePeerEnum = new SafeCollabEnum();
            UInt32 appCount = 0;
            int errorCode = 0;
 
            //
            // Enumerate and get all the registered applications from native
            //
 
            try{
                errorCode = UnsafeCollabNativeMethods.PeerCollabEnumApplications(IntPtr.Zero, IntPtr.Zero, out handlePeerEnum);
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabEnumApplications returned with errorcode {0}", errorCode);
                    throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetLocalAppsFailed), errorCode));
                }
 
                errorCode = UnsafeCollabNativeMethods.PeerGetItemCount(handlePeerEnum, ref appCount);
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetItemCount returned with errorcode {0}", errorCode);
                    throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetLocalAppsFailed), errorCode));
                }
 
                if (appCount == 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "No local registered PeerApplications found.");
                    return peerAppColl;
                }
 
                unsafe{
                    SafeCollabData appArray = null;
                    try{
                        errorCode = UnsafeCollabNativeMethods.PeerGetNextItem(handlePeerEnum, ref appCount, out appArray);
                        if (errorCode != 0){
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetNextItem returned with errorcode {0}", errorCode);
                            throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetLocalAppsFailed), errorCode));
                        }
 
                        //
                        // Marshal each application from the array
                        //
 
                        IntPtr pPEER_APLICATION = appArray.DangerousGetHandle();
                        IntPtr* pApps = (IntPtr*)pPEER_APLICATION;
                        for (ulong i = 0; i < appCount; i++){
                            PEER_APPLICATION* pPeerApp = (PEER_APPLICATION*)pApps[i];
                            string description = Marshal.PtrToStringUni(pPeerApp->pwzDescription);
                            byte[] data = null;
 
                            if (pPeerApp->data.cbData != 0){
                                data = new byte[pPeerApp->data.cbData];
                                Marshal.Copy(pPeerApp->data.pbData, data, 0, (int)pPeerApp->data.cbData);
                            }
 
                            PeerApplication peerApp = new PeerApplication(  CollaborationHelperFunctions.ConvertGUIDToGuid(pPeerApp->guid), 
                                                                            description, data, null, null, PeerScope.None);
                            peerAppColl.Add(peerApp);
                        }
                    }
                    finally{
                        appArray.Dispose();
                    }
                }
            }
            finally{
                handlePeerEnum.Dispose();
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Got all local registered Applications. Start filtering");
 
            PeerApplicationCollection peerAppCollFiltered = new PeerApplicationCollection();
 
            //
            // Filter the apps according to the Registration type the user wants
            //
 
            foreach (PeerApplication peerApplication in peerAppColl)
            {
                GUID guid = CollaborationHelperFunctions.ConvertGuidToGUID(peerApplication.Id);
                SafeCollabData safeAppRegInfo = new SafeCollabData();
 
                try{
                    errorCode = UnsafeCollabNativeMethods.PeerCollabGetApplicationRegistrationInfo(ref guid,
                                                                                                    type,
                                                                                                    out safeAppRegInfo);
                    if (errorCode != 0)
                        Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabGetApplicationRegistrationInfo returned with errorcode {0}", errorCode);
 
                    if (!safeAppRegInfo.IsInvalid){
                        PEER_APPLICATION_REGISTRATION_INFO pari = (PEER_APPLICATION_REGISTRATION_INFO)
                                                                Marshal.PtrToStructure(safeAppRegInfo.DangerousGetHandle(),
                                                                                        typeof(PEER_APPLICATION_REGISTRATION_INFO));
                        peerApplication.Path = pari.pwzApplicationToLaunch;
                        peerApplication.CommandLineArgs = pari.pwzApplicationArguments;
                        peerApplication.PeerScope = (PeerScope)pari.dwPublicationScope;
                        
                        peerAppCollFiltered.Add(peerApplication);
                    }
                }
                finally{
                    safeAppRegInfo.Dispose();
                }
 
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Filtering successful. Returning collection with {0} applications", peerAppCollFiltered.Count);
 
            return peerAppCollFiltered;
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.Copy(System.Byte[],System.Int32,System.IntPtr,System.Int32):System.Void" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabSetObject(System.Net.PeerToPeer.Collaboration.PEER_OBJECT&):System.Int32" />
        // <ReferencesCritical Name="Local data of type: SafeCollabMemory" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // <ReferencesCritical Name="Method: SafeCollabMemory..ctor(System.Int32)" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static void SetObject(PeerObject peerObject)
        {
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (peerObject == null){
                throw new ArgumentNullException("peerObject");
            }
 
            CollaborationHelperFunctions.Initialize();
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "SetObject() is called with the following info");
                peerObject.TracePeerObject();
            }
 
            PEER_OBJECT po = new PEER_OBJECT();
            int errorCode = 0;
 
            //
            // Create the native PEER_OBJECT struct
            //
 
            po.guid = CollaborationHelperFunctions.ConvertGuidToGUID(peerObject.Id);
            po.dwPublicationScope = (uint)peerObject.PeerScope;
            SafeCollabMemory data = null;
 
            try{
                if ((peerObject.Data != null) && (peerObject.Data.Length > 0)){
                    data = new SafeCollabMemory(peerObject.Data.Length);
                    po.data.pbData = data.DangerousGetHandle();
                    po.data.cbData = (UInt32)peerObject.Data.Length;
 
                    Marshal.Copy(peerObject.Data, 0, po.data.pbData, peerObject.Data.Length);
                }
                else{
                    po.data.pbData = IntPtr.Zero;
                    po.data.cbData = 0;
                }
 
                errorCode = UnsafeCollabNativeMethods.PeerCollabSetObject(ref po);
            }
            finally{
                if (data != null) data.Dispose();
            }
 
            if (errorCode == UnsafeCollabReturnCodes.PEER_E_ALREADY_EXISTS){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabSetObject returned with errorcode {0}. Object already set.", errorCode);
                throw new ArgumentException(SR.GetString(SR.Collab_ObjectSetFailed) + " " + SR.GetString(SR.Collab_ObjectExists));
            }
            else if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabSetObject returned with errorcode {0}", errorCode);
                throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_ObjectSetFailed), errorCode));
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Set Object successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabDeleteObject(System.Net.PeerToPeer.Collaboration.GUID&):System.Int32" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static void DeleteObject(PeerObject peerObject)
        {
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
 
            if (peerObject == null){
                throw new ArgumentNullException("peerObject");
            }
 
            CollaborationHelperFunctions.Initialize();
 
            if (Logging.P2PTraceSource.Switch.ShouldTrace(TraceEventType.Information)){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "DeleteObject() is called with the following info");
                peerObject.TracePeerObject();
            }
 
            GUID guid = CollaborationHelperFunctions.ConvertGuidToGUID(peerObject.Id);
            int errorCode = UnsafeCollabNativeMethods.PeerCollabDeleteObject(ref guid);
 
            if (errorCode != 0){
                Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabDeleteObject returned with errorcode {0}", errorCode);
                throw (PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_ObjectDeleteFailed), errorCode));
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Delete Object successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <UsesUnsafeCode Name="Local pObjects of type: IntPtr*" />
        // <UsesUnsafeCode Name="Local pPeerObject of type: PEER_OBJECT*" />
        // <UsesUnsafeCode Name="Method: IntPtr.op_Explicit(System.IntPtr):System.Void*" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.Copy(System.IntPtr,System.Byte[],System.Int32,System.Int32):System.Void" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabEnumObjects(System.IntPtr,System.IntPtr,System.Net.PeerToPeer.Collaboration.SafeCollabEnum&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerGetItemCount(System.Net.PeerToPeer.Collaboration.SafeCollabEnum,System.UInt32&):System.Int32" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerGetNextItem(System.Net.PeerToPeer.Collaboration.SafeCollabEnum,System.UInt32&,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local handlePeerEnum of type: SafeCollabEnum" Ring="1" />
        // <ReferencesCritical Name="Local objectArray of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        public static PeerObjectCollection GetLocalSetObjects()
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering GetLocalSetObjects.");
 
            PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
            
            CollaborationHelperFunctions.Initialize();
 
            PeerObjectCollection peerObjectColl = new PeerObjectCollection();
            SafeCollabEnum handlePeerEnum = null;
            UInt32 objectCount = 0;
            int errorCode = 0;
 
            //
            // Enumerate through all the objects from native
            //
 
            try{
                errorCode = UnsafeCollabNativeMethods.PeerCollabEnumObjects(IntPtr.Zero, IntPtr.Zero, out handlePeerEnum);
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerCollabEnumObjects returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetLocalObjectsFailed), errorCode);
                }
 
                errorCode = UnsafeCollabNativeMethods.PeerGetItemCount(handlePeerEnum, ref objectCount);
                if (errorCode != 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetItemCount returned with errorcode {0}", errorCode);
                    throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetLocalObjectsFailed), errorCode);
                }
 
                if (objectCount == 0){
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "No local PeerObjects found.");
                    return peerObjectColl;
                }
 
                unsafe{
                    SafeCollabData objectArray = null;
                    try{
                        errorCode = UnsafeCollabNativeMethods.PeerGetNextItem(handlePeerEnum, ref objectCount, out objectArray);
                        if (errorCode != 0){
                            Logging.P2PTraceSource.TraceEvent(TraceEventType.Error, 0, "PeerGetNextItem returned with errorcode {0}", errorCode);
                            throw PeerToPeerException.CreateFromHr(SR.GetString(SR.Collab_GetLocalObjectsFailed), errorCode);
                        }
 
                        //
                        // Marshal each object from the array
                        //
 
                        IntPtr pPEER_OBJECT = objectArray.DangerousGetHandle();
                        IntPtr* pObjects = (IntPtr*)pPEER_OBJECT;
                        for (ulong i = 0; i < objectCount; i++){
                            PEER_OBJECT* pPeerObject = (PEER_OBJECT*)pObjects[i];
                            byte[] data = null;
 
                            if (pPeerObject->data.cbData != 0){
                                data = new byte[pPeerObject->data.cbData];
                                Marshal.Copy(pPeerObject->data.pbData, data, 0, (int)pPeerObject->data.cbData);
                            }
 
                            PeerObject peerObject = new PeerObject(CollaborationHelperFunctions.ConvertGUIDToGuid(pPeerObject->guid), data, (PeerScope)pPeerObject->dwPublicationScope);
                            peerObjectColl.Add(peerObject);
                        }
                    }
                    finally{
                        objectArray.Dispose();
                    }
                }
            }
            finally{
                handlePeerEnum.Dispose();
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Returning collection with {0} objects", peerObjectColl.Count);
            return peerObjectColl;
        }
 
        private static event EventHandler<NameChangedEventArgs> s_nameChanged;
        public static event EventHandler<NameChangedEventArgs> LocalNameChanged
        {
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // <ReferencesCritical Name="Method: AddNameChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.NameChangedEventArgs>):Void" Ring="1" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            add
            {
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                CollaborationHelperFunctions.Initialize();
 
                AddNameChanged(value);
            }
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // <ReferencesCritical Name="Method: RemoveNameChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.NameChangedEventArgs>):Void" Ring="2" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            remove
            {
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                CollaborationHelperFunctions.Initialize();
 
                RemoveNameChanged(value);
            }
        }
 
        #region Name changed event variables
        private static object s_lockNameChangedEvent;
        private static object LockNameChangedEvent
        {
            get{
                if (s_lockNameChangedEvent == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref s_lockNameChangedEvent, o, null);
                }
                return s_lockNameChangedEvent;
            }
        }
 
        private static RegisteredWaitHandle s_regNameChangedWaitHandle;
        private static AutoResetEvent s_nameChangedEvent;
        private static SafeCollabEvent s_safeNameChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="WaitHandle.get_SafeWaitHandle():Microsoft.Win32.SafeHandles.SafeWaitHandle" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabRegisterEvent(Microsoft.Win32.SafeHandles.SafeWaitHandle,System.UInt32,System.Net.PeerToPeer.Collaboration.PEER_COLLAB_EVENT_REGISTRATION&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&):System.Int32" />
        // <ReferencesCritical Name="Method: NameChangedCallback(Object, Boolean):Void" Ring="1" />
        // <ReferencesCritical Name="Field: s_safeNameChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        private static void AddNameChanged(EventHandler<NameChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Entering AddNameChanged().");
 
            //
            // Register a wait handle if one has not been registered already
            //
            lock (LockNameChangedEvent)
            {
                if (s_nameChanged == null){
                    s_nameChangedEvent = new AutoResetEvent(false);
 
                    //
                    // Register callback with a wait handle
                    //
 
                    s_regNameChangedWaitHandle = ThreadPool.RegisterWaitForSingleObject(s_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.MyEndPointChanged;
                    pcer.pInstance = IntPtr.Zero;
 
                    //
                    // Register event with collab
                    //
 
                    int errorCode = UnsafeCollabNativeMethods.PeerCollabRegisterEvent(
                                                                s_nameChangedEvent.SafeWaitHandle,
                                                                1,
                                                                ref pcer,
                                                                out s_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);
                    }
                }
                s_nameChanged += callback;
            }
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "AddNameChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: s_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 static void RemoveNameChanged(EventHandler<NameChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveNameChanged() called.");
            lock (LockNameChangedEvent){
                s_nameChanged -= callback;
                if (s_nameChanged == null){
                    CollaborationHelperFunctions.CleanEventVars(ref s_regNameChangedWaitHandle,
                                                                ref s_safeNameChangedEvent,
                                                                ref s_nameChangedEvent);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean NameChangedEvent variables successful.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveNameChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Field: s_safeNameChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        private static 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 (s_safeNameChangedEvent.IsInvalid) return;
                        errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(s_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.MyEndPointChanged){
 
                        if (ped.endpointChangedData.pEndPoint != IntPtr.Zero){
                            //
                            // This means its an endpoint on my contact which is not on the local machine
                            // so we dont care
                            //
                            return;
                        }
 
 
                        string newName = PeerCollaboration.LocalEndPointName;
 
                        nameChangedArgs = new NameChangedEventArgs( null,
                                                                    null,
                                                                    newName);
                    }
                }
                finally{
                    if (eventData != null) eventData.Dispose();
                }
 
                //
                // Fire the callback with the marshalled event args data
                //
                EventHandler<NameChangedEventArgs> handlerCopy = s_nameChanged;
 
                if ((nameChangedArgs != null) && (handlerCopy != null)){
                    if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                        SynchronizingObject.BeginInvoke(handlerCopy, new object[] { null, nameChangedArgs });
                    else
                        handlerCopy(null, nameChangedArgs);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the name changed event callback.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving NameChangedCallback().");
        }
 
        static event EventHandler<PresenceChangedEventArgs> s_presenceChanged;
        public static event EventHandler<PresenceChangedEventArgs> LocalPresenceChanged
        {
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // <ReferencesCritical Name="Method: AddPresenceChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.PresenceChangedEventArgs>):Void" Ring="2" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            add
            {
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                CollaborationHelperFunctions.Initialize();
 
                AddPresenceChanged(value);
            }
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // <ReferencesCritical Name="Method: RemovePresenceChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.PresenceChangedEventArgs>):Void" Ring="2" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            remove
            {
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                CollaborationHelperFunctions.Initialize();
 
                RemovePresenceChanged(value);
            }
        }
 
        #region Presence changed event variables
        static object s_lockPresenceChangedEvent;
        static object LockPresenceChangedEvent
        {
            get{
                if (s_lockPresenceChangedEvent == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref s_lockPresenceChangedEvent, o, null);
                }
                return s_lockPresenceChangedEvent;
            }
        }
 
        static RegisteredWaitHandle s_regPresenceChangedWaitHandle;
        static AutoResetEvent s_presenceChangedEvent;
        static SafeCollabEvent s_safePresenceChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: s_safePresenceChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PresenceChangedCallback(Object, Boolean):Void" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.AddMyPresenceChanged(System.EventHandler`1<System.Net.PeerToPeer.Collaboration.PresenceChangedEventArgs>,System.EventHandler`1<System.Net.PeerToPeer.Collaboration.PresenceChangedEventArgs>&,System.Object,System.Threading.RegisteredWaitHandle&,System.Threading.AutoResetEvent&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&,System.Threading.WaitOrTimerCallback):System.Void" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        static void AddPresenceChanged(EventHandler<PresenceChangedEventArgs> callback)
        {
            CollaborationHelperFunctions.AddMyPresenceChanged(callback, ref s_presenceChanged, LockPresenceChangedEvent,
                                                                    ref s_regPresenceChangedWaitHandle, ref s_presenceChangedEvent,
                                                                    ref s_safePresenceChangedEvent, new WaitOrTimerCallback(PresenceChangedCallback));
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: s_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]
        static void RemovePresenceChanged(EventHandler<PresenceChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemovePresenceChanged() called.");
            lock (LockPresenceChangedEvent){
                s_presenceChanged -= callback;
                if (s_presenceChanged == null){
                    CollaborationHelperFunctions.CleanEventVars(ref s_regPresenceChangedWaitHandle,
                                                                ref s_safePresenceChangedEvent,
                                                                ref s_presenceChangedEvent);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean PresenceChanged variables successful.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemovePresenceChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Field: s_safePresenceChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: PeerToPeerException.CreateFromHr(System.String,System.Int32):System.Net.PeerToPeer.PeerToPeerException" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        static 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 (s_safePresenceChangedEvent.IsInvalid) return;
                        errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(s_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.MyPresenceChanged){
                        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;
                        }
 
                        if (presenceData.pEndPoint != IntPtr.Zero){
                            //
                            // This means its an endpoint on my contact which is not on the local machine
                            // so we dont care
                            //
                            return;
                        }
 
                        presenceChangedArgs = new PresenceChangedEventArgs( null,
                                                                            null,
                                                                            presenceData.changeType,
                                                                            peerPresenceInfo);
                    }
                }
                finally{
                    if (eventData != null) eventData.Dispose();
                }
 
                //
                // Fire the callback with the marshalled event args data
                //
 
                EventHandler<PresenceChangedEventArgs> handlerCopy = s_presenceChanged;
 
                if ((presenceChangedArgs != null) && (handlerCopy != null)){
                    if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                        SynchronizingObject.BeginInvoke(handlerCopy, new object[] { null, presenceChangedArgs });
                    else
                        handlerCopy(null, presenceChangedArgs);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the presence changed event callback.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving PresenceChangedCallback().");
        }
 
        static EventHandler<ObjectChangedEventArgs> s_objectChanged;
 
        public static event EventHandler<ObjectChangedEventArgs> LocalObjectChanged
        {
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // <ReferencesCritical Name="Method: AddObjectChangedEvent(EventHandler`1<System.Net.PeerToPeer.Collaboration.ObjectChangedEventArgs>):Void" Ring="2" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            add
            {
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                CollaborationHelperFunctions.Initialize();
 
                AddObjectChangedEvent(value);
            }
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // <ReferencesCritical Name="Method: RemoveObjectChangedEvent(EventHandler`1<System.Net.PeerToPeer.Collaboration.ObjectChangedEventArgs>):Void" Ring="2" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            remove
            {
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                CollaborationHelperFunctions.Initialize();
 
                RemoveObjectChangedEvent(value);
            }
        }
 
        #region Object changed event variables
        static object s_lockObjChangedEvent;
        static object LockObjChangedEvent
        {
            get{
                if (s_lockObjChangedEvent == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref s_lockObjChangedEvent, o, null);
                }
                return s_lockObjChangedEvent;
            }
        }
 
        static RegisteredWaitHandle s_regObjChangedWaitHandle;
        static AutoResetEvent s_objChangedEvent;
        static SafeCollabEvent s_safeObjChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: s_safeObjChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: ObjectChangedCallback(Object, Boolean):Void" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.AddMyObjectChanged(System.EventHandler`1<System.Net.PeerToPeer.Collaboration.ObjectChangedEventArgs>,System.EventHandler`1<System.Net.PeerToPeer.Collaboration.ObjectChangedEventArgs>&,System.Object,System.Threading.RegisteredWaitHandle&,System.Threading.AutoResetEvent&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&,System.Threading.WaitOrTimerCallback):System.Void" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        static void AddObjectChangedEvent(EventHandler<ObjectChangedEventArgs> callback)
        {
            CollaborationHelperFunctions.AddMyObjectChanged(callback, ref s_objectChanged, LockObjChangedEvent,
                                                                    ref s_regObjChangedWaitHandle, ref s_objChangedEvent,
                                                                    ref s_safeObjChangedEvent, new WaitOrTimerCallback(ObjectChangedCallback));
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: s_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]
        static void RemoveObjectChangedEvent(EventHandler<ObjectChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveObjectChangedEvent() called.");
            lock (LockObjChangedEvent){
                s_objectChanged -= callback;
                if (s_objectChanged == null){
                    CollaborationHelperFunctions.CleanEventVars(ref s_regObjChangedWaitHandle,
                                                                ref s_safeObjChangedEvent,
                                                                ref s_objChangedEvent);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean ObjectChangedEvent variables successful.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveObjectChangedEvent() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Field: s_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" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        static void ObjectChangedCallback(object state, bool timedOut)
        {
            SafeCollabData eventData = null;
            int errorCode = 0;
 
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "ObjectChangedCallback() called.");
 
            while (true)
            {
                ObjectChangedEventArgs objChangedArgs = null;
 
                //
                // Get the event data for the fired event
                //
                try
                {
                    lock (LockObjChangedEvent){
                        if (s_safeObjChangedEvent.IsInvalid) return;
                        errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(s_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.MyObjectChanged){
                        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); ;
 
                        PeerEndPoint peerEndPoint = null;
                        if (objData.pEndPoint != IntPtr.Zero){
                            PEER_ENDPOINT pe = (PEER_ENDPOINT)Marshal.PtrToStructure(objData.pEndPoint, typeof(PEER_ENDPOINT));
                            peerEndPoint = CollaborationHelperFunctions.ConvertPEER_ENDPOINTToPeerEndPoint(pe);
                        }
 
                        objChangedArgs = new ObjectChangedEventArgs(peerEndPoint,
                                                                                            null,
                                                                                            objData.changeType,
                                                                                            peerObject);
                    }
                }
                finally{
                    if (eventData != null) eventData.Dispose();
                }
 
                //
                // Fire the callback with the marshalled event args data
                //
 
                EventHandler<ObjectChangedEventArgs> handlerCopy = s_objectChanged;
 
                if ((objChangedArgs != null) && (handlerCopy != null)){
                    if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                        SynchronizingObject.BeginInvoke(handlerCopy, new object[] { null, objChangedArgs });
                    else
                        handlerCopy(null, objChangedArgs);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the object changed event callback.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving ObjectChangedCallback().");
        }
 
        static event EventHandler<ApplicationChangedEventArgs> s_applicationChanged;
 
        public static event EventHandler<ApplicationChangedEventArgs> LocalApplicationChanged
        {
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // <ReferencesCritical Name="Method: AddApplicationChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.ApplicationChangedEventArgs>):Void" Ring="2" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            add
            {
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                CollaborationHelperFunctions.Initialize();
 
                AddApplicationChanged(value);
            }
            // <SecurityKernel Critical="True" Ring="1">
            // <ReferencesCritical Name="Method: CollaborationHelperFunctions.Initialize():System.Void" Ring="1" />
            // <ReferencesCritical Name="Method: RemoveApplicationChanged(EventHandler`1<System.Net.PeerToPeer.Collaboration.ApplicationChangedEventArgs>):Void" Ring="2" />
            // </SecurityKernel>
            [System.Security.SecurityCritical]
            remove
            {
                PeerCollaborationPermission.UnrestrictedPeerCollaborationPermission.Demand();
                CollaborationHelperFunctions.Initialize();
 
                RemoveApplicationChanged(value);
            }
        }
 
        #region Application changed event variables
        static object s_lockAppChangedEvent;
        static object LockAppChangedEvent
        {
            get{
                if (s_lockAppChangedEvent == null){
                    object o = new object();
                    Interlocked.CompareExchange(ref s_lockAppChangedEvent, o, null);
                }
                return s_lockAppChangedEvent;
            }
        }
 
        static RegisteredWaitHandle s_regAppChangedWaitHandle;
        static AutoResetEvent s_appChangedEvent;
        static SafeCollabEvent s_safeAppChangedEvent;
        #endregion
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: s_safeAppChangedEvent" Ring="1" />
        // <ReferencesCritical Name="Method: ApplicationChangedCallback(Object, Boolean):Void" Ring="1" />
        // <ReferencesCritical Name="Method: CollaborationHelperFunctions.AddMyApplicationChanged(System.EventHandler`1<System.Net.PeerToPeer.Collaboration.ApplicationChangedEventArgs>,System.EventHandler`1<System.Net.PeerToPeer.Collaboration.ApplicationChangedEventArgs>&,System.Object,System.Threading.RegisteredWaitHandle&,System.Threading.AutoResetEvent&,System.Net.PeerToPeer.Collaboration.SafeCollabEvent&,System.Threading.WaitOrTimerCallback):System.Void" Ring="1" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        static void AddApplicationChanged(EventHandler<ApplicationChangedEventArgs> callback)
        {
            CollaborationHelperFunctions.AddMyApplicationChanged(callback, ref s_applicationChanged, LockAppChangedEvent,
                                                                    ref s_regAppChangedWaitHandle, ref s_appChangedEvent,
                                                                    ref s_safeAppChangedEvent, new WaitOrTimerCallback(ApplicationChangedCallback));
        }
 
        // <SecurityKernel Critical="True" Ring="1">
        // <ReferencesCritical Name="Field: s_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]
        static void RemoveApplicationChanged(EventHandler<ApplicationChangedEventArgs> callback)
        {
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveApplicationChanged() called.");
            lock (LockAppChangedEvent){
                s_applicationChanged -= callback;
                if (s_applicationChanged == null){
                    CollaborationHelperFunctions.CleanEventVars(ref s_regAppChangedWaitHandle,
                                                                ref s_safeAppChangedEvent,
                                                                ref s_appChangedEvent);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Clean ApplicationChangEvent variables successful.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "RemoveApplicationChanged() successful.");
        }
 
        // <SecurityKernel Critical="True" Ring="0">
        // <SatisfiesLinkDemand Name="SafeHandle.get_IsInvalid():System.Boolean" />
        // <SatisfiesLinkDemand Name="SafeHandle.DangerousGetHandle():System.IntPtr" />
        // <SatisfiesLinkDemand Name="Marshal.PtrToStructure(System.IntPtr,System.Type):System.Object" />
        // <SatisfiesLinkDemand Name="SafeHandle.Dispose():System.Void" />
        // <CallsSuppressUnmanagedCode Name="UnsafeCollabNativeMethods.PeerCollabGetEventData(System.Net.PeerToPeer.Collaboration.SafeCollabEvent,System.Net.PeerToPeer.Collaboration.SafeCollabData&):System.Int32" />
        // <ReferencesCritical Name="Local eventData of type: SafeCollabData" Ring="1" />
        // <ReferencesCritical Name="Field: s_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" />
        // </SecurityKernel>
        [System.Security.SecurityCritical]
        static 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 (s_safeAppChangedEvent.IsInvalid) return;
                        errorCode = UnsafeCollabNativeMethods.PeerCollabGetEventData(s_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.MyApplicationChanged){
                        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); ;
 
                        if (appData.pEndPoint != IntPtr.Zero){
                            //
                            // This means its an endpoint on my contact which is not on the local machine
                            // so we dont care
                            //
                            return;
                        }
 
                        appChangedArgs = new ApplicationChangedEventArgs(   null,
                                                                            null,
                                                                            appData.changeType,
                                                                            peerApplication);
                    }
                }
                finally{
                    if (eventData != null) eventData.Dispose();
                }
 
                //
                // Fire the callback with the marshalled event args data
                //
                EventHandler<ApplicationChangedEventArgs> handlerCopy = s_applicationChanged;
 
                if ((appChangedArgs != null) && (handlerCopy != null)){
                    if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                        SynchronizingObject.BeginInvoke(handlerCopy, new object[] { null, appChangedArgs });
                    else
                        handlerCopy(null, appChangedArgs);
                    Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Fired the application changed event callback.");
                }
            }
            Logging.P2PTraceSource.TraceEvent(TraceEventType.Information, 0, "Leaving ApplicationChangedCallback().");
        }
 
 
    }
}