Debug.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / Configuration / System / Configuration / Debug.cs / 1 / Debug.cs

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

namespace System.Configuration { 
    using Microsoft.Win32; 
    using Microsoft.Win32.SafeHandles;
    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization; 
    using System.Reflection;
    using System.Runtime.ConstrainedExecution; 
    using System.Runtime.InteropServices; 
    using System.Security;
    using System.Security.Permissions; 
    using System.Threading;

    internal static class Debug {
 
        internal const string   TAG_INTERNAL = "Internal";
        internal const string   TAG_EXTERNAL = "External"; 
        internal const string   TAG_ALL      = "*"; 

        internal const string   DATE_FORMAT = @"yyyy/MM/dd HH:mm:ss.ffff"; 
        internal const string   TIME_FORMAT = @"HH:mm:ss:ffff";

#if DBG
        [System.Security.SuppressUnmanagedCodeSecurityAttribute()] 
        private static class NativeMethods {
            [DllImport("kernel32.dll")] 
            internal extern static int GetCurrentProcessId(); 

            [DllImport("kernel32.dll")] 
            internal extern static int GetCurrentThreadId();

            [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
            internal extern static IntPtr GetCurrentProcess(); 

            [DllImport("kernel32.dll", SetLastError=true)] 
            internal extern static bool TerminateProcess(HandleRef processHandle, int exitCode); 

            [DllImport("kernel32.dll", CharSet=CharSet.Auto, BestFitMapping=false)] 
            internal extern static void OutputDebugString(string message);

            internal const int PM_NOREMOVE = 0x0000;
            internal const int PM_REMOVE = 0x0001; 

            [StructLayout(LayoutKind.Sequential)] 
            internal struct MSG { 
                internal IntPtr   hwnd;
                internal int      message; 
                internal IntPtr   wParam;
                internal IntPtr   lParam;
                internal int      time;
                internal int      pt_x; 
                internal int      pt_y;
            } 
 
            [DllImport("user32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto)]
            internal extern static bool PeekMessage([In, Out] ref MSG msg, HandleRef hwnd, int msgMin, int msgMax, int remove); 

            internal const int
                MB_OK = 0x00000000,
                MB_OKCANCEL = 0x00000001, 
                MB_ABORTRETRYIGNORE = 0x00000002,
                MB_YESNOCANCEL = 0x00000003, 
                MB_YESNO = 0x00000004, 
                MB_RETRYCANCEL = 0x00000005,
                MB_ICONHAND = 0x00000010, 
                MB_ICONQUESTION = 0x00000020,
                MB_ICONEXCLAMATION = 0x00000030,
                MB_ICONASTERISK = 0x00000040,
                MB_USERICON = 0x00000080, 
                MB_ICONWARNING = 0x00000030,
                MB_ICONERROR = 0x00000010, 
                MB_ICONINFORMATION = 0x00000040, 
                MB_DEFBUTTON1 = 0x00000000,
                MB_DEFBUTTON2 = 0x00000100, 
                MB_DEFBUTTON3 = 0x00000200,
                MB_DEFBUTTON4 = 0x00000300,
                MB_APPLMODAL = 0x00000000,
                MB_SYSTEMMODAL = 0x00001000, 
                MB_TASKMODAL = 0x00002000,
                MB_HELP = 0x00004000, 
                MB_NOFOCUS = 0x00008000, 
                MB_SETFOREGROUND = 0x00010000,
                MB_DEFAULT_DESKTOP_ONLY = 0x00020000, 
                MB_TOPMOST = 0x00040000,
                MB_RIGHT = 0x00080000,
                MB_RTLREADING = 0x00100000,
                MB_SERVICE_NOTIFICATION = 0x00200000, 
                MB_SERVICE_NOTIFICATION_NT3X = 0x00040000,
                MB_TYPEMASK = 0x0000000F, 
                MB_ICONMASK = 0x000000F0, 
                MB_DEFMASK = 0x00000F00,
                MB_MODEMASK = 0x00003000, 
                MB_MISCMASK = 0x0000C000;

            internal const int
                IDOK = 1, 
                IDCANCEL = 2,
                IDABORT = 3, 
                IDRETRY = 4, 
                IDIGNORE = 5,
                IDYES = 6, 
                IDNO = 7,
                IDCLOSE = 8,
                IDHELP = 9;
 

            [DllImport("user32.dll", CharSet=CharSet.Auto, BestFitMapping=false)] 
            internal extern static int MessageBox(HandleRef hWnd, string text, string caption, int type); 

            internal static readonly IntPtr HKEY_LOCAL_MACHINE = unchecked((IntPtr)(int)0x80000002); 

            internal const int READ_CONTROL           = 0x00020000;
            internal const int STANDARD_RIGHTS_READ   = READ_CONTROL;
 
            internal const int SYNCHRONIZE            = 0x00100000;
 
            internal const int KEY_QUERY_VALUE        = 0x0001; 
            internal const int KEY_ENUMERATE_SUB_KEYS = 0x0008;
            internal const int KEY_NOTIFY             = 0x0010; 


            internal const int KEY_READ               = ((STANDARD_RIGHTS_READ |
                                                               KEY_QUERY_VALUE | 
                                                               KEY_ENUMERATE_SUB_KEYS |
                                                               KEY_NOTIFY) 
                                                              & 
                                                              (~SYNCHRONIZE));
 
            internal const int REG_NOTIFY_CHANGE_NAME       = 1;
            internal const int REG_NOTIFY_CHANGE_LAST_SET   = 4;

 
            [DllImport("advapi32.dll", CharSet=CharSet.Auto, BestFitMapping=false, SetLastError=true)]
            internal extern static int RegOpenKeyEx(IntPtr hKey, string lpSubKey, int ulOptions, int samDesired, out SafeRegistryHandle hkResult); 
 
            [DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true)]
            internal extern static int RegNotifyChangeKeyValue(SafeRegistryHandle hKey, bool watchSubTree, uint notifyFilter, SafeWaitHandle regEvent, bool async); 
        }

        private class SafeRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid {
 
            // Note: Officially -1 is the recommended invalid handle value for
            // registry keys, but we'll also get back 0 as an invalid handle from 
            // RegOpenKeyEx. 

            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)] 
            internal SafeRegistryHandle() : base(true) {}

            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)]
            internal SafeRegistryHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) { 
                SetHandle(preexistingHandle);
            } 
 
            [DllImport("advapi32.dll"),
             SuppressUnmanagedCodeSecurity, 
             ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            private static extern int RegCloseKey(IntPtr hKey);

            override protected bool ReleaseHandle() 
            {
                // Returns a Win32 error code, 0 for success 
                int r = RegCloseKey(handle); 
                return r == 0;
            } 
        }

        private enum TagValue {
            Disabled = 0, 
            Enabled = 1,
            Break = 2, 
 
            Min = Disabled,
            Max = Break, 
        }

        private const string            TAG_ASSERT = "Assert";
        private const string            TAG_ASSERT_BREAK = "AssertBreak"; 

        private const string            TAG_DEBUG_VERBOSE = "DebugVerbose"; 
        private const string            TAG_DEBUG_MONITOR = "DebugMonitor"; 
        private const string            TAG_DEBUG_PREFIX = "DebugPrefix";
        private const string            TAG_DEBUG_THREAD_PREFIX = "DebugThreadPrefix"; 

        private const string            PRODUCT = "Microsoft .NET Framework";
        private const string            COMPONENT = "System.Configuration";
 
        private static string           s_regKeyName = @"Software\Microsoft\ASP.NET\Debug";
        private static string           s_listenKeyName = @"Software\Microsoft"; 
 
        private static bool             s_assert;
        private static bool             s_assertBreak; 

        private static bool             s_includePrefix;
        private static bool             s_includeThreadPrefix;
        private static bool             s_monitor; 

        private static object           s_lock; 
        private static volatile bool    s_inited; 
        private static ReadOnlyCollection  s_tagDefaults;
        private static List        s_tags; 

        private static AutoResetEvent       s_notifyEvent;
        private static RegisteredWaitHandle s_waitHandle;
        private static SafeRegistryHandle   s_regHandle; 
        private static bool                 s_stopMonitoring;
 
        private static Hashtable        s_tableAlwaysValidate; 
        private static Type[]           s_DumpArgs;
        private static Type[]           s_ValidateArgs; 


        private class Tag {
            string      _name; 
            TagValue    _value;
            int         _prefixLength; 
 
            internal Tag(string name, TagValue value) {
                _name = name; 
                _value = value;

                if (_name[_name.Length - 1] == '*') {
                    _prefixLength = _name.Length - 1; 
                }
                else { 
                    _prefixLength = -1; 
                }
            } 

            internal string Name {
                get {return _name;}
            } 

            internal TagValue Value { 
                get {return _value;} 
            }
 
            internal int PrefixLength {
                get {return _prefixLength;}
            }
        } 

        static Debug() { 
            s_lock = new object(); 
        }
 
        private static void EnsureInit() {
            bool continueInit = false;

            if (!s_inited) { 
                lock (s_lock) {
                    if (!s_inited) { 
                        s_tableAlwaysValidate = new Hashtable(); 
                        s_DumpArgs = new Type[1] {typeof(string)};
                        s_ValidateArgs = new Type[0]; 

                        List tagDefaults = new List();
                        tagDefaults.Add(new Tag(TAG_ALL, TagValue.Disabled));
                        tagDefaults.Add(new Tag(TAG_INTERNAL, TagValue.Enabled)); 
                        tagDefaults.Add(new Tag(TAG_EXTERNAL, TagValue.Enabled));
                        tagDefaults.Add(new Tag(TAG_ASSERT, TagValue.Break)); 
                        tagDefaults.Add(new Tag(TAG_ASSERT_BREAK, TagValue.Disabled)); 
                        tagDefaults.Add(new Tag(TAG_DEBUG_VERBOSE, TagValue.Enabled));
                        tagDefaults.Add(new Tag(TAG_DEBUG_MONITOR, TagValue.Enabled)); 
                        tagDefaults.Add(new Tag(TAG_DEBUG_PREFIX, TagValue.Enabled));
                        tagDefaults.Add(new Tag(TAG_DEBUG_THREAD_PREFIX, TagValue.Enabled));

                        s_tagDefaults = tagDefaults.AsReadOnly(); 
                        s_tags = new List(s_tagDefaults);
                        GetBuiltinTagValues(); 
 
                        continueInit = true;
                        s_inited = true; 
                    }
                }
            }
 
            // Work to do outside the init lock.
            if (continueInit) { 
                ReadTagsFromRegistry(); 
                Trace(TAG_DEBUG_VERBOSE, "Debugging package initialized");
 
                // Need to read tags before starting to monitor in order to get TAG_DEBUG_MONITOR
                StartRegistryMonitor();
            }
        } 

        private static bool StringEqualsIgnoreCase(string s1, string s2) { 
            return StringComparer.OrdinalIgnoreCase.Equals(s1, s2); 
        }
 
        [RegistryPermission(SecurityAction.Assert, Unrestricted=true)]
        private static void WriteTagsToRegistry() {
            try {
                using (RegistryKey key = Registry.LocalMachine.CreateSubKey(s_regKeyName)) { 
                    List tags = s_tags;
                    foreach (Tag tag in tags) { 
                        key.SetValue(tag.Name, tag.Value, RegistryValueKind.DWord); 
                    }
                } 
            }
            catch {
            }
        } 

        private static void GetBuiltinTagValues() { 
            // Use GetTagValue instead of IsTagEnabled because it does not call EnsureInit 
            // and potentially recurse.
            s_assert              = (GetTagValue(TAG_ASSERT) != TagValue.Disabled); 
            s_assertBreak         = (GetTagValue(TAG_ASSERT_BREAK) != TagValue.Disabled);
            s_includePrefix       = (GetTagValue(TAG_DEBUG_PREFIX) != TagValue.Disabled);
            s_includeThreadPrefix = (GetTagValue(TAG_DEBUG_THREAD_PREFIX) != TagValue.Disabled);
            s_monitor             = (GetTagValue(TAG_DEBUG_MONITOR) != TagValue.Disabled); 
        }
 
        [RegistryPermission(SecurityAction.Assert, Unrestricted=true)] 
        private static void ReadTagsFromRegistry() {
            lock (s_lock) { 
                try {
                    List tags = new List(s_tagDefaults);
                    string[] names = null;
 
                    bool writeTags = false;
                    using (RegistryKey key = Registry.LocalMachine.OpenSubKey(s_regKeyName, false)) { 
                        if (key != null) { 
                            names = key.GetValueNames();
                            foreach (string name in names) { 
                                TagValue value = TagValue.Disabled;
                                try {
                                    TagValue keyvalue = (TagValue) key.GetValue(name);
                                    if (TagValue.Min <= keyvalue && keyvalue <= TagValue.Max) { 
                                        value = keyvalue;
                                    } 
                                    else { 
                                        writeTags = true;
                                    } 
                                }
                                catch {
                                    writeTags = true;
                                } 

                                // Add tag to list, making sure it is unique. 
                                Tag tag = new Tag(name, (TagValue) value); 
                                bool found = false;
                                for (int i = 0; i < s_tagDefaults.Count; i++) { 
                                    if (StringEqualsIgnoreCase(name, tags[i].Name)) {
                                        found = true;
                                        tags[i] = tag;
                                        break; 
                                    }
                                } 
 
                                if (!found) {
                                    tags.Add(tag); 
                                }
                            }
                        }
                    } 

                    s_tags = tags; 
                    GetBuiltinTagValues(); 

                    // Write tags out if there was an invalid value or 
                    // not all default tags are present.
                    if (writeTags || (names != null && names.Length < tags.Count)) {
                        WriteTagsToRegistry();
                    } 
                }
                catch { 
                    s_tags = new List(s_tagDefaults); 
                }
            } 
        }

        private static void StartRegistryMonitor() {
            if (!s_monitor) { 
                Trace(TAG_DEBUG_VERBOSE, "WARNING: Registry monitoring disabled, changes during process execution will not be recognized.");
                return; 
            } 

            Trace(TAG_DEBUG_VERBOSE, "Monitoring registry key " + s_listenKeyName + " for changes."); 

            // Event used to notify of changes.
            s_notifyEvent = new AutoResetEvent(false);
 
            // Register a wait on the event.
            s_waitHandle = ThreadPool.RegisterWaitForSingleObject(s_notifyEvent, OnRegChangeKeyValue, null, -1, false); 
 
            // Monitor the registry.
            MonitorRegistryForOneChange(); 
        }

        private static void StopRegistryMonitor() {
            // Cleanup allocated handles 
            s_stopMonitoring = true;
 
            if (s_regHandle != null) { 
                s_regHandle.Close();
                s_regHandle = null; 
            }

            if (s_waitHandle != null) {
                s_waitHandle.Unregister(s_notifyEvent); 
                s_waitHandle = null;
            } 
 
            if (s_notifyEvent != null) {
                s_notifyEvent.Close(); 
                s_notifyEvent = null;
            }

            Trace(TAG_DEBUG_VERBOSE, "Registry monitoring stopped."); 
        }
 
        public static void OnRegChangeKeyValue(object state, bool timedOut) { 
            if (!s_stopMonitoring) {
                if (timedOut) { 
                    StopRegistryMonitor();
                }
                else {
                    // Monitor again 
                    MonitorRegistryForOneChange();
 
                    // Once we're monitoring, read the changes to the registry. 
                    // We have to do this after we start monitoring in order
                    // to catch all changes to the registry. 
                    ReadTagsFromRegistry();
                }
            }
        } 

        private static void MonitorRegistryForOneChange() { 
            // Close the open reg handle 
            if (s_regHandle != null) {
                s_regHandle.Close(); 
                s_regHandle = null;
            }

            // Open the reg key 
            int result = NativeMethods.RegOpenKeyEx(NativeMethods.HKEY_LOCAL_MACHINE, s_listenKeyName, 0, NativeMethods.KEY_READ, out s_regHandle);
            if (result != 0) { 
                StopRegistryMonitor(); 
                return;
            } 

            // Listen for changes.
            result = NativeMethods.RegNotifyChangeKeyValue(
                    s_regHandle, 
                    true,
                    NativeMethods.REG_NOTIFY_CHANGE_NAME | NativeMethods.REG_NOTIFY_CHANGE_LAST_SET, 
                    s_notifyEvent.SafeWaitHandle, 
                    true);
 
            if (result != 0) {
                StopRegistryMonitor();
            }
        } 

        private static Tag FindMatchingTag(string name, bool exact) { 
            List tags = s_tags; 

            // Look for exact match first 
            foreach (Tag tag in tags) {
                if (StringEqualsIgnoreCase(name, tag.Name)) {
                    return tag;
                } 
            }
 
            if (exact) { 
                return null;
            } 

            Tag longestTag = null;
            int longestPrefix = -1;
            foreach (Tag tag in tags) { 
                if (    tag.PrefixLength > longestPrefix &&
                        0 == string.Compare(name, 0, tag.Name, 0, tag.PrefixLength, StringComparison.OrdinalIgnoreCase)) { 
 
                    longestTag = tag;
                    longestPrefix = tag.PrefixLength; 
                }
            }

            return longestTag; 
        }
 
        private static TagValue GetTagValue(string name) { 
            Tag tag = FindMatchingTag(name, false);
            if (tag != null) { 
                return tag.Value;
            }
            else {
                return TagValue.Disabled; 
            }
        } 
 
        private static bool TraceBreak(string tagName, string message, Exception e, bool includePrefix) {
            EnsureInit(); 

            TagValue tagValue = GetTagValue(tagName);
            if (tagValue == TagValue.Disabled) {
                return false; 
            }
 
            bool isAssert = object.ReferenceEquals(tagName, TAG_ASSERT); 
            if (isAssert) {
                tagName = ""; 
            }

            string exceptionMessage = null;
            if (e != null) { 
                string errorCode = null;
                if (e is ExternalException) { 
                    errorCode = "_hr=0x" + ((ExternalException)e).ErrorCode.ToString("x", CultureInfo.InvariantCulture); 
                }
 
                // Use e.ToString() in order to get inner exception
                if (errorCode != null) {
                    exceptionMessage = "Exception " + e.ToString() + "\n" + errorCode;
                } 
                else {
                    exceptionMessage = "Exception " + e.ToString(); 
                } 
            }
 
            if (string.IsNullOrEmpty(message) & exceptionMessage != null) {
                message = exceptionMessage;
                exceptionMessage = null;
            } 

            string traceFormat; 
            int idThread = 0; 
            int idProcess = 0;
 
            if (!includePrefix || !s_includePrefix) {
                traceFormat = "{4}\n{5}";
            }
            else { 
                if (s_includeThreadPrefix) {
                    idThread = NativeMethods.GetCurrentThreadId(); 
                    idProcess = NativeMethods.GetCurrentProcessId(); 
                    traceFormat = "[0x{0:x}.{1:x} {2} {3}] {4}\n{5}";
                } 
                else {
                    traceFormat = "[{2} {3}] {4}\n{5}";
                }
            } 

            string suffix = ""; 
            if (exceptionMessage != null) { 
                suffix += exceptionMessage + "\n";
            } 

            bool doBreak = (tagValue == TagValue.Break);
            if (doBreak && !isAssert) {
                suffix += "Breaking into debugger...\n"; 
            }
 
            string traceMessage = string.Format(CultureInfo.InvariantCulture, traceFormat, idProcess, idThread, COMPONENT, tagName, message, suffix); 

            NativeMethods.OutputDebugString(traceMessage); 

            return doBreak;
        }
 
        private class MBResult {
            internal int Result; 
        } 

        static bool DoAssert(string message) { 
            if (!s_assert) {
                return false;
            }
 
            // Skip 2 frames - one for this function, one for
            // the public Assert function that called this function. 
            System.Diagnostics.StackFrame frame = new System.Diagnostics.StackFrame(2, true); 
            System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(2, true);
 
            string fileName = frame.GetFileName();
            int lineNumber = frame.GetFileLineNumber();

            string traceFormat; 
            if (!string.IsNullOrEmpty(fileName)) {
                traceFormat = "ASSERTION FAILED: {0}\nFile: {1}:{2}\nStack trace:\n{3}"; 
            } 
            else {
                traceFormat = "ASSERTION FAILED: {0}\nStack trace:\n{3}"; 
            }

            string traceMessage = string.Format(CultureInfo.InvariantCulture, traceFormat, message, fileName, lineNumber, trace.ToString());
 
            if (!TraceBreak(TAG_ASSERT, traceMessage, null, true)) {
                // If the value of "Assert" is not TagValue.Break, then don't even ask user. 
                return false; 
            }
 
            if (s_assertBreak) {
                // If "AssertBreak" is enabled, then always break.
                return true;
            } 

            string dialogFormat; 
            if (!string.IsNullOrEmpty(fileName)) { 
                dialogFormat =
@"Failed expression: {0} 
File: {1}:{2}
Component: {3}
PID={4} TID={5}
Stack trace: 
{6}
 
A=Exit process R=Debug I=Continue"; 
            }
            else { 
                dialogFormat =
@"Failed expression: {0}
(no file information available)
Component: {3} 
PID={4} TID={5}
Stack trace: 
{6} 

A=Exit process R=Debug I=Continue"; 
            }

            string dialogMessage = string.Format(
                CultureInfo.InvariantCulture, 
                dialogFormat,
                message, 
                fileName, lineNumber, 
                COMPONENT,
                NativeMethods.GetCurrentProcessId(), NativeMethods.GetCurrentThreadId(), 
                trace.ToString());

            MBResult mbResult = new MBResult();
 
            Thread thread = new Thread(
                delegate() { 
                    for (int i = 0; i < 100; i++) { 
                        NativeMethods.MSG msg = new NativeMethods.MSG();
                        NativeMethods.PeekMessage(ref msg, new HandleRef(mbResult, IntPtr.Zero), 0, 0, NativeMethods.PM_REMOVE); 
                    }

                    mbResult.Result = NativeMethods.MessageBox(new HandleRef(mbResult, IntPtr.Zero), dialogMessage, PRODUCT + " Assertion",
                        NativeMethods.MB_SERVICE_NOTIFICATION | 
                        NativeMethods.MB_TOPMOST |
                        NativeMethods.MB_ABORTRETRYIGNORE | 
                        NativeMethods.MB_ICONEXCLAMATION); 
                }
            ); 

            thread.Start();
            thread.Join();
 
            if (mbResult.Result == NativeMethods.IDABORT) {
                IntPtr currentProcess = NativeMethods.GetCurrentProcess(); 
                NativeMethods.TerminateProcess(new HandleRef(mbResult, currentProcess), 1); 
            }
 
            return mbResult.Result == NativeMethods.IDRETRY;
        }
#endif
 
        //
        // Sends the message to the debugger if the tag is enabled. 
        // Also breaks into the debugger the value of the tag is 2 (TagValue.Break). 
        //
        [System.Diagnostics.Conditional("DBG")] 
        internal static void Trace(string tagName, string message) {
#if DBG
            if (TraceBreak(tagName, message, null, true)) {
                Break(); 
            }
#endif 
        } 

        // 
        // Sends the message to the debugger if the tag is enabled.
        // Also breaks into the debugger the value of the tag is 2 (TagValue.Break).
        //
        [System.Diagnostics.Conditional("DBG")] 
        internal static void Trace(string tagName, string message, bool includePrefix) {
#if DBG 
            if (TraceBreak(tagName, message, null, includePrefix)) { 
                Break();
            } 
#endif
        }

        // 
        // Sends the message to the debugger if the tag is enabled.
        // Also breaks into the debugger the value of the tag is 2 (TagValue.Break). 
        // 
        [System.Diagnostics.Conditional("DBG")]
        internal static void Trace(string tagName, string message, Exception e) { 
#if DBG
            if (TraceBreak(tagName, message, e, true)) {
                Break();
            } 
#endif
        } 
 
        //
        // Sends the message to the debugger if the tag is enabled. 
        // Also breaks into the debugger the value of the tag is 2 (TagValue.Break).
        //
        [System.Diagnostics.Conditional("DBG")]
        internal static void Trace(string tagName, Exception e) { 
#if DBG
            if (TraceBreak(tagName, null, e, true)) { 
                Break(); 
            }
#endif 
        }

        //
        // Sends the message to the debugger if the tag is enabled. 
        // Also breaks into the debugger the value of the tag is 2 (TagValue.Break).
        // 
        [System.Diagnostics.Conditional("DBG")] 
        internal static void Trace(string tagName, string message, Exception e, bool includePrefix) {
#if DBG 
            if (TraceBreak(tagName, message, e, includePrefix)) {
                Break();
            }
#endif 
        }
 
#if DBG 
#endif
 
#if UNUSED_CODE
        [System.Diagnostics.Conditional("DBG")]
        public static void TraceException(String tagName, Exception e) {
#if DBG 
            if (TraceBreak(tagName, null, e, true)) {
                Break(); 
            } 
#endif
        } 
#endif


        // 
        // If the assertion is false and the 'Assert' tag is enabled:
        //      * Send a message to the debugger. 
        //      * If the 'AssertBreak' tag is enabled, immediately break into the debugger 
        //      * Else display a dialog box asking the user to Abort, Retry (break), or Ignore
        // 
        [System.Diagnostics.Conditional("DBG")]
        internal static void Assert(bool assertion, string message) {
#if DBG
            EnsureInit(); 
            if (assertion == false) {
                if (DoAssert(message)) { 
                    Break(); 
                }
            } 
#endif
        }

 
        //
        // If the assertion is false and the 'Assert' tag is enabled: 
        //      * Send a message to the debugger. 
        //      * If the 'AssertBreak' tag is enabled, immediately break into the debugger
        //      * Else display a dialog box asking the user to Abort, Retry (break), or Ignore 
        //
        [System.Diagnostics.Conditional("DBG")]
        internal static void Assert(bool assertion) {
#if DBG 
            EnsureInit();
            if (assertion == false) { 
                if (DoAssert(null)) { 
                    Break();
                } 
            }
#endif
        }
 
        //
        // Like Assert, but the assertion is always considered to be false. 
        // 
        [System.Diagnostics.Conditional("DBG")]
        internal static void Fail(string message) { 
#if DBG
            Assert(false, message);
#endif
        } 

        // 
        // Returns true if the tag is enabled, false otherwise. 
        // Note that the tag needn't be an exact match.
        // 
        internal static bool IsTagEnabled(string tagName) {
#if DBG
            EnsureInit();
            return GetTagValue(tagName) != TagValue.Disabled; 
#else
            return false; 
#endif 
        }
 
        //
        // Returns true if the tag present.
        // This function chekcs for an exact match.
        // 
        internal static bool IsTagPresent(string tagName) {
#if DBG 
            EnsureInit(); 
            return FindMatchingTag(tagName, true) != null;
#else 
            return false;
#endif
        }
 
        //
        // Breaks into the debugger, or launches one if not yet attached. 
        // 
        [System.Diagnostics.Conditional("DBG")]
        internal static void Break() { 
#if DBG
            if (!System.Diagnostics.Debugger.IsAttached) {
                System.Diagnostics.Debugger.Launch();
            } 
            else {
                System.Diagnostics.Debugger.Break(); 
            } 
#endif
        } 


        //
        // Tells the debug system to always validate calls for a 
        // particular tag. This is useful for temporarily enabling
        // validation in stress tests or other situations where you 
        // may not have control over the debug tags that are enabled 
        // on a particular machine.
        // 
        [System.Diagnostics.Conditional("DBG")]
        internal static void AlwaysValidate(string tagName) {
#if DBG
            EnsureInit(); 
            s_tableAlwaysValidate[tagName] = tagName;
#endif 
        } 

 
        //
        // Throws an exception if the assertion is not valid.
        // Use this function from a DebugValidate method where
        // you would otherwise use Assert. 
        //
        [System.Diagnostics.Conditional("DBG")] 
        internal static void CheckValid(bool assertion, string message) { 
#if DBG
            if (!assertion) { 
                throw new Exception(message);
            }
#endif
        } 

        // 
        // Calls DebugValidate on an object if such a method exists. 
        //
        // This method should be used from implementations of DebugValidate 
        // where it is unknown whether an object has a DebugValidate method.
        // For example, the DoubleLink class uses it to validate the
        // item of type Object which it points to.
        // 
        // This method should NOT be used when code wants to conditionally
        // validate an object and have a failed validation caught in an assert. 
        // Use Debug.Validate(tagName, obj) for that purpose. 
        //
        [System.Diagnostics.Conditional("DBG")] 
        internal static void Validate(Object obj) {
#if DBG
            Type        type;
            MethodInfo  mi; 

            if (obj != null) { 
                type = obj.GetType(); 

                mi = type.GetMethod( 
                        "DebugValidate",
                        BindingFlags.NonPublic | BindingFlags.Instance,
                        null,
                        s_ValidateArgs, 
                        null);
 
                if (mi != null) { 
                    object[] tempIndex = null;
                    mi.Invoke(obj, tempIndex); 
                }
            }
#endif
        } 

        // 
        // Validates an object is the "Validate" tag is enabled, or when 
        // the "Validate" tag is not disabled and the given 'tag' is enabled.
        // An Assertion is made if the validation fails. 
        //
        [System.Diagnostics.Conditional("DBG")]
        internal static void Validate(string tagName, Object obj) {
#if DBG 
            EnsureInit();
 
            if (    obj != null 
                    && (    IsTagEnabled("Validate")
                            ||  (   !IsTagPresent("Validate") 
                                    && (   s_tableAlwaysValidate[tagName] != null
                                           ||  IsTagEnabled(tagName))))) {
                try {
                    Debug.Validate(obj); 
                }
                catch (Exception e) { 
                    Debug.Assert(false, "Validate failed: " + e.InnerException.Message); 
                }
                catch { 
                    Debug.Assert(false, "Validate failed.  Non-CLS compliant exception caught.");
                }
            }
#endif 
        }
 
#if DBG 

        // 
        // Calls DebugDescription on an object to get its description.
        //
        // This method should only be used in implementations of DebugDescription
        // where it is not known whether a nested objects has an implementation 
        // of DebugDescription. For example, the double linked list class uses
        // GetDescription to get the description of the item it points to. 
        // 
        // This method should NOT be used when you want to conditionally
        // dump an object. Use Debug.Dump instead. 
        //
        // @param obj      The object to call DebugDescription on. May be null.
        // @param indent   A prefix for each line in the description. This is used
        //                 to allow the nested display of objects within other objects. 
        //                 The indent is usually a multiple of four spaces.
        // 
        // @return         The description. 
        //
        [ReflectionPermission(SecurityAction.Assert, Unrestricted=true)] 
        internal static string GetDescription(Object obj, string indent) {
            string      description;
            Type        type;
            MethodInfo  mi; 
            Object[]   parameters;
 
            if (obj == null) { 
                description = "\n";
            } 
            else {
                type = obj.GetType();
                mi = type.GetMethod(
                        "DebugDescription", 
                        BindingFlags.NonPublic | BindingFlags.Instance,
                        null, 
                        s_DumpArgs, 
                        null);
 
                if (mi == null || mi.ReturnType != typeof(string)) {
                    description = indent + obj.ToString();
                }
                else { 
                    parameters = new Object[1] {(Object) indent};
                    description = (string) mi.Invoke(obj, parameters); 
                } 
            }
 
            return description;
        }
#endif
 

        // 
        // Dumps an object to the debugger if the "Dump" tag is enabled, 
        // or if the "Dump" tag is not present and the 'tag' is enabled.
        // 
        // @param tagName  The tag to Dump with.
        // @param obj  The object to dump.
        //
        [System.Diagnostics.Conditional("DBG")] 
        internal static void Dump(string tagName, Object obj) {
#if DBG 
            EnsureInit(); 

            string  description; 
            string  traceTag = null;
            bool    dumpEnabled, dumpPresent;

            if (obj != null) { 
                dumpEnabled = IsTagEnabled("Dump");
                dumpPresent = IsTagPresent("Dump"); 
                if (dumpEnabled || !dumpPresent) { 
                    if (IsTagEnabled(tagName)) {
                        traceTag = tagName; 
                    }
                    else if (dumpEnabled) {
                        traceTag = "Dump";
                    } 

                    if (traceTag != null) { 
                        description = GetDescription(obj, string.Empty); 
                        Debug.Trace(traceTag, "Dump\n" + description);
                    } 
                }
            }
#endif
        } 

#if UNUSED_CODE 
 
#if DBG
        static internal string ToStringMaybeNull(object o) { 
            if (o != null) {
                return o.ToString();
            }
 
            return "";
        } 
#endif 

        static internal string FormatUtcDate(DateTime utcTime) { 
#if DBG
            DateTime localTime = DateTimeUtil.ConvertToLocalTime(utcTime);
            return localTime.ToString(DATE_FORMAT, CultureInfo.InvariantCulture);
#else 
            return string.Empty;
#endif 
        } 

        static internal string FormatLocalDate(DateTime localTime) { 
#if DBG
            return localTime.ToString(DATE_FORMAT, CultureInfo.InvariantCulture);
#else
            return string.Empty; 
#endif
        } 
 
#endif // UNUSED_CODE
 
    }
}

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

namespace System.Configuration { 
    using Microsoft.Win32; 
    using Microsoft.Win32.SafeHandles;
    using System; 
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization; 
    using System.Reflection;
    using System.Runtime.ConstrainedExecution; 
    using System.Runtime.InteropServices; 
    using System.Security;
    using System.Security.Permissions; 
    using System.Threading;

    internal static class Debug {
 
        internal const string   TAG_INTERNAL = "Internal";
        internal const string   TAG_EXTERNAL = "External"; 
        internal const string   TAG_ALL      = "*"; 

        internal const string   DATE_FORMAT = @"yyyy/MM/dd HH:mm:ss.ffff"; 
        internal const string   TIME_FORMAT = @"HH:mm:ss:ffff";

#if DBG
        [System.Security.SuppressUnmanagedCodeSecurityAttribute()] 
        private static class NativeMethods {
            [DllImport("kernel32.dll")] 
            internal extern static int GetCurrentProcessId(); 

            [DllImport("kernel32.dll")] 
            internal extern static int GetCurrentThreadId();

            [DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
            internal extern static IntPtr GetCurrentProcess(); 

            [DllImport("kernel32.dll", SetLastError=true)] 
            internal extern static bool TerminateProcess(HandleRef processHandle, int exitCode); 

            [DllImport("kernel32.dll", CharSet=CharSet.Auto, BestFitMapping=false)] 
            internal extern static void OutputDebugString(string message);

            internal const int PM_NOREMOVE = 0x0000;
            internal const int PM_REMOVE = 0x0001; 

            [StructLayout(LayoutKind.Sequential)] 
            internal struct MSG { 
                internal IntPtr   hwnd;
                internal int      message; 
                internal IntPtr   wParam;
                internal IntPtr   lParam;
                internal int      time;
                internal int      pt_x; 
                internal int      pt_y;
            } 
 
            [DllImport("user32.dll", CharSet=System.Runtime.InteropServices.CharSet.Auto)]
            internal extern static bool PeekMessage([In, Out] ref MSG msg, HandleRef hwnd, int msgMin, int msgMax, int remove); 

            internal const int
                MB_OK = 0x00000000,
                MB_OKCANCEL = 0x00000001, 
                MB_ABORTRETRYIGNORE = 0x00000002,
                MB_YESNOCANCEL = 0x00000003, 
                MB_YESNO = 0x00000004, 
                MB_RETRYCANCEL = 0x00000005,
                MB_ICONHAND = 0x00000010, 
                MB_ICONQUESTION = 0x00000020,
                MB_ICONEXCLAMATION = 0x00000030,
                MB_ICONASTERISK = 0x00000040,
                MB_USERICON = 0x00000080, 
                MB_ICONWARNING = 0x00000030,
                MB_ICONERROR = 0x00000010, 
                MB_ICONINFORMATION = 0x00000040, 
                MB_DEFBUTTON1 = 0x00000000,
                MB_DEFBUTTON2 = 0x00000100, 
                MB_DEFBUTTON3 = 0x00000200,
                MB_DEFBUTTON4 = 0x00000300,
                MB_APPLMODAL = 0x00000000,
                MB_SYSTEMMODAL = 0x00001000, 
                MB_TASKMODAL = 0x00002000,
                MB_HELP = 0x00004000, 
                MB_NOFOCUS = 0x00008000, 
                MB_SETFOREGROUND = 0x00010000,
                MB_DEFAULT_DESKTOP_ONLY = 0x00020000, 
                MB_TOPMOST = 0x00040000,
                MB_RIGHT = 0x00080000,
                MB_RTLREADING = 0x00100000,
                MB_SERVICE_NOTIFICATION = 0x00200000, 
                MB_SERVICE_NOTIFICATION_NT3X = 0x00040000,
                MB_TYPEMASK = 0x0000000F, 
                MB_ICONMASK = 0x000000F0, 
                MB_DEFMASK = 0x00000F00,
                MB_MODEMASK = 0x00003000, 
                MB_MISCMASK = 0x0000C000;

            internal const int
                IDOK = 1, 
                IDCANCEL = 2,
                IDABORT = 3, 
                IDRETRY = 4, 
                IDIGNORE = 5,
                IDYES = 6, 
                IDNO = 7,
                IDCLOSE = 8,
                IDHELP = 9;
 

            [DllImport("user32.dll", CharSet=CharSet.Auto, BestFitMapping=false)] 
            internal extern static int MessageBox(HandleRef hWnd, string text, string caption, int type); 

            internal static readonly IntPtr HKEY_LOCAL_MACHINE = unchecked((IntPtr)(int)0x80000002); 

            internal const int READ_CONTROL           = 0x00020000;
            internal const int STANDARD_RIGHTS_READ   = READ_CONTROL;
 
            internal const int SYNCHRONIZE            = 0x00100000;
 
            internal const int KEY_QUERY_VALUE        = 0x0001; 
            internal const int KEY_ENUMERATE_SUB_KEYS = 0x0008;
            internal const int KEY_NOTIFY             = 0x0010; 


            internal const int KEY_READ               = ((STANDARD_RIGHTS_READ |
                                                               KEY_QUERY_VALUE | 
                                                               KEY_ENUMERATE_SUB_KEYS |
                                                               KEY_NOTIFY) 
                                                              & 
                                                              (~SYNCHRONIZE));
 
            internal const int REG_NOTIFY_CHANGE_NAME       = 1;
            internal const int REG_NOTIFY_CHANGE_LAST_SET   = 4;

 
            [DllImport("advapi32.dll", CharSet=CharSet.Auto, BestFitMapping=false, SetLastError=true)]
            internal extern static int RegOpenKeyEx(IntPtr hKey, string lpSubKey, int ulOptions, int samDesired, out SafeRegistryHandle hkResult); 
 
            [DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true)]
            internal extern static int RegNotifyChangeKeyValue(SafeRegistryHandle hKey, bool watchSubTree, uint notifyFilter, SafeWaitHandle regEvent, bool async); 
        }

        private class SafeRegistryHandle : SafeHandleZeroOrMinusOneIsInvalid {
 
            // Note: Officially -1 is the recommended invalid handle value for
            // registry keys, but we'll also get back 0 as an invalid handle from 
            // RegOpenKeyEx. 

            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)] 
            internal SafeRegistryHandle() : base(true) {}

            [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)]
            internal SafeRegistryHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) { 
                SetHandle(preexistingHandle);
            } 
 
            [DllImport("advapi32.dll"),
             SuppressUnmanagedCodeSecurity, 
             ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            private static extern int RegCloseKey(IntPtr hKey);

            override protected bool ReleaseHandle() 
            {
                // Returns a Win32 error code, 0 for success 
                int r = RegCloseKey(handle); 
                return r == 0;
            } 
        }

        private enum TagValue {
            Disabled = 0, 
            Enabled = 1,
            Break = 2, 
 
            Min = Disabled,
            Max = Break, 
        }

        private const string            TAG_ASSERT = "Assert";
        private const string            TAG_ASSERT_BREAK = "AssertBreak"; 

        private const string            TAG_DEBUG_VERBOSE = "DebugVerbose"; 
        private const string            TAG_DEBUG_MONITOR = "DebugMonitor"; 
        private const string            TAG_DEBUG_PREFIX = "DebugPrefix";
        private const string            TAG_DEBUG_THREAD_PREFIX = "DebugThreadPrefix"; 

        private const string            PRODUCT = "Microsoft .NET Framework";
        private const string            COMPONENT = "System.Configuration";
 
        private static string           s_regKeyName = @"Software\Microsoft\ASP.NET\Debug";
        private static string           s_listenKeyName = @"Software\Microsoft"; 
 
        private static bool             s_assert;
        private static bool             s_assertBreak; 

        private static bool             s_includePrefix;
        private static bool             s_includeThreadPrefix;
        private static bool             s_monitor; 

        private static object           s_lock; 
        private static volatile bool    s_inited; 
        private static ReadOnlyCollection  s_tagDefaults;
        private static List        s_tags; 

        private static AutoResetEvent       s_notifyEvent;
        private static RegisteredWaitHandle s_waitHandle;
        private static SafeRegistryHandle   s_regHandle; 
        private static bool                 s_stopMonitoring;
 
        private static Hashtable        s_tableAlwaysValidate; 
        private static Type[]           s_DumpArgs;
        private static Type[]           s_ValidateArgs; 


        private class Tag {
            string      _name; 
            TagValue    _value;
            int         _prefixLength; 
 
            internal Tag(string name, TagValue value) {
                _name = name; 
                _value = value;

                if (_name[_name.Length - 1] == '*') {
                    _prefixLength = _name.Length - 1; 
                }
                else { 
                    _prefixLength = -1; 
                }
            } 

            internal string Name {
                get {return _name;}
            } 

            internal TagValue Value { 
                get {return _value;} 
            }
 
            internal int PrefixLength {
                get {return _prefixLength;}
            }
        } 

        static Debug() { 
            s_lock = new object(); 
        }
 
        private static void EnsureInit() {
            bool continueInit = false;

            if (!s_inited) { 
                lock (s_lock) {
                    if (!s_inited) { 
                        s_tableAlwaysValidate = new Hashtable(); 
                        s_DumpArgs = new Type[1] {typeof(string)};
                        s_ValidateArgs = new Type[0]; 

                        List tagDefaults = new List();
                        tagDefaults.Add(new Tag(TAG_ALL, TagValue.Disabled));
                        tagDefaults.Add(new Tag(TAG_INTERNAL, TagValue.Enabled)); 
                        tagDefaults.Add(new Tag(TAG_EXTERNAL, TagValue.Enabled));
                        tagDefaults.Add(new Tag(TAG_ASSERT, TagValue.Break)); 
                        tagDefaults.Add(new Tag(TAG_ASSERT_BREAK, TagValue.Disabled)); 
                        tagDefaults.Add(new Tag(TAG_DEBUG_VERBOSE, TagValue.Enabled));
                        tagDefaults.Add(new Tag(TAG_DEBUG_MONITOR, TagValue.Enabled)); 
                        tagDefaults.Add(new Tag(TAG_DEBUG_PREFIX, TagValue.Enabled));
                        tagDefaults.Add(new Tag(TAG_DEBUG_THREAD_PREFIX, TagValue.Enabled));

                        s_tagDefaults = tagDefaults.AsReadOnly(); 
                        s_tags = new List(s_tagDefaults);
                        GetBuiltinTagValues(); 
 
                        continueInit = true;
                        s_inited = true; 
                    }
                }
            }
 
            // Work to do outside the init lock.
            if (continueInit) { 
                ReadTagsFromRegistry(); 
                Trace(TAG_DEBUG_VERBOSE, "Debugging package initialized");
 
                // Need to read tags before starting to monitor in order to get TAG_DEBUG_MONITOR
                StartRegistryMonitor();
            }
        } 

        private static bool StringEqualsIgnoreCase(string s1, string s2) { 
            return StringComparer.OrdinalIgnoreCase.Equals(s1, s2); 
        }
 
        [RegistryPermission(SecurityAction.Assert, Unrestricted=true)]
        private static void WriteTagsToRegistry() {
            try {
                using (RegistryKey key = Registry.LocalMachine.CreateSubKey(s_regKeyName)) { 
                    List tags = s_tags;
                    foreach (Tag tag in tags) { 
                        key.SetValue(tag.Name, tag.Value, RegistryValueKind.DWord); 
                    }
                } 
            }
            catch {
            }
        } 

        private static void GetBuiltinTagValues() { 
            // Use GetTagValue instead of IsTagEnabled because it does not call EnsureInit 
            // and potentially recurse.
            s_assert              = (GetTagValue(TAG_ASSERT) != TagValue.Disabled); 
            s_assertBreak         = (GetTagValue(TAG_ASSERT_BREAK) != TagValue.Disabled);
            s_includePrefix       = (GetTagValue(TAG_DEBUG_PREFIX) != TagValue.Disabled);
            s_includeThreadPrefix = (GetTagValue(TAG_DEBUG_THREAD_PREFIX) != TagValue.Disabled);
            s_monitor             = (GetTagValue(TAG_DEBUG_MONITOR) != TagValue.Disabled); 
        }
 
        [RegistryPermission(SecurityAction.Assert, Unrestricted=true)] 
        private static void ReadTagsFromRegistry() {
            lock (s_lock) { 
                try {
                    List tags = new List(s_tagDefaults);
                    string[] names = null;
 
                    bool writeTags = false;
                    using (RegistryKey key = Registry.LocalMachine.OpenSubKey(s_regKeyName, false)) { 
                        if (key != null) { 
                            names = key.GetValueNames();
                            foreach (string name in names) { 
                                TagValue value = TagValue.Disabled;
                                try {
                                    TagValue keyvalue = (TagValue) key.GetValue(name);
                                    if (TagValue.Min <= keyvalue && keyvalue <= TagValue.Max) { 
                                        value = keyvalue;
                                    } 
                                    else { 
                                        writeTags = true;
                                    } 
                                }
                                catch {
                                    writeTags = true;
                                } 

                                // Add tag to list, making sure it is unique. 
                                Tag tag = new Tag(name, (TagValue) value); 
                                bool found = false;
                                for (int i = 0; i < s_tagDefaults.Count; i++) { 
                                    if (StringEqualsIgnoreCase(name, tags[i].Name)) {
                                        found = true;
                                        tags[i] = tag;
                                        break; 
                                    }
                                } 
 
                                if (!found) {
                                    tags.Add(tag); 
                                }
                            }
                        }
                    } 

                    s_tags = tags; 
                    GetBuiltinTagValues(); 

                    // Write tags out if there was an invalid value or 
                    // not all default tags are present.
                    if (writeTags || (names != null && names.Length < tags.Count)) {
                        WriteTagsToRegistry();
                    } 
                }
                catch { 
                    s_tags = new List(s_tagDefaults); 
                }
            } 
        }

        private static void StartRegistryMonitor() {
            if (!s_monitor) { 
                Trace(TAG_DEBUG_VERBOSE, "WARNING: Registry monitoring disabled, changes during process execution will not be recognized.");
                return; 
            } 

            Trace(TAG_DEBUG_VERBOSE, "Monitoring registry key " + s_listenKeyName + " for changes."); 

            // Event used to notify of changes.
            s_notifyEvent = new AutoResetEvent(false);
 
            // Register a wait on the event.
            s_waitHandle = ThreadPool.RegisterWaitForSingleObject(s_notifyEvent, OnRegChangeKeyValue, null, -1, false); 
 
            // Monitor the registry.
            MonitorRegistryForOneChange(); 
        }

        private static void StopRegistryMonitor() {
            // Cleanup allocated handles 
            s_stopMonitoring = true;
 
            if (s_regHandle != null) { 
                s_regHandle.Close();
                s_regHandle = null; 
            }

            if (s_waitHandle != null) {
                s_waitHandle.Unregister(s_notifyEvent); 
                s_waitHandle = null;
            } 
 
            if (s_notifyEvent != null) {
                s_notifyEvent.Close(); 
                s_notifyEvent = null;
            }

            Trace(TAG_DEBUG_VERBOSE, "Registry monitoring stopped."); 
        }
 
        public static void OnRegChangeKeyValue(object state, bool timedOut) { 
            if (!s_stopMonitoring) {
                if (timedOut) { 
                    StopRegistryMonitor();
                }
                else {
                    // Monitor again 
                    MonitorRegistryForOneChange();
 
                    // Once we're monitoring, read the changes to the registry. 
                    // We have to do this after we start monitoring in order
                    // to catch all changes to the registry. 
                    ReadTagsFromRegistry();
                }
            }
        } 

        private static void MonitorRegistryForOneChange() { 
            // Close the open reg handle 
            if (s_regHandle != null) {
                s_regHandle.Close(); 
                s_regHandle = null;
            }

            // Open the reg key 
            int result = NativeMethods.RegOpenKeyEx(NativeMethods.HKEY_LOCAL_MACHINE, s_listenKeyName, 0, NativeMethods.KEY_READ, out s_regHandle);
            if (result != 0) { 
                StopRegistryMonitor(); 
                return;
            } 

            // Listen for changes.
            result = NativeMethods.RegNotifyChangeKeyValue(
                    s_regHandle, 
                    true,
                    NativeMethods.REG_NOTIFY_CHANGE_NAME | NativeMethods.REG_NOTIFY_CHANGE_LAST_SET, 
                    s_notifyEvent.SafeWaitHandle, 
                    true);
 
            if (result != 0) {
                StopRegistryMonitor();
            }
        } 

        private static Tag FindMatchingTag(string name, bool exact) { 
            List tags = s_tags; 

            // Look for exact match first 
            foreach (Tag tag in tags) {
                if (StringEqualsIgnoreCase(name, tag.Name)) {
                    return tag;
                } 
            }
 
            if (exact) { 
                return null;
            } 

            Tag longestTag = null;
            int longestPrefix = -1;
            foreach (Tag tag in tags) { 
                if (    tag.PrefixLength > longestPrefix &&
                        0 == string.Compare(name, 0, tag.Name, 0, tag.PrefixLength, StringComparison.OrdinalIgnoreCase)) { 
 
                    longestTag = tag;
                    longestPrefix = tag.PrefixLength; 
                }
            }

            return longestTag; 
        }
 
        private static TagValue GetTagValue(string name) { 
            Tag tag = FindMatchingTag(name, false);
            if (tag != null) { 
                return tag.Value;
            }
            else {
                return TagValue.Disabled; 
            }
        } 
 
        private static bool TraceBreak(string tagName, string message, Exception e, bool includePrefix) {
            EnsureInit(); 

            TagValue tagValue = GetTagValue(tagName);
            if (tagValue == TagValue.Disabled) {
                return false; 
            }
 
            bool isAssert = object.ReferenceEquals(tagName, TAG_ASSERT); 
            if (isAssert) {
                tagName = ""; 
            }

            string exceptionMessage = null;
            if (e != null) { 
                string errorCode = null;
                if (e is ExternalException) { 
                    errorCode = "_hr=0x" + ((ExternalException)e).ErrorCode.ToString("x", CultureInfo.InvariantCulture); 
                }
 
                // Use e.ToString() in order to get inner exception
                if (errorCode != null) {
                    exceptionMessage = "Exception " + e.ToString() + "\n" + errorCode;
                } 
                else {
                    exceptionMessage = "Exception " + e.ToString(); 
                } 
            }
 
            if (string.IsNullOrEmpty(message) & exceptionMessage != null) {
                message = exceptionMessage;
                exceptionMessage = null;
            } 

            string traceFormat; 
            int idThread = 0; 
            int idProcess = 0;
 
            if (!includePrefix || !s_includePrefix) {
                traceFormat = "{4}\n{5}";
            }
            else { 
                if (s_includeThreadPrefix) {
                    idThread = NativeMethods.GetCurrentThreadId(); 
                    idProcess = NativeMethods.GetCurrentProcessId(); 
                    traceFormat = "[0x{0:x}.{1:x} {2} {3}] {4}\n{5}";
                } 
                else {
                    traceFormat = "[{2} {3}] {4}\n{5}";
                }
            } 

            string suffix = ""; 
            if (exceptionMessage != null) { 
                suffix += exceptionMessage + "\n";
            } 

            bool doBreak = (tagValue == TagValue.Break);
            if (doBreak && !isAssert) {
                suffix += "Breaking into debugger...\n"; 
            }
 
            string traceMessage = string.Format(CultureInfo.InvariantCulture, traceFormat, idProcess, idThread, COMPONENT, tagName, message, suffix); 

            NativeMethods.OutputDebugString(traceMessage); 

            return doBreak;
        }
 
        private class MBResult {
            internal int Result; 
        } 

        static bool DoAssert(string message) { 
            if (!s_assert) {
                return false;
            }
 
            // Skip 2 frames - one for this function, one for
            // the public Assert function that called this function. 
            System.Diagnostics.StackFrame frame = new System.Diagnostics.StackFrame(2, true); 
            System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(2, true);
 
            string fileName = frame.GetFileName();
            int lineNumber = frame.GetFileLineNumber();

            string traceFormat; 
            if (!string.IsNullOrEmpty(fileName)) {
                traceFormat = "ASSERTION FAILED: {0}\nFile: {1}:{2}\nStack trace:\n{3}"; 
            } 
            else {
                traceFormat = "ASSERTION FAILED: {0}\nStack trace:\n{3}"; 
            }

            string traceMessage = string.Format(CultureInfo.InvariantCulture, traceFormat, message, fileName, lineNumber, trace.ToString());
 
            if (!TraceBreak(TAG_ASSERT, traceMessage, null, true)) {
                // If the value of "Assert" is not TagValue.Break, then don't even ask user. 
                return false; 
            }
 
            if (s_assertBreak) {
                // If "AssertBreak" is enabled, then always break.
                return true;
            } 

            string dialogFormat; 
            if (!string.IsNullOrEmpty(fileName)) { 
                dialogFormat =
@"Failed expression: {0} 
File: {1}:{2}
Component: {3}
PID={4} TID={5}
Stack trace: 
{6}
 
A=Exit process R=Debug I=Continue"; 
            }
            else { 
                dialogFormat =
@"Failed expression: {0}
(no file information available)
Component: {3} 
PID={4} TID={5}
Stack trace: 
{6} 

A=Exit process R=Debug I=Continue"; 
            }

            string dialogMessage = string.Format(
                CultureInfo.InvariantCulture, 
                dialogFormat,
                message, 
                fileName, lineNumber, 
                COMPONENT,
                NativeMethods.GetCurrentProcessId(), NativeMethods.GetCurrentThreadId(), 
                trace.ToString());

            MBResult mbResult = new MBResult();
 
            Thread thread = new Thread(
                delegate() { 
                    for (int i = 0; i < 100; i++) { 
                        NativeMethods.MSG msg = new NativeMethods.MSG();
                        NativeMethods.PeekMessage(ref msg, new HandleRef(mbResult, IntPtr.Zero), 0, 0, NativeMethods.PM_REMOVE); 
                    }

                    mbResult.Result = NativeMethods.MessageBox(new HandleRef(mbResult, IntPtr.Zero), dialogMessage, PRODUCT + " Assertion",
                        NativeMethods.MB_SERVICE_NOTIFICATION | 
                        NativeMethods.MB_TOPMOST |
                        NativeMethods.MB_ABORTRETRYIGNORE | 
                        NativeMethods.MB_ICONEXCLAMATION); 
                }
            ); 

            thread.Start();
            thread.Join();
 
            if (mbResult.Result == NativeMethods.IDABORT) {
                IntPtr currentProcess = NativeMethods.GetCurrentProcess(); 
                NativeMethods.TerminateProcess(new HandleRef(mbResult, currentProcess), 1); 
            }
 
            return mbResult.Result == NativeMethods.IDRETRY;
        }
#endif
 
        //
        // Sends the message to the debugger if the tag is enabled. 
        // Also breaks into the debugger the value of the tag is 2 (TagValue.Break). 
        //
        [System.Diagnostics.Conditional("DBG")] 
        internal static void Trace(string tagName, string message) {
#if DBG
            if (TraceBreak(tagName, message, null, true)) {
                Break(); 
            }
#endif 
        } 

        // 
        // Sends the message to the debugger if the tag is enabled.
        // Also breaks into the debugger the value of the tag is 2 (TagValue.Break).
        //
        [System.Diagnostics.Conditional("DBG")] 
        internal static void Trace(string tagName, string message, bool includePrefix) {
#if DBG 
            if (TraceBreak(tagName, message, null, includePrefix)) { 
                Break();
            } 
#endif
        }

        // 
        // Sends the message to the debugger if the tag is enabled.
        // Also breaks into the debugger the value of the tag is 2 (TagValue.Break). 
        // 
        [System.Diagnostics.Conditional("DBG")]
        internal static void Trace(string tagName, string message, Exception e) { 
#if DBG
            if (TraceBreak(tagName, message, e, true)) {
                Break();
            } 
#endif
        } 
 
        //
        // Sends the message to the debugger if the tag is enabled. 
        // Also breaks into the debugger the value of the tag is 2 (TagValue.Break).
        //
        [System.Diagnostics.Conditional("DBG")]
        internal static void Trace(string tagName, Exception e) { 
#if DBG
            if (TraceBreak(tagName, null, e, true)) { 
                Break(); 
            }
#endif 
        }

        //
        // Sends the message to the debugger if the tag is enabled. 
        // Also breaks into the debugger the value of the tag is 2 (TagValue.Break).
        // 
        [System.Diagnostics.Conditional("DBG")] 
        internal static void Trace(string tagName, string message, Exception e, bool includePrefix) {
#if DBG 
            if (TraceBreak(tagName, message, e, includePrefix)) {
                Break();
            }
#endif 
        }
 
#if DBG 
#endif
 
#if UNUSED_CODE
        [System.Diagnostics.Conditional("DBG")]
        public static void TraceException(String tagName, Exception e) {
#if DBG 
            if (TraceBreak(tagName, null, e, true)) {
                Break(); 
            } 
#endif
        } 
#endif


        // 
        // If the assertion is false and the 'Assert' tag is enabled:
        //      * Send a message to the debugger. 
        //      * If the 'AssertBreak' tag is enabled, immediately break into the debugger 
        //      * Else display a dialog box asking the user to Abort, Retry (break), or Ignore
        // 
        [System.Diagnostics.Conditional("DBG")]
        internal static void Assert(bool assertion, string message) {
#if DBG
            EnsureInit(); 
            if (assertion == false) {
                if (DoAssert(message)) { 
                    Break(); 
                }
            } 
#endif
        }

 
        //
        // If the assertion is false and the 'Assert' tag is enabled: 
        //      * Send a message to the debugger. 
        //      * If the 'AssertBreak' tag is enabled, immediately break into the debugger
        //      * Else display a dialog box asking the user to Abort, Retry (break), or Ignore 
        //
        [System.Diagnostics.Conditional("DBG")]
        internal static void Assert(bool assertion) {
#if DBG 
            EnsureInit();
            if (assertion == false) { 
                if (DoAssert(null)) { 
                    Break();
                } 
            }
#endif
        }
 
        //
        // Like Assert, but the assertion is always considered to be false. 
        // 
        [System.Diagnostics.Conditional("DBG")]
        internal static void Fail(string message) { 
#if DBG
            Assert(false, message);
#endif
        } 

        // 
        // Returns true if the tag is enabled, false otherwise. 
        // Note that the tag needn't be an exact match.
        // 
        internal static bool IsTagEnabled(string tagName) {
#if DBG
            EnsureInit();
            return GetTagValue(tagName) != TagValue.Disabled; 
#else
            return false; 
#endif 
        }
 
        //
        // Returns true if the tag present.
        // This function chekcs for an exact match.
        // 
        internal static bool IsTagPresent(string tagName) {
#if DBG 
            EnsureInit(); 
            return FindMatchingTag(tagName, true) != null;
#else 
            return false;
#endif
        }
 
        //
        // Breaks into the debugger, or launches one if not yet attached. 
        // 
        [System.Diagnostics.Conditional("DBG")]
        internal static void Break() { 
#if DBG
            if (!System.Diagnostics.Debugger.IsAttached) {
                System.Diagnostics.Debugger.Launch();
            } 
            else {
                System.Diagnostics.Debugger.Break(); 
            } 
#endif
        } 


        //
        // Tells the debug system to always validate calls for a 
        // particular tag. This is useful for temporarily enabling
        // validation in stress tests or other situations where you 
        // may not have control over the debug tags that are enabled 
        // on a particular machine.
        // 
        [System.Diagnostics.Conditional("DBG")]
        internal static void AlwaysValidate(string tagName) {
#if DBG
            EnsureInit(); 
            s_tableAlwaysValidate[tagName] = tagName;
#endif 
        } 

 
        //
        // Throws an exception if the assertion is not valid.
        // Use this function from a DebugValidate method where
        // you would otherwise use Assert. 
        //
        [System.Diagnostics.Conditional("DBG")] 
        internal static void CheckValid(bool assertion, string message) { 
#if DBG
            if (!assertion) { 
                throw new Exception(message);
            }
#endif
        } 

        // 
        // Calls DebugValidate on an object if such a method exists. 
        //
        // This method should be used from implementations of DebugValidate 
        // where it is unknown whether an object has a DebugValidate method.
        // For example, the DoubleLink class uses it to validate the
        // item of type Object which it points to.
        // 
        // This method should NOT be used when code wants to conditionally
        // validate an object and have a failed validation caught in an assert. 
        // Use Debug.Validate(tagName, obj) for that purpose. 
        //
        [System.Diagnostics.Conditional("DBG")] 
        internal static void Validate(Object obj) {
#if DBG
            Type        type;
            MethodInfo  mi; 

            if (obj != null) { 
                type = obj.GetType(); 

                mi = type.GetMethod( 
                        "DebugValidate",
                        BindingFlags.NonPublic | BindingFlags.Instance,
                        null,
                        s_ValidateArgs, 
                        null);
 
                if (mi != null) { 
                    object[] tempIndex = null;
                    mi.Invoke(obj, tempIndex); 
                }
            }
#endif
        } 

        // 
        // Validates an object is the "Validate" tag is enabled, or when 
        // the "Validate" tag is not disabled and the given 'tag' is enabled.
        // An Assertion is made if the validation fails. 
        //
        [System.Diagnostics.Conditional("DBG")]
        internal static void Validate(string tagName, Object obj) {
#if DBG 
            EnsureInit();
 
            if (    obj != null 
                    && (    IsTagEnabled("Validate")
                            ||  (   !IsTagPresent("Validate") 
                                    && (   s_tableAlwaysValidate[tagName] != null
                                           ||  IsTagEnabled(tagName))))) {
                try {
                    Debug.Validate(obj); 
                }
                catch (Exception e) { 
                    Debug.Assert(false, "Validate failed: " + e.InnerException.Message); 
                }
                catch { 
                    Debug.Assert(false, "Validate failed.  Non-CLS compliant exception caught.");
                }
            }
#endif 
        }
 
#if DBG 

        // 
        // Calls DebugDescription on an object to get its description.
        //
        // This method should only be used in implementations of DebugDescription
        // where it is not known whether a nested objects has an implementation 
        // of DebugDescription. For example, the double linked list class uses
        // GetDescription to get the description of the item it points to. 
        // 
        // This method should NOT be used when you want to conditionally
        // dump an object. Use Debug.Dump instead. 
        //
        // @param obj      The object to call DebugDescription on. May be null.
        // @param indent   A prefix for each line in the description. This is used
        //                 to allow the nested display of objects within other objects. 
        //                 The indent is usually a multiple of four spaces.
        // 
        // @return         The description. 
        //
        [ReflectionPermission(SecurityAction.Assert, Unrestricted=true)] 
        internal static string GetDescription(Object obj, string indent) {
            string      description;
            Type        type;
            MethodInfo  mi; 
            Object[]   parameters;
 
            if (obj == null) { 
                description = "\n";
            } 
            else {
                type = obj.GetType();
                mi = type.GetMethod(
                        "DebugDescription", 
                        BindingFlags.NonPublic | BindingFlags.Instance,
                        null, 
                        s_DumpArgs, 
                        null);
 
                if (mi == null || mi.ReturnType != typeof(string)) {
                    description = indent + obj.ToString();
                }
                else { 
                    parameters = new Object[1] {(Object) indent};
                    description = (string) mi.Invoke(obj, parameters); 
                } 
            }
 
            return description;
        }
#endif
 

        // 
        // Dumps an object to the debugger if the "Dump" tag is enabled, 
        // or if the "Dump" tag is not present and the 'tag' is enabled.
        // 
        // @param tagName  The tag to Dump with.
        // @param obj  The object to dump.
        //
        [System.Diagnostics.Conditional("DBG")] 
        internal static void Dump(string tagName, Object obj) {
#if DBG 
            EnsureInit(); 

            string  description; 
            string  traceTag = null;
            bool    dumpEnabled, dumpPresent;

            if (obj != null) { 
                dumpEnabled = IsTagEnabled("Dump");
                dumpPresent = IsTagPresent("Dump"); 
                if (dumpEnabled || !dumpPresent) { 
                    if (IsTagEnabled(tagName)) {
                        traceTag = tagName; 
                    }
                    else if (dumpEnabled) {
                        traceTag = "Dump";
                    } 

                    if (traceTag != null) { 
                        description = GetDescription(obj, string.Empty); 
                        Debug.Trace(traceTag, "Dump\n" + description);
                    } 
                }
            }
#endif
        } 

#if UNUSED_CODE 
 
#if DBG
        static internal string ToStringMaybeNull(object o) { 
            if (o != null) {
                return o.ToString();
            }
 
            return "";
        } 
#endif 

        static internal string FormatUtcDate(DateTime utcTime) { 
#if DBG
            DateTime localTime = DateTimeUtil.ConvertToLocalTime(utcTime);
            return localTime.ToString(DATE_FORMAT, CultureInfo.InvariantCulture);
#else 
            return string.Empty;
#endif 
        } 

        static internal string FormatLocalDate(DateTime localTime) { 
#if DBG
            return localTime.ToString(DATE_FORMAT, CultureInfo.InvariantCulture);
#else
            return string.Empty; 
#endif
        } 
 
#endif // UNUSED_CODE
 
    }
}

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

Link Menu

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