PageRenderTime 70ms CodeModel.GetById 7ms app.highlight 54ms RepoModel.GetById 2ms app.codeStats 0ms

/WCFWebApi/src/Microsoft.Server.Common/Microsoft/Server/Common/Diagnostics/DiagnosticEventProvider.cs

#
C# | 883 lines | 676 code | 73 blank | 134 comment | 149 complexity | aaed747b6a03d0f41415c779f1b6d62d MD5 | raw file
  1//-----------------------------------------------------------------------------
  2// Copyright (c) Microsoft Corporation.  All rights reserved.
  3//-----------------------------------------------------------------------------
  4
  5namespace Microsoft.Server.Common.Diagnostics
  6{
  7    using System;
  8    using System.Diagnostics.CodeAnalysis;
  9    using System.Globalization;
 10    using System.Runtime.InteropServices;
 11    using System.Security;
 12    using System.Security.Permissions;
 13    using System.Threading;
 14    using Microsoft.Server.Common.Interop;
 15
 16    // This is a class defined based on CLR's internal implementation of ETW provider
 17    // This class should be replaced with CLR's version (whenever avaialble) that exposes callback functionality
 18    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
 19    public class DiagnosticsEventProvider : IDisposable
 20    {
 21        [SecurityCritical]
 22        [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of UnsafeNativeMethods.EtwEnableCallback")]
 23        UnsafeNativeMethods.EtwEnableCallback etwCallback;      // Trace Callback function
 24        
 25        long traceRegistrationHandle;                              // Trace Registration Handle
 26        byte currentTraceLevel;                                    // Tracing Level
 27        long anyKeywordMask;                                       // Trace Enable Flags
 28        long allKeywordMask;                                       // Match all keyword
 29        bool isProviderEnabled;                                    // Enabled flag from Trace callback
 30        Guid providerId;                                           // Control Guid 
 31        int isDisposed;                                            // when 1, provider has unregister        
 32
 33        [ThreadStatic]
 34        static WriteEventErrorCode errorCode; // The last return code stored from a WriteEvent call
 35
 36        const int basicTypeAllocationBufferSize = 16;
 37        const int etwMaxNumberArguments = 32;
 38        const int etwAPIMaxStringCount = 8;
 39        const int maxEventDataDescriptors = 128;
 40        const int traceEventMaximumSize = 65482;
 41        const int traceEventMaximumStringSize = 32724;
 42        const int WindowsVistaMajorNumber = 6;
 43        
 44        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
 45        public enum WriteEventErrorCode : int
 46        {
 47            NoError,
 48            NoFreeBuffers,
 49            EventTooBig
 50        }
 51                
 52        /// <summary>
 53        /// Constructs a new EventProvider.  This causes the class to be registered with the OS
 54        /// if an ETW controller turns on the logging then logging will start. 
 55        /// </summary>
 56        /// <param name="providerGuid">The GUID that identifies this provider to the system.</param>
 57        [SecurityCritical]
 58        [PermissionSet(SecurityAction.Demand, Unrestricted = true)]
 59        [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", Justification = "Use of guid here is acceptable.")]
 60        protected DiagnosticsEventProvider(Guid providerGuid)
 61        {
 62            this.providerId = providerGuid;            
 63            EtwRegister();
 64        }
 65
 66        /// <summary>
 67        /// This method registers the controlGuid of this class with ETW.
 68        /// We need to be running on Vista or above. If not a 
 69        /// PlatformNotSupported exception will be thrown. 
 70        /// If for some reason the ETW EtwRegister call failed
 71        /// a NotSupported exception will be thrown. 
 72        /// </summary>        
 73        [SecurityCritical]
 74        [SuppressMessage("Reliability", "Reliability102:WrapExceptionsRule",
 75            Justification = "Don't trace exceptions thrown from the initialization API.")]
 76        unsafe void EtwRegister()
 77        {
 78            this.etwCallback = new UnsafeNativeMethods.EtwEnableCallback(EtwEnableCallBack);
 79            uint etwRegistrationStatus = UnsafeNativeMethods.EventRegister(ref this.providerId, this.etwCallback, null, ref this.traceRegistrationHandle);
 80            if (etwRegistrationStatus != 0)
 81            {
 82                throw new InvalidOperationException(SR.EtwRegistrationFailed(etwRegistrationStatus.ToString("x", CultureInfo.CurrentCulture)));
 83            }
 84        }
 85
 86        //
 87        // implement Dispose Pattern to early deregister from ETW instead of waiting for 
 88        // the finalizer to call deregistration.
 89        // Once the user is done with the provider it needs to call Close() or Dispose()
 90        // If neither are called the finalizer will unregister the provider anyway
 91        //
 92        public void Dispose()
 93        {
 94            Dispose(true);
 95            GC.SuppressFinalize(this);
 96        }
 97                
 98        [System.Security.SecuritySafeCritical]        
 99        protected virtual void Dispose(bool disposing)
100        {
101            if ((this.isDisposed != 1) && (Interlocked.Exchange(ref this.isDisposed, 1) == 0))
102            {
103                this.isProviderEnabled = false;
104                Deregister();
105            }
106        }
107
108        /// <summary>
109        /// This method deregisters the controlGuid of this class with ETW.        
110        /// </summary>
111        public virtual void Close()
112        {
113            Dispose();
114        }
115
116        ~DiagnosticsEventProvider()
117        {
118            Dispose(false);
119        }
120
121        /// <summary>
122        /// This method un-registers from ETW.
123        /// </summary>                
124        [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults")]
125        [SecurityCritical]
126        unsafe void Deregister()
127        {            
128            // Unregister from ETW using the RegHandle saved from
129            // the register call.            
130            if (this.traceRegistrationHandle != 0)
131            {
132                UnsafeNativeMethods.EventUnregister(this.traceRegistrationHandle);
133                this.traceRegistrationHandle = 0;
134            }
135        }
136                
137        [SecurityCritical]
138        unsafe void EtwEnableCallBack(
139                        [In] ref System.Guid sourceId,
140                        [In] int isEnabled,
141                        [In] byte setLevel,
142                        [In] long anyKeyword,
143                        [In] long allKeyword,
144                        [In] void* filterData,
145                        [In] void* callbackContext
146                        )
147        {
148            this.isProviderEnabled = (isEnabled != 0);
149            this.currentTraceLevel = setLevel;
150            this.anyKeywordMask = anyKeyword;
151            this.allKeywordMask = allKeyword;            
152            OnControllerCommand();
153        }
154                        
155        protected virtual void OnControllerCommand() { }              
156
157        /// <summary>
158        /// IsEnabled, method used to test if provider is enabled
159        /// </summary>
160        public bool IsEnabled()
161        {
162            return this.isProviderEnabled;
163        }
164
165        /// <summary>
166        /// IsEnabled, method used to test if event is enabled
167        /// </summary>
168        /// <param name="level">
169        /// Level  to test
170        /// </param>
171        /// <param name="keywords">
172        /// Keyword  to test
173        /// </param>
174        public bool IsEnabled(byte level, long keywords)
175        {
176            if (this.isProviderEnabled)
177            {
178                if ((level <= this.currentTraceLevel) ||
179                    (this.currentTraceLevel == 0)) // This also covers the case of Level == 0.
180                {                    
181                    // Check if Keyword is enabled
182                    if ((keywords == 0) ||
183                        (((keywords & this.anyKeywordMask) != 0) &&
184                         ((keywords & this.allKeywordMask) == this.allKeywordMask)))
185                    {
186                        return true;
187                    }
188                }                
189            }           
190
191            return false;
192        }
193
194        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
195        public static WriteEventErrorCode GetLastWriteEventError()
196        {
197            return errorCode;
198        }
199
200        //
201        // Helper function to set the last error on the thread
202        //
203        static void SetLastError(int error)
204        {
205            switch (error)
206            {
207                case UnsafeNativeMethods.ERROR_ARITHMETIC_OVERFLOW:
208                case UnsafeNativeMethods.ERROR_MORE_DATA:
209                    errorCode = WriteEventErrorCode.EventTooBig;
210                    break;
211                case UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY:
212                    errorCode = WriteEventErrorCode.NoFreeBuffers;
213                    break;
214            }
215        }
216        
217        /// <summary>
218        /// This routine is used by WriteEvent to unbox the object type and
219        /// to fill the passed in ETW data descriptor. 
220        /// </summary>
221        /// <param name="data">argument to be decoded</param>
222        /// <param name="dataDescriptor">pointer to the descriptor to be filled</param>
223        /// <param name="dataBuffer">storage buffer for storing user data, needed because cant get the address of the object</param>
224        /// <returns>null if the object is a basic type other than string. String otherwise</returns>
225        
226        [SecurityCritical]
227        static unsafe string EncodeObject(ref object data, UnsafeNativeMethods.EventData* dataDescriptor, byte* dataBuffer)        
228        {
229            dataDescriptor->Reserved = 0;
230
231            string sRet = data as string;
232            if (sRet != null)
233            {
234                dataDescriptor->Size = (uint)((sRet.Length + 1) * 2);
235                return sRet;
236            }
237
238            if (data is IntPtr)
239            {
240                dataDescriptor->Size = (uint)sizeof(IntPtr);
241                IntPtr* intptrPtr = (IntPtr*)dataBuffer;
242                *intptrPtr = (IntPtr)data;
243                dataDescriptor->DataPointer = (ulong)intptrPtr;
244            }
245            else if (data is int)
246            {
247                dataDescriptor->Size = (uint)sizeof(int);
248                int* intptrPtr = (int*)dataBuffer;
249                *intptrPtr = (int)data;
250                dataDescriptor->DataPointer = (ulong)intptrPtr;
251            }
252            else if (data is long)
253            {
254                dataDescriptor->Size = (uint)sizeof(long);
255                long* longptr = (long*)dataBuffer;
256                *longptr = (long)data;
257                dataDescriptor->DataPointer = (ulong)longptr;
258            }
259            else if (data is uint)
260            {
261                dataDescriptor->Size = (uint)sizeof(uint);
262                uint* uintptr = (uint*)dataBuffer;
263                *uintptr = (uint)data;
264                dataDescriptor->DataPointer = (ulong)uintptr;
265            }
266            else if (data is UInt64)
267            {
268                dataDescriptor->Size = (uint)sizeof(ulong);
269                UInt64* ulongptr = (ulong*)dataBuffer;
270                *ulongptr = (ulong)data;
271                dataDescriptor->DataPointer = (ulong)ulongptr;
272            }
273            else if (data is char)
274            {
275                dataDescriptor->Size = (uint)sizeof(char);
276                char* charptr = (char*)dataBuffer;
277                *charptr = (char)data;
278                dataDescriptor->DataPointer = (ulong)charptr;
279            }
280            else if (data is byte)
281            {
282                dataDescriptor->Size = (uint)sizeof(byte);
283                byte* byteptr = (byte*)dataBuffer;
284                *byteptr = (byte)data;
285                dataDescriptor->DataPointer = (ulong)byteptr;
286            }
287            else if (data is short)
288            {
289                dataDescriptor->Size = (uint)sizeof(short);
290                short* shortptr = (short*)dataBuffer;
291                *shortptr = (short)data;
292                dataDescriptor->DataPointer = (ulong)shortptr;
293            }
294            else if (data is sbyte)
295            {
296                dataDescriptor->Size = (uint)sizeof(sbyte);
297                sbyte* sbyteptr = (sbyte*)dataBuffer;
298                *sbyteptr = (sbyte)data;
299                dataDescriptor->DataPointer = (ulong)sbyteptr;
300            }
301            else if (data is ushort)
302            {
303                dataDescriptor->Size = (uint)sizeof(ushort);
304                ushort* ushortptr = (ushort*)dataBuffer;
305                *ushortptr = (ushort)data;
306                dataDescriptor->DataPointer = (ulong)ushortptr;
307            }
308            else if (data is float)
309            {
310                dataDescriptor->Size = (uint)sizeof(float);
311                float* floatptr = (float*)dataBuffer;
312                *floatptr = (float)data;
313                dataDescriptor->DataPointer = (ulong)floatptr;
314            }
315            else if (data is double)
316            {
317                dataDescriptor->Size = (uint)sizeof(double);
318                double* doubleptr = (double*)dataBuffer;
319                *doubleptr = (double)data;
320                dataDescriptor->DataPointer = (ulong)doubleptr;
321            }
322            else if (data is bool)
323            {
324                dataDescriptor->Size = (uint)sizeof(bool);
325                bool* boolptr = (bool*)dataBuffer;
326                *boolptr = (bool)data;
327                dataDescriptor->DataPointer = (ulong)boolptr;
328            }
329            else if (data is Guid)
330            {
331                dataDescriptor->Size = (uint)sizeof(Guid);
332                Guid* guidptr = (Guid*)dataBuffer;
333                *guidptr = (Guid)data;
334                dataDescriptor->DataPointer = (ulong)guidptr;
335            }
336            else if (data is decimal)
337            {
338                dataDescriptor->Size = (uint)sizeof(decimal);
339                decimal* decimalptr = (decimal*)dataBuffer;
340                *decimalptr = (decimal)data;
341                dataDescriptor->DataPointer = (ulong)decimalptr;
342            }
343            else if (data is Boolean)
344            {
345                dataDescriptor->Size = (uint)sizeof(Boolean);
346                Boolean* booleanptr = (Boolean*)dataBuffer;
347                *booleanptr = (Boolean)data;
348                dataDescriptor->DataPointer = (ulong)booleanptr;
349            }
350            else
351            {
352                // Everything else is a just a string
353                sRet = data.ToString();
354                dataDescriptor->Size = (uint)((sRet.Length + 1) * 2);
355                return sRet;
356            }
357
358            return null;
359        }
360
361        /// <summary>
362        /// WriteMessageEvent, method to write a string with level and Keyword
363        /// </summary>
364        /// <param name="level">
365        /// Level  to test  
366        /// </param>
367        /// <param name="Keyword">
368        /// Keyword  to test 
369        /// </param>        
370        [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
371        [SecurityCritical]
372        public bool WriteMessageEvent(EventTraceActivity eventTraceActivity, string eventMessage, byte eventLevel, long eventKeywords)
373        {
374            int status = 0;
375
376            if (eventMessage == null)
377            {
378                throw Fx.Exception.AsError(new ArgumentNullException("eventMessage"));
379            }
380
381            if (eventTraceActivity != null)
382            {
383                SetActivityId(ref eventTraceActivity.ActivityId); 
384            }
385
386            if (IsEnabled(eventLevel, eventKeywords))
387            {
388                if (eventMessage.Length > traceEventMaximumStringSize)
389                {
390                    errorCode = WriteEventErrorCode.EventTooBig;
391                    return false;
392                }
393                unsafe
394                {
395                    fixed (char* pdata = eventMessage)
396                    {
397                        status = (int)UnsafeNativeMethods.EventWriteString(this.traceRegistrationHandle, eventLevel, eventKeywords, pdata);
398                    }
399
400                    if (status != 0)
401                    {
402                        SetLastError(status);
403                        return false;
404                    }
405                }
406            }
407            return true;
408        }
409
410        /// <summary>
411        /// WriteMessageEvent, method to write a string with level=0 and Keyword=0
412        /// </summary>
413        /// <param name="eventMessage">
414        /// Message to log  
415        /// </param> 
416        [SecurityCritical]
417        [Fx.Tag.SecurityNote(Critical = "Accesses security critical code WriteMessageEvent")]
418        public bool WriteMessageEvent(EventTraceActivity eventTraceActivity, string eventMessage)
419        {
420            return WriteMessageEvent(eventTraceActivity, eventMessage, 0, 0);
421        }
422
423        /// <summary>
424        /// WriteEvent, method to write a parameters with event schema properties
425        /// </summary>
426        /// <param name="EventDescriptor">
427        /// Event Descriptor for this event. 
428        /// </param>        
429        [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
430        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Ported from WCF")]
431        [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
432        [SecurityCritical]
433        public bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, params object[] eventPayload)
434        {
435            uint status = 0;
436
437            if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
438            {
439                int argCount = 0;
440
441                if (eventTraceActivity != null)
442                {
443                    SetActivityId(ref eventTraceActivity.ActivityId);
444                }
445
446                unsafe
447                {
448                    if ((eventPayload == null)
449                        || (eventPayload.Length == 0)
450                        || (eventPayload.Length == 1))
451                    {
452                        string dataString = null;
453                        UnsafeNativeMethods.EventData userData;
454
455                        byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize]; // Assume a max of 16 chars for non-string argument
456
457                        userData.Size = 0;
458                        if ((eventPayload != null) && (eventPayload.Length != 0))
459                        {
460                            //
461                            // Figure out the type and fill the data descriptor
462                            //
463                            dataString = EncodeObject(ref eventPayload[0], &userData, dataBuffer);
464                            argCount = 1;
465                        }
466
467                        if (userData.Size > traceEventMaximumSize)
468                        {
469                            //
470                            // Maximum size of the event payload plus header is 64k
471                            //
472                            errorCode = WriteEventErrorCode.EventTooBig;
473                            return false;
474                        }
475
476                        if (dataString != null)
477                        {
478                            fixed (char* pdata = dataString)
479                            {
480                                userData.DataPointer = (ulong)pdata;
481                                status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, &userData);
482                            }
483                        }
484                        else
485                        {
486                            if (argCount == 0)
487                            {
488                                status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, 0, null);
489                            }
490                            else
491                            {
492                                status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, &userData);
493                            }
494
495                        }
496                    }
497                    else
498                    {
499
500                        argCount = eventPayload.Length;
501
502                        if (argCount > etwMaxNumberArguments)
503                        {
504                            //
505                            //too many arguments to log
506                            //
507                            throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
508                                SR.EtwMaxNumberArgumentsExceeded(etwMaxNumberArguments)));
509                        }
510
511                        uint totalEventSize = 0;
512                        int index;
513                        int stringIndex = 0;
514                        int[] stringPosition = new int[etwAPIMaxStringCount];
515                        string[] dataString = new string[etwAPIMaxStringCount];
516                        UnsafeNativeMethods.EventData* userData = stackalloc UnsafeNativeMethods.EventData[argCount];
517                        UnsafeNativeMethods.EventData* userDataPtr = (UnsafeNativeMethods.EventData*)userData;
518                        byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize * argCount]; // Assume 16 chars for non-string argument
519                        byte* currentBuffer = dataBuffer;
520
521                        //
522                        // The loop below goes through all the arguments and fills in the data 
523                        // descriptors. For strings save the location in the dataString array.
524                        // Caculates the total size of the event by adding the data descriptor
525                        // size value set in EncodeObjec method.
526                        //
527                        for (index = 0; index < eventPayload.Length; index++)
528                        {
529                            if (eventPayload[index] != null)
530                            {
531                                string isString;
532                                isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer);
533                                currentBuffer += basicTypeAllocationBufferSize;
534                                totalEventSize += userDataPtr->Size;
535                                userDataPtr++;
536                                if (isString != null)
537                                {
538                                    if (stringIndex < etwAPIMaxStringCount)
539                                    {
540                                        dataString[stringIndex] = isString;
541                                        stringPosition[stringIndex] = index;
542                                        stringIndex++;
543                                    }
544                                    else
545                                    {
546                                        throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
547                                            SR.EtwAPIMaxStringCountExceeded(etwAPIMaxStringCount))); 
548                                    }
549                                }
550                            }
551                        }
552
553                        if (totalEventSize > traceEventMaximumSize)
554                        {
555                            errorCode = WriteEventErrorCode.EventTooBig;
556                            return false;
557                        }
558
559                        //
560                        // now fix any string arguments and set the pointer on the data descriptor 
561                        //
562                        fixed (char* v0 = dataString[0], v1 = dataString[1], v2 = dataString[2], v3 = dataString[3],
563                                v4 = dataString[4], v5 = dataString[5], v6 = dataString[6], v7 = dataString[7])
564                        {
565                            userDataPtr = (UnsafeNativeMethods.EventData*)userData;
566                            if (dataString[0] != null)
567                            {
568                                userDataPtr[stringPosition[0]].DataPointer = (ulong)v0;
569                            }
570                            if (dataString[1] != null)
571                            {
572                                userDataPtr[stringPosition[1]].DataPointer = (ulong)v1;
573                            }
574                            if (dataString[2] != null)
575                            {
576                                userDataPtr[stringPosition[2]].DataPointer = (ulong)v2;
577                            }
578                            if (dataString[3] != null)
579                            {
580                                userDataPtr[stringPosition[3]].DataPointer = (ulong)v3;
581                            }
582                            if (dataString[4] != null)
583                            {
584                                userDataPtr[stringPosition[4]].DataPointer = (ulong)v4;
585                            }
586                            if (dataString[5] != null)
587                            {
588                                userDataPtr[stringPosition[5]].DataPointer = (ulong)v5;
589                            }
590                            if (dataString[6] != null)
591                            {
592                                userDataPtr[stringPosition[6]].DataPointer = (ulong)v6;
593                            }
594                            if (dataString[7] != null)
595                            {
596                                userDataPtr[stringPosition[7]].DataPointer = (ulong)v7;
597                            }
598
599                            status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)argCount, userData);
600                        }
601
602                    }
603                }
604            }
605
606            if (status != 0)
607            {
608                SetLastError((int)status);
609                return false;
610            }
611
612            return true;
613        }
614
615        /// <summary>
616        /// WriteEvent, method to write a string with event schema properties
617        /// </summary>
618        /// <param name="EventDescriptor">
619        /// Event Descriptor for this event. 
620        /// </param>
621        /// <param name="data">
622        /// string to log. 
623        /// </param> 
624        [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
625        [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
626        [SecurityCritical]
627        public bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, string data)
628        {
629            uint status = 0;
630            //check all strings for null
631            data = (data ?? string.Empty);
632
633            if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
634            {
635                if (data.Length > traceEventMaximumStringSize)
636                {
637                    errorCode = WriteEventErrorCode.EventTooBig;
638                    return false;
639                }
640
641                if (eventTraceActivity != null)
642                {
643                    SetActivityId(ref eventTraceActivity.ActivityId);
644                }
645
646                UnsafeNativeMethods.EventData userData;
647
648                userData.Size = (uint)((data.Length + 1) * 2);
649                userData.Reserved = 0;
650
651                unsafe
652                {
653                    fixed (char* pdata = data)
654                    {
655                        userData.DataPointer = (ulong)pdata;
656                        status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, 1, &userData);
657                    }
658                }
659            }
660
661            if (status != 0)
662            {
663                SetLastError((int)status);
664                return false;
665            }
666            return true;
667        }
668
669        /// <summary>
670        /// WriteEvent, method to be used by generated code on a derived class
671        /// </summary>
672        /// <param name="EventDescriptor">
673        /// Event Descriptor for this event. 
674        /// </param>
675        /// <param name="count">
676        /// number of event descriptors 
677        /// </param>
678        /// <param name="data">
679        /// pointer  do the event data
680        /// </param>
681        [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
682        [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
683        [SecurityCritical]
684        internal protected bool WriteEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, int dataCount, IntPtr data)
685        {
686            uint status = 0;
687
688            if (eventTraceActivity != null)
689            {
690                SetActivityId(ref eventTraceActivity.ActivityId);
691            }
692
693            unsafe
694            {
695                status = UnsafeNativeMethods.EventWrite(this.traceRegistrationHandle, ref eventDescriptor, (uint)dataCount, (UnsafeNativeMethods.EventData*)data);
696            }
697            if (status != 0)
698            {
699                SetLastError((int)status);
700                return false;
701            }
702            return true;
703        }
704
705        /// <summary>
706        /// WriteTransferEvent, method to write a parameters with event schema properties
707        /// </summary>
708        /// <param name="eventDescriptor">
709        /// Event Descriptor for this event. 
710        /// </param>        
711        [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
712        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Ported from WCF")]
713        [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
714        [SecurityCritical]
715        public bool WriteTransferEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, Guid relatedActivityId, params object[] eventPayload)
716        {
717            // ActivityId is required when writing transfer event
718            if (eventTraceActivity == null)
719            {
720                Fx.Assert(false, "eventTraceActivity should not be null for WriteTransferEvent");
721                eventTraceActivity = EventTraceActivity.Empty;
722            }
723
724            uint status = 0;
725            if (IsEnabled(eventDescriptor.Level, eventDescriptor.Keywords))
726            {
727                unsafe
728                {
729                    if ((eventPayload != null) && (eventPayload.Length != 0))
730                    {
731                        int argCount = eventPayload.Length;
732                        if (argCount > etwMaxNumberArguments)
733                        {
734                            //
735                            //too many arguments to log
736                            //
737                            throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
738                                SR.EtwMaxNumberArgumentsExceeded(etwMaxNumberArguments)));
739                        }
740
741                        uint totalEventSize = 0;
742                        int index;
743                        int stringIndex = 0;
744                        int[] stringPosition = new int[etwAPIMaxStringCount]; //used to keep the position of strings in the eventPayload parameter
745                        string[] dataString = new string[etwAPIMaxStringCount]; // string arrays from the eventPayload parameter
746                        UnsafeNativeMethods.EventData* userData = stackalloc UnsafeNativeMethods.EventData[argCount]; // allocation for the data descriptors
747                        UnsafeNativeMethods.EventData* userDataPtr = (UnsafeNativeMethods.EventData*)userData;
748                        byte* dataBuffer = stackalloc byte[basicTypeAllocationBufferSize * argCount]; // 16 byte for unboxing non-string argument
749                        byte* currentBuffer = dataBuffer;
750
751                        //
752                        // The loop below goes through all the arguments and fills in the data 
753                        // descriptors. For strings save the location in the dataString array.
754                        // Caculates the total size of the event by adding the data descriptor
755                        // size value set in EncodeObjec method.
756                        //
757                        for (index = 0; index < eventPayload.Length; index++)
758                        {
759                            if (eventPayload[index] != null)
760                            {
761                                string isString;
762                                isString = EncodeObject(ref eventPayload[index], userDataPtr, currentBuffer);
763                                currentBuffer += basicTypeAllocationBufferSize;
764                                totalEventSize += userDataPtr->Size;
765                                userDataPtr++;
766                                if (isString != null)
767                                {
768                                    if (stringIndex < etwAPIMaxStringCount)
769                                    {
770                                        dataString[stringIndex] = isString;
771                                        stringPosition[stringIndex] = index;
772                                        stringIndex++;
773                                    }
774                                    else
775                                    {                                        
776                                        throw Fx.Exception.AsError(new ArgumentOutOfRangeException("eventPayload",
777                                            SR.EtwAPIMaxStringCountExceeded(etwAPIMaxStringCount)));  
778                                    }
779                                }
780                            }
781                        }
782
783                        if (totalEventSize > traceEventMaximumSize)
784                        {
785                            errorCode = WriteEventErrorCode.EventTooBig;
786                            return false;
787                        }
788
789                        fixed (char* v0 = dataString[0], v1 = dataString[1], v2 = dataString[2], v3 = dataString[3],
790                                v4 = dataString[4], v5 = dataString[5], v6 = dataString[6], v7 = dataString[7])
791                        {
792                            userDataPtr = (UnsafeNativeMethods.EventData*)userData;
793                            if (dataString[0] != null)
794                            {
795                                userDataPtr[stringPosition[0]].DataPointer = (ulong)v0;
796                            }
797                            if (dataString[1] != null)
798                            {
799                                userDataPtr[stringPosition[1]].DataPointer = (ulong)v1;
800                            }
801                            if (dataString[2] != null)
802                            {
803                                userDataPtr[stringPosition[2]].DataPointer = (ulong)v2;
804                            }
805                            if (dataString[3] != null)
806                            {
807                                userDataPtr[stringPosition[3]].DataPointer = (ulong)v3;
808                            }
809                            if (dataString[4] != null)
810                            {
811                                userDataPtr[stringPosition[4]].DataPointer = (ulong)v4;
812                            }
813                            if (dataString[5] != null)
814                            {
815                                userDataPtr[stringPosition[5]].DataPointer = (ulong)v5;
816                            }
817                            if (dataString[6] != null)
818                            {
819                                userDataPtr[stringPosition[6]].DataPointer = (ulong)v6;
820                            }
821                            if (dataString[7] != null)
822                            {
823                                userDataPtr[stringPosition[7]].DataPointer = (ulong)v7;
824                            }
825
826                            status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle, ref eventDescriptor, ref eventTraceActivity.ActivityId, ref relatedActivityId, (uint)argCount, userData);
827                        }
828                    }
829                    else
830                    {
831                        status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle, ref eventDescriptor, ref eventTraceActivity.ActivityId, ref relatedActivityId, 0, null);
832                    }
833                }
834            }
835
836            if (status != 0)
837            {
838                SetLastError((int)status);
839                return false;
840            }
841
842            return true;
843        }
844
845        [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]  
846        [SecurityCritical]
847        [Fx.Tag.SecurityNote(Critical = "Calling Unsafe code; usage of EventDescriptor, which is protected by a LinkDemand")]
848        protected bool WriteTransferEvent(ref EventDescriptor eventDescriptor, EventTraceActivity eventTraceActivity, Guid relatedActivityId, int dataCount, IntPtr data)
849        {
850            // ActivityId is required when writing transfer event
851            if (eventTraceActivity == null)
852            {
853                throw Fx.Exception.ArgumentNull("eventTraceActivity");
854            }
855
856            uint status = 0;
857            unsafe
858            {
859                status = UnsafeNativeMethods.EventWriteTransfer(this.traceRegistrationHandle,
860                                                ref eventDescriptor,
861                                                ref eventTraceActivity.ActivityId,
862                                                ref relatedActivityId,
863                                                (uint)dataCount,
864                                                (UnsafeNativeMethods.EventData*)data);
865            }
866
867            if (status != 0)
868            {
869                SetLastError((int)status);
870                return false;
871            }
872            return true;
873        }
874                
875        [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "Microsoft.Server.Common.Interop.UnsafeNativeMethods.EventActivityIdControl(System.Int32,System.Guid@)", Justification = "Ported code from")]
876        [SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", Justification = "Existing API")]
877        [SecurityCritical]
878        public static void SetActivityId(ref Guid id)
879        {
880            UnsafeNativeMethods.EventActivityIdControl((int)ActivityControl.EVENT_ACTIVITY_CTRL_SET_ID, ref id);
881        }
882    }
883}