Exemplo n.º 1
0
        private static int ConnectDebuggerDumpHelper(DebugUtilities debugUtilities, string dumpFile, out SimpleDebugger debuggerInformation)
        {
            int hr;

            SimpleOutputHandler debuggerOutputCallbacks = null;
            SimpleEventHandler  debuggerEventCallbacks  = null;

            debuggerInformation = null;

            hr = SimpleOutputHandler.Install(debugUtilities, out debuggerOutputCallbacks);
            if (hr != S_OK)
            {
                goto Error;
            }

            hr = SimpleEventHandler.Install(debugUtilities, out debuggerEventCallbacks);
            if (hr != S_OK)
            {
                goto ErrorWithDetach;
            }

            hr = debugUtilities.DebugClient.OpenDumpFileWide(dumpFile, 0);
            if (FAILED(hr))
            {
                goto ErrorWithDetach;
            }

            while (debuggerEventCallbacks.SessionIsActive == false)
            {
                hr = debugUtilities.DebugControl.WaitForEvent(DEBUG_WAIT.DEFAULT, 50);
                if (FAILED(hr))
                {
                    goto ErrorWithDetach;
                }
            }

            debuggerInformation = new SimpleDebugger(debugUtilities, 0, true, debuggerOutputCallbacks, debuggerEventCallbacks);

            goto Exit;

ErrorWithDetach:
            debugUtilities.DebugClient.DetachProcesses();
            debugUtilities.DebugClient.EndSession(DEBUG_END.ACTIVE_DETACH);
Error:
            if (debuggerEventCallbacks != null)
            {
                debuggerEventCallbacks.Dispose();
            }
            if (debuggerOutputCallbacks != null)
            {
                debuggerOutputCallbacks.Dispose();
            }
Exit:
            return(hr);
        }
Exemplo n.º 2
0
        public ListEntryEnumerator(ulong head, int entryOffset, bool skipListHead, DebugUtilities d)
        {
            _d              = d;
            _head           = head;
            _entryOffset    = entryOffset;
            _isDisposed     = false;
            _skipListHead   = skipListHead;
            _headEnumerated = false;

            Reset();
        }
Exemplo n.º 3
0
        /// <summary>
        ///     Remove the output handler and restore the previously installed handler.
        ///     If we ever get into a situation where we are reverting but not the active output handler we will not overwrite the
        ///     current handler and will never restore the original handler!
        /// </summary>
        private void Dispose(bool disposing)
        {
            if (disposing == true)
            {
                if (Installed)
                {
                    Flush();
                    Installed = false;
                }

                IntPtr currentCallbacks = IntPtr.Zero;

                if (ExecutionUtilities != null)
                {
                    ExecutionUtilities.DebugClient.GetOutputCallbacksWide(out currentCallbacks); /* Will need to release this */
                    if (currentCallbacks == ThisIDebugOutputCallbacksPtr)
                    {
                        ExecutionUtilities.DebugClient.SetOutputCallbacksWide(PreviousCallbacks);
                    }
                    if (currentCallbacks != IntPtr.Zero)
                    {
                        Marshal.Release(currentCallbacks);
                        currentCallbacks = IntPtr.Zero;
                    }

                    if (PreviousCallbacks != IntPtr.Zero)
                    {
                        Marshal.Release(PreviousCallbacks);
                        PreviousCallbacks = IntPtr.Zero;
                    }
                    if (ThisIDebugOutputCallbacksPtr != IntPtr.Zero)
                    {
                        Marshal.Release(ThisIDebugOutputCallbacksPtr);
                        ThisIDebugOutputCallbacksPtr = IntPtr.Zero;
                    }

                    ExecutionUtilities = null; /* No need to release, just a copy of what was sent in */
                }
                if (LogFile != null)
                {
                    LogFile.Dispose();
                    LogFile = null;
                }

                foreach (BufferLine line in BufferedOutput)
                {
                    line.OutputLine(PassthroughUtilities);
                }
                BufferedOutput.Clear();
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Create a debugging connection to a process
        /// </summary>
        /// <param name="processID">The ID of the process to attach to</param>
        /// <param name="passive">Whether the debugger connection should be passive</param>
        /// <param name="debuggerInformation">An SimpleDebugger instance which contains connection information. Call Dispose() on this object.</param>
        /// <returns>HRESULT of the creation process</returns>
        public static int ConnectDebugger(uint processID, bool passive, out SimpleDebugger debuggerInformation)
        {
            IDebugClient debugClient = null;
            int          hr          = DebugCreate_IDebugClient(typeof(IDebugClient).GUID, out debugClient);

            if (FAILED(hr))
            {
                debuggerInformation = null;
                return(hr);
            }
            else
            {
                DebugUtilities debugUtilities = new DebugUtilities(debugClient);
                return(ConnectDebuggerLiveHelper(debugUtilities, processID, passive, out debuggerInformation));
            }
        }
        //FIX ME!!! This is a hack due to Win8:235420

        private void PassThroughLine(CallbackData cbd)
        {
            if (string.IsNullOrEmpty(cbd.Data?.ToString()))
            {
                return;
            }
            if (_reEnter == false)
            {
                _reEnter = true;

                if (cbd.Mask.HasFlag(DEBUG_OUTPUT.ADDR_TRANSLATE) && cbd.Mask.HasFlag(DEBUG_OUTPUT.NORMAL | DEBUG_OUTPUT.ERROR | DEBUG_OUTPUT.WARNING | DEBUG_OUTPUT.VERBOSE) == false)
                {
                    cbd.Mask = cbd.Mask | DEBUG_OUTPUT.NORMAL;
                }
                try
                {
                    if (_installedThreadId == Thread.CurrentThread.ManagedThreadId)
                    {
                        foreach (var bufferLine in _bufferedOutput)
                        {
                            bufferLine.Data.Insert(0, "BUFFERED ");
                            bufferLine.OutputLineMaskDisabled(_passthroughUtilities);
                        }
                        _bufferedOutput.Clear();
                        cbd.OutputLineMaskDisabled(_passthroughUtilities);
                    }
                    else
                    {
                        _bufferedOutput.Add(cbd);
                    }
                }
                catch
                {
                    DebugUtilities.CoUninitialize();
                    if (_installedThreadId == Thread.CurrentThread.ManagedThreadId)
                    {
                        cbd.OutputLineMaskDisabled(_passthroughUtilities);
                    }
                    else
                    {
                        _bufferedOutput.Add(cbd);
                    }
                }

                _reEnter = false;
            }
        }
Exemplo n.º 6
0
        /// <summary>
        ///     Creates a new SimpleOutputHandler instances and sets it as the active handler for the debugger.
        /// </summary>
        /// <param name="debugUtilities">A DebugUtilities associated with the debugger.</param>
        /// <param name="executionUtilities">
        ///     An utilities associated with the output handler. This interface should be used for all
        ///     actions where output should be redirected to the output handler.
        /// </param>
        /// <param name="outputCallbacks">
        ///     An out parameter to receive the new SimpleOutputHandler. CALL Revert AND/OR Dipose TO
        ///     REMOVE!
        /// </param>
        /// <param name="filter">An optional filter object to process the output data.</param>
        /// <param name="passThrough">
        ///     Whether the output data should be passed to the previously installed output handler. Default
        ///     is to cache locally only.
        /// </param>
        /// <param name="passThroughOnly">
        ///     Disables local caching of output data. Save memory and is more effient when the primary
        ///     goes it to pass the output data to the previously installed output handled (normally WinDbg).
        /// </param>
        /// <returns>Last HRESULT of the install process.</returns>
        public static int Install(DebugUtilities debugUtilities, out DebugUtilities executionUtilities, out SimpleOutputHandler outputCallbacks, OUTPUT_FILTER filter = null, bool passThrough = false, bool passThroughOnly = false)
        {
            IDebugClient executionClient;
            int          hr = debugUtilities.DebugClient.CreateClient(out executionClient);

            if (FAILED(hr))
            {
                debugUtilities.OutputVerboseLine("SimpleOutputHandler.Install Failed creating a new debug client for execution: {0:x8}", hr);
                outputCallbacks    = null;
                executionUtilities = null;
                return(hr);
            }

            executionUtilities = new DebugUtilities(executionClient);
            var oc = new SimpleOutputHandler(executionUtilities, debugUtilities, filter, passThrough, passThroughOnly);

            outputCallbacks = SUCCEEDED(oc.InstallationHRESULT) ? oc : null;
            return(oc.InstallationHRESULT);
        }
        /// <summary>
        ///     Creates a new SimpleOutputHandler instances and sets it as the active handler for the debugger.
        /// </summary>
        /// <param name="debugUtilities">A DebugUtilities associated with the debugger.</param>
        /// <param name="executionUtilities">
        ///     An utilities associated with the output handler. This interface should be used for all
        ///     actions where output should be redirected to the output handler.
        /// </param>
        /// <param name="outputCallbacks">
        ///     An out parameter to receive the new SimpleOutputHandler. CALL Revert AND/OR Dipose TO
        ///     REMOVE!
        /// </param>
        /// <param name="filter">An optional filter object to process the output data.</param>
        /// <param name="wantsDml">Whether DML should be accepted.</param>
        /// <param name="passThrough">
        ///     Whether the output data should be passed to the previously installed output handler. Default
        ///     is to cache locally only.
        /// </param>
        /// <param name="passThroughOnly">
        ///     Disables local caching of output data. Save memory and is more effient when the primary
        ///     goes it to pass the output data to the previously installed output handled (normally WinDbg).
        /// </param>
        /// <returns>Last HRESULT of the install process.</returns>
        public static int Install(DebugUtilities debugUtilities, out DebugUtilities executionUtilities, out SimpleOutputHandler2 outputCallbacks, OUTPUT_FILTER filter = null, bool wantsDml = true, bool passThrough = false, bool passThroughOnly = false)
        {
            IDebugClient executionClient;

            executionUtilities = new DebugUtilities(out executionClient);
            if (executionClient == null)
            {
                debugUtilities.OutputVerboseLine("SimpleOutputHandler.Install Failed creating a new debug client for execution");
                outputCallbacks    = null;
                executionUtilities = null;
                return(E_FAIL);
            }

            executionUtilities.IsFiltered = true;
            debugUtilities.IsFiltered     = true;
            var oc = new SimpleOutputHandler2(executionUtilities, debugUtilities, filter, wantsDml, passThrough, passThroughOnly);

            outputCallbacks = SUCCEEDED(oc.InstallationHRESULT) ? oc : null;
            return(oc.InstallationHRESULT);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Create a debugging connection to a process
        /// </summary>
        /// <param name="processName">The name of the process to attach to</param>
        /// <param name="passive">Whether the debugger connection should be passive</param>
        /// <param name="debuggerInformation">An SimpleDebugger instance which contains connection information. Call Dispose() on this object.</param>
        /// <returns>HRESULT of the creation process</returns>
        public static int ConnectDebugger(string processName, bool passive, out SimpleDebugger debuggerInformation)
        {
            IDebugClient debugClient = null;
            int          hr          = DebugCreate_IDebugClient(typeof(IDebugClient).GUID, out debugClient);

            if (FAILED(hr))
            {
                debuggerInformation = null;
                return(hr);
            }

            uint processID = 0;

            hr = debugClient.GetRunningProcessSystemIdByExecutableName(0, processName, 0, out processID);
            if (FAILED(hr))
            {
                goto Error;
            }

            DebugUtilities debugUtilities = new DebugUtilities(debugClient);

            hr = ConnectDebuggerLiveHelper(debugUtilities, processID, passive, out debuggerInformation);
            if (FAILED(hr))
            {
                goto Error;
            }

            goto Exit;

Error:
            if (debugClient != null)
            {
                ReleaseComObjectSafely(debugClient);
            }
            debuggerInformation = null;
Exit:
            return(hr);
        }
Exemplo n.º 9
0
            /// <summary>
            /// Detaches from the target process
            /// </summary>
            public void Detach(bool detaching)
            {
                if (Detached == false && detaching == true)
                {
                    if (OutputHandler != null)
                    {
                        OutputHandler.Dispose(); _OutputHandler = null;
                    }
                    if (EventHandler != null)
                    {
                        EventHandler.Dispose(); _EventHandler = null;
                    }
                    if (OriginatingDebugUtilities != null)
                    {
                        OriginatingDebugUtilities.DebugClient.DetachProcesses();
                        OriginatingDebugUtilities.DebugClient.EndSession(DEBUG_END.ACTIVE_DETACH);
                        DebugUtilities.ReleaseComObjectSafely(OriginatingDebugUtilities);
                        _OriginatingDebugUtilities = null;
                    }

                    Detached = true;
                }
            }
 private void Dispose(bool disposing)
 {
     if (_installed && disposing)
     {
         _installed = false;
         IntPtr currentCallbacks = IntPtr.Zero;
         _utilities.DebugClient.GetEventCallbacks(out currentCallbacks); /* We need to release this */
         if (this == Marshal.GetObjectForIUnknown(currentCallbacks))
         {
             _utilities.DebugClient.SetEventCallbacks(_previousCallbacks);
         }
         if (_previousCallbacks != IntPtr.Zero)
         {
             Marshal.Release(_previousCallbacks);
             _previousCallbacks = IntPtr.Zero;
         }
         if (currentCallbacks != IntPtr.Zero)
         {
             Marshal.Release(currentCallbacks);
             currentCallbacks = IntPtr.Zero;
         }
         _utilities = null;
     }
 }
            public int OutputLine(DebugUtilities d)
            {
                if (string.IsNullOrEmpty(Data.ToString()))
                {
                    return(S_OK);
                }
                DEBUG_OUTCTL outctl;

                if (d.IsFirstCommand)
                {
                    outctl = DEBUG_OUTCTL.ALL_CLIENTS;
                }
                else
                {
                    outctl = DEBUG_OUTCTL.THIS_CLIENT | DEBUG_OUTCTL.NOT_LOGGED;
                }

                if (IsDML)
                {
                    outctl |= DEBUG_OUTCTL.DML;
                }

                return(d.ControlledOutputWide(outctl, Mask, Data.ToString()));
            }
Exemplo n.º 12
0
 public void SetDebugUtilities(DebugUtilities d)
 {
     _utilities = d;
 }
Exemplo n.º 13
0
 /// <summary>
 ///     Appends a formatted string to the end of the buffer
 /// </summary>
 /// <param name="provider">Format provider</param>
 /// <param name="format">Format string</param>
 /// <param name="args">Arguments</param>
 /// <returns>The DbgStringBuilder instance</returns>
 public DbgStringBuilder AppendFormatEscaped(IFormatProvider provider, string format, params object[] args)
 {
     _sb.Append(DebugUtilities.EncodeTextForXml(_utilities.FormatString(provider, format, args)));
     return(this);
 }
Exemplo n.º 14
0
 /// <summary>
 ///     Appends an items to the end of the buffer followed by a newline, with XML special characters escaped
 /// </summary>
 /// <param name="addition">Value to insert</param>
 /// <returns>The DbgStringBuilder instance</returns>
 public DbgStringBuilder AppendLineEscaped(string addition)
 {
     _sb.Append(DebugUtilities.EncodeTextForXml(addition));
     _sb.Append('\n');
     return(this);
 }
Exemplo n.º 15
0
 /// <summary>
 ///     Constructor
 /// </summary>
 /// <param name="debugUtilities">A DebugUtilities associated with the debugger.</param>
 /// <param name="initialSize">Initial size of the buffer in characters</param>
 public DbgStringBuilder(DebugUtilities debugUtilities, int initialSize)
 {
     _sb        = new StringBuilder(initialSize);
     _utilities = debugUtilities;
 }
Exemplo n.º 16
0
 /// <summary>
 ///     Constructor
 /// </summary>
 /// <param name="debugUtilities">A DebugUtilities associated with the debugger.</param>
 public DbgStringBuilder(DebugUtilities debugUtilities)
 {
     _sb        = new StringBuilder();
     _utilities = debugUtilities;
 }
Exemplo n.º 17
0
            private static bool DecodePointerArguments(DebugUtilities d, string format, object param, out string outputString)
            {
                // fast exit code
                outputString = null;
                if (format[0] != 'p' && format[0] != 'P' && format[0] != 'q' && format[0] != 'Q')
                {
                    return(false);
                }

                switch (format[0])
                {
                case 'p':
                {
                    if (param == null)
                    {
                        outputString = "(null)";
                        return(true);
                    }
                    try
                    {
                        outputString = d.P2S((ulong)param);
                        break;
                    }
                    catch
                    {
                        if (format.Length == 1)
                        {
                            throw new Exception("Could not convert " + param + " to UInt64 for {x:p}");
                        }
                        return(false);
                    }
                }

                case 'P':
                {
                    if (param == null)
                    {
                        outputString = "(NULL)";
                        return(true);
                    }
                    try
                    {
                        outputString = d.P2SUC((ulong)param);
                        break;
                    }
                    catch
                    {
                        if (format.Length == 1)
                        {
                            throw new Exception("Could not convert " + param + " to UInt64 for {x:P}");
                        }
                        return(false);
                    }
                }

                case 'q':
                {
                    if (param == null)
                    {
                        outputString = "(null)";
                        return(true);
                    }
                    try
                    {
                        outputString = d.P2S((ulong)param, true);
                        break;
                    }
                    catch
                    {
                        if (format.Length == 1)
                        {
                            throw new Exception("Could not convert " + param + " to UInt64 for {x:q}");
                        }
                        return(false);
                    }
                }

                case 'Q':
                {
                    if (param == null)
                    {
                        outputString = "(NULL)";
                        return(true);
                    }
                    try
                    {
                        outputString = d.P2SUC((ulong)param, true);
                        break;
                    }
                    catch
                    {
                        if (format.Length == 1)
                        {
                            throw new Exception("Could not convert " + param + " to UInt64 for {x:Q}");
                        }
                        return(false);
                    }
                }
                }

                if (format.Length == 1)
                {
                    return(true);
                }

                if (outputString == null)
                {
                    return(false);
                }

                var sb = new StringBuilder(16);

                bool leftAlign;
                int  desiredWidth;

                if (!int.TryParse(format.Substring(1), out desiredWidth))
                {
                    outputString = null;
                    return(false);
                }

                if (desiredWidth < 0)
                {
                    desiredWidth = -desiredWidth;
                    leftAlign    = true;
                }
                else
                {
                    leftAlign = false;
                }

                var spacesToAdd = desiredWidth - outputString.Length;

                if (spacesToAdd > 0)
                {
                    if (leftAlign)
                    {
                        sb.Append(outputString);
                        sb.Append(' ', spacesToAdd);
                    }
                    else
                    {
                        sb.Append(' ', spacesToAdd);
                        sb.Append(outputString);
                    }
                }
                else
                {
                    sb.Append(outputString);
                }


                outputString = sb.ToString();

                return(true);
            }
Exemplo n.º 18
0
        private static int ConnectDebuggerLiveHelper(DebugUtilities debugUtilities, uint processID, bool passive, out SimpleDebugger debuggerInformation)
        {
            int hr;

            IDebugControl       debugControl       = null;
            IDebugSystemObjects debugSystemObjects = null;

            SimpleOutputHandler debuggerOutputCallbacks = null;
            SimpleEventHandler  debuggerEventCallbacks  = null;

            debuggerInformation = null;

            hr = SimpleOutputHandler.Install(debugUtilities, out debuggerOutputCallbacks);
            if (hr != S_OK)
            {
                goto Error;
            }

            hr = SimpleEventHandler.Install(debugUtilities, out debuggerEventCallbacks);
            if (hr != S_OK)
            {
                goto ErrorWithDetach;
            }

            DEBUG_ATTACH attachFlags = passive ? DEBUG_ATTACH.NONINVASIVE | DEBUG_ATTACH.NONINVASIVE_NO_SUSPEND : DEBUG_ATTACH.INVASIVE_RESUME_PROCESS;

            hr = debugUtilities.DebugClient.AttachProcess(0, processID, attachFlags);
            if (hr != S_OK)
            {
                goto ErrorWithDetach;
            }

            while (debuggerEventCallbacks.SessionIsActive == false)
            {
                hr = debugControl.WaitForEvent(DEBUG_WAIT.DEFAULT, 50);
                if (FAILED(hr))
                {
                    goto ErrorWithDetach;
                }
            }

            bool foundMatchingProcess = false;
            uint numProcesses;

            debugSystemObjects.GetNumberProcesses(out numProcesses);
            uint[] systemProcessIDs = new uint[numProcesses];
            uint[] engineProcessIDs = new uint[numProcesses];
            hr = debugSystemObjects.GetProcessIdsByIndex(0, numProcesses, engineProcessIDs, systemProcessIDs);
            for (uint i = 0; i < numProcesses; ++i)
            {
                if (systemProcessIDs[i] == processID)
                {
                    foundMatchingProcess = true;
                    hr = debugSystemObjects.SetCurrentProcessId(engineProcessIDs[i]);
                    if (FAILED(hr))
                    {
                        debuggerOutputCallbacks.AddNoteLine(String.Format(CultureInfo.InvariantCulture, "ERROR! Failed to set the active process! hr={0:x8}", hr));
                        goto ErrorWithDetach;
                    }
                    break;
                }
            }
            if (foundMatchingProcess == false)
            {
                hr = E_FAIL;
                debuggerOutputCallbacks.AddNoteLine(String.Format(CultureInfo.InvariantCulture, "ERROR! The debugger engine could not find the requested process ID ({0})!", processID));
                goto ErrorWithDetach;
            }

            debuggerInformation = new SimpleDebugger(debugUtilities, processID, passive, debuggerOutputCallbacks, debuggerEventCallbacks);

            goto Exit;

ErrorWithDetach:
            debugUtilities.DebugClient.DetachProcesses();
            debugUtilities.DebugClient.EndSession(DEBUG_END.ACTIVE_DETACH);
Error:
            if (debuggerEventCallbacks != null)
            {
                debuggerEventCallbacks.Dispose();
            }
            if (debuggerOutputCallbacks != null)
            {
                debuggerOutputCallbacks.Dispose();
            }
Exit:
            return(hr);
        }
 public int OutputLine(DebugUtilities d)
 {
     return(d.ControlledOutputWide(_outputControl, _mask, _data));
 }
Exemplo n.º 20
0
        public static List <ulong> EnumerateHashTable(DebugUtilities d, StructSymbolPlus HashTable)
        {
            // typedef struct _RTL_DYNAMIC_HASH_TABLE
            // {
            //
            //     // Entries initialized at creation
            //     ULONG Flags;
            //     ULONG Shift;
            //
            //     // Entries used in bucket computation.
            //     ULONG TableSize;
            //     ULONG Pivot;
            //     ULONG DivisorMask;
            //
            //     // Counters
            //     ULONG NumEntries;
            //     ULONG NonEmptyBuckets;
            //     ULONG NumEnumerators;
            //
            //     // The directory. This field is for internal use only.
            //     PVOID Directory;
            //
            // }
            // RTL_DYNAMIC_HASH_TABLE, *PRTL_DYNAMIC_HASH_TABLE;

            var entries   = new List <ulong>();
            var tableSize = HashTable.GetFieldValue("TableSize");

            ulong secondLevelDir   = 0;
            ulong dirIndex         = 0;
            ulong secondLevelIndex = 0;
            ulong bucket           = 0;
            ulong pDirectory       = 0;

            uint indirection = 0;

            if (tableSize <= KDEXT_RTL_HT_SECOND_LEVEL_DIR_SIZE)
            {
                indirection = BUCKET_ARRAY;
            }
            else
            {
                indirection = FIRST_LEVEL_DIR;  // First level dir
            }
            pDirectory = HashTable.GetFieldValue("Directory");

            for (bucket = 0; bucket < tableSize; bucket++)
            {
                ComputeDirIndices(bucket, out dirIndex, out secondLevelIndex);

                if (0 == secondLevelIndex)
                {
                    if (indirection == BUCKET_ARRAY)
                    {
                        secondLevelDir = pDirectory;
                    }
                    else // FIRST_LEVEL_DIR
                    {
                        var hr = d.ReadPointer(pDirectory + (dirIndex * d.PointerSize()),
                                               out secondLevelDir);
                        if (DebugUtilities.FAILED(hr))
                        {
                            d.OutputErrorLine("Failed to read second-level dir 0x{0:x}\n", dirIndex);
                            break;
                        }
                    }
                }

                //
                // Read the list head
                //

                var bucketHead    = secondLevelDir + secondLevelIndex * (2 * d.PointerSize());
                var bucketEntries = d.WalkList(bucketHead);

                entries.AddRange(bucketEntries);
            }

            foreach (var entry in entries)
            {
                //d.OutputDMLLine("Hash entry: 0x{0:x}", "!ddt netio!WFP_HASH_ENTRY 0x{0:x}", entry);
            }
            return(entries);
        }
Exemplo n.º 21
0
 public int OutputLine(DebugUtilities d)
 {
     return(d.ControlledOutputWide(OutputControl, Mask, Data));
 }
Exemplo n.º 22
0
 public DMLInterceptProvider(DebugUtilities d)
 {
     _d = d;
 }