PerformanceCounterLib.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / Services / Monitoring / system / Diagnosticts / PerformanceCounterLib.cs / 1 / PerformanceCounterLib.cs

                            namespace System.Diagnostics { 
    using System.Runtime.InteropServices;
    using System.Globalization;
    using System.Security.Permissions;
    using System.Security; 
    using System.Text;
    using System.Threading; 
    using System.Reflection; 
    using System.Collections;
    using System.ComponentModel; 
    using System.Collections.Specialized;
    using Microsoft.Win32;
    using System.IO;
    using System.Runtime.Serialization; 
    using System.Runtime.Versioning;
 
    internal class PerformanceCounterLib { 
        internal const string PerfShimName = "netfxperf.dll";
        internal const string OpenEntryPoint = "OpenPerformanceData"; 
        internal const string CollectEntryPoint = "CollectPerformanceData";
        internal const string CloseEntryPoint = "ClosePerformanceData";
        internal const string SingleInstanceName = "systemdiagnosticsperfcounterlibsingleinstance";
 
        private const string PerflibPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
        internal const string ServicePath = "SYSTEM\\CurrentControlSet\\Services"; 
        private const string categorySymbolPrefix = "OBJECT_"; 
        private const string conterSymbolPrefix = "DEVICE_COUNTER_";
        private const string helpSufix = "_HELP"; 
        private const string nameSufix = "_NAME";
        private const string textDefinition = "[text]";
        private const string infoDefinition = "[info]";
        private const string languageDefinition = "[languages]"; 
        private const string objectDefinition = "[objects]";
        private const string driverNameKeyword = "drivername"; 
        private const string symbolFileKeyword = "symbolfile"; 
        private const string defineKeyword = "#define";
        private const string languageKeyword = "language"; 
        private const string DllName = "netfxperf.dll";

        private static string computerName;
        private static string iniFilePath; 
        private static string symbolFilePath;
 
        private PerformanceMonitor performanceMonitor; 
        private string machineName;
        private string perfLcid; 

        private Hashtable customCategoryTable;
        private static Hashtable libraryTable;
        private Hashtable categoryTable; 
        private Hashtable nameTable;
        private Hashtable helpTable; 
        private readonly object CategoryTableLock = new Object(); 
        private readonly object NameTableLock = new Object();
        private readonly object HelpTableLock = new Object(); 

        private static Object s_InternalSyncObject;
        private static Object InternalSyncObject {
            get { 
                if (s_InternalSyncObject == null) {
                    Object o = new Object(); 
                    Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); 
                }
                return s_InternalSyncObject; 
            }
        }

        internal PerformanceCounterLib(string machineName, string lcid) { 
            this.machineName = machineName;
            this.perfLcid = lcid; 
        } 

        ///  
        internal static string ComputerName {
            get {
                if (computerName == null) {
                    lock (InternalSyncObject) { 
                        if (computerName == null) {
                            StringBuilder sb = new StringBuilder(256); 
                            SafeNativeMethods.GetComputerName(sb, new int[] {sb.Capacity}); 
                            computerName = sb.ToString();
                        } 
                    }
                }

                return computerName; 
            }
        } 
 
        private unsafe Hashtable CategoryTable {
            get { 
                if (this.categoryTable == null) {
                    lock (this.CategoryTableLock) {
                        if (this.categoryTable == null) {
                            byte[] perfData =  GetPerformanceData("Global"); 

                            fixed (byte* perfDataPtr = perfData) { 
                                IntPtr dataRef = new IntPtr( (void*) perfDataPtr); 
                                NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK();
                                Marshal.PtrToStructure(dataRef, dataBlock); 
                                dataRef = (IntPtr)((long)dataRef + dataBlock.HeaderLength);
                                int categoryNumber = dataBlock.NumObjectTypes;

                                // on some machines MSMQ claims to have 4 categories, even though it only has 2. 
                                // This causes us to walk past the end of our data, potentially ----ing up or reading
                                // data we shouldn't.  We use endPerfData to make sure we don't go past the end 
                                // of the perf data.  (ASURT 137097) 
                                long endPerfData = (long) perfDataPtr + dataBlock.TotalByteLength;
                                Hashtable tempCategoryTable = new Hashtable(categoryNumber, StringComparer.OrdinalIgnoreCase); 
                                for (int index = 0; index < categoryNumber && ((long) dataRef < endPerfData); index++) {
                                    NativeMethods.PERF_OBJECT_TYPE perfObject = new NativeMethods.PERF_OBJECT_TYPE();

                                    Marshal.PtrToStructure(dataRef, perfObject); 

                                    CategoryEntry newCategoryEntry = new CategoryEntry(perfObject); 
                                    IntPtr nextRef =  (IntPtr)((long)dataRef + perfObject.TotalByteLength); 
                                    dataRef = (IntPtr)((long)dataRef + perfObject.HeaderLength);
 
                                    int index3 = 0;
                                    int previousCounterIndex = -1;
                                    //Need to filter out counters that are repeated, some providers might
                                    //return several adyacent copies of the same counter. 
                                    for (int index2 = 0; index2 < newCategoryEntry.CounterIndexes.Length; ++ index2) {
                                        NativeMethods.PERF_COUNTER_DEFINITION perfCounter = new NativeMethods.PERF_COUNTER_DEFINITION(); 
                                        Marshal.PtrToStructure(dataRef, perfCounter); 
                                        if (perfCounter.CounterNameTitleIndex != previousCounterIndex) {
                                            newCategoryEntry.CounterIndexes[index3] =  perfCounter.CounterNameTitleIndex; 
                                            newCategoryEntry.HelpIndexes[index3] = perfCounter.CounterHelpTitleIndex;
                                            previousCounterIndex = perfCounter.CounterNameTitleIndex;
                                            ++ index3;
                                        } 
                                        dataRef = (IntPtr)((long)dataRef + perfCounter.ByteLength);
                                    } 
 
                                    //Lets adjust the entry counter arrays in case there were repeated copies
                                    if (index3 <  newCategoryEntry.CounterIndexes.Length) { 
                                        int[] adjustedCounterIndexes = new int[index3];
                                        int[] adjustedHelpIndexes = new int[index3];
                                        Array.Copy(newCategoryEntry.CounterIndexes, adjustedCounterIndexes, index3);
                                        Array.Copy(newCategoryEntry.HelpIndexes, adjustedHelpIndexes, index3); 
                                        newCategoryEntry.CounterIndexes = adjustedCounterIndexes;
                                        newCategoryEntry.HelpIndexes = adjustedHelpIndexes; 
                                    } 

                                    string categoryName = (string)this.NameTable[newCategoryEntry.NameIndex]; 
                                    if (categoryName != null)
                                        tempCategoryTable[categoryName] = newCategoryEntry;

                                    dataRef = nextRef; 
                                }
 
                                this.categoryTable = tempCategoryTable; 
                            }
                        } 
                    }
                }

                return this.categoryTable; 
            }
        } 
 
        internal Hashtable HelpTable {
            get { 
                if (this.helpTable == null) {
                    lock(this.HelpTableLock) {
                        if (this.helpTable == null)
                            this.helpTable = GetStringTable(true); 
                    }
                } 
 
                return this.helpTable;
            } 
        }

        // Returns a temp file name
        private static string IniFilePath { 
            [ResourceExposure(ResourceScope.AppDomain)]
            [ResourceConsumption(ResourceScope.AppDomain)] 
            get { 
                if (iniFilePath == null) {
                    lock (InternalSyncObject) { 
                        if (iniFilePath == null) {
                            // Need to assert Environment permissions here
                            //                        the environment check is not exposed as a public
                            //                        method 
                            EnvironmentPermission environmentPermission = new EnvironmentPermission(PermissionState.Unrestricted);
                            environmentPermission.Assert(); 
                            try { 
                                iniFilePath = Path.GetTempFileName();
                            } 
                            finally {
                                 EnvironmentPermission.RevertAssert();
                            }
                        } 
                    }
                } 
 
                return iniFilePath;
            } 
        }

        internal Hashtable NameTable {
            get { 
                if (this.nameTable == null) {
                    lock(this.NameTableLock) { 
                        if (this.nameTable == null) 
                            this.nameTable = GetStringTable(false);
                    } 
                }

                return this.nameTable;
            } 
        }
 
        // Returns a temp file name 
        private static string SymbolFilePath {
            [ResourceExposure(ResourceScope.AppDomain)] 
            [ResourceConsumption(ResourceScope.AppDomain)]
            get {
                if (symbolFilePath == null) {
                    lock (InternalSyncObject) { 
                        if (symbolFilePath == null) {
                            string tempPath; 
 
                            EnvironmentPermission environmentPermission = new EnvironmentPermission(PermissionState.Unrestricted);
                            environmentPermission.Assert(); 
                            tempPath = Path.GetTempPath();
                            EnvironmentPermission.RevertAssert();

                            // We need both FileIOPermission EvironmentPermission 
                            PermissionSet ps = new PermissionSet(PermissionState.None);
                            ps.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted)); 
                            ps.AddPermission(new FileIOPermission(FileIOPermissionAccess.Write, tempPath)); 
                            ps.Assert();
                            try { 
                                symbolFilePath = Path.GetTempFileName();
                            }
                            finally {
                                 PermissionSet.RevertAssert(); 
                            }
                        } 
                    } 
                }
 
                return symbolFilePath;
            }
        }
 
        internal static bool CategoryExists(string machine, string category) {
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009)); 
            if (!library.CategoryExists(category)) { 
                if (CultureInfo.CurrentCulture.Parent.LCID != 0x009) {
                    library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent); 
                    return library.CategoryExists(category);
                }

                return false; 
            }
            return true; 
        } 

        internal bool CategoryExists(string category) { 
            return CategoryTable.ContainsKey(category);
        }

        internal static void CloseAllLibraries() { 
            if (libraryTable != null) {
                foreach (PerformanceCounterLib library in libraryTable.Values) 
                    library.Close(); 

                libraryTable = null; 
            }
        }

        internal static void CloseAllTables() { 
            if (libraryTable != null) {
                foreach (PerformanceCounterLib library in libraryTable.Values) 
                    library.CloseTables(); 
            }
        } 

        internal void CloseTables() {
            this.nameTable = null;
            this.helpTable = null; 
            this.categoryTable = null;
            this.customCategoryTable = null; 
        } 

        internal void Close() { 
            if (this.performanceMonitor != null) {
                this.performanceMonitor.Close();
                this.performanceMonitor = null;
            } 

            CloseTables(); 
        } 

        internal static bool CounterExists(string machine, string category, string counter) { 
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009));
            bool categoryExists = false;
            bool counterExists = library.CounterExists(category, counter, ref categoryExists);
            if (!categoryExists && CultureInfo.CurrentCulture.Parent.LCID != 0x009) { 
                library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent);
                counterExists = library.CounterExists(category, counter, ref categoryExists); 
            } 

            if (!categoryExists) { 
                // Consider adding diagnostic logic here, may be we can dump the nameTable...
                throw new InvalidOperationException(SR.GetString(SR.MissingCategory));
            }
 
            return counterExists;
        } 
 
        private bool CounterExists(string category, string counter, ref bool categoryExists) {
            categoryExists = false; 
            if (!CategoryTable.ContainsKey(category))
                return false;
            else
                categoryExists = true; 

            CategoryEntry entry = (CategoryEntry)this.CategoryTable[category]; 
            for (int index = 0; index < entry.CounterIndexes.Length; ++ index) { 
                int counterIndex = entry.CounterIndexes[index];
                string counterName = (string)this.NameTable[counterIndex]; 
                if (counterName == null)
                   counterName = String.Empty;

                if (String.Compare(counterName, counter, StringComparison.OrdinalIgnoreCase) == 0) 
                    return true;
            } 
 
            return false;
        } 

        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private static void CreateIniFile(string categoryName, string categoryHelp, CounterCreationDataCollection creationData, string[] languageIds) { 
            //SECREVIEW: PerformanceCounterPermission must have been demanded before
            FileIOPermission permission = new FileIOPermission(PermissionState.Unrestricted); 
            permission.Assert(); 
            try {
                StreamWriter iniWriter = new StreamWriter(IniFilePath, false, Encoding.Unicode); 
                try {
                    //NT4 won't be able to parse Unicode ini files without this
                    //extra white space.
                    iniWriter.WriteLine(""); 
                    iniWriter.WriteLine(infoDefinition);
                    iniWriter.Write(driverNameKeyword); 
                    iniWriter.Write("="); 
                    iniWriter.WriteLine(categoryName);
                    iniWriter.Write(symbolFileKeyword); 
                    iniWriter.Write("=");
                    iniWriter.WriteLine(Path.GetFileName(SymbolFilePath));
                    iniWriter.WriteLine("");
 
                    iniWriter.WriteLine(languageDefinition);
                    foreach (string languageId in languageIds) { 
                        iniWriter.Write(languageId); 
                        iniWriter.Write("=");
                        iniWriter.Write(languageKeyword); 
                        iniWriter.WriteLine(languageId);
                    }
                    iniWriter.WriteLine("");
 
                    iniWriter.WriteLine(objectDefinition);
                    foreach (string languageId in languageIds) { 
                        iniWriter.Write(categorySymbolPrefix); 
                        iniWriter.Write("1_");
                        iniWriter.Write(languageId); 
                        iniWriter.Write(nameSufix);
                        iniWriter.Write("=");
                        iniWriter.WriteLine(categoryName);
                    } 
                    iniWriter.WriteLine("");
 
                    iniWriter.WriteLine(textDefinition); 
                    foreach (string languageId in languageIds) {
                        iniWriter.Write(categorySymbolPrefix); 
                        iniWriter.Write("1_");
                        iniWriter.Write(languageId);
                        iniWriter.Write(nameSufix);
                        iniWriter.Write("="); 
                        iniWriter.WriteLine(categoryName);
                        iniWriter.Write(categorySymbolPrefix); 
                        iniWriter.Write("1_"); 
                        iniWriter.Write(languageId);
                        iniWriter.Write(helpSufix); 
                        iniWriter.Write("=");
                        if (categoryHelp == null || categoryHelp == String.Empty)
                            iniWriter.WriteLine(SR.GetString(SR.HelpNotAvailable));
                        else 
                            iniWriter.WriteLine(categoryHelp);
 
 
                        int counterIndex = 0;
                        foreach (CounterCreationData counterData in creationData) { 
                            ++counterIndex;
                            iniWriter.WriteLine("");
                            iniWriter.Write(conterSymbolPrefix);
                            iniWriter.Write(counterIndex.ToString(CultureInfo.InvariantCulture)); 
                            iniWriter.Write("_");
                            iniWriter.Write(languageId); 
                            iniWriter.Write(nameSufix); 
                            iniWriter.Write("=");
                            iniWriter.WriteLine(counterData.CounterName); 

                            iniWriter.Write(conterSymbolPrefix);
                            iniWriter.Write(counterIndex.ToString(CultureInfo.InvariantCulture));
                            iniWriter.Write("_"); 
                            iniWriter.Write(languageId);
                            iniWriter.Write(helpSufix); 
                            iniWriter.Write("="); 

                            Debug.Assert(!String.IsNullOrEmpty(counterData.CounterHelp), "CounterHelp should have been fixed up by the caller"); 
                            iniWriter.WriteLine(counterData.CounterHelp);
                        }
                    }
 
                    iniWriter.WriteLine("");
                } 
                finally { 
                    iniWriter.Close();
                } 
            }
            finally {
                FileIOPermission.RevertAssert();
            } 
        }
 
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private static void CreateRegistryEntry(string categoryName, PerformanceCounterCategoryType categoryType, CounterCreationDataCollection creationData, ref bool iniRegistered) { 
            RegistryKey serviceParentKey = null;
            RegistryKey serviceKey = null;
            RegistryKey linkageKey = null;
 
            //SECREVIEW: Whoever is able to call this function, must already
            //                         have demmanded PerformanceCounterPermission 
            //                         we can therefore assert the RegistryPermission. 
            RegistryPermission registryPermission = new RegistryPermission(PermissionState.Unrestricted);
            registryPermission.Assert(); 
            try {
                serviceParentKey = Registry.LocalMachine.OpenSubKey(ServicePath, true);

                serviceKey = serviceParentKey.OpenSubKey(categoryName + "\\Performance", true); 
                if (serviceKey == null)
                    serviceKey = serviceParentKey.CreateSubKey(categoryName + "\\Performance"); 
 
                serviceKey.SetValue("Open","OpenPerformanceData");
                serviceKey.SetValue("Collect", "CollectPerformanceData"); 
                serviceKey.SetValue("Close","ClosePerformanceData");
                serviceKey.SetValue("Library", DllName);
                serviceKey.SetValue("IsMultiInstance", (int) categoryType, RegistryValueKind.DWord);
                serviceKey.SetValue("CategoryOptions", 0x3, RegistryValueKind.DWord); 

                string [] counters = new string[creationData.Count]; 
                string [] counterTypes = new string[creationData.Count]; 
                for (int i = 0; i < creationData.Count; i++) {
                    counters[i] = creationData[i].CounterName; 
                    counterTypes[i] = ((int) creationData[i].CounterType).ToString(CultureInfo.InvariantCulture);
                }

                linkageKey = serviceParentKey.OpenSubKey(categoryName + "\\Linkage" , true); 
                if (linkageKey == null)
                    linkageKey = serviceParentKey.CreateSubKey(categoryName + "\\Linkage" ); 
 
                linkageKey.SetValue("Export", new string[]{categoryName});
 
                serviceKey.SetValue("Counter Types", (object) counterTypes);
                serviceKey.SetValue("Counter Names", (object) counters);

                object firstID = serviceKey.GetValue("First Counter"); 
                if (firstID != null)
                    iniRegistered  = true; 
                else 
                    iniRegistered  = false;
            } 
            finally {
                if (serviceKey != null)
                    serviceKey.Close();
 
                if (linkageKey != null)
                    linkageKey.Close(); 
 
                if (serviceParentKey != null)
                    serviceParentKey.Close(); 

                RegistryPermission.RevertAssert();
            }
        } 

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        private static void CreateSymbolFile(CounterCreationDataCollection creationData) {
            //SECREVIEW: PerformanceCounterPermission must have been demanded before 
            FileIOPermission permission = new FileIOPermission(PermissionState.Unrestricted);
            permission.Assert();
            try {
                StreamWriter symbolWriter = new StreamWriter(SymbolFilePath); 
                try {
                    symbolWriter.Write(defineKeyword); 
                    symbolWriter.Write(" "); 
                    symbolWriter.Write(categorySymbolPrefix);
                    symbolWriter.WriteLine("1 0;"); 

                    for (int counterIndex = 1; counterIndex <= creationData.Count; ++ counterIndex) {
                        symbolWriter.Write(defineKeyword);
                        symbolWriter.Write(" "); 
                        symbolWriter.Write(conterSymbolPrefix);
                        symbolWriter.Write(counterIndex.ToString(CultureInfo.InvariantCulture)); 
                        symbolWriter.Write(" "); 
                        symbolWriter.Write((counterIndex * 2).ToString(CultureInfo.InvariantCulture));
                        symbolWriter.WriteLine(";"); 
                    }

                    symbolWriter.WriteLine("");
                } 
                finally {
                    symbolWriter.Close(); 
                } 
            }
            finally { 
                FileIOPermission.RevertAssert();
            }
        }
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        private static void DeleteRegistryEntry(string categoryName) { 
            RegistryKey serviceKey = null;
 
            //SECREVIEW: Whoever is able to call this function, must already
            //                         have demmanded PerformanceCounterPermission
            //                         we can therefore assert the RegistryPermission.
            RegistryPermission registryPermission = new RegistryPermission(PermissionState.Unrestricted); 
            registryPermission.Assert();
            try { 
                serviceKey = Registry.LocalMachine.OpenSubKey(ServicePath, true); 

                bool deleteCategoryKey = false; 
                using (RegistryKey categoryKey = serviceKey.OpenSubKey(categoryName, true)) {
                    if (categoryKey != null) {
                        if (categoryKey.GetValueNames().Length == 0) {
                            deleteCategoryKey = true; 
                        }
                        else { 
                            categoryKey.DeleteSubKeyTree("Linkage"); 
                            categoryKey.DeleteSubKeyTree("Performance");
                        } 
                    }
                }
                if (deleteCategoryKey)
                    serviceKey.DeleteSubKeyTree(categoryName); 

            } 
            finally { 
                if (serviceKey != null)
                    serviceKey.Close(); 

                RegistryPermission.RevertAssert();
            }
        } 

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        private static void DeleteTemporaryFiles() {
            try { 
                File.Delete(IniFilePath);
            }
            catch {
            } 

            try { 
                File.Delete(SymbolFilePath); 
            }
            catch { 
            }
        }

        // Ensures that the customCategoryTable is initialized and decides whether the category passed in 
        //  1) is a custom category
        //  2) is a multi instance custom category 
        // The return value is whether the category is a custom category or not. 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        internal bool FindCustomCategory(string category, out PerformanceCounterCategoryType categoryType) {
            RegistryKey key = null;
            RegistryKey baseKey = null;
            categoryType = PerformanceCounterCategoryType.Unknown; 

            if (this.customCategoryTable == null) 
                this.customCategoryTable = new Hashtable(StringComparer.OrdinalIgnoreCase); 

            if (this.customCategoryTable.ContainsKey(category)) { 
                categoryType= (PerformanceCounterCategoryType) this.customCategoryTable[category];
                return true;
            }
            else { 
                //SECREVIEW: Whoever is able to call this function, must already
                //                         have demmanded PerformanceCounterPermission 
                //                         we can therefore assert the RegistryPermission. 
                PermissionSet ps = new PermissionSet(PermissionState.None);
                ps.AddPermission(new RegistryPermission(PermissionState.Unrestricted)); 
                ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
                ps.Assert();
                try {
                    string keyPath = ServicePath + "\\" + category + "\\Performance"; 
                    if (machineName == "." || String.Compare(this.machineName, ComputerName, StringComparison.OrdinalIgnoreCase) == 0) {
                        key = Registry.LocalMachine.OpenSubKey(keyPath); 
                    } 
                    else {
                        baseKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "\\\\" + this.machineName); 
                        if (baseKey != null) {
                            try {
                                key =  baseKey.OpenSubKey(keyPath);
                            } catch (SecurityException) { 
                                // we may not have permission to read the registry key on the remote machine.  The security exception
                                // is thrown when RegOpenKeyEx returns ERROR_ACCESS_DENIED or ERROR_BAD_IMPERSONATION_LEVEL 
                                // 
                                // In this case we return an 'Unknown' category type and 'false' to indicate the category is *not* custom.
                                // 
                                categoryType = PerformanceCounterCategoryType.Unknown;
                                this.customCategoryTable[category] = categoryType;
                                return false;
                            } 
                        }
                    } 
 
                    if (key != null) {
                        object systemDllName = key.GetValue("Library"); 
                        if (systemDllName != null && systemDllName is string && String.Compare((string)systemDllName, PerformanceCounterLib.PerfShimName, StringComparison.OrdinalIgnoreCase) == 0) {

                            object isMultiInstanceObject = key.GetValue("IsMultiInstance");
                            if (isMultiInstanceObject != null) { 
                                categoryType = (PerformanceCounterCategoryType) isMultiInstanceObject;
                                if (categoryType < PerformanceCounterCategoryType.Unknown || categoryType > PerformanceCounterCategoryType.MultiInstance) 
                                    categoryType = PerformanceCounterCategoryType.Unknown; 
                            }
                            else 
                                categoryType = PerformanceCounterCategoryType.Unknown;

                            object objectID = key.GetValue("First Counter");
                            if (objectID != null) { 
                                int firstID = (int)objectID;
 
                                this.customCategoryTable[category] = categoryType; 
                                return true;
                            } 
                        }
                    }
                }
                finally { 
                    if (key != null) key.Close();
                    if (baseKey != null) baseKey.Close(); 
                    PermissionSet.RevertAssert(); 
                }
            } 
            return false;
        }

        internal static string[] GetCategories(string machineName) { 
            PerformanceCounterLib library = GetPerformanceCounterLib(machineName, CultureInfo.CurrentCulture.Parent);
            string[] categories = library.GetCategories(); 
            if (categories.Length == 0 && CultureInfo.CurrentCulture.Parent.LCID != 0x009) { 
                library = GetPerformanceCounterLib(machineName, new CultureInfo(0x009));
                categories = library.GetCategories(); 
            }

            return categories;
        } 

        internal string[] GetCategories() { 
            ICollection keys = CategoryTable.Keys; 
            string[] categories = new string[keys.Count];
            keys.CopyTo(categories, 0); 
            return categories;
        }

        internal static string GetCategoryHelp(string machine, string category) { 
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009));
            string help = library.GetCategoryHelp(category); 
            if (help == null && CultureInfo.CurrentCulture.Parent.LCID != 0x009) { 
                library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent);
                help = library.GetCategoryHelp(category); 
            }

            if (help == null)
                throw new InvalidOperationException(SR.GetString(SR.MissingCategory)); 

            return help; 
        } 

        private string GetCategoryHelp(string category) { 
            CategoryEntry entry = (CategoryEntry)this.CategoryTable[category];
            if (entry == null)
                return null;
 
            return (string)this.HelpTable[entry.HelpIndex];
        } 
 
        internal static CategorySample GetCategorySample(string machine, string category) {
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009)); 
            CategorySample sample = library.GetCategorySample(category);
            if (sample == null && CultureInfo.CurrentCulture.Parent.LCID != 0x009) {
                library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent);
                sample = library.GetCategorySample(category); 
            }
            if (sample == null) 
                throw new InvalidOperationException(SR.GetString(SR.MissingCategory)); 

            return sample; 
        }

        private CategorySample GetCategorySample(string category) {
            CategoryEntry entry = (CategoryEntry)this.CategoryTable[category]; 
            if (entry == null)
                return null; 
 
            CategorySample sample = null;
            byte[] dataRef = GetPerformanceData(entry.NameIndex.ToString(CultureInfo.InvariantCulture)); 
            if (dataRef == null)
                throw new InvalidOperationException(SR.GetString(SR.CantReadCategory, category));

            sample = new CategorySample(dataRef, entry, this); 
            return sample;
        } 
 
        internal static string[] GetCounters(string machine, string category) {
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009)); 
            bool categoryExists = false;
            string[] counters = library.GetCounters(category, ref categoryExists);
            if (!categoryExists && CultureInfo.CurrentCulture.Parent.LCID != 0x009) {
                library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent); 
                counters = library.GetCounters(category, ref categoryExists);
            } 
 
            if (!categoryExists)
                throw new InvalidOperationException(SR.GetString(SR.MissingCategory)); 

            return counters;
        }
 
        private string[] GetCounters(string category, ref bool categoryExists) {
            categoryExists = false; 
            CategoryEntry entry = (CategoryEntry)this.CategoryTable[category]; 
            if (entry == null)
                return null; 
            else
                categoryExists = true;

            int index2 = 0; 
            string[] counters = new string[entry.CounterIndexes.Length];
            for (int index = 0; index < counters.Length; ++ index) { 
                int counterIndex = entry.CounterIndexes[index]; 
                string counterName = (string)this.NameTable[counterIndex];
                if (counterName != null && counterName != String.Empty) { 
                    counters[index2] = counterName;
                    ++index2;
                }
            } 

            //Lets adjust the array in case there were null entries 
            if (index2 < counters.Length) { 
                string[] adjustedCounters = new string[index2];
                Array.Copy(counters, adjustedCounters, index2); 
                counters = adjustedCounters;
            }

            return counters; 
        }
 
        internal static string GetCounterHelp(string machine, string category, string counter) { 
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009));
            bool categoryExists = false; 
            string help = library.GetCounterHelp(category, counter, ref categoryExists);
            if (!categoryExists && CultureInfo.CurrentCulture.Parent.LCID != 0x009) {
                library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent);
                help = library.GetCounterHelp(category, counter, ref categoryExists); 
            }
 
            if (!categoryExists) 
                throw new InvalidOperationException(SR.GetString(SR.MissingCategoryDetail, category));
 
            return help;
        }

        private string GetCounterHelp(string category, string counter, ref bool categoryExists) { 
            categoryExists = false;
            CategoryEntry entry = (CategoryEntry)this.CategoryTable[category]; 
            if (entry == null) 
                return null;
            else 
                categoryExists = true;

            int helpIndex = -1;
            for (int index = 0; index < entry.CounterIndexes.Length; ++ index) { 
                int counterIndex = entry.CounterIndexes[index];
                string counterName = (string)this.NameTable[counterIndex]; 
                if (counterName == null) 
                   counterName = String.Empty;
 
                if (String.Compare(counterName, counter, StringComparison.OrdinalIgnoreCase) == 0) {
                    helpIndex = entry.HelpIndexes[index];
                    break;
                } 
            }
 
            if (helpIndex == -1) 
                throw new InvalidOperationException(SR.GetString(SR.MissingCounter, counter));
 
            string help = (string)this.HelpTable[helpIndex];
            if (help == null)
                return String.Empty;
            else 
                return help;
        } 
 
        internal string GetCounterName(int index) {
            if (this.NameTable.ContainsKey(index)) 
                return (string)this.NameTable[index];

            return "";
        } 

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        private static string[] GetLanguageIds() {
            RegistryKey libraryParentKey = null; 
            string[] ids = new string[0];
            new RegistryPermission(PermissionState.Unrestricted).Assert();
            try {
                libraryParentKey = Registry.LocalMachine.OpenSubKey(PerflibPath); 

                if (libraryParentKey != null) 
                    ids = libraryParentKey.GetSubKeyNames(); 
            }
            finally { 
                if (libraryParentKey != null)
                    libraryParentKey.Close();

                RegistryPermission.RevertAssert(); 
            }
 
            return ids; 
        }
 
        internal static PerformanceCounterLib GetPerformanceCounterLib(string machineName, CultureInfo culture) {
            SharedUtils.CheckEnvironment();

            string lcidString = culture.LCID.ToString("X3", CultureInfo.InvariantCulture); 
            if (machineName.CompareTo(".") == 0)
                machineName = ComputerName.ToLower(CultureInfo.InvariantCulture); 
            else 
                machineName = machineName.ToLower(CultureInfo.InvariantCulture);
 
            if (PerformanceCounterLib.libraryTable == null)
                PerformanceCounterLib.libraryTable = new Hashtable();

            string libraryKey = machineName + ":" + lcidString; 
            if (PerformanceCounterLib.libraryTable.Contains(libraryKey))
                return (PerformanceCounterLib)PerformanceCounterLib.libraryTable[libraryKey]; 
            else { 
                PerformanceCounterLib library = new PerformanceCounterLib(machineName, lcidString);
                PerformanceCounterLib.libraryTable[libraryKey] = library; 
                return library;
            }
        }
 
        internal byte[] GetPerformanceData(string item) {
            if (this.performanceMonitor == null) { 
                lock (this) { 
                    if (this.performanceMonitor == null)
                        this.performanceMonitor = new PerformanceMonitor(this.machineName); 
                }
            }

           return this.performanceMonitor.GetData(item); 
        }
 
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private Hashtable GetStringTable(bool isHelp) { 
            Hashtable stringTable;
            RegistryKey libraryKey;

            PermissionSet ps = new PermissionSet(PermissionState.None); 
            ps.AddPermission(new RegistryPermission(PermissionState.Unrestricted));
            ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)); 
            ps.Assert(); 

            if (String.Compare(this.machineName, ComputerName, StringComparison.OrdinalIgnoreCase) == 0) 
                libraryKey = Registry.PerformanceData;
            else {
                libraryKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.PerformanceData, this.machineName);
            } 

            try { 
                string[] names = null; 
                int waitRetries = 14;   //((2^13)-1)*10ms == approximately 1.4mins
                int waitSleep = 0; 

                // In some stress situations, querying counter values from
                // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009
                // often returns null/empty data back. We should build fault-tolerance logic to 
                // make it more reliable because getting null back once doesn't necessarily mean
                // that the data is corrupted, most of the time we would get the data just fine 
                // in subsequent tries. 
                while (waitRetries > 0) {
                    try { 
                        if (!isHelp)
                            names = (string[])libraryKey.GetValue("Counter " + perfLcid);
                        else
                            names = (string[])libraryKey.GetValue("Explain " + perfLcid); 

                        if ((names == null) || (names.Length == 0)) { 
                            --waitRetries; 
                            if (waitSleep == 0)
                                waitSleep = 10; 
                            else {
                                System.Threading.Thread.Sleep(waitSleep);
                                waitSleep *= 2;
                            } 
                        }
                        else 
                            break; 
                    }
                    catch (IOException) { 
                        // RegistryKey throws if it can't find the value.  We want to return an empty table
                        // and throw a different exception higher up the stack.
                        names = null;
                        break; 
                    }
 
                } 

                if (names == null) 
                    stringTable = new Hashtable();
                else {
                    stringTable = new Hashtable(names.Length/2);
 
                    for (int index = 0; index < (names.Length/2); ++ index) {
                        string nameString =  names[(index *2) + 1]; 
                        if (nameString == null) 
                            nameString = String.Empty;
 
                        stringTable[Int32.Parse(names[index * 2], CultureInfo.InvariantCulture)] = nameString;
                    }
                }
            } 
            finally {
                libraryKey.Close(); 
            } 

            return stringTable; 
        }

        internal static bool IsCustomCategory(string machine, string category) {
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009)); 
            if (!library.IsCustomCategory(category)) {
                if (CultureInfo.CurrentCulture.Parent.LCID != 0x009) { 
                    library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent); 
                    return library.IsCustomCategory(category);
                } 

                return false;
            }
            return true; 
        }
 
        internal static bool IsBaseCounter(int type) { 
            return (type == NativeMethods.PERF_AVERAGE_BASE ||
                    type == NativeMethods.PERF_COUNTER_MULTI_BASE || 
                    type == NativeMethods.PERF_RAW_BASE  ||
                    type == NativeMethods.PERF_LARGE_RAW_BASE  ||
                    type == NativeMethods.PERF_SAMPLE_BASE);
        } 

        private bool IsCustomCategory(string category) { 
            PerformanceCounterCategoryType categoryType; 

            return FindCustomCategory(category, out categoryType); 
        }

        internal static PerformanceCounterCategoryType GetCategoryType(string machine, string category) {
            PerformanceCounterCategoryType categoryType = PerformanceCounterCategoryType.Unknown; 

            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009)); 
            if (!library.FindCustomCategory(category, out categoryType)) { 
                if (CultureInfo.CurrentCulture.Parent.LCID != 0x009) {
                    library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent); 
                    library.FindCustomCategory(category, out categoryType);
                }
            }
            return categoryType; 
        }
 
        /* 
        // Creates a category with an ini file supplied by the user.  Currently this is not available.
        internal static void RegisterCategory(string machineName, string categoryName, string categoryHelp, CounterCreationDataCollection creationData, string localizedIniFilePath) { 
            bool iniRegistered = false;
            CreateRegistryEntry(machineName, categoryName, creationData, ref iniRegistered);
            if (!iniRegistered)
                RegisterFiles(machineName, localizedIniFilePath, false); 

            CloseAllTables(); 
        } 
        */
 
        internal static void RegisterCategory(string categoryName, PerformanceCounterCategoryType categoryType, string categoryHelp, CounterCreationDataCollection creationData) {
            try {
                bool iniRegistered = false;
                CreateRegistryEntry(categoryName, categoryType, creationData, ref iniRegistered); 
                if (!iniRegistered) {
                    string[] languageIds = GetLanguageIds(); 
                    CreateIniFile(categoryName, categoryHelp, creationData, languageIds); 
                    CreateSymbolFile(creationData);
                    RegisterFiles(IniFilePath, false); 
                }
                CloseAllTables();
                CloseAllLibraries();
            } 
            finally {
                DeleteTemporaryFiles(); 
            } 
        }
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private static void RegisterFiles(string arg0, bool unregister) {
            Process p; 
            ProcessStartInfo processStartInfo = new ProcessStartInfo();
            processStartInfo.UseShellExecute = false; 
            processStartInfo.CreateNoWindow = true; 
            processStartInfo.ErrorDialog = false;
            processStartInfo.WindowStyle = ProcessWindowStyle.Hidden; 
            processStartInfo.WorkingDirectory = Environment.SystemDirectory;

            if (unregister)
                processStartInfo.FileName = Environment.SystemDirectory + "\\unlodctr.exe"; 
            else
                processStartInfo.FileName = Environment.SystemDirectory + "\\lodctr.exe"; 
 
            int res = 0;
            new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); 
            try {
                processStartInfo.Arguments = "\"" + arg0 + "\"";
                p = Process.Start(processStartInfo);
                p.WaitForExit(); 

                res = p.ExitCode; 
            } 
            finally {
                SecurityPermission.RevertAssert(); 
            }

            // Look at Q269225, unlodctr might return 2 when WMI is not installed.
            if (unregister && res == 2) 
                res = 0;
 
            if (res != 0) 
                throw SharedUtils.CreateSafeWin32Exception(res);
        } 

        internal static void UnregisterCategory(string categoryName) {
            RegisterFiles(categoryName, true);
            DeleteRegistryEntry(categoryName); 
            CloseAllTables();
            CloseAllLibraries(); 
        } 
    }
 
    internal class PerformanceMonitor {
        private RegistryKey perfDataKey = null;
        private string machineName;
 
        internal PerformanceMonitor(string machineName) {
            this.machineName = machineName; 
            Init(); 
        }
 
        private void Init() {
            try {
                if (machineName != "." && String.Compare(machineName, PerformanceCounterLib.ComputerName, StringComparison.OrdinalIgnoreCase) != 0) {
                    new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); 
                    perfDataKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.PerformanceData, machineName);
                } 
                else 
                    perfDataKey = Registry.PerformanceData;
            } 
            catch (UnauthorizedAccessException) {
                // we need to do this for compatibility with v1.1 and v1.0.
                throw new Win32Exception(NativeMethods.ERROR_ACCESS_DENIED);
            } 
            catch (IOException e) {
                // we need to do this for compatibility with v1.1 and v1.0. 
                throw new Win32Exception(Marshal.GetHRForException(e)); 
            }
        } 

        internal void Close() {
            if( perfDataKey != null)
                perfDataKey.Close(); 

            perfDataKey = null; 
        } 

        // Win32 RegQueryValueEx for perf data could deadlock (for a Mutex) up to 2mins in some 
        // scenarios before they detect it and exit gracefully. In the mean time, ERROR_BUSY,
        // ERROR_NOT_READY etc can be seen by other concurrent calls (which is the reason for the
        // wait loop and switch case below). We want to wait most certainly more than a 2min window.
        // The curent wait time of up to 10mins takes care of the known stress deadlock issues. In most 
        // cases we wouldn't wait for more than 2mins anyways but in worst cases how much ever time
        // we wait may not be sufficient if the Win32 code keeps running into this deadlock again 
        // and again. A condition very rare but possible in theory. We would get back to the user 
        // in this case with InvalidOperationException after the wait time expires.
        internal byte[] GetData(string item) { 
            int waitRetries = 17;   //2^16*10ms == approximately 10mins
            int waitSleep = 0;
            byte[] data = null;
            int error = 0; 

            // no need to revert here since we'll fall off the end of the method 
            new RegistryPermission(PermissionState.Unrestricted).Assert(); 
            while (waitRetries > 0) {
                try { 
                    data = (byte[]) perfDataKey.GetValue(item);
                    return data;
                }
                catch (IOException e) { 
                    error = Marshal.GetHRForException(e);
                    switch (error) { 
                        case NativeMethods.RPC_S_CALL_FAILED: 
                        case NativeMethods.ERROR_INVALID_HANDLE:
                        case NativeMethods.RPC_S_SERVER_UNAVAILABLE: 
                            Init();
                            goto case NativeMethods.WAIT_TIMEOUT;

                        case NativeMethods.WAIT_TIMEOUT: 
                        case NativeMethods.ERROR_NOT_READY:
                        case NativeMethods.ERROR_LOCK_FAILED: 
                        case NativeMethods.ERROR_BUSY: 
                            --waitRetries;
                            if (waitSleep == 0) { 
                                waitSleep = 10;
                            }
                            else {
                                System.Threading.Thread.Sleep(waitSleep); 
                                waitSleep *= 2;
                            } 
                            break; 

                        default: 
                            throw SharedUtils.CreateSafeWin32Exception(error);
                    }
                }
            } 

            throw SharedUtils.CreateSafeWin32Exception(error); 
        } 

    } 

    internal class CategoryEntry {
        internal int NameIndex;
        internal int HelpIndex; 
        internal int[] CounterIndexes;
        internal int[] HelpIndexes; 
 
        internal CategoryEntry(NativeMethods.PERF_OBJECT_TYPE perfObject) {
            this.NameIndex = perfObject.ObjectNameTitleIndex; 
            this.HelpIndex = perfObject.ObjectHelpTitleIndex;
            this.CounterIndexes = new int[perfObject.NumCounters];
            this.HelpIndexes = new int[perfObject.NumCounters];
        } 
    }
 
    internal class CategorySample { 
        internal readonly long SystemFrequency;
        internal readonly long TimeStamp; 
        internal readonly long TimeStamp100nSec;
        internal readonly long CounterFrequency;
        internal readonly long CounterTimeStamp;
        internal Hashtable CounterTable; 
        internal Hashtable InstanceNameTable;
        internal bool IsMultiInstance; 
        private CategoryEntry entry; 
        private PerformanceCounterLib library;
 
        internal unsafe CategorySample(byte[] data, CategoryEntry entry, PerformanceCounterLib library) {
            this.entry = entry;
            this.library = library;
            int categoryIndex = entry.NameIndex; 
            NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK();
            fixed (byte* dataPtr = data) { 
                IntPtr dataRef = new IntPtr((void*) dataPtr); 

                Marshal.PtrToStructure(dataRef, dataBlock); 
                this.SystemFrequency = dataBlock.PerfFreq;
                this.TimeStamp = dataBlock.PerfTime;
                this.TimeStamp100nSec = dataBlock.PerfTime100nSec;
                dataRef = (IntPtr)((long)dataRef + dataBlock.HeaderLength); 
                int numPerfObjects = dataBlock.NumObjectTypes;
                if (numPerfObjects == 0) { 
                    this.CounterTable = new Hashtable(); 
                    this.InstanceNameTable = new Hashtable(StringComparer.OrdinalIgnoreCase);
                    return; 
                }

                //Need to find the right category, GetPerformanceData might return
                //several of them. 
                NativeMethods.PERF_OBJECT_TYPE perfObject = null;
                bool foundCategory = false; 
                for (int index = 0; index < numPerfObjects; index++) { 
                    perfObject = new NativeMethods.PERF_OBJECT_TYPE();
                    Marshal.PtrToStructure(dataRef, perfObject); 

                   if (perfObject.ObjectNameTitleIndex == categoryIndex) {
                        foundCategory = true;
                        break; 
                    }
 
                    dataRef = (IntPtr)((long)dataRef + perfObject.TotalByteLength); 
                }
 
                if (!foundCategory)
                    throw new InvalidOperationException(SR.GetString(SR.CantReadCategoryIndex, categoryIndex.ToString(CultureInfo.CurrentCulture)));

                this.CounterFrequency = perfObject.PerfFreq; 
                this.CounterTimeStamp = perfObject.PerfTime;
                int counterNumber = perfObject.NumCounters; 
                int instanceNumber = perfObject.NumInstances; 

                if (instanceNumber == -1) 
                    IsMultiInstance = false;
                else
                    IsMultiInstance = true;
 
                // Move pointer forward to end of PERF_OBJECT_TYPE
                dataRef = (IntPtr)((long)dataRef + perfObject.HeaderLength); 
 
                CounterDefinitionSample[] samples = new CounterDefinitionSample[counterNumber];
                this.CounterTable = new Hashtable(counterNumber); 
                for (int index = 0; index < samples.Length; ++ index) {
                    NativeMethods.PERF_COUNTER_DEFINITION perfCounter = new NativeMethods.PERF_COUNTER_DEFINITION();
                    Marshal.PtrToStructure(dataRef, perfCounter);
                    samples[index] = new CounterDefinitionSample(perfCounter, this, instanceNumber); 
                    dataRef = (IntPtr)((long)dataRef + perfCounter.ByteLength);
 
                    int currentSampleType = samples[index].CounterType; 
                    if (!PerformanceCounterLib.IsBaseCounter(currentSampleType)) {
                        // We'll put only non-base counters in the table. 
                        if (currentSampleType != NativeMethods.PERF_COUNTER_NODATA)
                            this.CounterTable[samples[index].NameIndex] = samples[index];
                    }
                    else { 
                        // it's a base counter, try to hook it up to the main counter.
                        Debug.Assert(index > 0, "Index > 0 because base counters should never be at index 0"); 
                        if (index > 0) 
                            samples[index-1].BaseCounterDefinitionSample = samples[index];
                    } 
                }

                // now set up the InstanceNameTable.
                if (!IsMultiInstance) { 
                    this.InstanceNameTable = new Hashtable(1, StringComparer.OrdinalIgnoreCase);
                    this.InstanceNameTable[PerformanceCounterLib.SingleInstanceName] = 0; 
 
                    for (int index = 0; index < samples.Length; ++ index)  {
                        samples[index].SetInstanceValue(0, dataRef); 
                    }
                }
                else {
                    string[] parentInstanceNames = null; 
                    this.InstanceNameTable = new Hashtable(instanceNumber, StringComparer.OrdinalIgnoreCase);
                    for (int i = 0; i < instanceNumber; i++) { 
                        NativeMethods.PERF_INSTANCE_DEFINITION perfInstance = new NativeMethods.PERF_INSTANCE_DEFINITION(); 
                        Marshal.PtrToStructure(dataRef, perfInstance);
                        if (perfInstance.ParentObjectTitleIndex > 0 && parentInstanceNames == null) 
                            parentInstanceNames = GetInstanceNamesFromIndex(perfInstance.ParentObjectTitleIndex);

                        string instanceName;
                        if (parentInstanceNames != null && perfInstance.ParentObjectInstance >= 0 && perfInstance.ParentObjectInstance < parentInstanceNames.Length - 1) 
                            instanceName = parentInstanceNames[perfInstance.ParentObjectInstance] + "/" + Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset));
                        else 
                            instanceName = Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset)); 

                        //In some cases instance names are not unique (Process), same as perfmon 
                        //generate a unique name.
                        string newInstanceName = instanceName;
                        int newInstanceNumber = 1;
                        while (true) { 
                            if (!this.InstanceNameTable.ContainsKey(newInstanceName)) {
                                this.InstanceNameTable[newInstanceName] = i; 
                                break; 
                            }
                            else { 
                                newInstanceName =  instanceName + "#" + newInstanceNumber.ToString(CultureInfo.InvariantCulture);
                                ++  newInstanceNumber;
                            }
                        } 

 
                        dataRef = (IntPtr)((long)dataRef + perfInstance.ByteLength); 
                        for (int index = 0; index < samples.Length; ++ index)
                            samples[index].SetInstanceValue(i, dataRef); 

                        dataRef = (IntPtr)((long)dataRef + Marshal.ReadInt32(dataRef));
                    }
                } 
            }
        } 
 
        internal unsafe string[] GetInstanceNamesFromIndex(int categoryIndex) {
            byte[] data = library.GetPerformanceData(categoryIndex.ToString(CultureInfo.InvariantCulture)); 
            fixed (byte* dataPtr = data) {
                IntPtr dataRef = new IntPtr((void*) dataPtr);

                NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK(); 
                Marshal.PtrToStructure(dataRef, dataBlock);
                dataRef = (IntPtr)((long)dataRef + dataBlock.HeaderLength); 
                int numPerfObjects = dataBlock.NumObjectTypes; 

                NativeMethods.PERF_OBJECT_TYPE perfObject = null; 
                bool foundCategory = false;
                for (int index = 0; index < numPerfObjects; index++) {
                    perfObject = new NativeMethods.PERF_OBJECT_TYPE();
                    Marshal.PtrToStructure(dataRef, perfObject); 

                    if (perfObject.ObjectNameTitleIndex == categoryIndex) { 
                        foundCategory = true; 
                        break;
                    } 

                    dataRef = (IntPtr)((long)dataRef + perfObject.TotalByteLength);
                }
 
                if (!foundCategory)
                    return new string[0]; 
 
                int counterNumber = perfObject.NumCounters;
                int instanceNumber = perfObject.NumInstances; 
                dataRef = (IntPtr)((long)dataRef + perfObject.HeaderLength);

                if (instanceNumber == -1)
                    return new string[0]; 

                CounterDefinitionSample[] samples = new CounterDefinitionSample[counterNumber]; 
                for (int index = 0; index < samples.Length; ++ index) { 
                    NativeMethods.PERF_COUNTER_DEFINITION perfCounter = new NativeMethods.PERF_COUNTER_DEFINITION();
                    Marshal.PtrToStructure(dataRef, perfCounter); 
                    dataRef = (IntPtr)((long)dataRef + perfCounter.ByteLength);
                }

                string[] instanceNames = new string[instanceNumber]; 
                for (int i = 0; i < instanceNumber; i++) {
                    NativeMethods.PERF_INSTANCE_DEFINITION perfInstance = new NativeMethods.PERF_INSTANCE_DEFINITION(); 
                    Marshal.PtrToStructure(dataRef, perfInstance); 
                    instanceNames[i] =  Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset));
                    dataRef = (IntPtr)((long)dataRef + perfInstance.ByteLength); 
                    dataRef = (IntPtr)((long)dataRef + Marshal.ReadInt32(dataRef));
                }

                return instanceNames; 
            }
        } 
 
        internal CounterDefinitionSample GetCounterDefinitionSample(string counter) {
            for (int index = 0; index < this.entry.CounterIndexes.Length; ++ index) { 
                int counterIndex = entry.CounterIndexes[index];
                string counterName = (string)this.library.NameTable[counterIndex];
                if (counterName != null) {
                    if (String.Compare(counterName, counter, StringComparison.OrdinalIgnoreCase) == 0) { 
                        CounterDefinitionSample sample = (CounterDefinitionSample)this.CounterTable[counterIndex];
                        if (sample == null) { 
                            //This is a base counter and has not been added to the table 
                            foreach (CounterDefinitionSample multiSample in this.CounterTable.Values) {
                                if (multiSample.BaseCounterDefinitionSample != null && 
                                    multiSample.BaseCounterDefinitionSample.NameIndex == counterIndex)
                                    return multiSample.BaseCounterDefinitionSample;
                            }
 
                            throw new InvalidOperationException(SR.GetString(SR.CounterLayout));
                        } 
                        return sample; 
                    }
                } 
            }

            throw new InvalidOperationException(SR.GetString(SR.CantReadCounter, counter));
        } 

        internal InstanceDataCollectionCollection ReadCategory() { 
 
#pragma warning disable 618
            InstanceDataCollectionCollection data = new InstanceDataCollectionCollection(); 
#pragma warning restore 618
            for (int index = 0; index < this.entry.CounterIndexes.Length; ++ index) {
                int counterIndex = entry.CounterIndexes[index];
 
                string name = (string)library.NameTable[counterIndex];
                if (name != null && name != String.Empty) { 
                    CounterDefinitionSample sample = (CounterDefinitionSample)this.CounterTable[counterIndex]; 
                    if (sample != null)
                        //If the current index refers to a counter base, 
                        //the sample will be null
                        data.Add(name, sample.ReadInstanceData(name));
                }
            } 

            return data; 
        } 
    }
 
    internal class CounterDefinitionSample {
        internal readonly int NameIndex;
        internal readonly int CounterType;
        internal CounterDefinitionSample BaseCounterDefinitionSample; 

        private readonly int size; 
        private readonly int offset; 
        private long[] instanceValues;
        private CategorySample categorySample; 

        internal CounterDefinitionSample(NativeMethods.PERF_COUNTER_DEFINITION perfCounter, CategorySample categorySample, int instanceNumber) {
            this.NameIndex = perfCounter.CounterNameTitleIndex;
            this.CounterType = perfCounter.CounterType; 
            this.offset = perfCounter.CounterOffset;
            this.size = perfCounter.CounterSize; 
            if (instanceNumber == -1) { 
                this.instanceValues = new long[1];
            } 
            else
                this.instanceValues = new long[instanceNumber];

            this.categorySample = categorySample; 
        }
 
        private long ReadValue(IntPtr pointer) { 
            if (this.size == 4) {
                return (long)(uint)Marshal.ReadInt32((IntPtr)((long)pointer + this.offset)); 
            }
            else if (this.size == 8) {
                return (long)Marshal.ReadInt64((IntPtr)((long)pointer + this.offset));
            } 

            return -1; 
        } 

        internal CounterSample GetInstanceValue(string instanceName) { 

            if (!categorySample.InstanceNameTable.ContainsKey(instanceName)) {
                // Our native dll truncates instance names to 128 characters.  If we can't find the instance
                // with the full name, try truncating to 128 characters. 
                if (instanceName.Length > SharedPerformanceCounter.InstanceNameMaxLength)
                    instanceName = instanceName.Substring(0, SharedPerformanceCounter.InstanceNameMaxLength); 
 
                if (!categorySample.InstanceNameTable.ContainsKey(instanceName))
                    throw new InvalidOperationException(SR.GetString(SR.CantReadInstance, instanceName)); 
            }

            int index = (int)categorySample.InstanceNameTable[instanceName];
            long rawValue = this.instanceValues[index]; 
            long baseValue = 0;
            if (this.BaseCounterDefinitionSample != null) { 
                CategorySample baseCategorySample = this.BaseCounterDefinitionSample.categorySample; 
                int baseIndex = (int)baseCategorySample.InstanceNameTable[instanceName];
                baseValue = this.BaseCounterDefinitionSample.instanceValues[baseIndex]; 
            }

            return new CounterSample(rawValue,
                                                        baseValue, 
                                                        categorySample.CounterFrequency,
                                                        categorySample.SystemFrequency, 
                                                        categorySample.TimeStamp, 
                                                        categorySample.TimeStamp100nSec,
                                                        (PerformanceCounterType)this.CounterType, 
                                                        categorySample.CounterTimeStamp);

        }
 
        internal InstanceDataCollection ReadInstanceData(string counterName) {
#pragma warning disable 618 
            InstanceDataCollection data = new InstanceDataCollection(counterName); 
#pragma warning restore 618
 
            string[] keys = new string[categorySample.InstanceNameTable.Count];
            categorySample.InstanceNameTable.Keys.CopyTo(keys, 0);
            int[] indexes = new int[categorySample.InstanceNameTable.Count];
            categorySample.InstanceNameTable.Values.CopyTo(indexes, 0); 
            for (int index = 0; index < keys.Length; ++ index) {
                long baseValue = 0; 
                if (this.BaseCounterDefinitionSample != null) { 
                    CategorySample baseCategorySample = this.BaseCounterDefinitionSample.categorySample;
                    int baseIndex = (int)baseCategorySample.InstanceNameTable[keys[index]]; 
                    baseValue = this.BaseCounterDefinitionSample.instanceValues[baseIndex];
                }

                CounterSample sample = new CounterSample(this.instanceValues[indexes[index]], 
                                                        baseValue,
                                                        categorySample.CounterFrequency, 
                                                        categorySample.SystemFrequency, 
                                                        categorySample.TimeStamp,
                                                        categorySample.TimeStamp100nSec, 
                                                        (PerformanceCounterType)this.CounterType,
                                                        categorySample.CounterTimeStamp);

                data.Add(keys[index], new InstanceData(keys[index], sample)); 
            }
 
            return data; 
        }
 
        internal CounterSample GetSingleValue() {
            long rawValue = this.instanceValues[0];
            long baseValue = 0;
            if (this.BaseCounterDefinitionSample != null) 
                baseValue = this.BaseCounterDefinitionSample.instanceValues[0];
 
            return new CounterSample(rawValue, 
                                                        baseValue,
                                                        categorySample.CounterFrequency, 
                                                        categorySample.SystemFrequency,
                                                        categorySample.TimeStamp,
                                                        categorySample.TimeStamp100nSec,
                                                        (PerformanceCounterType)this.CounterType, 
                                                        categorySample.CounterTimeStamp);
        } 
 
        internal void SetInstanceValue(int index, IntPtr dataRef) {
            long rawValue = ReadValue(dataRef); 
            this.instanceValues[index] = rawValue;
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
namespace System.Diagnostics { 
    using System.Runtime.InteropServices;
    using System.Globalization;
    using System.Security.Permissions;
    using System.Security; 
    using System.Text;
    using System.Threading; 
    using System.Reflection; 
    using System.Collections;
    using System.ComponentModel; 
    using System.Collections.Specialized;
    using Microsoft.Win32;
    using System.IO;
    using System.Runtime.Serialization; 
    using System.Runtime.Versioning;
 
    internal class PerformanceCounterLib { 
        internal const string PerfShimName = "netfxperf.dll";
        internal const string OpenEntryPoint = "OpenPerformanceData"; 
        internal const string CollectEntryPoint = "CollectPerformanceData";
        internal const string CloseEntryPoint = "ClosePerformanceData";
        internal const string SingleInstanceName = "systemdiagnosticsperfcounterlibsingleinstance";
 
        private const string PerflibPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
        internal const string ServicePath = "SYSTEM\\CurrentControlSet\\Services"; 
        private const string categorySymbolPrefix = "OBJECT_"; 
        private const string conterSymbolPrefix = "DEVICE_COUNTER_";
        private const string helpSufix = "_HELP"; 
        private const string nameSufix = "_NAME";
        private const string textDefinition = "[text]";
        private const string infoDefinition = "[info]";
        private const string languageDefinition = "[languages]"; 
        private const string objectDefinition = "[objects]";
        private const string driverNameKeyword = "drivername"; 
        private const string symbolFileKeyword = "symbolfile"; 
        private const string defineKeyword = "#define";
        private const string languageKeyword = "language"; 
        private const string DllName = "netfxperf.dll";

        private static string computerName;
        private static string iniFilePath; 
        private static string symbolFilePath;
 
        private PerformanceMonitor performanceMonitor; 
        private string machineName;
        private string perfLcid; 

        private Hashtable customCategoryTable;
        private static Hashtable libraryTable;
        private Hashtable categoryTable; 
        private Hashtable nameTable;
        private Hashtable helpTable; 
        private readonly object CategoryTableLock = new Object(); 
        private readonly object NameTableLock = new Object();
        private readonly object HelpTableLock = new Object(); 

        private static Object s_InternalSyncObject;
        private static Object InternalSyncObject {
            get { 
                if (s_InternalSyncObject == null) {
                    Object o = new Object(); 
                    Interlocked.CompareExchange(ref s_InternalSyncObject, o, null); 
                }
                return s_InternalSyncObject; 
            }
        }

        internal PerformanceCounterLib(string machineName, string lcid) { 
            this.machineName = machineName;
            this.perfLcid = lcid; 
        } 

        ///  
        internal static string ComputerName {
            get {
                if (computerName == null) {
                    lock (InternalSyncObject) { 
                        if (computerName == null) {
                            StringBuilder sb = new StringBuilder(256); 
                            SafeNativeMethods.GetComputerName(sb, new int[] {sb.Capacity}); 
                            computerName = sb.ToString();
                        } 
                    }
                }

                return computerName; 
            }
        } 
 
        private unsafe Hashtable CategoryTable {
            get { 
                if (this.categoryTable == null) {
                    lock (this.CategoryTableLock) {
                        if (this.categoryTable == null) {
                            byte[] perfData =  GetPerformanceData("Global"); 

                            fixed (byte* perfDataPtr = perfData) { 
                                IntPtr dataRef = new IntPtr( (void*) perfDataPtr); 
                                NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK();
                                Marshal.PtrToStructure(dataRef, dataBlock); 
                                dataRef = (IntPtr)((long)dataRef + dataBlock.HeaderLength);
                                int categoryNumber = dataBlock.NumObjectTypes;

                                // on some machines MSMQ claims to have 4 categories, even though it only has 2. 
                                // This causes us to walk past the end of our data, potentially ----ing up or reading
                                // data we shouldn't.  We use endPerfData to make sure we don't go past the end 
                                // of the perf data.  (ASURT 137097) 
                                long endPerfData = (long) perfDataPtr + dataBlock.TotalByteLength;
                                Hashtable tempCategoryTable = new Hashtable(categoryNumber, StringComparer.OrdinalIgnoreCase); 
                                for (int index = 0; index < categoryNumber && ((long) dataRef < endPerfData); index++) {
                                    NativeMethods.PERF_OBJECT_TYPE perfObject = new NativeMethods.PERF_OBJECT_TYPE();

                                    Marshal.PtrToStructure(dataRef, perfObject); 

                                    CategoryEntry newCategoryEntry = new CategoryEntry(perfObject); 
                                    IntPtr nextRef =  (IntPtr)((long)dataRef + perfObject.TotalByteLength); 
                                    dataRef = (IntPtr)((long)dataRef + perfObject.HeaderLength);
 
                                    int index3 = 0;
                                    int previousCounterIndex = -1;
                                    //Need to filter out counters that are repeated, some providers might
                                    //return several adyacent copies of the same counter. 
                                    for (int index2 = 0; index2 < newCategoryEntry.CounterIndexes.Length; ++ index2) {
                                        NativeMethods.PERF_COUNTER_DEFINITION perfCounter = new NativeMethods.PERF_COUNTER_DEFINITION(); 
                                        Marshal.PtrToStructure(dataRef, perfCounter); 
                                        if (perfCounter.CounterNameTitleIndex != previousCounterIndex) {
                                            newCategoryEntry.CounterIndexes[index3] =  perfCounter.CounterNameTitleIndex; 
                                            newCategoryEntry.HelpIndexes[index3] = perfCounter.CounterHelpTitleIndex;
                                            previousCounterIndex = perfCounter.CounterNameTitleIndex;
                                            ++ index3;
                                        } 
                                        dataRef = (IntPtr)((long)dataRef + perfCounter.ByteLength);
                                    } 
 
                                    //Lets adjust the entry counter arrays in case there were repeated copies
                                    if (index3 <  newCategoryEntry.CounterIndexes.Length) { 
                                        int[] adjustedCounterIndexes = new int[index3];
                                        int[] adjustedHelpIndexes = new int[index3];
                                        Array.Copy(newCategoryEntry.CounterIndexes, adjustedCounterIndexes, index3);
                                        Array.Copy(newCategoryEntry.HelpIndexes, adjustedHelpIndexes, index3); 
                                        newCategoryEntry.CounterIndexes = adjustedCounterIndexes;
                                        newCategoryEntry.HelpIndexes = adjustedHelpIndexes; 
                                    } 

                                    string categoryName = (string)this.NameTable[newCategoryEntry.NameIndex]; 
                                    if (categoryName != null)
                                        tempCategoryTable[categoryName] = newCategoryEntry;

                                    dataRef = nextRef; 
                                }
 
                                this.categoryTable = tempCategoryTable; 
                            }
                        } 
                    }
                }

                return this.categoryTable; 
            }
        } 
 
        internal Hashtable HelpTable {
            get { 
                if (this.helpTable == null) {
                    lock(this.HelpTableLock) {
                        if (this.helpTable == null)
                            this.helpTable = GetStringTable(true); 
                    }
                } 
 
                return this.helpTable;
            } 
        }

        // Returns a temp file name
        private static string IniFilePath { 
            [ResourceExposure(ResourceScope.AppDomain)]
            [ResourceConsumption(ResourceScope.AppDomain)] 
            get { 
                if (iniFilePath == null) {
                    lock (InternalSyncObject) { 
                        if (iniFilePath == null) {
                            // Need to assert Environment permissions here
                            //                        the environment check is not exposed as a public
                            //                        method 
                            EnvironmentPermission environmentPermission = new EnvironmentPermission(PermissionState.Unrestricted);
                            environmentPermission.Assert(); 
                            try { 
                                iniFilePath = Path.GetTempFileName();
                            } 
                            finally {
                                 EnvironmentPermission.RevertAssert();
                            }
                        } 
                    }
                } 
 
                return iniFilePath;
            } 
        }

        internal Hashtable NameTable {
            get { 
                if (this.nameTable == null) {
                    lock(this.NameTableLock) { 
                        if (this.nameTable == null) 
                            this.nameTable = GetStringTable(false);
                    } 
                }

                return this.nameTable;
            } 
        }
 
        // Returns a temp file name 
        private static string SymbolFilePath {
            [ResourceExposure(ResourceScope.AppDomain)] 
            [ResourceConsumption(ResourceScope.AppDomain)]
            get {
                if (symbolFilePath == null) {
                    lock (InternalSyncObject) { 
                        if (symbolFilePath == null) {
                            string tempPath; 
 
                            EnvironmentPermission environmentPermission = new EnvironmentPermission(PermissionState.Unrestricted);
                            environmentPermission.Assert(); 
                            tempPath = Path.GetTempPath();
                            EnvironmentPermission.RevertAssert();

                            // We need both FileIOPermission EvironmentPermission 
                            PermissionSet ps = new PermissionSet(PermissionState.None);
                            ps.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted)); 
                            ps.AddPermission(new FileIOPermission(FileIOPermissionAccess.Write, tempPath)); 
                            ps.Assert();
                            try { 
                                symbolFilePath = Path.GetTempFileName();
                            }
                            finally {
                                 PermissionSet.RevertAssert(); 
                            }
                        } 
                    } 
                }
 
                return symbolFilePath;
            }
        }
 
        internal static bool CategoryExists(string machine, string category) {
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009)); 
            if (!library.CategoryExists(category)) { 
                if (CultureInfo.CurrentCulture.Parent.LCID != 0x009) {
                    library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent); 
                    return library.CategoryExists(category);
                }

                return false; 
            }
            return true; 
        } 

        internal bool CategoryExists(string category) { 
            return CategoryTable.ContainsKey(category);
        }

        internal static void CloseAllLibraries() { 
            if (libraryTable != null) {
                foreach (PerformanceCounterLib library in libraryTable.Values) 
                    library.Close(); 

                libraryTable = null; 
            }
        }

        internal static void CloseAllTables() { 
            if (libraryTable != null) {
                foreach (PerformanceCounterLib library in libraryTable.Values) 
                    library.CloseTables(); 
            }
        } 

        internal void CloseTables() {
            this.nameTable = null;
            this.helpTable = null; 
            this.categoryTable = null;
            this.customCategoryTable = null; 
        } 

        internal void Close() { 
            if (this.performanceMonitor != null) {
                this.performanceMonitor.Close();
                this.performanceMonitor = null;
            } 

            CloseTables(); 
        } 

        internal static bool CounterExists(string machine, string category, string counter) { 
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009));
            bool categoryExists = false;
            bool counterExists = library.CounterExists(category, counter, ref categoryExists);
            if (!categoryExists && CultureInfo.CurrentCulture.Parent.LCID != 0x009) { 
                library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent);
                counterExists = library.CounterExists(category, counter, ref categoryExists); 
            } 

            if (!categoryExists) { 
                // Consider adding diagnostic logic here, may be we can dump the nameTable...
                throw new InvalidOperationException(SR.GetString(SR.MissingCategory));
            }
 
            return counterExists;
        } 
 
        private bool CounterExists(string category, string counter, ref bool categoryExists) {
            categoryExists = false; 
            if (!CategoryTable.ContainsKey(category))
                return false;
            else
                categoryExists = true; 

            CategoryEntry entry = (CategoryEntry)this.CategoryTable[category]; 
            for (int index = 0; index < entry.CounterIndexes.Length; ++ index) { 
                int counterIndex = entry.CounterIndexes[index];
                string counterName = (string)this.NameTable[counterIndex]; 
                if (counterName == null)
                   counterName = String.Empty;

                if (String.Compare(counterName, counter, StringComparison.OrdinalIgnoreCase) == 0) 
                    return true;
            } 
 
            return false;
        } 

        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private static void CreateIniFile(string categoryName, string categoryHelp, CounterCreationDataCollection creationData, string[] languageIds) { 
            //SECREVIEW: PerformanceCounterPermission must have been demanded before
            FileIOPermission permission = new FileIOPermission(PermissionState.Unrestricted); 
            permission.Assert(); 
            try {
                StreamWriter iniWriter = new StreamWriter(IniFilePath, false, Encoding.Unicode); 
                try {
                    //NT4 won't be able to parse Unicode ini files without this
                    //extra white space.
                    iniWriter.WriteLine(""); 
                    iniWriter.WriteLine(infoDefinition);
                    iniWriter.Write(driverNameKeyword); 
                    iniWriter.Write("="); 
                    iniWriter.WriteLine(categoryName);
                    iniWriter.Write(symbolFileKeyword); 
                    iniWriter.Write("=");
                    iniWriter.WriteLine(Path.GetFileName(SymbolFilePath));
                    iniWriter.WriteLine("");
 
                    iniWriter.WriteLine(languageDefinition);
                    foreach (string languageId in languageIds) { 
                        iniWriter.Write(languageId); 
                        iniWriter.Write("=");
                        iniWriter.Write(languageKeyword); 
                        iniWriter.WriteLine(languageId);
                    }
                    iniWriter.WriteLine("");
 
                    iniWriter.WriteLine(objectDefinition);
                    foreach (string languageId in languageIds) { 
                        iniWriter.Write(categorySymbolPrefix); 
                        iniWriter.Write("1_");
                        iniWriter.Write(languageId); 
                        iniWriter.Write(nameSufix);
                        iniWriter.Write("=");
                        iniWriter.WriteLine(categoryName);
                    } 
                    iniWriter.WriteLine("");
 
                    iniWriter.WriteLine(textDefinition); 
                    foreach (string languageId in languageIds) {
                        iniWriter.Write(categorySymbolPrefix); 
                        iniWriter.Write("1_");
                        iniWriter.Write(languageId);
                        iniWriter.Write(nameSufix);
                        iniWriter.Write("="); 
                        iniWriter.WriteLine(categoryName);
                        iniWriter.Write(categorySymbolPrefix); 
                        iniWriter.Write("1_"); 
                        iniWriter.Write(languageId);
                        iniWriter.Write(helpSufix); 
                        iniWriter.Write("=");
                        if (categoryHelp == null || categoryHelp == String.Empty)
                            iniWriter.WriteLine(SR.GetString(SR.HelpNotAvailable));
                        else 
                            iniWriter.WriteLine(categoryHelp);
 
 
                        int counterIndex = 0;
                        foreach (CounterCreationData counterData in creationData) { 
                            ++counterIndex;
                            iniWriter.WriteLine("");
                            iniWriter.Write(conterSymbolPrefix);
                            iniWriter.Write(counterIndex.ToString(CultureInfo.InvariantCulture)); 
                            iniWriter.Write("_");
                            iniWriter.Write(languageId); 
                            iniWriter.Write(nameSufix); 
                            iniWriter.Write("=");
                            iniWriter.WriteLine(counterData.CounterName); 

                            iniWriter.Write(conterSymbolPrefix);
                            iniWriter.Write(counterIndex.ToString(CultureInfo.InvariantCulture));
                            iniWriter.Write("_"); 
                            iniWriter.Write(languageId);
                            iniWriter.Write(helpSufix); 
                            iniWriter.Write("="); 

                            Debug.Assert(!String.IsNullOrEmpty(counterData.CounterHelp), "CounterHelp should have been fixed up by the caller"); 
                            iniWriter.WriteLine(counterData.CounterHelp);
                        }
                    }
 
                    iniWriter.WriteLine("");
                } 
                finally { 
                    iniWriter.Close();
                } 
            }
            finally {
                FileIOPermission.RevertAssert();
            } 
        }
 
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private static void CreateRegistryEntry(string categoryName, PerformanceCounterCategoryType categoryType, CounterCreationDataCollection creationData, ref bool iniRegistered) { 
            RegistryKey serviceParentKey = null;
            RegistryKey serviceKey = null;
            RegistryKey linkageKey = null;
 
            //SECREVIEW: Whoever is able to call this function, must already
            //                         have demmanded PerformanceCounterPermission 
            //                         we can therefore assert the RegistryPermission. 
            RegistryPermission registryPermission = new RegistryPermission(PermissionState.Unrestricted);
            registryPermission.Assert(); 
            try {
                serviceParentKey = Registry.LocalMachine.OpenSubKey(ServicePath, true);

                serviceKey = serviceParentKey.OpenSubKey(categoryName + "\\Performance", true); 
                if (serviceKey == null)
                    serviceKey = serviceParentKey.CreateSubKey(categoryName + "\\Performance"); 
 
                serviceKey.SetValue("Open","OpenPerformanceData");
                serviceKey.SetValue("Collect", "CollectPerformanceData"); 
                serviceKey.SetValue("Close","ClosePerformanceData");
                serviceKey.SetValue("Library", DllName);
                serviceKey.SetValue("IsMultiInstance", (int) categoryType, RegistryValueKind.DWord);
                serviceKey.SetValue("CategoryOptions", 0x3, RegistryValueKind.DWord); 

                string [] counters = new string[creationData.Count]; 
                string [] counterTypes = new string[creationData.Count]; 
                for (int i = 0; i < creationData.Count; i++) {
                    counters[i] = creationData[i].CounterName; 
                    counterTypes[i] = ((int) creationData[i].CounterType).ToString(CultureInfo.InvariantCulture);
                }

                linkageKey = serviceParentKey.OpenSubKey(categoryName + "\\Linkage" , true); 
                if (linkageKey == null)
                    linkageKey = serviceParentKey.CreateSubKey(categoryName + "\\Linkage" ); 
 
                linkageKey.SetValue("Export", new string[]{categoryName});
 
                serviceKey.SetValue("Counter Types", (object) counterTypes);
                serviceKey.SetValue("Counter Names", (object) counters);

                object firstID = serviceKey.GetValue("First Counter"); 
                if (firstID != null)
                    iniRegistered  = true; 
                else 
                    iniRegistered  = false;
            } 
            finally {
                if (serviceKey != null)
                    serviceKey.Close();
 
                if (linkageKey != null)
                    linkageKey.Close(); 
 
                if (serviceParentKey != null)
                    serviceParentKey.Close(); 

                RegistryPermission.RevertAssert();
            }
        } 

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        private static void CreateSymbolFile(CounterCreationDataCollection creationData) {
            //SECREVIEW: PerformanceCounterPermission must have been demanded before 
            FileIOPermission permission = new FileIOPermission(PermissionState.Unrestricted);
            permission.Assert();
            try {
                StreamWriter symbolWriter = new StreamWriter(SymbolFilePath); 
                try {
                    symbolWriter.Write(defineKeyword); 
                    symbolWriter.Write(" "); 
                    symbolWriter.Write(categorySymbolPrefix);
                    symbolWriter.WriteLine("1 0;"); 

                    for (int counterIndex = 1; counterIndex <= creationData.Count; ++ counterIndex) {
                        symbolWriter.Write(defineKeyword);
                        symbolWriter.Write(" "); 
                        symbolWriter.Write(conterSymbolPrefix);
                        symbolWriter.Write(counterIndex.ToString(CultureInfo.InvariantCulture)); 
                        symbolWriter.Write(" "); 
                        symbolWriter.Write((counterIndex * 2).ToString(CultureInfo.InvariantCulture));
                        symbolWriter.WriteLine(";"); 
                    }

                    symbolWriter.WriteLine("");
                } 
                finally {
                    symbolWriter.Close(); 
                } 
            }
            finally { 
                FileIOPermission.RevertAssert();
            }
        }
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        private static void DeleteRegistryEntry(string categoryName) { 
            RegistryKey serviceKey = null;
 
            //SECREVIEW: Whoever is able to call this function, must already
            //                         have demmanded PerformanceCounterPermission
            //                         we can therefore assert the RegistryPermission.
            RegistryPermission registryPermission = new RegistryPermission(PermissionState.Unrestricted); 
            registryPermission.Assert();
            try { 
                serviceKey = Registry.LocalMachine.OpenSubKey(ServicePath, true); 

                bool deleteCategoryKey = false; 
                using (RegistryKey categoryKey = serviceKey.OpenSubKey(categoryName, true)) {
                    if (categoryKey != null) {
                        if (categoryKey.GetValueNames().Length == 0) {
                            deleteCategoryKey = true; 
                        }
                        else { 
                            categoryKey.DeleteSubKeyTree("Linkage"); 
                            categoryKey.DeleteSubKeyTree("Performance");
                        } 
                    }
                }
                if (deleteCategoryKey)
                    serviceKey.DeleteSubKeyTree(categoryName); 

            } 
            finally { 
                if (serviceKey != null)
                    serviceKey.Close(); 

                RegistryPermission.RevertAssert();
            }
        } 

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        private static void DeleteTemporaryFiles() {
            try { 
                File.Delete(IniFilePath);
            }
            catch {
            } 

            try { 
                File.Delete(SymbolFilePath); 
            }
            catch { 
            }
        }

        // Ensures that the customCategoryTable is initialized and decides whether the category passed in 
        //  1) is a custom category
        //  2) is a multi instance custom category 
        // The return value is whether the category is a custom category or not. 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        internal bool FindCustomCategory(string category, out PerformanceCounterCategoryType categoryType) {
            RegistryKey key = null;
            RegistryKey baseKey = null;
            categoryType = PerformanceCounterCategoryType.Unknown; 

            if (this.customCategoryTable == null) 
                this.customCategoryTable = new Hashtable(StringComparer.OrdinalIgnoreCase); 

            if (this.customCategoryTable.ContainsKey(category)) { 
                categoryType= (PerformanceCounterCategoryType) this.customCategoryTable[category];
                return true;
            }
            else { 
                //SECREVIEW: Whoever is able to call this function, must already
                //                         have demmanded PerformanceCounterPermission 
                //                         we can therefore assert the RegistryPermission. 
                PermissionSet ps = new PermissionSet(PermissionState.None);
                ps.AddPermission(new RegistryPermission(PermissionState.Unrestricted)); 
                ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
                ps.Assert();
                try {
                    string keyPath = ServicePath + "\\" + category + "\\Performance"; 
                    if (machineName == "." || String.Compare(this.machineName, ComputerName, StringComparison.OrdinalIgnoreCase) == 0) {
                        key = Registry.LocalMachine.OpenSubKey(keyPath); 
                    } 
                    else {
                        baseKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, "\\\\" + this.machineName); 
                        if (baseKey != null) {
                            try {
                                key =  baseKey.OpenSubKey(keyPath);
                            } catch (SecurityException) { 
                                // we may not have permission to read the registry key on the remote machine.  The security exception
                                // is thrown when RegOpenKeyEx returns ERROR_ACCESS_DENIED or ERROR_BAD_IMPERSONATION_LEVEL 
                                // 
                                // In this case we return an 'Unknown' category type and 'false' to indicate the category is *not* custom.
                                // 
                                categoryType = PerformanceCounterCategoryType.Unknown;
                                this.customCategoryTable[category] = categoryType;
                                return false;
                            } 
                        }
                    } 
 
                    if (key != null) {
                        object systemDllName = key.GetValue("Library"); 
                        if (systemDllName != null && systemDllName is string && String.Compare((string)systemDllName, PerformanceCounterLib.PerfShimName, StringComparison.OrdinalIgnoreCase) == 0) {

                            object isMultiInstanceObject = key.GetValue("IsMultiInstance");
                            if (isMultiInstanceObject != null) { 
                                categoryType = (PerformanceCounterCategoryType) isMultiInstanceObject;
                                if (categoryType < PerformanceCounterCategoryType.Unknown || categoryType > PerformanceCounterCategoryType.MultiInstance) 
                                    categoryType = PerformanceCounterCategoryType.Unknown; 
                            }
                            else 
                                categoryType = PerformanceCounterCategoryType.Unknown;

                            object objectID = key.GetValue("First Counter");
                            if (objectID != null) { 
                                int firstID = (int)objectID;
 
                                this.customCategoryTable[category] = categoryType; 
                                return true;
                            } 
                        }
                    }
                }
                finally { 
                    if (key != null) key.Close();
                    if (baseKey != null) baseKey.Close(); 
                    PermissionSet.RevertAssert(); 
                }
            } 
            return false;
        }

        internal static string[] GetCategories(string machineName) { 
            PerformanceCounterLib library = GetPerformanceCounterLib(machineName, CultureInfo.CurrentCulture.Parent);
            string[] categories = library.GetCategories(); 
            if (categories.Length == 0 && CultureInfo.CurrentCulture.Parent.LCID != 0x009) { 
                library = GetPerformanceCounterLib(machineName, new CultureInfo(0x009));
                categories = library.GetCategories(); 
            }

            return categories;
        } 

        internal string[] GetCategories() { 
            ICollection keys = CategoryTable.Keys; 
            string[] categories = new string[keys.Count];
            keys.CopyTo(categories, 0); 
            return categories;
        }

        internal static string GetCategoryHelp(string machine, string category) { 
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009));
            string help = library.GetCategoryHelp(category); 
            if (help == null && CultureInfo.CurrentCulture.Parent.LCID != 0x009) { 
                library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent);
                help = library.GetCategoryHelp(category); 
            }

            if (help == null)
                throw new InvalidOperationException(SR.GetString(SR.MissingCategory)); 

            return help; 
        } 

        private string GetCategoryHelp(string category) { 
            CategoryEntry entry = (CategoryEntry)this.CategoryTable[category];
            if (entry == null)
                return null;
 
            return (string)this.HelpTable[entry.HelpIndex];
        } 
 
        internal static CategorySample GetCategorySample(string machine, string category) {
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009)); 
            CategorySample sample = library.GetCategorySample(category);
            if (sample == null && CultureInfo.CurrentCulture.Parent.LCID != 0x009) {
                library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent);
                sample = library.GetCategorySample(category); 
            }
            if (sample == null) 
                throw new InvalidOperationException(SR.GetString(SR.MissingCategory)); 

            return sample; 
        }

        private CategorySample GetCategorySample(string category) {
            CategoryEntry entry = (CategoryEntry)this.CategoryTable[category]; 
            if (entry == null)
                return null; 
 
            CategorySample sample = null;
            byte[] dataRef = GetPerformanceData(entry.NameIndex.ToString(CultureInfo.InvariantCulture)); 
            if (dataRef == null)
                throw new InvalidOperationException(SR.GetString(SR.CantReadCategory, category));

            sample = new CategorySample(dataRef, entry, this); 
            return sample;
        } 
 
        internal static string[] GetCounters(string machine, string category) {
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009)); 
            bool categoryExists = false;
            string[] counters = library.GetCounters(category, ref categoryExists);
            if (!categoryExists && CultureInfo.CurrentCulture.Parent.LCID != 0x009) {
                library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent); 
                counters = library.GetCounters(category, ref categoryExists);
            } 
 
            if (!categoryExists)
                throw new InvalidOperationException(SR.GetString(SR.MissingCategory)); 

            return counters;
        }
 
        private string[] GetCounters(string category, ref bool categoryExists) {
            categoryExists = false; 
            CategoryEntry entry = (CategoryEntry)this.CategoryTable[category]; 
            if (entry == null)
                return null; 
            else
                categoryExists = true;

            int index2 = 0; 
            string[] counters = new string[entry.CounterIndexes.Length];
            for (int index = 0; index < counters.Length; ++ index) { 
                int counterIndex = entry.CounterIndexes[index]; 
                string counterName = (string)this.NameTable[counterIndex];
                if (counterName != null && counterName != String.Empty) { 
                    counters[index2] = counterName;
                    ++index2;
                }
            } 

            //Lets adjust the array in case there were null entries 
            if (index2 < counters.Length) { 
                string[] adjustedCounters = new string[index2];
                Array.Copy(counters, adjustedCounters, index2); 
                counters = adjustedCounters;
            }

            return counters; 
        }
 
        internal static string GetCounterHelp(string machine, string category, string counter) { 
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009));
            bool categoryExists = false; 
            string help = library.GetCounterHelp(category, counter, ref categoryExists);
            if (!categoryExists && CultureInfo.CurrentCulture.Parent.LCID != 0x009) {
                library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent);
                help = library.GetCounterHelp(category, counter, ref categoryExists); 
            }
 
            if (!categoryExists) 
                throw new InvalidOperationException(SR.GetString(SR.MissingCategoryDetail, category));
 
            return help;
        }

        private string GetCounterHelp(string category, string counter, ref bool categoryExists) { 
            categoryExists = false;
            CategoryEntry entry = (CategoryEntry)this.CategoryTable[category]; 
            if (entry == null) 
                return null;
            else 
                categoryExists = true;

            int helpIndex = -1;
            for (int index = 0; index < entry.CounterIndexes.Length; ++ index) { 
                int counterIndex = entry.CounterIndexes[index];
                string counterName = (string)this.NameTable[counterIndex]; 
                if (counterName == null) 
                   counterName = String.Empty;
 
                if (String.Compare(counterName, counter, StringComparison.OrdinalIgnoreCase) == 0) {
                    helpIndex = entry.HelpIndexes[index];
                    break;
                } 
            }
 
            if (helpIndex == -1) 
                throw new InvalidOperationException(SR.GetString(SR.MissingCounter, counter));
 
            string help = (string)this.HelpTable[helpIndex];
            if (help == null)
                return String.Empty;
            else 
                return help;
        } 
 
        internal string GetCounterName(int index) {
            if (this.NameTable.ContainsKey(index)) 
                return (string)this.NameTable[index];

            return "";
        } 

        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] 
        private static string[] GetLanguageIds() {
            RegistryKey libraryParentKey = null; 
            string[] ids = new string[0];
            new RegistryPermission(PermissionState.Unrestricted).Assert();
            try {
                libraryParentKey = Registry.LocalMachine.OpenSubKey(PerflibPath); 

                if (libraryParentKey != null) 
                    ids = libraryParentKey.GetSubKeyNames(); 
            }
            finally { 
                if (libraryParentKey != null)
                    libraryParentKey.Close();

                RegistryPermission.RevertAssert(); 
            }
 
            return ids; 
        }
 
        internal static PerformanceCounterLib GetPerformanceCounterLib(string machineName, CultureInfo culture) {
            SharedUtils.CheckEnvironment();

            string lcidString = culture.LCID.ToString("X3", CultureInfo.InvariantCulture); 
            if (machineName.CompareTo(".") == 0)
                machineName = ComputerName.ToLower(CultureInfo.InvariantCulture); 
            else 
                machineName = machineName.ToLower(CultureInfo.InvariantCulture);
 
            if (PerformanceCounterLib.libraryTable == null)
                PerformanceCounterLib.libraryTable = new Hashtable();

            string libraryKey = machineName + ":" + lcidString; 
            if (PerformanceCounterLib.libraryTable.Contains(libraryKey))
                return (PerformanceCounterLib)PerformanceCounterLib.libraryTable[libraryKey]; 
            else { 
                PerformanceCounterLib library = new PerformanceCounterLib(machineName, lcidString);
                PerformanceCounterLib.libraryTable[libraryKey] = library; 
                return library;
            }
        }
 
        internal byte[] GetPerformanceData(string item) {
            if (this.performanceMonitor == null) { 
                lock (this) { 
                    if (this.performanceMonitor == null)
                        this.performanceMonitor = new PerformanceMonitor(this.machineName); 
                }
            }

           return this.performanceMonitor.GetData(item); 
        }
 
        [ResourceExposure(ResourceScope.None)] 
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private Hashtable GetStringTable(bool isHelp) { 
            Hashtable stringTable;
            RegistryKey libraryKey;

            PermissionSet ps = new PermissionSet(PermissionState.None); 
            ps.AddPermission(new RegistryPermission(PermissionState.Unrestricted));
            ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)); 
            ps.Assert(); 

            if (String.Compare(this.machineName, ComputerName, StringComparison.OrdinalIgnoreCase) == 0) 
                libraryKey = Registry.PerformanceData;
            else {
                libraryKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.PerformanceData, this.machineName);
            } 

            try { 
                string[] names = null; 
                int waitRetries = 14;   //((2^13)-1)*10ms == approximately 1.4mins
                int waitSleep = 0; 

                // In some stress situations, querying counter values from
                // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009
                // often returns null/empty data back. We should build fault-tolerance logic to 
                // make it more reliable because getting null back once doesn't necessarily mean
                // that the data is corrupted, most of the time we would get the data just fine 
                // in subsequent tries. 
                while (waitRetries > 0) {
                    try { 
                        if (!isHelp)
                            names = (string[])libraryKey.GetValue("Counter " + perfLcid);
                        else
                            names = (string[])libraryKey.GetValue("Explain " + perfLcid); 

                        if ((names == null) || (names.Length == 0)) { 
                            --waitRetries; 
                            if (waitSleep == 0)
                                waitSleep = 10; 
                            else {
                                System.Threading.Thread.Sleep(waitSleep);
                                waitSleep *= 2;
                            } 
                        }
                        else 
                            break; 
                    }
                    catch (IOException) { 
                        // RegistryKey throws if it can't find the value.  We want to return an empty table
                        // and throw a different exception higher up the stack.
                        names = null;
                        break; 
                    }
 
                } 

                if (names == null) 
                    stringTable = new Hashtable();
                else {
                    stringTable = new Hashtable(names.Length/2);
 
                    for (int index = 0; index < (names.Length/2); ++ index) {
                        string nameString =  names[(index *2) + 1]; 
                        if (nameString == null) 
                            nameString = String.Empty;
 
                        stringTable[Int32.Parse(names[index * 2], CultureInfo.InvariantCulture)] = nameString;
                    }
                }
            } 
            finally {
                libraryKey.Close(); 
            } 

            return stringTable; 
        }

        internal static bool IsCustomCategory(string machine, string category) {
            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009)); 
            if (!library.IsCustomCategory(category)) {
                if (CultureInfo.CurrentCulture.Parent.LCID != 0x009) { 
                    library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent); 
                    return library.IsCustomCategory(category);
                } 

                return false;
            }
            return true; 
        }
 
        internal static bool IsBaseCounter(int type) { 
            return (type == NativeMethods.PERF_AVERAGE_BASE ||
                    type == NativeMethods.PERF_COUNTER_MULTI_BASE || 
                    type == NativeMethods.PERF_RAW_BASE  ||
                    type == NativeMethods.PERF_LARGE_RAW_BASE  ||
                    type == NativeMethods.PERF_SAMPLE_BASE);
        } 

        private bool IsCustomCategory(string category) { 
            PerformanceCounterCategoryType categoryType; 

            return FindCustomCategory(category, out categoryType); 
        }

        internal static PerformanceCounterCategoryType GetCategoryType(string machine, string category) {
            PerformanceCounterCategoryType categoryType = PerformanceCounterCategoryType.Unknown; 

            PerformanceCounterLib library = GetPerformanceCounterLib(machine, new CultureInfo(0x009)); 
            if (!library.FindCustomCategory(category, out categoryType)) { 
                if (CultureInfo.CurrentCulture.Parent.LCID != 0x009) {
                    library = GetPerformanceCounterLib(machine, CultureInfo.CurrentCulture.Parent); 
                    library.FindCustomCategory(category, out categoryType);
                }
            }
            return categoryType; 
        }
 
        /* 
        // Creates a category with an ini file supplied by the user.  Currently this is not available.
        internal static void RegisterCategory(string machineName, string categoryName, string categoryHelp, CounterCreationDataCollection creationData, string localizedIniFilePath) { 
            bool iniRegistered = false;
            CreateRegistryEntry(machineName, categoryName, creationData, ref iniRegistered);
            if (!iniRegistered)
                RegisterFiles(machineName, localizedIniFilePath, false); 

            CloseAllTables(); 
        } 
        */
 
        internal static void RegisterCategory(string categoryName, PerformanceCounterCategoryType categoryType, string categoryHelp, CounterCreationDataCollection creationData) {
            try {
                bool iniRegistered = false;
                CreateRegistryEntry(categoryName, categoryType, creationData, ref iniRegistered); 
                if (!iniRegistered) {
                    string[] languageIds = GetLanguageIds(); 
                    CreateIniFile(categoryName, categoryHelp, creationData, languageIds); 
                    CreateSymbolFile(creationData);
                    RegisterFiles(IniFilePath, false); 
                }
                CloseAllTables();
                CloseAllLibraries();
            } 
            finally {
                DeleteTemporaryFiles(); 
            } 
        }
 
        [ResourceExposure(ResourceScope.None)]
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        private static void RegisterFiles(string arg0, bool unregister) {
            Process p; 
            ProcessStartInfo processStartInfo = new ProcessStartInfo();
            processStartInfo.UseShellExecute = false; 
            processStartInfo.CreateNoWindow = true; 
            processStartInfo.ErrorDialog = false;
            processStartInfo.WindowStyle = ProcessWindowStyle.Hidden; 
            processStartInfo.WorkingDirectory = Environment.SystemDirectory;

            if (unregister)
                processStartInfo.FileName = Environment.SystemDirectory + "\\unlodctr.exe"; 
            else
                processStartInfo.FileName = Environment.SystemDirectory + "\\lodctr.exe"; 
 
            int res = 0;
            new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); 
            try {
                processStartInfo.Arguments = "\"" + arg0 + "\"";
                p = Process.Start(processStartInfo);
                p.WaitForExit(); 

                res = p.ExitCode; 
            } 
            finally {
                SecurityPermission.RevertAssert(); 
            }

            // Look at Q269225, unlodctr might return 2 when WMI is not installed.
            if (unregister && res == 2) 
                res = 0;
 
            if (res != 0) 
                throw SharedUtils.CreateSafeWin32Exception(res);
        } 

        internal static void UnregisterCategory(string categoryName) {
            RegisterFiles(categoryName, true);
            DeleteRegistryEntry(categoryName); 
            CloseAllTables();
            CloseAllLibraries(); 
        } 
    }
 
    internal class PerformanceMonitor {
        private RegistryKey perfDataKey = null;
        private string machineName;
 
        internal PerformanceMonitor(string machineName) {
            this.machineName = machineName; 
            Init(); 
        }
 
        private void Init() {
            try {
                if (machineName != "." && String.Compare(machineName, PerformanceCounterLib.ComputerName, StringComparison.OrdinalIgnoreCase) != 0) {
                    new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); 
                    perfDataKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.PerformanceData, machineName);
                } 
                else 
                    perfDataKey = Registry.PerformanceData;
            } 
            catch (UnauthorizedAccessException) {
                // we need to do this for compatibility with v1.1 and v1.0.
                throw new Win32Exception(NativeMethods.ERROR_ACCESS_DENIED);
            } 
            catch (IOException e) {
                // we need to do this for compatibility with v1.1 and v1.0. 
                throw new Win32Exception(Marshal.GetHRForException(e)); 
            }
        } 

        internal void Close() {
            if( perfDataKey != null)
                perfDataKey.Close(); 

            perfDataKey = null; 
        } 

        // Win32 RegQueryValueEx for perf data could deadlock (for a Mutex) up to 2mins in some 
        // scenarios before they detect it and exit gracefully. In the mean time, ERROR_BUSY,
        // ERROR_NOT_READY etc can be seen by other concurrent calls (which is the reason for the
        // wait loop and switch case below). We want to wait most certainly more than a 2min window.
        // The curent wait time of up to 10mins takes care of the known stress deadlock issues. In most 
        // cases we wouldn't wait for more than 2mins anyways but in worst cases how much ever time
        // we wait may not be sufficient if the Win32 code keeps running into this deadlock again 
        // and again. A condition very rare but possible in theory. We would get back to the user 
        // in this case with InvalidOperationException after the wait time expires.
        internal byte[] GetData(string item) { 
            int waitRetries = 17;   //2^16*10ms == approximately 10mins
            int waitSleep = 0;
            byte[] data = null;
            int error = 0; 

            // no need to revert here since we'll fall off the end of the method 
            new RegistryPermission(PermissionState.Unrestricted).Assert(); 
            while (waitRetries > 0) {
                try { 
                    data = (byte[]) perfDataKey.GetValue(item);
                    return data;
                }
                catch (IOException e) { 
                    error = Marshal.GetHRForException(e);
                    switch (error) { 
                        case NativeMethods.RPC_S_CALL_FAILED: 
                        case NativeMethods.ERROR_INVALID_HANDLE:
                        case NativeMethods.RPC_S_SERVER_UNAVAILABLE: 
                            Init();
                            goto case NativeMethods.WAIT_TIMEOUT;

                        case NativeMethods.WAIT_TIMEOUT: 
                        case NativeMethods.ERROR_NOT_READY:
                        case NativeMethods.ERROR_LOCK_FAILED: 
                        case NativeMethods.ERROR_BUSY: 
                            --waitRetries;
                            if (waitSleep == 0) { 
                                waitSleep = 10;
                            }
                            else {
                                System.Threading.Thread.Sleep(waitSleep); 
                                waitSleep *= 2;
                            } 
                            break; 

                        default: 
                            throw SharedUtils.CreateSafeWin32Exception(error);
                    }
                }
            } 

            throw SharedUtils.CreateSafeWin32Exception(error); 
        } 

    } 

    internal class CategoryEntry {
        internal int NameIndex;
        internal int HelpIndex; 
        internal int[] CounterIndexes;
        internal int[] HelpIndexes; 
 
        internal CategoryEntry(NativeMethods.PERF_OBJECT_TYPE perfObject) {
            this.NameIndex = perfObject.ObjectNameTitleIndex; 
            this.HelpIndex = perfObject.ObjectHelpTitleIndex;
            this.CounterIndexes = new int[perfObject.NumCounters];
            this.HelpIndexes = new int[perfObject.NumCounters];
        } 
    }
 
    internal class CategorySample { 
        internal readonly long SystemFrequency;
        internal readonly long TimeStamp; 
        internal readonly long TimeStamp100nSec;
        internal readonly long CounterFrequency;
        internal readonly long CounterTimeStamp;
        internal Hashtable CounterTable; 
        internal Hashtable InstanceNameTable;
        internal bool IsMultiInstance; 
        private CategoryEntry entry; 
        private PerformanceCounterLib library;
 
        internal unsafe CategorySample(byte[] data, CategoryEntry entry, PerformanceCounterLib library) {
            this.entry = entry;
            this.library = library;
            int categoryIndex = entry.NameIndex; 
            NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK();
            fixed (byte* dataPtr = data) { 
                IntPtr dataRef = new IntPtr((void*) dataPtr); 

                Marshal.PtrToStructure(dataRef, dataBlock); 
                this.SystemFrequency = dataBlock.PerfFreq;
                this.TimeStamp = dataBlock.PerfTime;
                this.TimeStamp100nSec = dataBlock.PerfTime100nSec;
                dataRef = (IntPtr)((long)dataRef + dataBlock.HeaderLength); 
                int numPerfObjects = dataBlock.NumObjectTypes;
                if (numPerfObjects == 0) { 
                    this.CounterTable = new Hashtable(); 
                    this.InstanceNameTable = new Hashtable(StringComparer.OrdinalIgnoreCase);
                    return; 
                }

                //Need to find the right category, GetPerformanceData might return
                //several of them. 
                NativeMethods.PERF_OBJECT_TYPE perfObject = null;
                bool foundCategory = false; 
                for (int index = 0; index < numPerfObjects; index++) { 
                    perfObject = new NativeMethods.PERF_OBJECT_TYPE();
                    Marshal.PtrToStructure(dataRef, perfObject); 

                   if (perfObject.ObjectNameTitleIndex == categoryIndex) {
                        foundCategory = true;
                        break; 
                    }
 
                    dataRef = (IntPtr)((long)dataRef + perfObject.TotalByteLength); 
                }
 
                if (!foundCategory)
                    throw new InvalidOperationException(SR.GetString(SR.CantReadCategoryIndex, categoryIndex.ToString(CultureInfo.CurrentCulture)));

                this.CounterFrequency = perfObject.PerfFreq; 
                this.CounterTimeStamp = perfObject.PerfTime;
                int counterNumber = perfObject.NumCounters; 
                int instanceNumber = perfObject.NumInstances; 

                if (instanceNumber == -1) 
                    IsMultiInstance = false;
                else
                    IsMultiInstance = true;
 
                // Move pointer forward to end of PERF_OBJECT_TYPE
                dataRef = (IntPtr)((long)dataRef + perfObject.HeaderLength); 
 
                CounterDefinitionSample[] samples = new CounterDefinitionSample[counterNumber];
                this.CounterTable = new Hashtable(counterNumber); 
                for (int index = 0; index < samples.Length; ++ index) {
                    NativeMethods.PERF_COUNTER_DEFINITION perfCounter = new NativeMethods.PERF_COUNTER_DEFINITION();
                    Marshal.PtrToStructure(dataRef, perfCounter);
                    samples[index] = new CounterDefinitionSample(perfCounter, this, instanceNumber); 
                    dataRef = (IntPtr)((long)dataRef + perfCounter.ByteLength);
 
                    int currentSampleType = samples[index].CounterType; 
                    if (!PerformanceCounterLib.IsBaseCounter(currentSampleType)) {
                        // We'll put only non-base counters in the table. 
                        if (currentSampleType != NativeMethods.PERF_COUNTER_NODATA)
                            this.CounterTable[samples[index].NameIndex] = samples[index];
                    }
                    else { 
                        // it's a base counter, try to hook it up to the main counter.
                        Debug.Assert(index > 0, "Index > 0 because base counters should never be at index 0"); 
                        if (index > 0) 
                            samples[index-1].BaseCounterDefinitionSample = samples[index];
                    } 
                }

                // now set up the InstanceNameTable.
                if (!IsMultiInstance) { 
                    this.InstanceNameTable = new Hashtable(1, StringComparer.OrdinalIgnoreCase);
                    this.InstanceNameTable[PerformanceCounterLib.SingleInstanceName] = 0; 
 
                    for (int index = 0; index < samples.Length; ++ index)  {
                        samples[index].SetInstanceValue(0, dataRef); 
                    }
                }
                else {
                    string[] parentInstanceNames = null; 
                    this.InstanceNameTable = new Hashtable(instanceNumber, StringComparer.OrdinalIgnoreCase);
                    for (int i = 0; i < instanceNumber; i++) { 
                        NativeMethods.PERF_INSTANCE_DEFINITION perfInstance = new NativeMethods.PERF_INSTANCE_DEFINITION(); 
                        Marshal.PtrToStructure(dataRef, perfInstance);
                        if (perfInstance.ParentObjectTitleIndex > 0 && parentInstanceNames == null) 
                            parentInstanceNames = GetInstanceNamesFromIndex(perfInstance.ParentObjectTitleIndex);

                        string instanceName;
                        if (parentInstanceNames != null && perfInstance.ParentObjectInstance >= 0 && perfInstance.ParentObjectInstance < parentInstanceNames.Length - 1) 
                            instanceName = parentInstanceNames[perfInstance.ParentObjectInstance] + "/" + Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset));
                        else 
                            instanceName = Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset)); 

                        //In some cases instance names are not unique (Process), same as perfmon 
                        //generate a unique name.
                        string newInstanceName = instanceName;
                        int newInstanceNumber = 1;
                        while (true) { 
                            if (!this.InstanceNameTable.ContainsKey(newInstanceName)) {
                                this.InstanceNameTable[newInstanceName] = i; 
                                break; 
                            }
                            else { 
                                newInstanceName =  instanceName + "#" + newInstanceNumber.ToString(CultureInfo.InvariantCulture);
                                ++  newInstanceNumber;
                            }
                        } 

 
                        dataRef = (IntPtr)((long)dataRef + perfInstance.ByteLength); 
                        for (int index = 0; index < samples.Length; ++ index)
                            samples[index].SetInstanceValue(i, dataRef); 

                        dataRef = (IntPtr)((long)dataRef + Marshal.ReadInt32(dataRef));
                    }
                } 
            }
        } 
 
        internal unsafe string[] GetInstanceNamesFromIndex(int categoryIndex) {
            byte[] data = library.GetPerformanceData(categoryIndex.ToString(CultureInfo.InvariantCulture)); 
            fixed (byte* dataPtr = data) {
                IntPtr dataRef = new IntPtr((void*) dataPtr);

                NativeMethods.PERF_DATA_BLOCK dataBlock = new NativeMethods.PERF_DATA_BLOCK(); 
                Marshal.PtrToStructure(dataRef, dataBlock);
                dataRef = (IntPtr)((long)dataRef + dataBlock.HeaderLength); 
                int numPerfObjects = dataBlock.NumObjectTypes; 

                NativeMethods.PERF_OBJECT_TYPE perfObject = null; 
                bool foundCategory = false;
                for (int index = 0; index < numPerfObjects; index++) {
                    perfObject = new NativeMethods.PERF_OBJECT_TYPE();
                    Marshal.PtrToStructure(dataRef, perfObject); 

                    if (perfObject.ObjectNameTitleIndex == categoryIndex) { 
                        foundCategory = true; 
                        break;
                    } 

                    dataRef = (IntPtr)((long)dataRef + perfObject.TotalByteLength);
                }
 
                if (!foundCategory)
                    return new string[0]; 
 
                int counterNumber = perfObject.NumCounters;
                int instanceNumber = perfObject.NumInstances; 
                dataRef = (IntPtr)((long)dataRef + perfObject.HeaderLength);

                if (instanceNumber == -1)
                    return new string[0]; 

                CounterDefinitionSample[] samples = new CounterDefinitionSample[counterNumber]; 
                for (int index = 0; index < samples.Length; ++ index) { 
                    NativeMethods.PERF_COUNTER_DEFINITION perfCounter = new NativeMethods.PERF_COUNTER_DEFINITION();
                    Marshal.PtrToStructure(dataRef, perfCounter); 
                    dataRef = (IntPtr)((long)dataRef + perfCounter.ByteLength);
                }

                string[] instanceNames = new string[instanceNumber]; 
                for (int i = 0; i < instanceNumber; i++) {
                    NativeMethods.PERF_INSTANCE_DEFINITION perfInstance = new NativeMethods.PERF_INSTANCE_DEFINITION(); 
                    Marshal.PtrToStructure(dataRef, perfInstance); 
                    instanceNames[i] =  Marshal.PtrToStringUni((IntPtr)((long)dataRef + perfInstance.NameOffset));
                    dataRef = (IntPtr)((long)dataRef + perfInstance.ByteLength); 
                    dataRef = (IntPtr)((long)dataRef + Marshal.ReadInt32(dataRef));
                }

                return instanceNames; 
            }
        } 
 
        internal CounterDefinitionSample GetCounterDefinitionSample(string counter) {
            for (int index = 0; index < this.entry.CounterIndexes.Length; ++ index) { 
                int counterIndex = entry.CounterIndexes[index];
                string counterName = (string)this.library.NameTable[counterIndex];
                if (counterName != null) {
                    if (String.Compare(counterName, counter, StringComparison.OrdinalIgnoreCase) == 0) { 
                        CounterDefinitionSample sample = (CounterDefinitionSample)this.CounterTable[counterIndex];
                        if (sample == null) { 
                            //This is a base counter and has not been added to the table 
                            foreach (CounterDefinitionSample multiSample in this.CounterTable.Values) {
                                if (multiSample.BaseCounterDefinitionSample != null && 
                                    multiSample.BaseCounterDefinitionSample.NameIndex == counterIndex)
                                    return multiSample.BaseCounterDefinitionSample;
                            }
 
                            throw new InvalidOperationException(SR.GetString(SR.CounterLayout));
                        } 
                        return sample; 
                    }
                } 
            }

            throw new InvalidOperationException(SR.GetString(SR.CantReadCounter, counter));
        } 

        internal InstanceDataCollectionCollection ReadCategory() { 
 
#pragma warning disable 618
            InstanceDataCollectionCollection data = new InstanceDataCollectionCollection(); 
#pragma warning restore 618
            for (int index = 0; index < this.entry.CounterIndexes.Length; ++ index) {
                int counterIndex = entry.CounterIndexes[index];
 
                string name = (string)library.NameTable[counterIndex];
                if (name != null && name != String.Empty) { 
                    CounterDefinitionSample sample = (CounterDefinitionSample)this.CounterTable[counterIndex]; 
                    if (sample != null)
                        //If the current index refers to a counter base, 
                        //the sample will be null
                        data.Add(name, sample.ReadInstanceData(name));
                }
            } 

            return data; 
        } 
    }
 
    internal class CounterDefinitionSample {
        internal readonly int NameIndex;
        internal readonly int CounterType;
        internal CounterDefinitionSample BaseCounterDefinitionSample; 

        private readonly int size; 
        private readonly int offset; 
        private long[] instanceValues;
        private CategorySample categorySample; 

        internal CounterDefinitionSample(NativeMethods.PERF_COUNTER_DEFINITION perfCounter, CategorySample categorySample, int instanceNumber) {
            this.NameIndex = perfCounter.CounterNameTitleIndex;
            this.CounterType = perfCounter.CounterType; 
            this.offset = perfCounter.CounterOffset;
            this.size = perfCounter.CounterSize; 
            if (instanceNumber == -1) { 
                this.instanceValues = new long[1];
            } 
            else
                this.instanceValues = new long[instanceNumber];

            this.categorySample = categorySample; 
        }
 
        private long ReadValue(IntPtr pointer) { 
            if (this.size == 4) {
                return (long)(uint)Marshal.ReadInt32((IntPtr)((long)pointer + this.offset)); 
            }
            else if (this.size == 8) {
                return (long)Marshal.ReadInt64((IntPtr)((long)pointer + this.offset));
            } 

            return -1; 
        } 

        internal CounterSample GetInstanceValue(string instanceName) { 

            if (!categorySample.InstanceNameTable.ContainsKey(instanceName)) {
                // Our native dll truncates instance names to 128 characters.  If we can't find the instance
                // with the full name, try truncating to 128 characters. 
                if (instanceName.Length > SharedPerformanceCounter.InstanceNameMaxLength)
                    instanceName = instanceName.Substring(0, SharedPerformanceCounter.InstanceNameMaxLength); 
 
                if (!categorySample.InstanceNameTable.ContainsKey(instanceName))
                    throw new InvalidOperationException(SR.GetString(SR.CantReadInstance, instanceName)); 
            }

            int index = (int)categorySample.InstanceNameTable[instanceName];
            long rawValue = this.instanceValues[index]; 
            long baseValue = 0;
            if (this.BaseCounterDefinitionSample != null) { 
                CategorySample baseCategorySample = this.BaseCounterDefinitionSample.categorySample; 
                int baseIndex = (int)baseCategorySample.InstanceNameTable[instanceName];
                baseValue = this.BaseCounterDefinitionSample.instanceValues[baseIndex]; 
            }

            return new CounterSample(rawValue,
                                                        baseValue, 
                                                        categorySample.CounterFrequency,
                                                        categorySample.SystemFrequency, 
                                                        categorySample.TimeStamp, 
                                                        categorySample.TimeStamp100nSec,
                                                        (PerformanceCounterType)this.CounterType, 
                                                        categorySample.CounterTimeStamp);

        }
 
        internal InstanceDataCollection ReadInstanceData(string counterName) {
#pragma warning disable 618 
            InstanceDataCollection data = new InstanceDataCollection(counterName); 
#pragma warning restore 618
 
            string[] keys = new string[categorySample.InstanceNameTable.Count];
            categorySample.InstanceNameTable.Keys.CopyTo(keys, 0);
            int[] indexes = new int[categorySample.InstanceNameTable.Count];
            categorySample.InstanceNameTable.Values.CopyTo(indexes, 0); 
            for (int index = 0; index < keys.Length; ++ index) {
                long baseValue = 0; 
                if (this.BaseCounterDefinitionSample != null) { 
                    CategorySample baseCategorySample = this.BaseCounterDefinitionSample.categorySample;
                    int baseIndex = (int)baseCategorySample.InstanceNameTable[keys[index]]; 
                    baseValue = this.BaseCounterDefinitionSample.instanceValues[baseIndex];
                }

                CounterSample sample = new CounterSample(this.instanceValues[indexes[index]], 
                                                        baseValue,
                                                        categorySample.CounterFrequency, 
                                                        categorySample.SystemFrequency, 
                                                        categorySample.TimeStamp,
                                                        categorySample.TimeStamp100nSec, 
                                                        (PerformanceCounterType)this.CounterType,
                                                        categorySample.CounterTimeStamp);

                data.Add(keys[index], new InstanceData(keys[index], sample)); 
            }
 
            return data; 
        }
 
        internal CounterSample GetSingleValue() {
            long rawValue = this.instanceValues[0];
            long baseValue = 0;
            if (this.BaseCounterDefinitionSample != null) 
                baseValue = this.BaseCounterDefinitionSample.instanceValues[0];
 
            return new CounterSample(rawValue, 
                                                        baseValue,
                                                        categorySample.CounterFrequency, 
                                                        categorySample.SystemFrequency,
                                                        categorySample.TimeStamp,
                                                        categorySample.TimeStamp100nSec,
                                                        (PerformanceCounterType)this.CounterType, 
                                                        categorySample.CounterTimeStamp);
        } 
 
        internal void SetInstanceValue(int index, IntPtr dataRef) {
            long rawValue = ReadValue(dataRef); 
            this.instanceValues[index] = rawValue;
        }
    }
} 

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

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