_AutoWebProxyScriptEngine.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / _AutoWebProxyScriptEngine.cs / 1305376 / _AutoWebProxyScriptEngine.cs

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

namespace System.Net 
{ 
    using System.IO;
    using System.Collections; 
    using System.Collections.Specialized;
    using System.Threading;
    using System.Text;
    using System.Net.Cache; 
#if !FEATURE_PAL
    using System.Net.NetworkInformation; 
    using System.Security.Principal; 
#endif
    using System.Globalization; 
    using System.Net.Configuration;
    using System.Security.Permissions;
    using System.Collections.Generic;
    using System.Runtime.InteropServices; 
    using Microsoft.Win32;
 
    // This class (and its helper classes implementing IWebRequestFinder interface) are responsible for 
    // determining the location of the PAC file, download and execute it, in order to retrieve proxy
    // information. 
    // This class also monitors the Registry and re-reads proxy configuration settings, if the corresponding
    // Registry values change.
    internal class AutoWebProxyScriptEngine
    { 
        private bool automaticallyDetectSettings;
        private Uri automaticConfigurationScript; 
 
        private WebProxy webProxy;
        private IWebProxyFinder webProxyFinder; 

        // Used by abortable lock.
        private bool m_LockHeld;
 
        private bool m_UseRegistry;
 
#if !FEATURE_PAL 
        // Used to get notifications of network changes and do AutoDetection (which are global).
        private int m_NetworkChangeStatus; 
        private AutoDetector m_AutoDetector;

        // This has to hold on to the creating user's registry hive and impersonation context.
        private SafeRegistryHandle hkcu; 
        private WindowsIdentity m_Identity;
#endif // !FEATURE_PAL 
 
        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)]
        internal AutoWebProxyScriptEngine(WebProxy proxy, bool useRegistry) 
        {
            GlobalLog.Assert(proxy != null, "'proxy' must be assigned.");
            webProxy = proxy;
            m_UseRegistry = useRegistry; 

#if !FEATURE_PAL 
            m_AutoDetector = AutoDetector.CurrentAutoDetector; 
            m_NetworkChangeStatus = m_AutoDetector.NetworkChangeStatus;
 
            SafeRegistryHandle.RegOpenCurrentUser(UnsafeNclNativeMethods.RegistryHelper.KEY_READ, out hkcu);
            if (m_UseRegistry)
            {
                ListenForRegistry(); 

                // Keep track of the identity we used to read the registry, in case we need to read it again later. 
                m_Identity = WindowsIdentity.GetCurrent(); 
            }
 
#endif // !FEATURE_PAL

            // In Win2003 winhttp added a Windows Service handling the auto-proxy discovery. In XP using winhttp
            // APIs will load, compile and execute the wpad file in-process. This will also load COM, since 
            // WinHttp requires COM to compile the file. For these reasons, we don't use WinHttp on XP, but
            // only on newer OS versions where the "WinHTTP Web Proxy Auto-Discovery Service" exists. 
            if (ComNetOS.IsWin2k3) 
            {
                webProxyFinder = new HybridWebProxyFinder(this); 
            }
            else
            {
                webProxyFinder = new NetWebProxyFinder(this); 
            }
        } 
 
        // AutoWebProxyScriptEngine has special abortable locking.  No one should ever lock (this) except the locking helper methods below.
        private static class SyncStatus 
        {
            internal const int Unlocked = 0;
            internal const int Locking = 1;
            internal const int LockOwner = 2; 
            internal const int AbortedLocked = 3;
            internal const int Aborted = 4; 
        } 

        private void EnterLock(ref int syncStatus) 
        {
            if (syncStatus == SyncStatus.Unlocked)
            {
                lock (this) 
                {
                    if (syncStatus != SyncStatus.Aborted) 
                    { 
                        syncStatus = SyncStatus.Locking;
                        while (true) 
                        {
                            if (!m_LockHeld)
                            {
                                syncStatus = SyncStatus.LockOwner; 
                                m_LockHeld = true;
                                return; 
                            } 
                            Monitor.Wait(this);
                            if (syncStatus == SyncStatus.Aborted) 
                            {
                                Monitor.Pulse(this);  // This is to ensure that a Pulse meant to let someone take the lock isn't lost.
                                return;
                            } 
                        }
                    } 
                } 
            }
        } 

        private void ExitLock(ref int syncStatus)
        {
            if (syncStatus != SyncStatus.Unlocked && syncStatus != SyncStatus.Aborted) 
            {
                lock (this) 
                { 
                    m_LockHeld = false;
                    if (syncStatus == SyncStatus.AbortedLocked) 
                    {
                        webProxyFinder.Reset();
                        syncStatus = SyncStatus.Aborted;
                    } 
                    else
                    { 
                        syncStatus = SyncStatus.Unlocked; 
                    }
                    Monitor.Pulse(this); 
                }
            }
        }
 
        internal void Abort(ref int syncStatus)
        { 
            lock (this) 
            {
                switch (syncStatus) 
                {
                    case SyncStatus.Unlocked:
                        syncStatus = SyncStatus.Aborted;
                        break; 

                    case SyncStatus.Locking: 
                        syncStatus = SyncStatus.Aborted; 
                        Monitor.PulseAll(this);
                        break; 

                    case SyncStatus.LockOwner:
                        syncStatus = SyncStatus.AbortedLocked;
                        webProxyFinder.Abort(); 
                        break;
                } 
            } 
        }
        // End of locking helper methods. 


        // The lock is always held while these three are modified.
        internal bool AutomaticallyDetectSettings 
        {
            get 
            { 
                return automaticallyDetectSettings;
            } 
            set
            {
                if (automaticallyDetectSettings != value)
                { 
                    automaticallyDetectSettings = value;
                    webProxyFinder.Reset(); 
                } 
            }
        } 

        internal Uri AutomaticConfigurationScript
        {
            get 
            {
                return automaticConfigurationScript; 
            } 
            set
            { 
                if (!object.Equals(automaticConfigurationScript, value))
                {
                    automaticConfigurationScript = value;
                    webProxyFinder.Reset(); 
                }
            } 
        } 

        internal ICredentials Credentials 
        {
            get
            {
                return webProxy.Credentials; 
            }
        } 
 
        internal bool GetProxies(Uri destination, out IList proxyList)
        { 
            int syncStatus = SyncStatus.Unlocked;
            return GetProxies(destination, out proxyList, ref syncStatus);
        }
 
        internal bool GetProxies(Uri destination, out IList proxyList, ref int syncStatus)
        { 
            GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::GetProxies()"); 

            proxyList = null; 

#if !FEATURE_PAL
            // See if we need to reinitialize based on registry or other changes.
#if !AUTOPROXY_SKIP_CHECK 
            CheckForChanges(ref syncStatus);
#endif 
#endif // !FEATURE_PAL 

            if (!webProxyFinder.IsValid) 
            {
                // This is to improve performance on e.g. home networks, where auto-detect will always
                // fail, but IE settings turn auto-detect ON by default. I.e. in home networks on each
                // call we would try to retrieve the PAC location. 
                // The downside of this approach is that if after some time the PAC file can be downloaded,
                // we don't do it. An application restart, changes in the proxy Registry settings, or a 
                // connection change (e.g. dial-up/VPN) are required in order to retry to retrieve the PAC file. 
                return false;
            } 

            // This whole thing has to be locked, both to prevent simultaneous downloading / compilation, and
            // because the script isn't threadsafe.
            try 
            {
                EnterLock(ref syncStatus); 
                if (syncStatus != SyncStatus.LockOwner) 
                {
                    // This is typically because a download got aborted. 
                    return false;
                }

                return webProxyFinder.GetProxies(destination, out proxyList); 
            }
            finally 
            { 
                ExitLock(ref syncStatus);
                GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::GetProxies() proxies:" + ValidationHelper.ToString(proxyList)); 
            }
        }

        internal WebProxyData GetWebProxyData() 
        {
            // PS DevDiv bug #217205 / TFS Dev10 #588370: use winhttp.WinhttpGetIEProxyConfigForCurrentUser 
            WebProxyDataBuilder builder = null; 

            if (ComNetOS.IsWin7) 
            {
                builder = new WinHttpWebProxyBuilder();
            }
            else 
            {
                builder = new RegBlobWebProxyDataBuilder(m_AutoDetector.Connectoid, hkcu); 
            } 

            return builder.Build(); 
        }

        internal void Close()
        { 
#if !FEATURE_PAL
            // m_AutoDetector is always set up in the constructor, use it to lock 
            if (m_AutoDetector != null) 
            {
                int syncStatus = SyncStatus.Unlocked; 
                try
                {
                    EnterLock(ref syncStatus);
                    GlobalLog.Assert(syncStatus == SyncStatus.LockOwner, "AutoWebProxyScriptEngine#{0}::Close()|Failed to acquire lock.", ValidationHelper.HashString(this)); 

                    if (m_AutoDetector != null) 
                    { 
                        registrySuppress = true;
                        if (registryChangeEventPolicy != null) 
                        {
                            registryChangeEventPolicy.Close();
                            registryChangeEventPolicy = null;
                        } 
                        if (registryChangeEventLM != null)
                        { 
                            registryChangeEventLM.Close(); 
                            registryChangeEventLM = null;
                        } 
                        if (registryChangeEvent != null)
                        {
                            registryChangeEvent.Close();
                            registryChangeEvent = null; 
                        }
 
                        if (regKeyPolicy != null && !regKeyPolicy.IsInvalid) 
                        {
                            regKeyPolicy.Close(); 
                        }
                        if (regKeyLM != null && !regKeyLM.IsInvalid)
                        {
                            regKeyLM.Close(); 
                        }
                        if (regKey != null && !regKey.IsInvalid) 
                        { 
                            regKey.Close();
                        } 

                        if (hkcu != null)
                        {
                            hkcu.RegCloseKey(); 
                            hkcu = null;
                        } 
 
                        if (m_Identity != null)
                        { 
                            m_Identity.Dispose();
                            m_Identity = null;
                        }
 
                        webProxyFinder.Dispose();
 
                        m_AutoDetector = null; 
                    }
                } 
                finally
                {
                    ExitLock(ref syncStatus);
                } 
            }
#endif // !FEATURE_PAL 
        } 

#if !FEATURE_PAL 
        private SafeRegistryHandle regKey;
        private SafeRegistryHandle regKeyLM;
        private SafeRegistryHandle regKeyPolicy;
        private AutoResetEvent registryChangeEvent; 
        private AutoResetEvent registryChangeEventLM;
        private AutoResetEvent registryChangeEventPolicy; 
        private bool registryChangeDeferred; 
        private bool registryChangeLMDeferred;
        private bool registryChangePolicyDeferred; 
        private bool needRegistryUpdate;
        private bool needConnectoidUpdate;
        private bool registrySuppress;
 
        internal void ListenForRegistry()
        { 
            GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry()"); 
            if (!registrySuppress)
            { 
                if (registryChangeEvent == null)
                {
                    GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() hooking HKCU.");
                    ListenForRegistryHelper(ref regKey, ref registryChangeEvent, IntPtr.Zero, 
                        RegBlobWebProxyDataBuilder.ProxyKey);
                } 
                if (registryChangeEventLM == null) 
                {
                    GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() hooking HKLM."); 
                    ListenForRegistryHelper(ref regKeyLM, ref registryChangeEventLM,
                        UnsafeNclNativeMethods.RegistryHelper.HKEY_LOCAL_MACHINE, RegBlobWebProxyDataBuilder.ProxyKey);
                }
                if (registryChangeEventPolicy == null) 
                {
                    GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() hooking HKLM/Policies."); 
                    ListenForRegistryHelper(ref regKeyPolicy, ref registryChangeEventPolicy, 
                        UnsafeNclNativeMethods.RegistryHelper.HKEY_LOCAL_MACHINE, RegBlobWebProxyDataBuilder.PolicyKey);
                } 

                // If any succeeded, we should monitor it.
                if (registryChangeEvent == null && registryChangeEventLM == null && registryChangeEventPolicy == null)
                { 
                    registrySuppress = true;
                } 
            } 
        }
 
        private void ListenForRegistryHelper(ref SafeRegistryHandle key, ref AutoResetEvent changeEvent, IntPtr baseKey, string subKey)
        {
            uint errorCode = 0;
 
            // First time through?
            if (key == null || key.IsInvalid) 
            { 
                if (baseKey == IntPtr.Zero)
                { 
                    // Impersonation requires extra effort.
                    GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() RegOpenCurrentUser() using hkcu:" + hkcu.DangerousGetHandle().ToString("x"));
                    if (hkcu != null)
                    { 
                        errorCode = hkcu.RegOpenKeyEx(subKey, 0, UnsafeNclNativeMethods.RegistryHelper.KEY_READ, out key);
                        GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() RegOpenKeyEx() returned errorCode:" + errorCode + " key:" + key.DangerousGetHandle().ToString("x")); 
                    } 
                    else
                    { 
                        errorCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND;
                    }
                }
                else 
                {
                    errorCode = SafeRegistryHandle.RegOpenKeyEx(baseKey, subKey, 0, UnsafeNclNativeMethods.RegistryHelper.KEY_READ, out key); 
                    //GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() RegOpenKeyEx() returned errorCode:" + errorCode + " key:" + key.DangerousGetHandle().ToString("x")); 
                }
                if (errorCode == 0) 
                {
                    changeEvent = new AutoResetEvent(false);
                }
            } 
            if (errorCode == 0)
            { 
                // accessing Handle is protected by a link demand, OK for System.dll 
                errorCode = key.RegNotifyChangeKeyValue(true, UnsafeNclNativeMethods.RegistryHelper.REG_NOTIFY_CHANGE_LAST_SET, changeEvent.SafeWaitHandle, true);
                GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() RegNotifyChangeKeyValue() returned errorCode:" + errorCode); 
            }
            if (errorCode != 0)
            {
                if (key != null && !key.IsInvalid) 
                {
                    try 
                    { 
                        errorCode = key.RegCloseKey();
                    } 
                    catch (Exception exception)
                    {
                        if (NclUtilities.IsFatal(exception)) throw;
                    } 
                    GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() RegCloseKey() returned errorCode:" + errorCode);
                } 
                key = null; 
                if (changeEvent != null)
                { 
                    changeEvent.Close();
                    changeEvent = null;
                }
            } 
        }
 
        private void RegistryChanged() 
        {
            GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::RegistryChanged()"); 
            if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_log_proxy_system_setting_update));

            // always refresh settings because they might have changed
            WebProxyData webProxyData; 
            using (m_Identity.Impersonate())
            { 
                webProxyData = GetWebProxyData(); 
            }
            webProxy.Update(webProxyData); 
        }

        private void ConnectoidChanged()
        { 
            GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ConnectoidChanged()");
            if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_log_proxy_update_due_to_ip_config_change)); 
 
            // Get the new connectoid/detector.  Only do this after detecting a change, to avoid ----s with other people detecting changes.
            // (We don't want to end up using a detector/connectoid that doesn't match what we read from the registry.) 
            m_AutoDetector = AutoDetector.CurrentAutoDetector;

            if (m_UseRegistry)
            { 
                // update the engine and proxy
                WebProxyData webProxyData; 
                using (m_Identity.Impersonate()) 
                {
                    webProxyData = GetWebProxyData(); 
                }
                webProxy.Update(webProxyData);
            }
 
            // Always uninitialized if the connectoid/address changed and we are autodetecting.
            if (automaticallyDetectSettings) 
                webProxyFinder.Reset(); 
        }
 
        internal void CheckForChanges()
        {
            int syncStatus = SyncStatus.Unlocked;
            CheckForChanges(ref syncStatus); 
        }
 
        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)] 
        private void CheckForChanges(ref int syncStatus)
        { 
            // Catch ObjectDisposedException instead of synchronizing with Close().
            try
            {
                bool changed = AutoDetector.CheckForNetworkChanges(ref m_NetworkChangeStatus); 
                bool ignoreRegistryChange = false;
                if (changed || needConnectoidUpdate) 
                { 
                    try
                    { 
                        EnterLock(ref syncStatus);
                        if (changed || needConnectoidUpdate)   // Make sure no one else took care of it before we got the lock.
                        {
                            needConnectoidUpdate = syncStatus != SyncStatus.LockOwner; 
                            if (!needConnectoidUpdate)
                            { 
                                ConnectoidChanged(); 

                                // We usually get a registry change at the same time.  Since the connectoid change does more, 
                                // we can skip reading the registry info twice.
                                ignoreRegistryChange = true;
                            }
                        } 
                    }
                    finally 
                    { 
                        ExitLock(ref syncStatus);
                    } 
                }

                if (!m_UseRegistry)
                { 
                    return;
                } 
 
                bool forReal = false;
                AutoResetEvent tempEvent = registryChangeEvent; 
                if (registryChangeDeferred || (forReal = (tempEvent != null && tempEvent.WaitOne(0, false))))
                {
                    try
                    { 
                        EnterLock(ref syncStatus);
                        if (forReal || registryChangeDeferred)  // Check if someone else handled it before I got the lock. 
                        { 
                            registryChangeDeferred = syncStatus != SyncStatus.LockOwner;
                            if (!registryChangeDeferred && registryChangeEvent != null) 
                            {
                                try
                                {
                                    using (m_Identity.Impersonate()) 
                                    {
                                        ListenForRegistryHelper(ref regKey, ref registryChangeEvent, IntPtr.Zero, 
                                            RegBlobWebProxyDataBuilder.ProxyKey); 
                                    }
                                } 
                                catch
                                {
                                    throw;
                                } 
                                needRegistryUpdate = true;
                            } 
                        } 
                    }
                    finally 
                    {
                        ExitLock(ref syncStatus);
                    }
                } 

                forReal = false; 
                tempEvent = registryChangeEventLM; 
                if (registryChangeLMDeferred || (forReal = (tempEvent != null && tempEvent.WaitOne(0, false))))
                { 
                    try
                    {
                        EnterLock(ref syncStatus);
                        if (forReal || registryChangeLMDeferred)  // Check if someone else handled it before I got the lock. 
                        {
                            registryChangeLMDeferred = syncStatus != SyncStatus.LockOwner; 
                            if (!registryChangeLMDeferred && registryChangeEventLM != null) 
                            {
                                try 
                                {
                                    using (m_Identity.Impersonate())
                                    {
                                        ListenForRegistryHelper(ref regKeyLM, ref registryChangeEventLM, 
                                            UnsafeNclNativeMethods.RegistryHelper.HKEY_LOCAL_MACHINE,
                                            RegBlobWebProxyDataBuilder.ProxyKey); 
                                    } 
                                }
                                catch 
                                {
                                    throw;
                                }
                                needRegistryUpdate = true; 
                            }
                        } 
                    } 
                    finally
                    { 
                        ExitLock(ref syncStatus);
                    }
                }
 
                forReal = false;
                tempEvent = registryChangeEventPolicy; 
                if (registryChangePolicyDeferred || (forReal = (tempEvent != null && tempEvent.WaitOne(0, false)))) 
                {
                    try 
                    {
                        EnterLock(ref syncStatus);
                        if (forReal || registryChangePolicyDeferred)  // Check if someone else handled it before I got the lock.
                        { 
                            registryChangePolicyDeferred = syncStatus != SyncStatus.LockOwner;
                            if (!registryChangePolicyDeferred && registryChangeEventPolicy != null) 
                            { 
                                try
                                { 
                                    using (m_Identity.Impersonate())
                                    {
                                        ListenForRegistryHelper(ref regKeyPolicy, ref registryChangeEventPolicy,
                                            UnsafeNclNativeMethods.RegistryHelper.HKEY_LOCAL_MACHINE, 
                                            RegBlobWebProxyDataBuilder.PolicyKey);
                                    } 
                                } 
                                catch
                                { 
                                    throw;
                                }
                                needRegistryUpdate = true;
                            } 
                        }
                    } 
                    finally 
                    {
                        ExitLock(ref syncStatus); 
                    }
                }

                if (needRegistryUpdate) 
                {
                    try 
                    { 
                        EnterLock(ref syncStatus);
                        if (needRegistryUpdate && syncStatus == SyncStatus.LockOwner) 
                        {
                            needRegistryUpdate = false;

                            // We don't need to process this now if we just did it for the connectoid. 
                            if (!ignoreRegistryChange)
                            { 
                                RegistryChanged(); 
                            }
                        } 
                    }
                    finally
                    {
                        ExitLock(ref syncStatus); 
                    }
                } 
            } 
            catch (ObjectDisposedException) { }
        } 

        private class AutoDetector
        {
            private static NetworkAddressChangePolled s_AddressChange; 
            private static UnsafeNclNativeMethods.RasHelper s_RasHelper;
 
            private static int s_CurrentVersion = 0; 
            private volatile static AutoDetector s_CurrentAutoDetector;
            private volatile static bool s_Initialized; 
            private static object s_LockObject;

            static AutoDetector()
            { 
                s_LockObject = new object();
            } 
 
            private static void Initialize()
            { 
                if (!s_Initialized)
                {
                    lock (s_LockObject)
                    { 
                        if (!s_Initialized)
                        { 
                            s_CurrentAutoDetector = new AutoDetector(UnsafeNclNativeMethods.RasHelper.GetCurrentConnectoid(), 1); 
                            if (NetworkChange.CanListenForNetworkChanges)
                            { 
                                s_AddressChange = new NetworkAddressChangePolled();
                            }
                            if (UnsafeNclNativeMethods.RasHelper.RasSupported)
                            { 
                                s_RasHelper = new UnsafeNclNativeMethods.RasHelper();
                            } 
                            s_CurrentVersion = 1; 
                            s_Initialized = true;
                        } 
                    }
                }
            }
 
            internal static bool CheckForNetworkChanges(ref int changeStatus)
            { 
                Initialize(); 
                CheckForChanges();
                int oldStatus = changeStatus; 
                changeStatus = s_CurrentVersion;
                return oldStatus != changeStatus;
            }
 
            private static void CheckForChanges()
            { 
                bool changed = false; 
                if (s_RasHelper != null && s_RasHelper.HasChanged)
                { 
                    s_RasHelper.Reset();
                    changed = true;
                }
                if (s_AddressChange != null && s_AddressChange.CheckAndReset()) 
                {
                    changed = true; 
                } 
                if (changed)
                { 
                    Interlocked.Increment(ref s_CurrentVersion);
                    s_CurrentAutoDetector = new AutoDetector(UnsafeNclNativeMethods.RasHelper.GetCurrentConnectoid(), s_CurrentVersion);
                }
            } 

            internal static AutoDetector CurrentAutoDetector 
            { 
                get
                { 
                    Initialize();
                    return s_CurrentAutoDetector;
                }
            } 

 
            private readonly string m_Connectoid; 
            private readonly int m_CurrentVersion;
 
            private AutoDetector(string connectoid, int currentVersion)
            {
                m_Connectoid = connectoid;
                m_CurrentVersion = currentVersion; 
            }
 
            internal string Connectoid 
            {
                get 
                {
                    return m_Connectoid;
                }
            } 

            internal int NetworkChangeStatus 
            { 
                get
                { 
                    return m_CurrentVersion;
                }
            }
        } 
#endif
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Net 
{ 
    using System.IO;
    using System.Collections; 
    using System.Collections.Specialized;
    using System.Threading;
    using System.Text;
    using System.Net.Cache; 
#if !FEATURE_PAL
    using System.Net.NetworkInformation; 
    using System.Security.Principal; 
#endif
    using System.Globalization; 
    using System.Net.Configuration;
    using System.Security.Permissions;
    using System.Collections.Generic;
    using System.Runtime.InteropServices; 
    using Microsoft.Win32;
 
    // This class (and its helper classes implementing IWebRequestFinder interface) are responsible for 
    // determining the location of the PAC file, download and execute it, in order to retrieve proxy
    // information. 
    // This class also monitors the Registry and re-reads proxy configuration settings, if the corresponding
    // Registry values change.
    internal class AutoWebProxyScriptEngine
    { 
        private bool automaticallyDetectSettings;
        private Uri automaticConfigurationScript; 
 
        private WebProxy webProxy;
        private IWebProxyFinder webProxyFinder; 

        // Used by abortable lock.
        private bool m_LockHeld;
 
        private bool m_UseRegistry;
 
#if !FEATURE_PAL 
        // Used to get notifications of network changes and do AutoDetection (which are global).
        private int m_NetworkChangeStatus; 
        private AutoDetector m_AutoDetector;

        // This has to hold on to the creating user's registry hive and impersonation context.
        private SafeRegistryHandle hkcu; 
        private WindowsIdentity m_Identity;
#endif // !FEATURE_PAL 
 
        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)]
        internal AutoWebProxyScriptEngine(WebProxy proxy, bool useRegistry) 
        {
            GlobalLog.Assert(proxy != null, "'proxy' must be assigned.");
            webProxy = proxy;
            m_UseRegistry = useRegistry; 

#if !FEATURE_PAL 
            m_AutoDetector = AutoDetector.CurrentAutoDetector; 
            m_NetworkChangeStatus = m_AutoDetector.NetworkChangeStatus;
 
            SafeRegistryHandle.RegOpenCurrentUser(UnsafeNclNativeMethods.RegistryHelper.KEY_READ, out hkcu);
            if (m_UseRegistry)
            {
                ListenForRegistry(); 

                // Keep track of the identity we used to read the registry, in case we need to read it again later. 
                m_Identity = WindowsIdentity.GetCurrent(); 
            }
 
#endif // !FEATURE_PAL

            // In Win2003 winhttp added a Windows Service handling the auto-proxy discovery. In XP using winhttp
            // APIs will load, compile and execute the wpad file in-process. This will also load COM, since 
            // WinHttp requires COM to compile the file. For these reasons, we don't use WinHttp on XP, but
            // only on newer OS versions where the "WinHTTP Web Proxy Auto-Discovery Service" exists. 
            if (ComNetOS.IsWin2k3) 
            {
                webProxyFinder = new HybridWebProxyFinder(this); 
            }
            else
            {
                webProxyFinder = new NetWebProxyFinder(this); 
            }
        } 
 
        // AutoWebProxyScriptEngine has special abortable locking.  No one should ever lock (this) except the locking helper methods below.
        private static class SyncStatus 
        {
            internal const int Unlocked = 0;
            internal const int Locking = 1;
            internal const int LockOwner = 2; 
            internal const int AbortedLocked = 3;
            internal const int Aborted = 4; 
        } 

        private void EnterLock(ref int syncStatus) 
        {
            if (syncStatus == SyncStatus.Unlocked)
            {
                lock (this) 
                {
                    if (syncStatus != SyncStatus.Aborted) 
                    { 
                        syncStatus = SyncStatus.Locking;
                        while (true) 
                        {
                            if (!m_LockHeld)
                            {
                                syncStatus = SyncStatus.LockOwner; 
                                m_LockHeld = true;
                                return; 
                            } 
                            Monitor.Wait(this);
                            if (syncStatus == SyncStatus.Aborted) 
                            {
                                Monitor.Pulse(this);  // This is to ensure that a Pulse meant to let someone take the lock isn't lost.
                                return;
                            } 
                        }
                    } 
                } 
            }
        } 

        private void ExitLock(ref int syncStatus)
        {
            if (syncStatus != SyncStatus.Unlocked && syncStatus != SyncStatus.Aborted) 
            {
                lock (this) 
                { 
                    m_LockHeld = false;
                    if (syncStatus == SyncStatus.AbortedLocked) 
                    {
                        webProxyFinder.Reset();
                        syncStatus = SyncStatus.Aborted;
                    } 
                    else
                    { 
                        syncStatus = SyncStatus.Unlocked; 
                    }
                    Monitor.Pulse(this); 
                }
            }
        }
 
        internal void Abort(ref int syncStatus)
        { 
            lock (this) 
            {
                switch (syncStatus) 
                {
                    case SyncStatus.Unlocked:
                        syncStatus = SyncStatus.Aborted;
                        break; 

                    case SyncStatus.Locking: 
                        syncStatus = SyncStatus.Aborted; 
                        Monitor.PulseAll(this);
                        break; 

                    case SyncStatus.LockOwner:
                        syncStatus = SyncStatus.AbortedLocked;
                        webProxyFinder.Abort(); 
                        break;
                } 
            } 
        }
        // End of locking helper methods. 


        // The lock is always held while these three are modified.
        internal bool AutomaticallyDetectSettings 
        {
            get 
            { 
                return automaticallyDetectSettings;
            } 
            set
            {
                if (automaticallyDetectSettings != value)
                { 
                    automaticallyDetectSettings = value;
                    webProxyFinder.Reset(); 
                } 
            }
        } 

        internal Uri AutomaticConfigurationScript
        {
            get 
            {
                return automaticConfigurationScript; 
            } 
            set
            { 
                if (!object.Equals(automaticConfigurationScript, value))
                {
                    automaticConfigurationScript = value;
                    webProxyFinder.Reset(); 
                }
            } 
        } 

        internal ICredentials Credentials 
        {
            get
            {
                return webProxy.Credentials; 
            }
        } 
 
        internal bool GetProxies(Uri destination, out IList proxyList)
        { 
            int syncStatus = SyncStatus.Unlocked;
            return GetProxies(destination, out proxyList, ref syncStatus);
        }
 
        internal bool GetProxies(Uri destination, out IList proxyList, ref int syncStatus)
        { 
            GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::GetProxies()"); 

            proxyList = null; 

#if !FEATURE_PAL
            // See if we need to reinitialize based on registry or other changes.
#if !AUTOPROXY_SKIP_CHECK 
            CheckForChanges(ref syncStatus);
#endif 
#endif // !FEATURE_PAL 

            if (!webProxyFinder.IsValid) 
            {
                // This is to improve performance on e.g. home networks, where auto-detect will always
                // fail, but IE settings turn auto-detect ON by default. I.e. in home networks on each
                // call we would try to retrieve the PAC location. 
                // The downside of this approach is that if after some time the PAC file can be downloaded,
                // we don't do it. An application restart, changes in the proxy Registry settings, or a 
                // connection change (e.g. dial-up/VPN) are required in order to retry to retrieve the PAC file. 
                return false;
            } 

            // This whole thing has to be locked, both to prevent simultaneous downloading / compilation, and
            // because the script isn't threadsafe.
            try 
            {
                EnterLock(ref syncStatus); 
                if (syncStatus != SyncStatus.LockOwner) 
                {
                    // This is typically because a download got aborted. 
                    return false;
                }

                return webProxyFinder.GetProxies(destination, out proxyList); 
            }
            finally 
            { 
                ExitLock(ref syncStatus);
                GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::GetProxies() proxies:" + ValidationHelper.ToString(proxyList)); 
            }
        }

        internal WebProxyData GetWebProxyData() 
        {
            // PS DevDiv bug #217205 / TFS Dev10 #588370: use winhttp.WinhttpGetIEProxyConfigForCurrentUser 
            WebProxyDataBuilder builder = null; 

            if (ComNetOS.IsWin7) 
            {
                builder = new WinHttpWebProxyBuilder();
            }
            else 
            {
                builder = new RegBlobWebProxyDataBuilder(m_AutoDetector.Connectoid, hkcu); 
            } 

            return builder.Build(); 
        }

        internal void Close()
        { 
#if !FEATURE_PAL
            // m_AutoDetector is always set up in the constructor, use it to lock 
            if (m_AutoDetector != null) 
            {
                int syncStatus = SyncStatus.Unlocked; 
                try
                {
                    EnterLock(ref syncStatus);
                    GlobalLog.Assert(syncStatus == SyncStatus.LockOwner, "AutoWebProxyScriptEngine#{0}::Close()|Failed to acquire lock.", ValidationHelper.HashString(this)); 

                    if (m_AutoDetector != null) 
                    { 
                        registrySuppress = true;
                        if (registryChangeEventPolicy != null) 
                        {
                            registryChangeEventPolicy.Close();
                            registryChangeEventPolicy = null;
                        } 
                        if (registryChangeEventLM != null)
                        { 
                            registryChangeEventLM.Close(); 
                            registryChangeEventLM = null;
                        } 
                        if (registryChangeEvent != null)
                        {
                            registryChangeEvent.Close();
                            registryChangeEvent = null; 
                        }
 
                        if (regKeyPolicy != null && !regKeyPolicy.IsInvalid) 
                        {
                            regKeyPolicy.Close(); 
                        }
                        if (regKeyLM != null && !regKeyLM.IsInvalid)
                        {
                            regKeyLM.Close(); 
                        }
                        if (regKey != null && !regKey.IsInvalid) 
                        { 
                            regKey.Close();
                        } 

                        if (hkcu != null)
                        {
                            hkcu.RegCloseKey(); 
                            hkcu = null;
                        } 
 
                        if (m_Identity != null)
                        { 
                            m_Identity.Dispose();
                            m_Identity = null;
                        }
 
                        webProxyFinder.Dispose();
 
                        m_AutoDetector = null; 
                    }
                } 
                finally
                {
                    ExitLock(ref syncStatus);
                } 
            }
#endif // !FEATURE_PAL 
        } 

#if !FEATURE_PAL 
        private SafeRegistryHandle regKey;
        private SafeRegistryHandle regKeyLM;
        private SafeRegistryHandle regKeyPolicy;
        private AutoResetEvent registryChangeEvent; 
        private AutoResetEvent registryChangeEventLM;
        private AutoResetEvent registryChangeEventPolicy; 
        private bool registryChangeDeferred; 
        private bool registryChangeLMDeferred;
        private bool registryChangePolicyDeferred; 
        private bool needRegistryUpdate;
        private bool needConnectoidUpdate;
        private bool registrySuppress;
 
        internal void ListenForRegistry()
        { 
            GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry()"); 
            if (!registrySuppress)
            { 
                if (registryChangeEvent == null)
                {
                    GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() hooking HKCU.");
                    ListenForRegistryHelper(ref regKey, ref registryChangeEvent, IntPtr.Zero, 
                        RegBlobWebProxyDataBuilder.ProxyKey);
                } 
                if (registryChangeEventLM == null) 
                {
                    GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() hooking HKLM."); 
                    ListenForRegistryHelper(ref regKeyLM, ref registryChangeEventLM,
                        UnsafeNclNativeMethods.RegistryHelper.HKEY_LOCAL_MACHINE, RegBlobWebProxyDataBuilder.ProxyKey);
                }
                if (registryChangeEventPolicy == null) 
                {
                    GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() hooking HKLM/Policies."); 
                    ListenForRegistryHelper(ref regKeyPolicy, ref registryChangeEventPolicy, 
                        UnsafeNclNativeMethods.RegistryHelper.HKEY_LOCAL_MACHINE, RegBlobWebProxyDataBuilder.PolicyKey);
                } 

                // If any succeeded, we should monitor it.
                if (registryChangeEvent == null && registryChangeEventLM == null && registryChangeEventPolicy == null)
                { 
                    registrySuppress = true;
                } 
            } 
        }
 
        private void ListenForRegistryHelper(ref SafeRegistryHandle key, ref AutoResetEvent changeEvent, IntPtr baseKey, string subKey)
        {
            uint errorCode = 0;
 
            // First time through?
            if (key == null || key.IsInvalid) 
            { 
                if (baseKey == IntPtr.Zero)
                { 
                    // Impersonation requires extra effort.
                    GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() RegOpenCurrentUser() using hkcu:" + hkcu.DangerousGetHandle().ToString("x"));
                    if (hkcu != null)
                    { 
                        errorCode = hkcu.RegOpenKeyEx(subKey, 0, UnsafeNclNativeMethods.RegistryHelper.KEY_READ, out key);
                        GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() RegOpenKeyEx() returned errorCode:" + errorCode + " key:" + key.DangerousGetHandle().ToString("x")); 
                    } 
                    else
                    { 
                        errorCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_FOUND;
                    }
                }
                else 
                {
                    errorCode = SafeRegistryHandle.RegOpenKeyEx(baseKey, subKey, 0, UnsafeNclNativeMethods.RegistryHelper.KEY_READ, out key); 
                    //GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() RegOpenKeyEx() returned errorCode:" + errorCode + " key:" + key.DangerousGetHandle().ToString("x")); 
                }
                if (errorCode == 0) 
                {
                    changeEvent = new AutoResetEvent(false);
                }
            } 
            if (errorCode == 0)
            { 
                // accessing Handle is protected by a link demand, OK for System.dll 
                errorCode = key.RegNotifyChangeKeyValue(true, UnsafeNclNativeMethods.RegistryHelper.REG_NOTIFY_CHANGE_LAST_SET, changeEvent.SafeWaitHandle, true);
                GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() RegNotifyChangeKeyValue() returned errorCode:" + errorCode); 
            }
            if (errorCode != 0)
            {
                if (key != null && !key.IsInvalid) 
                {
                    try 
                    { 
                        errorCode = key.RegCloseKey();
                    } 
                    catch (Exception exception)
                    {
                        if (NclUtilities.IsFatal(exception)) throw;
                    } 
                    GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ListenForRegistry() RegCloseKey() returned errorCode:" + errorCode);
                } 
                key = null; 
                if (changeEvent != null)
                { 
                    changeEvent.Close();
                    changeEvent = null;
                }
            } 
        }
 
        private void RegistryChanged() 
        {
            GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::RegistryChanged()"); 
            if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_log_proxy_system_setting_update));

            // always refresh settings because they might have changed
            WebProxyData webProxyData; 
            using (m_Identity.Impersonate())
            { 
                webProxyData = GetWebProxyData(); 
            }
            webProxy.Update(webProxyData); 
        }

        private void ConnectoidChanged()
        { 
            GlobalLog.Print("AutoWebProxyScriptEngine#" + ValidationHelper.HashString(this) + "::ConnectoidChanged()");
            if (Logging.On) Logging.PrintWarning(Logging.Web, SR.GetString(SR.net_log_proxy_update_due_to_ip_config_change)); 
 
            // Get the new connectoid/detector.  Only do this after detecting a change, to avoid ----s with other people detecting changes.
            // (We don't want to end up using a detector/connectoid that doesn't match what we read from the registry.) 
            m_AutoDetector = AutoDetector.CurrentAutoDetector;

            if (m_UseRegistry)
            { 
                // update the engine and proxy
                WebProxyData webProxyData; 
                using (m_Identity.Impersonate()) 
                {
                    webProxyData = GetWebProxyData(); 
                }
                webProxy.Update(webProxyData);
            }
 
            // Always uninitialized if the connectoid/address changed and we are autodetecting.
            if (automaticallyDetectSettings) 
                webProxyFinder.Reset(); 
        }
 
        internal void CheckForChanges()
        {
            int syncStatus = SyncStatus.Unlocked;
            CheckForChanges(ref syncStatus); 
        }
 
        [SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)] 
        private void CheckForChanges(ref int syncStatus)
        { 
            // Catch ObjectDisposedException instead of synchronizing with Close().
            try
            {
                bool changed = AutoDetector.CheckForNetworkChanges(ref m_NetworkChangeStatus); 
                bool ignoreRegistryChange = false;
                if (changed || needConnectoidUpdate) 
                { 
                    try
                    { 
                        EnterLock(ref syncStatus);
                        if (changed || needConnectoidUpdate)   // Make sure no one else took care of it before we got the lock.
                        {
                            needConnectoidUpdate = syncStatus != SyncStatus.LockOwner; 
                            if (!needConnectoidUpdate)
                            { 
                                ConnectoidChanged(); 

                                // We usually get a registry change at the same time.  Since the connectoid change does more, 
                                // we can skip reading the registry info twice.
                                ignoreRegistryChange = true;
                            }
                        } 
                    }
                    finally 
                    { 
                        ExitLock(ref syncStatus);
                    } 
                }

                if (!m_UseRegistry)
                { 
                    return;
                } 
 
                bool forReal = false;
                AutoResetEvent tempEvent = registryChangeEvent; 
                if (registryChangeDeferred || (forReal = (tempEvent != null && tempEvent.WaitOne(0, false))))
                {
                    try
                    { 
                        EnterLock(ref syncStatus);
                        if (forReal || registryChangeDeferred)  // Check if someone else handled it before I got the lock. 
                        { 
                            registryChangeDeferred = syncStatus != SyncStatus.LockOwner;
                            if (!registryChangeDeferred && registryChangeEvent != null) 
                            {
                                try
                                {
                                    using (m_Identity.Impersonate()) 
                                    {
                                        ListenForRegistryHelper(ref regKey, ref registryChangeEvent, IntPtr.Zero, 
                                            RegBlobWebProxyDataBuilder.ProxyKey); 
                                    }
                                } 
                                catch
                                {
                                    throw;
                                } 
                                needRegistryUpdate = true;
                            } 
                        } 
                    }
                    finally 
                    {
                        ExitLock(ref syncStatus);
                    }
                } 

                forReal = false; 
                tempEvent = registryChangeEventLM; 
                if (registryChangeLMDeferred || (forReal = (tempEvent != null && tempEvent.WaitOne(0, false))))
                { 
                    try
                    {
                        EnterLock(ref syncStatus);
                        if (forReal || registryChangeLMDeferred)  // Check if someone else handled it before I got the lock. 
                        {
                            registryChangeLMDeferred = syncStatus != SyncStatus.LockOwner; 
                            if (!registryChangeLMDeferred && registryChangeEventLM != null) 
                            {
                                try 
                                {
                                    using (m_Identity.Impersonate())
                                    {
                                        ListenForRegistryHelper(ref regKeyLM, ref registryChangeEventLM, 
                                            UnsafeNclNativeMethods.RegistryHelper.HKEY_LOCAL_MACHINE,
                                            RegBlobWebProxyDataBuilder.ProxyKey); 
                                    } 
                                }
                                catch 
                                {
                                    throw;
                                }
                                needRegistryUpdate = true; 
                            }
                        } 
                    } 
                    finally
                    { 
                        ExitLock(ref syncStatus);
                    }
                }
 
                forReal = false;
                tempEvent = registryChangeEventPolicy; 
                if (registryChangePolicyDeferred || (forReal = (tempEvent != null && tempEvent.WaitOne(0, false)))) 
                {
                    try 
                    {
                        EnterLock(ref syncStatus);
                        if (forReal || registryChangePolicyDeferred)  // Check if someone else handled it before I got the lock.
                        { 
                            registryChangePolicyDeferred = syncStatus != SyncStatus.LockOwner;
                            if (!registryChangePolicyDeferred && registryChangeEventPolicy != null) 
                            { 
                                try
                                { 
                                    using (m_Identity.Impersonate())
                                    {
                                        ListenForRegistryHelper(ref regKeyPolicy, ref registryChangeEventPolicy,
                                            UnsafeNclNativeMethods.RegistryHelper.HKEY_LOCAL_MACHINE, 
                                            RegBlobWebProxyDataBuilder.PolicyKey);
                                    } 
                                } 
                                catch
                                { 
                                    throw;
                                }
                                needRegistryUpdate = true;
                            } 
                        }
                    } 
                    finally 
                    {
                        ExitLock(ref syncStatus); 
                    }
                }

                if (needRegistryUpdate) 
                {
                    try 
                    { 
                        EnterLock(ref syncStatus);
                        if (needRegistryUpdate && syncStatus == SyncStatus.LockOwner) 
                        {
                            needRegistryUpdate = false;

                            // We don't need to process this now if we just did it for the connectoid. 
                            if (!ignoreRegistryChange)
                            { 
                                RegistryChanged(); 
                            }
                        } 
                    }
                    finally
                    {
                        ExitLock(ref syncStatus); 
                    }
                } 
            } 
            catch (ObjectDisposedException) { }
        } 

        private class AutoDetector
        {
            private static NetworkAddressChangePolled s_AddressChange; 
            private static UnsafeNclNativeMethods.RasHelper s_RasHelper;
 
            private static int s_CurrentVersion = 0; 
            private volatile static AutoDetector s_CurrentAutoDetector;
            private volatile static bool s_Initialized; 
            private static object s_LockObject;

            static AutoDetector()
            { 
                s_LockObject = new object();
            } 
 
            private static void Initialize()
            { 
                if (!s_Initialized)
                {
                    lock (s_LockObject)
                    { 
                        if (!s_Initialized)
                        { 
                            s_CurrentAutoDetector = new AutoDetector(UnsafeNclNativeMethods.RasHelper.GetCurrentConnectoid(), 1); 
                            if (NetworkChange.CanListenForNetworkChanges)
                            { 
                                s_AddressChange = new NetworkAddressChangePolled();
                            }
                            if (UnsafeNclNativeMethods.RasHelper.RasSupported)
                            { 
                                s_RasHelper = new UnsafeNclNativeMethods.RasHelper();
                            } 
                            s_CurrentVersion = 1; 
                            s_Initialized = true;
                        } 
                    }
                }
            }
 
            internal static bool CheckForNetworkChanges(ref int changeStatus)
            { 
                Initialize(); 
                CheckForChanges();
                int oldStatus = changeStatus; 
                changeStatus = s_CurrentVersion;
                return oldStatus != changeStatus;
            }
 
            private static void CheckForChanges()
            { 
                bool changed = false; 
                if (s_RasHelper != null && s_RasHelper.HasChanged)
                { 
                    s_RasHelper.Reset();
                    changed = true;
                }
                if (s_AddressChange != null && s_AddressChange.CheckAndReset()) 
                {
                    changed = true; 
                } 
                if (changed)
                { 
                    Interlocked.Increment(ref s_CurrentVersion);
                    s_CurrentAutoDetector = new AutoDetector(UnsafeNclNativeMethods.RasHelper.GetCurrentConnectoid(), s_CurrentVersion);
                }
            } 

            internal static AutoDetector CurrentAutoDetector 
            { 
                get
                { 
                    Initialize();
                    return s_CurrentAutoDetector;
                }
            } 

 
            private readonly string m_Connectoid; 
            private readonly int m_CurrentVersion;
 
            private AutoDetector(string connectoid, int currentVersion)
            {
                m_Connectoid = connectoid;
                m_CurrentVersion = currentVersion; 
            }
 
            internal string Connectoid 
            {
                get 
                {
                    return m_Connectoid;
                }
            } 

            internal int NetworkChangeStatus 
            { 
                get
                { 
                    return m_CurrentVersion;
                }
            }
        } 
#endif
    } 
} 

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

                        

Link Menu

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