//----------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.Runtime.Diagnostics { using System; using Microsoft.Win32; using System.Globalization; using System.Runtime.Interop; using System.Threading; using System.Security; using System.Collections.Generic; using System.Security.Permissions; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Diagnostics.CodeAnalysis; // This is a class defined based on CLR's internal implementation of ETW provider // This class should be replaced with CLR's version (whenever avaialble) that exposes callback functionality [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] abstract class DiagnosticsEventProvider : IDisposable { [SecurityCritical] [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of UnsafeNativeMethods.EtwEnableCallback")] UnsafeNativeMethods.EtwEnableCallback etwCallback; // Trace Callback function long traceRegistrationHandle; // Trace Registration Handle byte currentTraceLevel; // Tracing Level long anyKeywordMask; // Trace Enable Flags long allKeywordMask; // Match all keyword bool isProviderEnabled; // Enabled flag from Trace callback Guid providerId; // Control Guid int isDisposed; // when 1, provider has unregister [ThreadStatic] static WriteEventErrorCode errorCode; // The last return code stored from a WriteEvent call const int basicTypeAllocationBufferSize = 16; const int etwMaxNumberArguments = 32; const int etwAPIMaxStringCount = 8; const int maxEventDataDescriptors = 128; const int traceEventMaximumSize = 65482; const int traceEventMaximumStringSize = 32724; const int WindowsVistaMajorNumber = 6; [SuppressMessage(FxCop.Category.Design, FxCop.Rule.NestedTypesShouldNotBeVisible)] public enum WriteEventErrorCode : int { NoError, NoFreeBuffers, EventTooBig } /// /// Constructs a new EventProvider. This causes the class to be registered with the OS /// if an ETW controller turns on the logging then logging will start. /// /// The GUID that identifies this provider to the system. [SecurityCritical] [PermissionSet(SecurityAction.Demand, Unrestricted = true)] protected DiagnosticsEventProvider(Guid providerGuid) { this.providerId = providerGuid; var p = (int) Environment.OSVersion.Platform; if (p == 4 || p == 128) return; EtwRegister(); } /// /// This method registers the controlGuid of this class with ETW. /// We need to be running on Vista or above. If not a /// PlatformNotSupported exception will be thrown. /// If for some reason the ETW EtwRegister call failed /// a NotSupported exception will be thrown. /// [SecurityCritical] [SuppressMessage(FxCop.Category.ReliabilityBasic, FxCop.Rule.WrapExceptionsRule, Justification = "Don't trace exceptions thrown from the initialization API.")] unsafe void EtwRegister() { this.etwCallback = new UnsafeNativeMethods.EtwEnableCallback(EtwEnableCallBack); uint etwRegistrationStatus = UnsafeNativeMethods.EventRegister(ref this.providerId, this.etwCallback, null, ref this.traceRegistrationHandle); if (etwRegistrationStatus != 0) { throw new InvalidOperationException(InternalSR.EtwRegistrationFailed(etwRegistrationStatus.ToString("x", CultureInfo.CurrentCulture))); } } // // implement Dispose Pattern to early deregister from ETW instead of waiting for // the finalizer to call deregistration. // Once the user is done with the provider it needs to call Close() or Dispose() // If neither are called the finalizer will unregister the provider anyway // public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } [System.Security.SecuritySafeCritical] protected virtual void Dispose(bool disposing) { if ((this.isDisposed != 1) && (Interlocked.Exchange(ref this.isDisposed, 1) == 0)) { this.isProviderEnabled = false; Deregister(); } } /// /// This method deregisters the controlGuid of this class with ETW. /// public virtual void Close() { Dispose(); } ~DiagnosticsEventProvider() { Dispose(false); } /// /// This method un-registers from ETW. /// [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.DoNotIgnoreMethodResults)] [SecurityCritical] unsafe void Deregister() { // Unregister from ETW using the RegHandle saved from // the register call. if (this.traceRegistrationHandle != 0) { UnsafeNativeMethods.EventUnregister(this.traceRegistrationHandle); this.traceRegistrationHandle = 0; } } [SecurityCritical] unsafe void EtwEnableCallBack( [In] ref System.Guid sourceId, [In] int isEnabled, [In] byte setLevel, [In] long anyKeyword, [In] long allKeyword, [In] void* filterData, [In] void* callbackContext ) { this.isProviderEnabled = (isEnabled != 0); this.currentTraceLevel = setLevel; this.anyKeywordMask = anyKeyword; this.allKeywordMask = allKeyword; OnControllerCommand(); } protected abstract void OnControllerCommand(); /// /// IsEnabled, method used to test if provider is enabled /// public bool IsEnabled() { return this.isProviderEnabled; } /// /// IsEnabled, method used to test if event is enabled /// /// /// Level to test /// /// /// Keyword to test /// public bool IsEnabled(byte level, long keywords) { if (this.isProviderEnabled) { if ((level <= this.currentTraceLevel) || (this.currentTraceLevel == 0)) // This also covers the case of Level == 0. { // Check if Keyword is enabled if ((keywords == 0) || (((keywords & this.anyKeywordMask) != 0) && ((keywords & this.allKeywordMask) == this.allKeywordMask))) { return true; } } } return false; } /// /// IsEventEnabled, method used to test if event is enabled /// /// /// EventDescriptor for the method to test /// [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")] [SecurityCritical] public bool IsEventEnabled(ref EventDescriptor eventDescriptor) { if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords)) { return UnsafeNativeMethods.EventEnabled(this.traceRegistrationHandle, ref eventDescriptor); } return false; } [SuppressMessage(FxCop.Category.Design, FxCop.Rule.UsePropertiesWhereAppropriate)] public static WriteEventErrorCode GetLastWriteEventError() { return errorCode; } // // Helper function to set the last error on the thread // static void SetLastError(int error) { switch (error) { case UnsafeNativeMethods.ERROR_ARITHMETIC_OVERFLOW: case UnsafeNativeMethods.ERROR_MORE_DATA: errorCode = WriteEventErrorCode.EventTooBig; break; case UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY: errorCode = WriteEventErrorCode.NoFreeBuffers; break; } } /// /// This routine is used by WriteEvent to unbox the object type and /// to fill the passed in ETW data descriptor. /// /// argument to be decoded /// pointer to the descriptor to be filled /// storage buffer for storing user data, needed because cant get the address of the object /// null if the object is a basic type other than string. String otherwise [SecurityCritical] static unsafe string EncodeObject(ref object data, UnsafeNativeMethods.EventData* dataDescriptor, byte* dataBuffer) { dataDescriptor->Reserved = 0; string sRet = data as string; if (sRet != null) { dataDescriptor->Size = (uint)((sRet.Length + 1) * 2); return sRet; } if (data is IntPtr) { dataDescriptor->Size = (uint)sizeof(IntPtr); IntPtr* intptrPtr = (IntPtr*)dataBuffer; *intptrPtr = (IntPtr)data; dataDescriptor->DataPointer = (ulong)intptrPtr; } else if (data is int) { dataDescriptor->Size = (uint)sizeof(int); int* intptrPtr = (int*)dataBuffer; *intptrPtr = (int)data; dataDescriptor->DataPointer = (ulong)intptrPtr; } else if (data is long) { dataDescriptor->Size = (uint)sizeof(long); long* longptr = (long*)dataBuffer; *longptr = (long)data; dataDescriptor->DataPointer = (ulong)longptr; } else if (data is uint) { dataDescriptor->Size = (uint)sizeof(uint); uint* uintptr = (uint*)dataBuffer; *uintptr = (uint)data; dataDescriptor->DataPointer = (ulong)uintptr; } else if (data is UInt64) { dataDescriptor->Size = (uint)sizeof(ulong); UInt64* ulongptr = (ulong*)dataBuffer; *ulongptr = (ulong)data; dataDescriptor->DataPointer = (ulong)ulongptr; } else if (data is char) { dataDescriptor->Size = (uint)sizeof(char); char* charptr = (char*)dataBuffer; *charptr = (char)data; dataDescriptor->DataPointer = (ulong)charptr; } else if (data is byte) { dataDescriptor->Size = (uint)sizeof(byte); byte* byteptr = (byte*)dataBuffer; *byteptr = (byte)data; dataDescriptor->DataPointer = (ulong)byteptr; } else if (data is short) { dataDescriptor->Size = (uint)sizeof(short); short* shortptr = (short*)dataBuffer; *shortptr = (short)data; dataDescriptor->DataPointer = (ulong)shortptr; } else if (data is sbyte) { dataDescriptor->Size = (uint)sizeof(sbyte); sbyte* sbyteptr = (sbyte*)dataBuffer; *sbyteptr = (sbyte)data; dataDescriptor->DataPointer = (ulong)sbyteptr; } else if (data is ushort) { dataDescriptor->Size = (uint)sizeof(ushort); ushort* ushortptr = (ushort*)dataBuffer; *ushortptr = (ushort)data; dataDescriptor->DataPointer = (ulong)ushortptr; } else if (data is float) { dataDescriptor->Size = (uint)sizeof(float); float* floatptr = (float*)dataBuffer; *floatptr = (float)data; dataDescriptor->DataPointer = (ulong)floatptr; } else if (data is double) { dataDescriptor->Size = (uint)sizeof(double); double* doubleptr = (double*)dataBuffer; *doubleptr = (double)data; dataDescriptor->DataPointer = (ulong)doubleptr; } else if (data is bool) { dataDescriptor->Size = (uint)sizeof(bool); bool* boolptr = (bool*)dataBuffer; *boolptr = (bool)data; dataDescriptor->DataPointer = (ulong)boolptr; } else if (data is Guid) { dataDescriptor->Size = (uint)sizeof(Guid); Guid* guidptr = (Guid*)dataBuffer; *guidptr = (Guid)data; dataDescriptor->DataPointer = (ulong)guidptr; } else if (data is decimal) { dataDescriptor->Size = (uint)sizeof(decimal); decimal* decimalptr = (decimal*)dataBuffer; *decimalptr = (decimal)data; dataDescriptor->DataPointer = (ulong)decimalptr; } else if (data is Boolean) { dataDescriptor->Size = (uint)sizeof(Boolean); Boolean* booleanptr = (Boolean*)dataBuffer; *booleanptr = (Boolean)data; dataDescriptor->DataPointer = (ulong)booleanptr; } else { // Everything else is a just a string sRet = data.ToString(); dataDescriptor->Size = (uint)((sRet.Length + 1) * 2); return sRet; } return null; } /// /// WriteMessageEvent, method to write a string with level and Keyword /// /// /// Level to test /// /// /// Keyword to test /// [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")] [SecurityCritical] public bool WriteMessageEvent(EventTraceActivity eventTraceActivity, string eventMessage, byte eventLevel, long eventKeywords) { int status = 0; if (eventMessage == null) { throw Fx.Exception.AsError(new ArgumentNullException("eventMessage")); } if (eventTraceActivity != null) { SetActivityId(ref eventTraceActivity.ActivityId); } if (IsEnabled(eventLevel, eventKeywords)) { if (eventMessage.Length > traceEventMaximumStringSize) { errorCode = WriteEventErrorCode.EventTooBig; return false; } unsafe { fixed (char* pdata = eventMessage) { status = (int)UnsafeNativeMethods.EventWriteString(this.traceRegistrationHandle, eventLevel, eventKeywords, pdata); } if (status != 0) { SetLastError(status); return false; } } } return true; } /// /// WriteMessageEvent, method to write a string with level=0 and Keyword=0 /// /// /// Message to log /// [SecurityCritical] [Fx.Tag.SecurityNote(Critical = "Accesses security critical code WriteMessageEvent")] public bool WriteMessageEvent(EventTraceActivity eventTraceActivity, string eventMessage) { return WriteMessageEvent(eventTraceActivity, eventMessage, 0, 0); } /// /// WriteEvent, method to write a parameters with event schema properties /// /// /// Event Descriptor for this event. /// [SuppressMessage(FxCop.Category.Maintainability, FxCop.Rule.AvoidExcessiveComplexity, Justification = "Performance-critical code")] [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")] [SecurityCritical] public bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, params object[] eventPayload) { uint status = 0; if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords)) { int argCount = 0; if (eventTraceActivity != null) { SetActivityId(ref eventTraceActivity.ActivityId); } unsafe { if ((eventPayload == null) || (eventPayload.Length == 0) || (eventPayload.Length == 1)) { string dataString = null; UnsafeNativeMethods.EventData userData; byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize]; // Assume a max of 16 chars for non-string argument userData.Size = 0; if ((eventPayload != null) && (eventPayload.Length != 0)) { // // Figure out the type and fill the data descriptor // dataString = EncodeObject(ref eventPayload[0], &userData, dataBuffer); argCount = 1; } if (userData.Size > traceEventMaximumSize) { // // Maximum size of the event payload plus header is 64k // errorCode = WriteEventErrorCode.EventTooBig; return false; } if (dataString != null) { fixed (char* pdata = dataString) { userData.DataPointer = (ulong)pdata; status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, &userData); } } else { if (argCount == 0) { status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, 0, null); } else { status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, &userData); } } } else { argCount = eventPayload.Length; if (argCount > etwMaxNumberArguments) { // //too many arguments to log // throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload", InternalSR.EtwMaxNumberArgumentsExceeded(etwMaxNumberArguments))); } uint totalEventSize = 0; int index; int stringIndex = 0; int[] stringPosition = new int[etwAPIMaxStringCount]; string[] dataString = new string[etwAPIMaxStringCount]; UnsafeNativeMethods.EventData* userData = stackalloc UnsafeNativeMethods.EventData[argCount]; UnsafeNativeMethods.EventData* userDataPtr = (UnsafeNativeMethods.EventData*)userData; byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize * argCount]; // Assume 16 chars for non-string argument byte* currentBuffer = dataBuffer; // // The loop below goes through all the arguments and fills in the data // descriptors. For strings save the location in the dataString array. // Caculates the total size of the event by adding the data descriptor // size value set in EncodeObjec method. // for (index = 0; index < eventPayload.Length; index++) { if (eventPayload[index] != null) { string isString; isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer); currentBuffer += basicTypeAllocationBufferSize; totalEventSize += userDataPtr->Size; userDataPtr++; if (isString != null) { if (stringIndex < etwAPIMaxStringCount) { dataString[stringIndex] = isString; stringPosition[stringIndex] = index; stringIndex++; } else { throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload", InternalSR.EtwAPIMaxStringCountExceeded(etwAPIMaxStringCount))); } } } } if (totalEventSize > traceEventMaximumSize) { errorCode = WriteEventErrorCode.EventTooBig; return false; } // // now fix any string arguments and set the pointer on the data descriptor // fixed (char* v0 = dataString[0], v1 = dataString[1], v2 = dataString[2], v3 = dataString[3], v4 = dataString[4], v5 = dataString[5], v6 = dataString[6], v7 = dataString[7]) { userDataPtr = (UnsafeNativeMethods.EventData*)userData; if (dataString[0] != null) { userDataPtr[stringPosition[0]].DataPointer = (ulong)v0; } if (dataString[1] != null) { userDataPtr[stringPosition[1]].DataPointer = (ulong)v1; } if (dataString[2] != null) { userDataPtr[stringPosition[2]].DataPointer = (ulong)v2; } if (dataString[3] != null) { userDataPtr[stringPosition[3]].DataPointer = (ulong)v3; } if (dataString[4] != null) { userDataPtr[stringPosition[4]].DataPointer = (ulong)v4; } if (dataString[5] != null) { userDataPtr[stringPosition[5]].DataPointer = (ulong)v5; } if (dataString[6] != null) { userDataPtr[stringPosition[6]].DataPointer = (ulong)v6; } if (dataString[7] != null) { userDataPtr[stringPosition[7]].DataPointer = (ulong)v7; } status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, userData); } } } } if (status != 0) { SetLastError((int)status); return false; } return true; } /// /// WriteEvent, method to write a string with event schema properties /// /// /// Event Descriptor for this event. /// /// /// string to log. /// [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")] [SecurityCritical] public bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, string data) { uint status = 0; //check all strings for null data = (data ?? string.Empty); if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords)) { if (data.Length > traceEventMaximumStringSize) { errorCode = WriteEventErrorCode.EventTooBig; return false; } if (eventTraceActivity != null) { SetActivityId(ref eventTraceActivity.ActivityId); } UnsafeNativeMethods.EventData userData; userData.Size = (uint)((data.Length + 1) * 2); userData.Reserved = 0; unsafe { fixed (char* pdata = data) { userData.DataPointer = (ulong)pdata; status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, 1, &userData); } } } if (status != 0) { SetLastError((int)status); return false; } return true; } /// /// WriteEvent, method to be used by generated code on a derived class /// /// /// Event Descriptor for this event. /// /// /// number of event descriptors /// /// /// pointer do the event data /// [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")] [SecurityCritical] internal protected bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, int dataCount, IntPtr data) { uint status = 0; if (eventTraceActivity != null) { SetActivityId(ref eventTraceActivity.ActivityId); } unsafe { status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)dataCount, (UnsafeNativeMethods.EventData*)data); } if (status != 0) { SetLastError((int)status); return false; } return true; } /// /// WriteTransferEvent, method to write a parameters with event schema properties /// /// /// Event Descriptor for this event. /// [SuppressMessage(FxCop.Category.Maintainability, FxCop.Rule.AvoidExcessiveComplexity, Justification = "Performance-critical code")] [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")] [SecurityCritical] public bool WriteTransferEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, Guid relatedActivityId, params object[] eventPayload) { // ActivityId is required when writing transfer event if (eventTraceActivity == null) { Fx.Assert(false, "eventTraceActivity should not be null for WriteTransferEvent"); eventTraceActivity = EventTraceActivity.Empty; } uint status = 0; if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords)) { unsafe { if ((eventPayload != null) && (eventPayload.Length != 0)) { int argCount = eventPayload.Length; if (argCount > etwMaxNumberArguments) { // //too many arguments to log // throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload", InternalSR.EtwMaxNumberArgumentsExceeded(etwMaxNumberArguments))); } uint totalEventSize = 0; int index; int stringIndex = 0; int[] stringPosition = new int[etwAPIMaxStringCount]; //used to keep the position of strings in the eventPayload parameter string[] dataString = new string[etwAPIMaxStringCount]; // string arrays from the eventPayload parameter UnsafeNativeMethods.EventData* userData = stackalloc UnsafeNativeMethods.EventData[argCount]; // allocation for the data descriptors UnsafeNativeMethods.EventData* userDataPtr = (UnsafeNativeMethods.EventData*)userData; byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize * argCount]; // 16 byte for unboxing non-string argument byte* currentBuffer = dataBuffer; // // The loop below goes through all the arguments and fills in the data // descriptors. For strings save the location in the dataString array. // Caculates the total size of the event by adding the data descriptor // size value set in EncodeObjec method. // for (index = 0; index < eventPayload.Length; index++) { if (eventPayload[index] != null) { string isString; isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer); currentBuffer += basicTypeAllocationBufferSize; totalEventSize += userDataPtr->Size; userDataPtr++; if (isString != null) { if (stringIndex < etwAPIMaxStringCount) { dataString[stringIndex] = isString; stringPosition[stringIndex] = index; stringIndex++; } else { throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload", InternalSR.EtwAPIMaxStringCountExceeded(etwAPIMaxStringCount))); } } } } if (totalEventSize > traceEventMaximumSize) { errorCode = WriteEventErrorCode.EventTooBig; return false; } fixed (char* v0 = dataString[0], v1 = dataString[1], v2 = dataString[2], v3 = dataString[3], v4 = dataString[4], v5 = dataString[5], v6 = dataString[6], v7 = dataString[7]) { userDataPtr = (UnsafeNativeMethods.EventData*)userData; if (dataString[0] != null) { userDataPtr[stringPosition[0]].DataPointer = (ulong)v0; } if (dataString[1] != null) { userDataPtr[stringPosition[1]].DataPointer = (ulong)v1; } if (dataString[2] != null) { userDataPtr[stringPosition[2]].DataPointer = (ulong)v2; } if (dataString[3] != null) { userDataPtr[stringPosition[3]].DataPointer = (ulong)v3; } if (dataString[4] != null) { userDataPtr[stringPosition[4]].DataPointer = (ulong)v4; } if (dataString[5] != null) { userDataPtr[stringPosition[5]].DataPointer = (ulong)v5; } if (dataString[6] != null) { userDataPtr[stringPosition[6]].DataPointer = (ulong)v6; } if (dataString[7] != null) { userDataPtr[stringPosition[7]].DataPointer = (ulong)v7; } status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle, ref eventDescriptor, ref eventTraceActivity.ActivityId, ref relatedActivityId, (uint)argCount, userData); } } else { status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle, ref eventDescriptor, ref eventTraceActivity.ActivityId, ref relatedActivityId, 0, null); } } } if (status != 0) { SetLastError((int)status); return false; } return true; } [SecurityCritical] [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")] protected bool WriteTransferEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, Guid relatedActivityId, int dataCount, IntPtr data) { // ActivityId is required when writing transfer event if (eventTraceActivity == null) { throw Fx.Exception.ArgumentNull("eventTraceActivity"); } uint status = 0; unsafe { status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle, ref eventDescriptor, ref eventTraceActivity.ActivityId, ref relatedActivityId, (uint)dataCount, (UnsafeNativeMethods.EventData*)data); } if (status != 0) { SetLastError((int)status); return false; } return true; } [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.DoNotIgnoreMethodResults, MessageId = "System.Runtime.Interop.UnsafeNativeMethods.EventActivityIdControl(System.Int32,System.Guid@)")] [SecurityCritical] public static void SetActivityId(ref Guid id) { UnsafeNativeMethods.EventActivityIdControl((int)ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, ref id); } } }