TraceProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Shared / MS / Utility / TraceProvider.cs / 1305600 / TraceProvider.cs

                            //---------------------------------------------------------------------------- 
// File: TraceProvider
//
// A Managed wrapper for Event Tracing for Windows
// Based on TraceEvent.cs found in nt\base\wmi\trace.net 
// Provides an internal Avalon API to replace Microsoft.Windows.EventTracing.dll
// 
//--------------------------------------------------------------------------- 
#if !SILVERLIGHTXAML
using System; 
using MS.Win32;
using MS.Internal;
using System.Runtime.InteropServices;
using System.Security; 
using System.Globalization; //for CultureInfo
using System.Diagnostics; 
using MS.Internal.WindowsBase; 

#pragma warning disable 1634, 1691  //disable warnings about unknown pragma 

#if SYSTEM_XAML
using System.Xaml;
namespace MS.Internal.Xaml 
#else
namespace MS.Utility 
#endif 
{
    [StructLayout(LayoutKind.Explicit, Size = 16)] 
    internal struct EventData
    {
        [FieldOffset(0)]
        internal unsafe ulong Ptr; 
        [FieldOffset(8)]
        internal uint Size; 
        [FieldOffset(12)] 
        internal uint Reserved;
    } 

    internal abstract class TraceProvider
    {
        protected bool _enabled = false; 
        protected EventTrace.Level _level = EventTrace.Level.LogAlways;
        protected EventTrace.Keyword _keywords = (EventTrace.Keyword)0; /* aka Flags */ 
        protected EventTrace.Keyword _matchAllKeyword = (EventTrace.Keyword)0; /*Vista only*/ 
        protected SecurityCriticalDataForSet _registrationHandle;
 
        private const int s_basicTypeAllocationBufferSize = sizeof(decimal);
        private const int s_traceEventMaximumSize = 65482; // maximum buffer size is 64k - header size
        private const int s_etwMaxNumberArguments = 32;
        private const int s_etwAPIMaxStringCount = 8; // Arbitrary limit on the number of strings you can emit. This is just to limit allocations so raise it if necessary. 
        private const int ErrorEventTooBig = 2;
 
 
        [SecurityCritical]
        internal TraceProvider() 
        {
            _registrationHandle = new SecurityCriticalDataForSet(0);
        }
 
        [SecurityCritical]
        internal abstract void Register(Guid providerGuid); 
        [SecurityCritical] 
        internal unsafe abstract uint EventWrite(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level, int argc, EventData* argv);
 
        internal uint TraceEvent(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level)
        {
            // Optimization for 0-1 arguments
            return TraceEvent(eventID, keywords, level, (object)null); 
        }
 
        #region Properties and Structs 

        // 
        // Properties
        //
        internal EventTrace.Keyword Keywords
        { 
            get
            { 
                return _keywords; 
            }
        } 

        internal EventTrace.Keyword MatchAllKeywords
        {
            get 
            {
                return _matchAllKeyword; 
            } 
        }
 
        internal EventTrace.Level Level
        {
            get
            { 
                return _level;
            } 
        } 

        #endregion 

        internal bool IsEnabled(EventTrace.Keyword keyword, EventTrace.Level level)
        {
           return _enabled && 
                  (level <= _level) &&
                  (keyword & _keywords) != 0 && 
                  (keyword & _matchAllKeyword) == _matchAllKeyword; 
        }
 
        // Optimization for 0-1 arguments
        [SecurityCritical, SecurityTreatAsSafe]
        internal unsafe uint TraceEvent(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level, object eventData)
        { 
            // It is the responsibility of the caller to check that flags/keywords are enabled before calling this method
            Debug.Assert(IsEnabled(keywords, level)); 
 
            uint status = 0;
            int argCount = 0; 

            EventData userData;
            userData.Size = 0;
            string dataString = null; 
            byte* dataBuffer = stackalloc byte[s_basicTypeAllocationBufferSize];
 
            if (eventData != null) 
            {
                dataString = EncodeObject(ref eventData, &userData, dataBuffer); 
                argCount = 1;
            }

            if (userData.Size > s_traceEventMaximumSize) 
            {
                return ErrorEventTooBig; 
            } 

            if (dataString != null) 
            {
                fixed(char* pdata = dataString)
                {
                    userData.Ptr = (ulong)pdata; 
                    status = EventWrite(eventID, keywords, level, argCount, &userData);
                } 
            } 
            else
            { 
                status = EventWrite(eventID, keywords, level, argCount, &userData);
            }

            return status; 
        }
 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal unsafe uint TraceEvent(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level, params object[] eventPayload)
        { 
            // It is the responsibility of the caller to check that flags/keywords are enabled before calling this method
            Debug.Assert(IsEnabled(keywords, level));

            int argCount = eventPayload.Length; 

            Debug.Assert(argCount <= s_etwMaxNumberArguments); 
 
            uint totalEventSize = 0;
            int stringIndex = 0; 
            int[] stringPosition =  new int[s_etwAPIMaxStringCount];
            string [] dataString = new string[s_etwAPIMaxStringCount];
            EventData* userData = stackalloc EventData[argCount];
            EventData* userDataPtr = userData; 
            byte* dataBuffer = stackalloc byte[s_basicTypeAllocationBufferSize * argCount];
            byte* currentBuffer = dataBuffer; 
 

            for (int index = 0; index < argCount; index++) 
            {
                if (eventPayload[index] != null)
                {
                    string isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer); 
                    currentBuffer += s_basicTypeAllocationBufferSize;
                    totalEventSize = userDataPtr->Size; 
                    userDataPtr++; 
                    if (isString != null)
                    { 
                        Debug.Assert(stringIndex < s_etwAPIMaxStringCount); // need to increase string count or emit fewer strings
                        dataString[stringIndex] = isString;
                        stringPosition[stringIndex] = index;
                        stringIndex++; 
                    }
                } 
            } 

            if (totalEventSize > s_traceEventMaximumSize) 
            {
                return ErrorEventTooBig;
            }
 
            fixed(char* s0 = dataString[0], s1 = dataString[1], s2 = dataString[2], s3 = dataString[3],
                    s4 = dataString[4], s5 = dataString[5], s6 = dataString[6], s7 = dataString[7]) 
            { 
                userDataPtr = userData;
                if (dataString[0] != null) 
                {
                    userDataPtr[stringPosition[0]].Ptr = (ulong)s0;
                }
                if (dataString[1] != null) 
                {
                    userDataPtr[stringPosition[1]].Ptr = (ulong)s1; 
                } 
                if (dataString[2] != null)
                { 
                    userDataPtr[stringPosition[2]].Ptr = (ulong)s2;
                }
                if (dataString[3] != null)
                { 
                    userDataPtr[stringPosition[3]].Ptr = (ulong)s3;
                } 
                if (dataString[4] != null) 
                {
                    userDataPtr[stringPosition[4]].Ptr = (ulong)s4; 
                }
                if (dataString[5] != null)
                {
                    userDataPtr[stringPosition[5]].Ptr = (ulong)s5; 
                }
                if (dataString[6] != null) 
                { 
                    userDataPtr[stringPosition[6]].Ptr = (ulong)s6;
                } 
                if (dataString[7] != null)
                {
                    userDataPtr[stringPosition[7]].Ptr = (ulong)s7;
                } 

                return EventWrite(eventID, keywords, level, argCount, userData); 
            } 
        }
 

        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        [SecurityCritical] 
        private static unsafe string EncodeObject(ref object data, EventData* dataDescriptor, byte* dataBuffer)
        /*++ 
 
        Routine Description:
 
           This routine is used by WriteEvent to unbox the object type and
           to fill the passed in ETW data descriptor.

        Arguments: 

           data - argument to be decoded 
 
           dataDescriptor - pointer to the descriptor to be filled
 
           dataBuffer - storage buffer for storing user data, needed because cant get the address of the object

        Return Value:
 
           null if the object is a basic type other than string. String otherwise
 
        --*/ 
        {
            dataDescriptor->Reserved = 0; 

            string sRet = data as string;
            if (sRet != null)
            { 
                dataDescriptor->Size = (uint)((sRet.Length + 1) * 2);
                return sRet; 
            } 

            // If the data is an enum we'll convert it to it's underlying type 
            Type dataType = data.GetType();
            if (dataType.IsEnum)
            {
                data = Convert.ChangeType(data, Enum.GetUnderlyingType(dataType), CultureInfo.InvariantCulture); 
            }
 
            if (data is IntPtr) 
            {
                dataDescriptor->Size = (uint)sizeof(IntPtr); 
                IntPtr* intptrPtr = (IntPtr*)dataBuffer;
                *intptrPtr = (IntPtr)data;
                dataDescriptor->Ptr = (ulong)intptrPtr;
            } 
            else if (data is int)
            { 
                dataDescriptor->Size = (uint)sizeof(int); 
                int* intptrPtr = (int*)dataBuffer;
                *intptrPtr = (int)data; 
                dataDescriptor->Ptr = (ulong)intptrPtr;
            }
            else if (data is long)
            { 
                dataDescriptor->Size = (uint)sizeof(long);
                long* longptr = (long*)dataBuffer; 
                *longptr = (long)data; 
                dataDescriptor->Ptr = (ulong)longptr;
            } 
            else if (data is uint)
            {
                dataDescriptor->Size = (uint)sizeof(uint);
                uint* uintptr = (uint*)dataBuffer; 
                *uintptr = (uint)data;
                dataDescriptor->Ptr = (ulong)uintptr; 
            } 
            else if (data is UInt64)
            { 
                dataDescriptor->Size = (uint)sizeof(ulong);
                ulong* ulongptr = (ulong*)dataBuffer;
                *ulongptr = (ulong)data;
                dataDescriptor->Ptr = (ulong)ulongptr; 
            }
            else if (data is char) 
            { 
                dataDescriptor->Size = (uint)sizeof(char);
                char* charptr = (char*)dataBuffer; 
                *charptr = (char)data;
                dataDescriptor->Ptr = (ulong)charptr;
            }
            else if (data is byte) 
            {
                dataDescriptor->Size = (uint)sizeof(byte); 
                byte* byteptr = (byte*)dataBuffer; 
                *byteptr = (byte)data;
                dataDescriptor->Ptr = (ulong)byteptr; 
            }
            else if (data is short)
            {
                dataDescriptor->Size = (uint)sizeof(short); 
                short* shortptr = (short*)dataBuffer;
                *shortptr = (short)data; 
                dataDescriptor->Ptr = (ulong)shortptr; 
            }
            else if (data is sbyte) 
            {
                dataDescriptor->Size = (uint)sizeof(sbyte);
                sbyte* sbyteptr = (sbyte*)dataBuffer;
                *sbyteptr = (sbyte)data; 
                dataDescriptor->Ptr = (ulong)sbyteptr;
            } 
            else if (data is ushort) 
            {
                dataDescriptor->Size = (uint)sizeof(ushort); 
                ushort* ushortptr = (ushort*)dataBuffer;
                *ushortptr = (ushort)data;
                dataDescriptor->Ptr = (ulong)ushortptr;
            } 
            else if (data is float)
            { 
                dataDescriptor->Size = (uint)sizeof(float); 
                float* floatptr = (float*)dataBuffer;
                *floatptr = (float)data; 
                dataDescriptor->Ptr = (ulong)floatptr;
            }
            else if (data is double)
            { 
                dataDescriptor->Size = (uint)sizeof(double);
                double* doubleptr = (double*)dataBuffer; 
                *doubleptr = (double)data; 
                dataDescriptor->Ptr = (ulong)doubleptr;
            } 
            else if (data is bool)
            {
                dataDescriptor->Size = (uint)sizeof(bool);
                bool* boolptr = (bool*)dataBuffer; 
                *boolptr = (bool)data;
                dataDescriptor->Ptr = (ulong)boolptr; 
            } 
            else if (data is Guid)
            { 
                dataDescriptor->Size = (uint)sizeof(Guid);
                Guid* guidptr = (Guid*)dataBuffer;
                *guidptr = (Guid)data;
                dataDescriptor->Ptr = (ulong)guidptr; 
            }
            else if (data is decimal) 
            { 
                dataDescriptor->Size = (uint)sizeof(decimal);
                decimal* decimalptr = (decimal*)dataBuffer; 
                *decimalptr = (decimal)data;
                dataDescriptor->Ptr = (ulong)decimalptr;
            }
            else if (data is Boolean) 
            {
                dataDescriptor->Size = (uint)sizeof(Boolean); 
                Boolean* booleanptr = (Boolean*)dataBuffer; 
                *booleanptr = (Boolean)data;
                dataDescriptor->Ptr = (ulong)booleanptr; 
            }
            else
            {
                //To our eyes, everything else is a just a string 
                sRet = data.ToString();
                dataDescriptor->Size = (uint)((sRet.Length + 1) * 2); 
                return sRet; 
            }
 
            return null;
        }
    }
 
    // XP
    internal sealed class ClassicTraceProvider : TraceProvider 
    { 
        private ulong _traceHandle = 0;
        private static ClassicEtw.ControlCallback _etwProc;   // Trace Callback function 

        [SecurityCritical]
        internal ClassicTraceProvider()
        { 
        }
 
        // 
        // Registers the providerGuid with an inbuilt callback
        // 
        ///
        /// Critical:  This calls critical code in UnsafeNativeMethods.EtwTrace
        /// and sets critical for set field _registrationHandle
        /// 
        [SecurityCritical]
        internal override unsafe void Register(Guid providerGuid) 
        { 
            ulong registrationHandle;
            ClassicEtw.TRACE_GUID_REGISTRATION guidReg; 

            Guid dummyGuid = new Guid(0xb4955bf0,
                                      0x3af1,
                                      0x4740, 
                                      0xb4,0x75,
                                      0x99,0x05,0x5d,0x3f,0xe9,0xaa); 
 
            _etwProc = new ClassicEtw.ControlCallback(EtwEnableCallback);
 
            // This dummyGuid is there for ETW backward compat issues and is the same for all downlevel trace providers
            guidReg.Guid = &dummyGuid;
            guidReg.RegHandle = null;
 
            ClassicEtw.RegisterTraceGuidsW(_etwProc, IntPtr.Zero, ref providerGuid, 1, ref guidReg, null, null, out registrationHandle);
            _registrationHandle.Value = registrationHandle; 
        } 

        // 
        // This callback function is called by ETW to enable or disable this provider
        //
        ///
        /// Critical:  This calls critical code in ClassicEtw 
        ///
        [SecurityCritical] 
        private unsafe uint EtwEnableCallback(ClassicEtw.WMIDPREQUESTCODE requestCode, IntPtr context, IntPtr bufferSize, ClassicEtw.WNODE_HEADER* buffer) 
        {
            try 
            {
                switch (requestCode)
                {
                    case ClassicEtw.WMIDPREQUESTCODE.EnableEvents: 
                        _traceHandle = buffer->HistoricalContext;
                        _keywords = (EventTrace.Keyword)ClassicEtw.GetTraceEnableFlags((ulong)buffer->HistoricalContext); 
                        _level = (EventTrace.Level)ClassicEtw.GetTraceEnableLevel((ulong)buffer->HistoricalContext); 
                        _enabled = true;
                        break; 
                    case ClassicEtw.WMIDPREQUESTCODE.DisableEvents:
                        _enabled = false;
                        _traceHandle = 0;
                        _level = EventTrace.Level.LogAlways; 
                        _keywords = 0;
                        break; 
                    default: 
                        _enabled = false;
                        _traceHandle = 0; 
                        break;
                }
                return 0;
            } 
            catch(Exception e)
            { 
                if (CriticalExceptions.IsCriticalException(e)) 
                {
                   throw; 
                }
                else
                {
                    return 0; 
                }
            } 
        } 

        /// 
        /// Critical:  This calls critical code in EtwTrace
        /// TreatAsSafe: the registration handle this passes in to UnregisterTraceGuids
        /// was generated by the ETW unmanaged API and can't be tampered with from our side
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        ~ClassicTraceProvider() 
        { 
            #pragma warning suppress 6031  //presharp suppression
            ClassicEtw.UnregisterTraceGuids(_registrationHandle.Value); 
        }

        // pack the argv data and emit the event using TraceEvent
        [SecurityCritical] 
        internal unsafe override uint EventWrite(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level, int argc, EventData* argv)
        { 
            ClassicEtw.EVENT_HEADER header; 
            header.Header.ClientContext = 0;
            header.Header.Flags = ClassicEtw.WNODE_FLAG_TRACED_GUID | ClassicEtw.WNODE_FLAG_USE_MOF_PTR; 
            header.Header.Guid = EventTrace.GetGuidForEvent(eventID);
            header.Header.Level = (byte)level;
            header.Header.Type = (byte)EventTrace.GetOpcodeForEvent(eventID);
            header.Header.Version = (ushort)EventTrace.GetVersionForEvent(eventID); 
            // Extra copy on XP to move argv to the end of the EVENT_HEADER
            EventData* eventData = &header.Data; 
 
            if (argc > ClassicEtw.MAX_MOF_FIELDS)
            { 
                // Data will be lost on XP
                argc = ClassicEtw.MAX_MOF_FIELDS;
            }
 
            header.Header.Size = (ushort) (argc * sizeof(EventData) + 48);
            for (int x = 0; x < argc; x++) 
            { 
                eventData[x].Ptr = argv[x].Ptr;
                eventData[x].Size = argv[x].Size; 
            }

            return ClassicEtw.TraceEvent(_traceHandle, &header);
        } 
    }
 
    // Vista and above 
    internal class ManifestTraceProvider : TraceProvider
    { 
        private static ManifestEtw.EtwEnableCallback _etwEnabledCallback;

        [SecurityCritical]
        internal ManifestTraceProvider() 
        {
        } 
 
        [SecurityCritical]
        internal unsafe override void Register(Guid providerGuid) 
        {
            _etwEnabledCallback =new ManifestEtw.EtwEnableCallback(EtwEnableCallback);
            ulong registrationHandle = 0;
            ManifestEtw.EventRegister(ref providerGuid, _etwEnabledCallback, null, ref registrationHandle); 
            _registrationHandle.Value = registrationHandle;
        } 
 
        [SecurityCritical]
        private unsafe void EtwEnableCallback(ref Guid sourceId, int isEnabled, byte level, long matchAnyKeywords, long matchAllKeywords, ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData, void* callbackContext) 
        {
            _enabled = isEnabled > 0;
            _level = (EventTrace.Level)level;
            _keywords = (EventTrace.Keyword) matchAnyKeywords; 
            _matchAllKeyword = (EventTrace.Keyword) matchAllKeywords;
 
            // todo: parse data from EVENT_FILTER_DESCRIPTOR - see CLR EventProvider::GetDataFromController 
        }
 
        [SecurityCritical, SecurityTreatAsSafe]
        ~ManifestTraceProvider()
        {
            ManifestEtw.EventUnregister(_registrationHandle.Value); 
        }
 
        [SecurityCritical] 
        internal unsafe override uint EventWrite(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level, int argc, EventData* argv)
        { 
            ManifestEtw.EventDescriptor eventDescriptor;
            eventDescriptor.Id = (ushort) eventID;
            eventDescriptor.Version = EventTrace.GetVersionForEvent(eventID);
            eventDescriptor.Channel = 0x10; // Since Channel isn't supported on XP we only use a single default channel. 
            eventDescriptor.Level = (byte)level;
            eventDescriptor.Opcode = EventTrace.GetOpcodeForEvent(eventID); 
            eventDescriptor.Task = EventTrace.GetTaskForEvent(eventID); 
            eventDescriptor.Keywords = (long)keywords;
            if (argc == 0) 
            {
                argv = null;
            }
 
            return ManifestEtw.EventWrite(_registrationHandle.Value, ref eventDescriptor, (uint)argc, argv);
        } 
 
    }
} 

#endif

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
// File: TraceProvider
//
// A Managed wrapper for Event Tracing for Windows
// Based on TraceEvent.cs found in nt\base\wmi\trace.net 
// Provides an internal Avalon API to replace Microsoft.Windows.EventTracing.dll
// 
//--------------------------------------------------------------------------- 
#if !SILVERLIGHTXAML
using System; 
using MS.Win32;
using MS.Internal;
using System.Runtime.InteropServices;
using System.Security; 
using System.Globalization; //for CultureInfo
using System.Diagnostics; 
using MS.Internal.WindowsBase; 

#pragma warning disable 1634, 1691  //disable warnings about unknown pragma 

#if SYSTEM_XAML
using System.Xaml;
namespace MS.Internal.Xaml 
#else
namespace MS.Utility 
#endif 
{
    [StructLayout(LayoutKind.Explicit, Size = 16)] 
    internal struct EventData
    {
        [FieldOffset(0)]
        internal unsafe ulong Ptr; 
        [FieldOffset(8)]
        internal uint Size; 
        [FieldOffset(12)] 
        internal uint Reserved;
    } 

    internal abstract class TraceProvider
    {
        protected bool _enabled = false; 
        protected EventTrace.Level _level = EventTrace.Level.LogAlways;
        protected EventTrace.Keyword _keywords = (EventTrace.Keyword)0; /* aka Flags */ 
        protected EventTrace.Keyword _matchAllKeyword = (EventTrace.Keyword)0; /*Vista only*/ 
        protected SecurityCriticalDataForSet _registrationHandle;
 
        private const int s_basicTypeAllocationBufferSize = sizeof(decimal);
        private const int s_traceEventMaximumSize = 65482; // maximum buffer size is 64k - header size
        private const int s_etwMaxNumberArguments = 32;
        private const int s_etwAPIMaxStringCount = 8; // Arbitrary limit on the number of strings you can emit. This is just to limit allocations so raise it if necessary. 
        private const int ErrorEventTooBig = 2;
 
 
        [SecurityCritical]
        internal TraceProvider() 
        {
            _registrationHandle = new SecurityCriticalDataForSet(0);
        }
 
        [SecurityCritical]
        internal abstract void Register(Guid providerGuid); 
        [SecurityCritical] 
        internal unsafe abstract uint EventWrite(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level, int argc, EventData* argv);
 
        internal uint TraceEvent(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level)
        {
            // Optimization for 0-1 arguments
            return TraceEvent(eventID, keywords, level, (object)null); 
        }
 
        #region Properties and Structs 

        // 
        // Properties
        //
        internal EventTrace.Keyword Keywords
        { 
            get
            { 
                return _keywords; 
            }
        } 

        internal EventTrace.Keyword MatchAllKeywords
        {
            get 
            {
                return _matchAllKeyword; 
            } 
        }
 
        internal EventTrace.Level Level
        {
            get
            { 
                return _level;
            } 
        } 

        #endregion 

        internal bool IsEnabled(EventTrace.Keyword keyword, EventTrace.Level level)
        {
           return _enabled && 
                  (level <= _level) &&
                  (keyword & _keywords) != 0 && 
                  (keyword & _matchAllKeyword) == _matchAllKeyword; 
        }
 
        // Optimization for 0-1 arguments
        [SecurityCritical, SecurityTreatAsSafe]
        internal unsafe uint TraceEvent(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level, object eventData)
        { 
            // It is the responsibility of the caller to check that flags/keywords are enabled before calling this method
            Debug.Assert(IsEnabled(keywords, level)); 
 
            uint status = 0;
            int argCount = 0; 

            EventData userData;
            userData.Size = 0;
            string dataString = null; 
            byte* dataBuffer = stackalloc byte[s_basicTypeAllocationBufferSize];
 
            if (eventData != null) 
            {
                dataString = EncodeObject(ref eventData, &userData, dataBuffer); 
                argCount = 1;
            }

            if (userData.Size > s_traceEventMaximumSize) 
            {
                return ErrorEventTooBig; 
            } 

            if (dataString != null) 
            {
                fixed(char* pdata = dataString)
                {
                    userData.Ptr = (ulong)pdata; 
                    status = EventWrite(eventID, keywords, level, argCount, &userData);
                } 
            } 
            else
            { 
                status = EventWrite(eventID, keywords, level, argCount, &userData);
            }

            return status; 
        }
 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal unsafe uint TraceEvent(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level, params object[] eventPayload)
        { 
            // It is the responsibility of the caller to check that flags/keywords are enabled before calling this method
            Debug.Assert(IsEnabled(keywords, level));

            int argCount = eventPayload.Length; 

            Debug.Assert(argCount <= s_etwMaxNumberArguments); 
 
            uint totalEventSize = 0;
            int stringIndex = 0; 
            int[] stringPosition =  new int[s_etwAPIMaxStringCount];
            string [] dataString = new string[s_etwAPIMaxStringCount];
            EventData* userData = stackalloc EventData[argCount];
            EventData* userDataPtr = userData; 
            byte* dataBuffer = stackalloc byte[s_basicTypeAllocationBufferSize * argCount];
            byte* currentBuffer = dataBuffer; 
 

            for (int index = 0; index < argCount; index++) 
            {
                if (eventPayload[index] != null)
                {
                    string isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer); 
                    currentBuffer += s_basicTypeAllocationBufferSize;
                    totalEventSize = userDataPtr->Size; 
                    userDataPtr++; 
                    if (isString != null)
                    { 
                        Debug.Assert(stringIndex < s_etwAPIMaxStringCount); // need to increase string count or emit fewer strings
                        dataString[stringIndex] = isString;
                        stringPosition[stringIndex] = index;
                        stringIndex++; 
                    }
                } 
            } 

            if (totalEventSize > s_traceEventMaximumSize) 
            {
                return ErrorEventTooBig;
            }
 
            fixed(char* s0 = dataString[0], s1 = dataString[1], s2 = dataString[2], s3 = dataString[3],
                    s4 = dataString[4], s5 = dataString[5], s6 = dataString[6], s7 = dataString[7]) 
            { 
                userDataPtr = userData;
                if (dataString[0] != null) 
                {
                    userDataPtr[stringPosition[0]].Ptr = (ulong)s0;
                }
                if (dataString[1] != null) 
                {
                    userDataPtr[stringPosition[1]].Ptr = (ulong)s1; 
                } 
                if (dataString[2] != null)
                { 
                    userDataPtr[stringPosition[2]].Ptr = (ulong)s2;
                }
                if (dataString[3] != null)
                { 
                    userDataPtr[stringPosition[3]].Ptr = (ulong)s3;
                } 
                if (dataString[4] != null) 
                {
                    userDataPtr[stringPosition[4]].Ptr = (ulong)s4; 
                }
                if (dataString[5] != null)
                {
                    userDataPtr[stringPosition[5]].Ptr = (ulong)s5; 
                }
                if (dataString[6] != null) 
                { 
                    userDataPtr[stringPosition[6]].Ptr = (ulong)s6;
                } 
                if (dataString[7] != null)
                {
                    userDataPtr[stringPosition[7]].Ptr = (ulong)s7;
                } 

                return EventWrite(eventID, keywords, level, argCount, userData); 
            } 
        }
 

        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        //  
        // 
        // 
        // 
        [SecurityCritical] 
        private static unsafe string EncodeObject(ref object data, EventData* dataDescriptor, byte* dataBuffer)
        /*++ 
 
        Routine Description:
 
           This routine is used by WriteEvent to unbox the object type and
           to fill the passed in ETW data descriptor.

        Arguments: 

           data - argument to be decoded 
 
           dataDescriptor - pointer to the descriptor to be filled
 
           dataBuffer - storage buffer for storing user data, needed because cant get the address of the object

        Return Value:
 
           null if the object is a basic type other than string. String otherwise
 
        --*/ 
        {
            dataDescriptor->Reserved = 0; 

            string sRet = data as string;
            if (sRet != null)
            { 
                dataDescriptor->Size = (uint)((sRet.Length + 1) * 2);
                return sRet; 
            } 

            // If the data is an enum we'll convert it to it's underlying type 
            Type dataType = data.GetType();
            if (dataType.IsEnum)
            {
                data = Convert.ChangeType(data, Enum.GetUnderlyingType(dataType), CultureInfo.InvariantCulture); 
            }
 
            if (data is IntPtr) 
            {
                dataDescriptor->Size = (uint)sizeof(IntPtr); 
                IntPtr* intptrPtr = (IntPtr*)dataBuffer;
                *intptrPtr = (IntPtr)data;
                dataDescriptor->Ptr = (ulong)intptrPtr;
            } 
            else if (data is int)
            { 
                dataDescriptor->Size = (uint)sizeof(int); 
                int* intptrPtr = (int*)dataBuffer;
                *intptrPtr = (int)data; 
                dataDescriptor->Ptr = (ulong)intptrPtr;
            }
            else if (data is long)
            { 
                dataDescriptor->Size = (uint)sizeof(long);
                long* longptr = (long*)dataBuffer; 
                *longptr = (long)data; 
                dataDescriptor->Ptr = (ulong)longptr;
            } 
            else if (data is uint)
            {
                dataDescriptor->Size = (uint)sizeof(uint);
                uint* uintptr = (uint*)dataBuffer; 
                *uintptr = (uint)data;
                dataDescriptor->Ptr = (ulong)uintptr; 
            } 
            else if (data is UInt64)
            { 
                dataDescriptor->Size = (uint)sizeof(ulong);
                ulong* ulongptr = (ulong*)dataBuffer;
                *ulongptr = (ulong)data;
                dataDescriptor->Ptr = (ulong)ulongptr; 
            }
            else if (data is char) 
            { 
                dataDescriptor->Size = (uint)sizeof(char);
                char* charptr = (char*)dataBuffer; 
                *charptr = (char)data;
                dataDescriptor->Ptr = (ulong)charptr;
            }
            else if (data is byte) 
            {
                dataDescriptor->Size = (uint)sizeof(byte); 
                byte* byteptr = (byte*)dataBuffer; 
                *byteptr = (byte)data;
                dataDescriptor->Ptr = (ulong)byteptr; 
            }
            else if (data is short)
            {
                dataDescriptor->Size = (uint)sizeof(short); 
                short* shortptr = (short*)dataBuffer;
                *shortptr = (short)data; 
                dataDescriptor->Ptr = (ulong)shortptr; 
            }
            else if (data is sbyte) 
            {
                dataDescriptor->Size = (uint)sizeof(sbyte);
                sbyte* sbyteptr = (sbyte*)dataBuffer;
                *sbyteptr = (sbyte)data; 
                dataDescriptor->Ptr = (ulong)sbyteptr;
            } 
            else if (data is ushort) 
            {
                dataDescriptor->Size = (uint)sizeof(ushort); 
                ushort* ushortptr = (ushort*)dataBuffer;
                *ushortptr = (ushort)data;
                dataDescriptor->Ptr = (ulong)ushortptr;
            } 
            else if (data is float)
            { 
                dataDescriptor->Size = (uint)sizeof(float); 
                float* floatptr = (float*)dataBuffer;
                *floatptr = (float)data; 
                dataDescriptor->Ptr = (ulong)floatptr;
            }
            else if (data is double)
            { 
                dataDescriptor->Size = (uint)sizeof(double);
                double* doubleptr = (double*)dataBuffer; 
                *doubleptr = (double)data; 
                dataDescriptor->Ptr = (ulong)doubleptr;
            } 
            else if (data is bool)
            {
                dataDescriptor->Size = (uint)sizeof(bool);
                bool* boolptr = (bool*)dataBuffer; 
                *boolptr = (bool)data;
                dataDescriptor->Ptr = (ulong)boolptr; 
            } 
            else if (data is Guid)
            { 
                dataDescriptor->Size = (uint)sizeof(Guid);
                Guid* guidptr = (Guid*)dataBuffer;
                *guidptr = (Guid)data;
                dataDescriptor->Ptr = (ulong)guidptr; 
            }
            else if (data is decimal) 
            { 
                dataDescriptor->Size = (uint)sizeof(decimal);
                decimal* decimalptr = (decimal*)dataBuffer; 
                *decimalptr = (decimal)data;
                dataDescriptor->Ptr = (ulong)decimalptr;
            }
            else if (data is Boolean) 
            {
                dataDescriptor->Size = (uint)sizeof(Boolean); 
                Boolean* booleanptr = (Boolean*)dataBuffer; 
                *booleanptr = (Boolean)data;
                dataDescriptor->Ptr = (ulong)booleanptr; 
            }
            else
            {
                //To our eyes, everything else is a just a string 
                sRet = data.ToString();
                dataDescriptor->Size = (uint)((sRet.Length + 1) * 2); 
                return sRet; 
            }
 
            return null;
        }
    }
 
    // XP
    internal sealed class ClassicTraceProvider : TraceProvider 
    { 
        private ulong _traceHandle = 0;
        private static ClassicEtw.ControlCallback _etwProc;   // Trace Callback function 

        [SecurityCritical]
        internal ClassicTraceProvider()
        { 
        }
 
        // 
        // Registers the providerGuid with an inbuilt callback
        // 
        ///
        /// Critical:  This calls critical code in UnsafeNativeMethods.EtwTrace
        /// and sets critical for set field _registrationHandle
        /// 
        [SecurityCritical]
        internal override unsafe void Register(Guid providerGuid) 
        { 
            ulong registrationHandle;
            ClassicEtw.TRACE_GUID_REGISTRATION guidReg; 

            Guid dummyGuid = new Guid(0xb4955bf0,
                                      0x3af1,
                                      0x4740, 
                                      0xb4,0x75,
                                      0x99,0x05,0x5d,0x3f,0xe9,0xaa); 
 
            _etwProc = new ClassicEtw.ControlCallback(EtwEnableCallback);
 
            // This dummyGuid is there for ETW backward compat issues and is the same for all downlevel trace providers
            guidReg.Guid = &dummyGuid;
            guidReg.RegHandle = null;
 
            ClassicEtw.RegisterTraceGuidsW(_etwProc, IntPtr.Zero, ref providerGuid, 1, ref guidReg, null, null, out registrationHandle);
            _registrationHandle.Value = registrationHandle; 
        } 

        // 
        // This callback function is called by ETW to enable or disable this provider
        //
        ///
        /// Critical:  This calls critical code in ClassicEtw 
        ///
        [SecurityCritical] 
        private unsafe uint EtwEnableCallback(ClassicEtw.WMIDPREQUESTCODE requestCode, IntPtr context, IntPtr bufferSize, ClassicEtw.WNODE_HEADER* buffer) 
        {
            try 
            {
                switch (requestCode)
                {
                    case ClassicEtw.WMIDPREQUESTCODE.EnableEvents: 
                        _traceHandle = buffer->HistoricalContext;
                        _keywords = (EventTrace.Keyword)ClassicEtw.GetTraceEnableFlags((ulong)buffer->HistoricalContext); 
                        _level = (EventTrace.Level)ClassicEtw.GetTraceEnableLevel((ulong)buffer->HistoricalContext); 
                        _enabled = true;
                        break; 
                    case ClassicEtw.WMIDPREQUESTCODE.DisableEvents:
                        _enabled = false;
                        _traceHandle = 0;
                        _level = EventTrace.Level.LogAlways; 
                        _keywords = 0;
                        break; 
                    default: 
                        _enabled = false;
                        _traceHandle = 0; 
                        break;
                }
                return 0;
            } 
            catch(Exception e)
            { 
                if (CriticalExceptions.IsCriticalException(e)) 
                {
                   throw; 
                }
                else
                {
                    return 0; 
                }
            } 
        } 

        /// 
        /// Critical:  This calls critical code in EtwTrace
        /// TreatAsSafe: the registration handle this passes in to UnregisterTraceGuids
        /// was generated by the ETW unmanaged API and can't be tampered with from our side
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        ~ClassicTraceProvider() 
        { 
            #pragma warning suppress 6031  //presharp suppression
            ClassicEtw.UnregisterTraceGuids(_registrationHandle.Value); 
        }

        // pack the argv data and emit the event using TraceEvent
        [SecurityCritical] 
        internal unsafe override uint EventWrite(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level, int argc, EventData* argv)
        { 
            ClassicEtw.EVENT_HEADER header; 
            header.Header.ClientContext = 0;
            header.Header.Flags = ClassicEtw.WNODE_FLAG_TRACED_GUID | ClassicEtw.WNODE_FLAG_USE_MOF_PTR; 
            header.Header.Guid = EventTrace.GetGuidForEvent(eventID);
            header.Header.Level = (byte)level;
            header.Header.Type = (byte)EventTrace.GetOpcodeForEvent(eventID);
            header.Header.Version = (ushort)EventTrace.GetVersionForEvent(eventID); 
            // Extra copy on XP to move argv to the end of the EVENT_HEADER
            EventData* eventData = &header.Data; 
 
            if (argc > ClassicEtw.MAX_MOF_FIELDS)
            { 
                // Data will be lost on XP
                argc = ClassicEtw.MAX_MOF_FIELDS;
            }
 
            header.Header.Size = (ushort) (argc * sizeof(EventData) + 48);
            for (int x = 0; x < argc; x++) 
            { 
                eventData[x].Ptr = argv[x].Ptr;
                eventData[x].Size = argv[x].Size; 
            }

            return ClassicEtw.TraceEvent(_traceHandle, &header);
        } 
    }
 
    // Vista and above 
    internal class ManifestTraceProvider : TraceProvider
    { 
        private static ManifestEtw.EtwEnableCallback _etwEnabledCallback;

        [SecurityCritical]
        internal ManifestTraceProvider() 
        {
        } 
 
        [SecurityCritical]
        internal unsafe override void Register(Guid providerGuid) 
        {
            _etwEnabledCallback =new ManifestEtw.EtwEnableCallback(EtwEnableCallback);
            ulong registrationHandle = 0;
            ManifestEtw.EventRegister(ref providerGuid, _etwEnabledCallback, null, ref registrationHandle); 
            _registrationHandle.Value = registrationHandle;
        } 
 
        [SecurityCritical]
        private unsafe void EtwEnableCallback(ref Guid sourceId, int isEnabled, byte level, long matchAnyKeywords, long matchAllKeywords, ManifestEtw.EVENT_FILTER_DESCRIPTOR* filterData, void* callbackContext) 
        {
            _enabled = isEnabled > 0;
            _level = (EventTrace.Level)level;
            _keywords = (EventTrace.Keyword) matchAnyKeywords; 
            _matchAllKeyword = (EventTrace.Keyword) matchAllKeywords;
 
            // todo: parse data from EVENT_FILTER_DESCRIPTOR - see CLR EventProvider::GetDataFromController 
        }
 
        [SecurityCritical, SecurityTreatAsSafe]
        ~ManifestTraceProvider()
        {
            ManifestEtw.EventUnregister(_registrationHandle.Value); 
        }
 
        [SecurityCritical] 
        internal unsafe override uint EventWrite(EventTrace.Event eventID, EventTrace.Keyword keywords, EventTrace.Level level, int argc, EventData* argv)
        { 
            ManifestEtw.EventDescriptor eventDescriptor;
            eventDescriptor.Id = (ushort) eventID;
            eventDescriptor.Version = EventTrace.GetVersionForEvent(eventID);
            eventDescriptor.Channel = 0x10; // Since Channel isn't supported on XP we only use a single default channel. 
            eventDescriptor.Level = (byte)level;
            eventDescriptor.Opcode = EventTrace.GetOpcodeForEvent(eventID); 
            eventDescriptor.Task = EventTrace.GetTaskForEvent(eventID); 
            eventDescriptor.Keywords = (long)keywords;
            if (argc == 0) 
            {
                argv = null;
            }
 
            return ManifestEtw.EventWrite(_registrationHandle.Value, ref eventDescriptor, (uint)argc, argv);
        } 
 
    }
} 

#endif

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

Link Menu

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