//---------------------------------------------------------------------------
// File: TraceEvent
//
// A Managed wrapper for Event Tracing for Windows
//
// Author: Melur Raghuraman 
// Extended By: Baskar Sridharan (7 June 2002). 
// Date:   10 Oct 2001
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Reflection;



namespace Microsoft.Win32.Diagnostics
{
    //
    // TODO: Cover all possible EventTypes
    //
    [System.CLSCompliant(false)]
    public sealed class EventType
    {
        // Ensure class cannot be instantiated
        private EventType() {}
        public const uint Info = 0x00;		// Information or Point Event
        public const uint StartEvent = 0x01;		// Start of an activity
        public const uint EndEvent = 0x02;		// End of an activity
        public const uint DcStart = 0x03;	// Event at Start of Data Collection
        public const uint DcEnd = 0x04;		// Event at End of Data Collection
        public const uint Extension = 0x05;	// Extension Event
        public const uint Reply = 0x06;		// Request-Reply Event
        public const uint Dequeue = 0x07;	// Enqueue-Dequeue Event
        public const uint Checkpoint = 0x08;// Checkpoint Event
        public const uint Reserved = 0x09;	// Reserved Event
        public const uint Message = 0xFF;	// Debug Message Event Type

        // new Event Types beyond Win32 types
        public const uint Connect = 0x10;	// Connect Event Type
        public const uint Disconnect = 0x11;// Disconnect Event Type


        // Open-Close, Connect-Disconnect, Request-Response
        // Send-Receive, Start-End, Enqueue-Dequeue, Lock-Unlock
        // Enter-Leave, Parent-child, Read-Write, Create-Delete
        // new-dispose, alloc-free, client-server, 

        // Checkpoint/Marker, 
    }

	
	[System.CLSCompliant(false)]
	internal struct TypeNumberMap
	{			
		internal const byte NULL_NO=0;
		internal const byte OBJECT_NO = 1;
		internal const byte STRING_NO = 2;
		internal const byte SBYTE_NO = 3;
		internal const byte BYTE_NO = 4;
		internal const byte INT16_NO = 5;
		internal const byte UINT16_NO = 6;
		internal const byte INT32_NO = 7;
		internal const byte UINT32_NO = 8;
		internal const byte INT64_NO = 9;
		internal const byte UINT64_NO = 10;
		internal const byte CHAR_NO = 11;
		internal const byte SINGLE_NO = 12;
		internal const byte DOUBLE_NO = 13;
		internal const byte BOOLEAN_NO = 14;
		internal const byte DECIMAL_NO = 15;
		
	}

	
    //
    // TODO: Check with Debug Level constants in NT and System.Diagnostics
    //
	
	public enum TraceFlags: int
	{
		Error=1, Warning=2, Info=4, Info1=8, Info2=16, Info3=32, Info4=64, Info5=128, Info6=256, Info7=512, Info8=1024,
		Performance=2048, Performance1=4096, Performance2=8192, Performance3=16384, Performance4=32768, Performance5=65536,
		Performance6=131072, Performance7=262144, Performance8=524288
	}
	[Guid("189456B1-2B4C-473f-A249-3856DD93F9D3")]
    [System.CLSCompliant(false)]
	public interface ITraceMessageDecoder
	{
		 unsafe int DecodeTraceMessage(byte* message, char* buffer, int bufferSize, ref int dataSize);
	}

    [System.CLSCompliant(false)]
	[Guid("748004CA-4959-409a-887C-6546438CF48E")]
    public  class TraceProvider : ITraceMessageDecoder
    {
        static private EtwTrace.EtwProc etwProc;  // Trace Callback function 
        private ulong  registrationHandle;        // Trace Registration Handle
        private ulong  traceHandle;               // Trace Logger Handle from callback

        private uint   level;                     // Tracing Level 
        private uint   flags;                     // Trace Enable Flags
        private bool   enabled;                   // Enabled flag from Trace callback
		private const byte noOfBytesPerArg = 3;
        private string defaultString = "Foo";
		private string defaultFmtStr = "Default Format String";
		private Hashtable messageFormatTable = new Hashtable();
		string applicationName= "CSharp Software Tracing App";
		//Default GUID used by Trace Message Strings.
        private Guid MessageGuid = new Guid("{b4955bf0-3af1-4740-b475-99055d3fe9aa}");

		
		public TraceProvider()
		{
			//Such a default constructor is required for COM Interop
		}
        public  TraceProvider(string applicationName, Guid controlGuid)
        {
            Level = 0;
            flags = 0;
            IsEnabled= false;
            traceHandle = 0;
            registrationHandle = 0;
			this.applicationName = applicationName; //Currently, we don't use this variable
            //
            // Register the controlGuid with ETW
            //			
            Register(controlGuid);
        }

		
        public TraceProvider(ulong traceHandle)
        {
            this.traceHandle = traceHandle;
        }

        ~TraceProvider()
        {
            //
            // Unregister from ETW using the registrationHandle saved from
            // the register call.
            //
            EtwTrace.UnregisterTraceGuids(registrationHandle);
            GC.KeepAlive(etwProc);
        }

		public uint Flags
		{
			get{
				return flags;
			}	
			
		}
		

		internal uint Level
		{
			get
			{
				return level;
			}
			// set should not be public
			set
			{
				level = value;
			}
		}

		public bool IsEnabled
		{
			get
			{
				return enabled;
			}
			set
			{
				enabled = value;
			}
		}
        

        //
        // This callback function is called by ETW to enable or disable Tracing dynamically
        //
        public unsafe uint MyCallback(uint requestCode, System.IntPtr context, System.IntPtr bufferSize, byte* byteBuffer)
        {
            try
            {
                BaseEvent* buffer = (BaseEvent *)byteBuffer;
                switch(requestCode) 
                {
                    case EtwTrace.RequestCodes.EnableEvents: 
                        traceHandle = buffer->HistoricalContext;
                        //traceHandle = EtwTrace.GetTraceLoggerHandle((BaseEvent *)buffer);
                        flags = (uint)EtwTrace.GetTraceEnableFlags((ulong)buffer->HistoricalContext);
                        Level = (uint)EtwTrace.GetTraceEnableLevel((ulong)buffer->HistoricalContext);
                        IsEnabled = true;
                        break;
                    case EtwTrace.RequestCodes.DisableEvents:                     
                        IsEnabled = false;
                        traceHandle = 0;
                        Level = 0 ;
                        flags = 0 ;
                        break;
                    default:
                        IsEnabled = false;
                        traceHandle = 0;                    
                        break;
                }
                return 0;
            }
            catch(Exception e)
            {
                Console.WriteLine("Exception caught - '{0}'", e.Message);
                return 0;//TODO: Shouldn't we be returning a different value here ?
            }
        }
        //
        // Registers a Dynamically Generated GUID automatically with an inbuilt callback
        //
        private unsafe uint Register(Guid controlGuid)
        {
            uint status;
            TraceGuidRegistration guidReg = new TraceGuidRegistration();
            Guid dummyGuid = new Guid("{b4955bf0-3af1-4740-b475-99055d3fe9aa}");
        
            etwProc = new EtwTrace.EtwProc(MyCallback);


            guidReg.Guid =  &dummyGuid;
            guidReg.RegHandle = null;

            status = EtwTrace.RegisterTraceGuids(etwProc, null, ref controlGuid, 1, ref guidReg, null, null,  out registrationHandle);

            if (status != 0) 
            {
                Console.WriteLine("Register() call Failed with Status {0}", status);
            }
            return status;
        } 

        public unsafe uint TraceEvent(Guid eventGuid, uint evtype)
        {
            BaseEvent ev;      // Takes up 192 bytes on the stack
            ev.ClientContext = 0;
            ev.Guid = eventGuid;
            ev.ProviderId = evtype;
            ev.BufferSize = 48; // sizeof(EVENT_TRACE_HEADER)

            return EtwTrace.TraceEvent(traceHandle, (char*)&ev);
        }

		

               //
        // This is the 1 object overload
        //
        public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0)
        {
			return TraceEvent(eventGuid, evtype, data0, null, null, null, null, null, null, null, null);
		}


        //
        // This is the 2 argument overload
        //
        public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1)
        {
			return TraceEvent(eventGuid, evtype, data0, data1, null, null, null, null, null, null, null);
		}

        //
        // This is the 3 argument overload
        //
        public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2)
        {
			return TraceEvent(eventGuid, evtype, data0, data1, data2, null, null, null, null, null, null);
		}


        //
        // This is the 4 argument overload
        //
        public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3)
        {
			return TraceEvent(eventGuid, evtype, data0, data1, data2, data3, null, null, null, null, null);
		}

        //
        // This is the 5 argument overload
        //
        public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3, object data4)
        {
			return TraceEvent(eventGuid, evtype, data0, data1, data2, data3, data4, null, null, null, null);
		}

        //
        // This is the 6 argument overload
        //
        public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3, object data4, object data5)
        {
			return TraceEvent(eventGuid, evtype, data0, data1, data2, data3, data4, data5, null, null, null);
		}

        //
        // This is the 7 argument overload
        //
        public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3, object data4, object data5, object data6)
        {
			return TraceEvent(eventGuid, evtype, data0, data1, data2, data3, data4, data5, data6, null, null);
		}

        //
        // This is the 8 argument overload
        //
		public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3, object data4, object data5, object data6, object data7)
		{
			return TraceEvent(eventGuid, evtype, data0, data1, data2, data3, data4, data5, data6, data7, null);
		}

		public unsafe uint TraceEvent(Guid eventGuid, uint evtype, object data0, object data1, object data2, object data3, object data4, object data5, object data6, object data7, object data8)
		{
			uint status = 0; 
			BaseEvent ev;      // Takes up 192 bytes on the stack
			char* buffer = stackalloc  char[128];
			uint offset = 0;
			char* ptr = buffer;
			string s0 , s1 , s2 , s3 , s4 , s5 , s6 , s7 , s8;
			int stringMask = 0;
			uint argCount=0;

			s0 = s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = defaultString;

			ev.Flags = 0x00120000; // define Constants
			ev.Guid = eventGuid;
			ev.ProviderId = evtype;
			MofField *be = null;
			if (data0 != null)
			{
				argCount++;
				be = &(&ev.UserData)[0];
				if ((s0 = ProcessOneObject(data0, be, ptr, ref offset)) != null) 
				{
					stringMask |= 0x00000001;
				}
			}
			if (data1 != null)
			{
				argCount++;
				be = &(&ev.UserData)[1];
				ptr = buffer + offset;
				if ((s1 = ProcessOneObject(data1, be, ptr, ref offset)) != null) 
				{
					stringMask |= 0x00000002;
				}
			}
			if (data2 != null)
			{
				argCount++;
				be = &(&ev.UserData)[2];
				ptr = buffer + offset;
				if ((s2 = ProcessOneObject(data2, be, ptr, ref offset)) != null) 
				{
					stringMask |= 0x00000004;
				}
			}
			if (data3 != null)
			{
				argCount++;
				be = &(&ev.UserData)[3];
				ptr = buffer + offset;
				if ((s3 = ProcessOneObject(data3, be, ptr, ref offset)) != null) 
				{
					stringMask |= 0x00000008;
				}
			}
			if (data4 != null)
			{
				argCount++;
				be = &(&ev.UserData)[4];
				ptr = buffer + offset;
				if ((s4 = ProcessOneObject(data4, be, ptr, ref offset)) != null) 
				{
					stringMask |= 0x00000010;
				}
			}
			if (data5 != null)
			{
				argCount++;
				be = &(&ev.UserData)[5];
				ptr = buffer + offset;
				if ((s5 = ProcessOneObject(data5, be, ptr, ref offset)) != null) 
				{
					stringMask |= 0x00000020;
				}
			}
			if (data6 != null)
			{
				argCount++;
				be = &(&ev.UserData)[6];
				ptr = buffer + offset;
				if ((s6 = ProcessOneObject(data6, be, ptr, ref offset)) != null) 
				{
					stringMask |= 0x00000040;
				}
			}
			if (data7 != null)
			{
				argCount++;
				be = &(&ev.UserData)[7];
				ptr = buffer + offset;
				if ((s7 = ProcessOneObject(data7, be, ptr, ref offset)) != null) 
				{
					stringMask |= 0x00000080;
				}
			}
			if (data8 != null)
			{
				argCount++;
				be = &(&ev.UserData)[8];
				ptr = buffer + offset;
				if ((s8 = ProcessOneObject(data8, be, ptr, ref offset)) != null) 
				{
					stringMask |= 0x00000100;
				}
			}

			//
			// Now pin all the strings and use the stringMask to pass them over through
			// mofField. 
			//

			fixed (char*  vptr0 = s0, vptr1 = s1, vptr2 = s2, vptr3 = s3, vptr4 = s4, vptr5 = s5, vptr6 = s6, vptr7 = s7, vptr8 = s8 )
			{
				if ((stringMask & 0x00000001) != 0)
				{
					(&ev.UserData)[0].DataLength = (uint) s0.Length * 2;
					(&ev.UserData)[0].DataPointer = (void*)vptr0;
					
				}
				if ((stringMask & 0x00000002)!= 0)
				{
					(&ev.UserData)[1].DataLength = (uint) s1.Length * 2;
					(&ev.UserData)[1].DataPointer = (void*)vptr1;
					
				}
				if ((stringMask & 0x00000004)!= 0)
				{
					(&ev.UserData)[2].DataLength = (uint) s2.Length * 2;
					(&ev.UserData)[2].DataPointer = (void*)vptr2;
					
				}
				if ((stringMask & 0x00000008)!= 0)
				{
					(&ev.UserData)[3].DataLength = (uint) s3.Length * 2;
					(&ev.UserData)[3].DataPointer = (void*)vptr3;
					
				}
				if ((stringMask & 0x00000010)!= 0)
				{
					(&ev.UserData)[4].DataLength = (uint) s4.Length * 2;
					(&ev.UserData)[4].DataPointer = (void*)vptr4;
					
				}
				if ((stringMask & 0x00000020)!= 0)
				{
					(&ev.UserData)[5].DataLength = (uint) s5.Length * 2;
					(&ev.UserData)[5].DataPointer = (void*)vptr5;
					
				}
				if ((stringMask & 0x00000040)!= 0)
				{
					(&ev.UserData)[6].DataLength = (uint) s6.Length * 2;
					(&ev.UserData)[6].DataPointer = (void*)vptr6;
					
				}
				if ((stringMask & 0x00000080)!= 0)
				{
					(&ev.UserData)[7].DataLength = (uint) s7.Length * 2;
					(&ev.UserData)[7].DataPointer = (void*)vptr7;
					
				}
				if ((stringMask & 0x00000100)!= 0)
				{
					(&ev.UserData)[8].DataLength = (uint) s8.Length * 2;
					(&ev.UserData)[8].DataPointer = (void*)vptr8;
					
				}
				ev.BufferSize = 48 + argCount * 16;
				status = EtwTrace.TraceEvent(traceHandle, (char*)&ev);
			}
			return status;
		}

		private unsafe string ProcessOneObject(object data, MofField * mofField, char* ptr, ref uint offSet)
		{
			return EncodeObject(data, mofField, ptr, ref offSet, (byte *)null);
		}
		//TODO[1]: Need to accomodate Win64 alignment issues. Code that might cause problems
		// have been tagged with "WIN64 Changes".
		private unsafe string EncodeObject(object data, MofField * mofField, char* ptr, ref uint offSet, byte* ptrArgInfo)
		{
			if (data == null)
			{
				*ptrArgInfo = (byte)0; //NULL type, WIN64 Changes
				*(ushort *)(ptrArgInfo+1) = (ushort)0;				
				mofField->DataLength = 0;				
				mofField->DataPointer=(void *)null; //WIN64 Changes (?)
				return null;
			}
			string sRet = data as string;						
			if (sRet != null)
			{
				*ptrArgInfo = (byte)2; //WIN64 Changes
				*(ushort *)(ptrArgInfo+1) = (ushort)(sRet.Length<65535?sRet.Length:65535); //WIN64 Changes				
				return sRet;
			}
			if (data is sbyte)
			{

				mofField->DataLength = sizeof(sbyte);
				*ptrArgInfo = (byte)3; //WIN64 Changes
				sbyte* sbyteptr = (sbyte*)ptr;
				*sbyteptr = (sbyte) data; //WIN64 Changes
				mofField->DataPointer = (void *) sbyteptr;				
				offSet += sizeof(sbyte);
			}
			else if (data is byte)
			{
				mofField->DataLength = sizeof(byte);
				*ptrArgInfo = (byte)4; //WIN64 Changes
				byte* byteptr = (byte*)ptr;
				*byteptr = (byte) data; //WIN64 Changes
				mofField->DataPointer = (void *) byteptr;				
				offSet += sizeof(byte);
			}
			else if (data is short)
			{
				mofField->DataLength = sizeof(short);
				*ptrArgInfo = (byte)5; //WIN64 Changes
				short* shortptr = (short*)ptr;
				*shortptr = (short) data; //WIN64 Changes
				mofField->DataPointer = (void *) shortptr;				
				offSet += sizeof(short);
			}
			else if (data is ushort)
			{
				mofField->DataLength = sizeof(ushort);
				*ptrArgInfo = (byte)6; //WIN64 Changes
				ushort* ushortptr = (ushort*)ptr;
				*ushortptr = (ushort) data; //WIN64 Changes
				mofField->DataPointer = (void *) ushortptr;				
				offSet += sizeof(ushort);
			}

			else if (data is int)
			{
				mofField->DataLength = sizeof(int);
				*ptrArgInfo = (byte)7; //WIN64 Changes
				int* intptr = (int*)ptr;
				*intptr = (int) data; //WIN64 Changes
				mofField->DataPointer = (void *) intptr;	
				offSet += sizeof(int);
			}
			else if (data is uint ) 
			{
				mofField->DataLength = sizeof(uint);
				*ptrArgInfo = (byte)8; //WIN64 Changes
				uint* uintptr = (uint*)ptr;
				*uintptr = (uint) data; //WIN64 Changes
				mofField->DataPointer = (void *) uintptr;				
				offSet += sizeof(uint);
			}
			else if (data is long ) 
			{
				mofField->DataLength = sizeof(long);
				*ptrArgInfo = (byte)9; //WIN64 Changes
				long* longptr = (long*)ptr;
				*longptr = (long) data; //WIN64 Changes
				mofField->DataPointer = (void *) longptr;				
				offSet += sizeof(long);
			}
			else if (data is ulong ) 
			{
				mofField->DataLength = sizeof(ulong);
				*ptrArgInfo = (byte)10; //WIN64 Changes
				ulong* ulongptr = (ulong*)ptr;
				*ulongptr = (ulong) data; //WIN64 Changes
				mofField->DataPointer = (void *) ulongptr;						
				offSet += sizeof(ulong);
			}
			else if (data is char)
			{
				mofField->DataLength = sizeof(char);
				*ptrArgInfo = (byte)11; //WIN64 Changes
				char* charptr = (char*)ptr;
				*charptr = (char) data; //WIN64 Changes
				mofField->DataPointer = (void *) charptr;				
				offSet += sizeof(char);
			}
			else if (data is float)
			{
				mofField->DataLength = sizeof(float);
				*ptrArgInfo = (byte)12; //WIN64 Changes
				float* floatptr = (float*)ptr;
				*floatptr = (float) data; //WIN64 Changes
				mofField->DataPointer = (void *) floatptr;				
				offSet += sizeof(float);
			}
			else if (data is double)
			{
				mofField->DataLength = sizeof(double);
				*ptrArgInfo = (byte)13; //WIN64 Changes
				double* doubleptr = (double*)ptr;
				*doubleptr = (double) data; //WIN64 Changes
				mofField->DataPointer = (void *) doubleptr;				
				offSet += sizeof(double);
			}
			else if (data is bool)
			{
				mofField->DataLength = sizeof(bool);
				*ptrArgInfo = (byte)14; //WIN64 Changes
				bool* boolptr = (bool*)ptr;
				*boolptr = (bool) data; //WIN64 Changes
				mofField->DataPointer = (void *) boolptr;				
				offSet += sizeof(bool);
			}
			else if (data is decimal)
			{
				mofField->DataLength = (uint)sizeof(decimal); 
				*ptrArgInfo = (byte)15; //WIN64 Changes
				decimal* decimalptr = (decimal*)ptr;
				*decimalptr = (decimal) data; //WIN64 Changes
				mofField->DataPointer = (void *) decimalptr;				
				offSet += (uint)sizeof(decimal);
			}
			else 
			{						
				//To our eyes, everything else is a just a string
				sRet = data.ToString();																
				*ptrArgInfo = (byte)2; //WIN64 Changes
				*(ushort *)(ptrArgInfo+1) = (ushort)(sRet.Length<65535?sRet.Length:65535); //WIN64 Changes
				return sRet;	
			}
			*(ushort *)(ptrArgInfo+1) = (ushort)(mofField->DataLength); //WIN64 Changes (?)
			return sRet;

		}


		private unsafe uint EncodeTraceMessage(Guid eventGuid, uint evtype, byte nargs,  object formatstring, object data2, object data3, object data4, object data5, object data6, object data7, object data8, object data9)
		{
			uint status = 0; 
			BaseEvent ev;      // Takes up 208 bytes on the stack
			char* buffer = stackalloc  char[144+(1+9*noOfBytesPerArg)/sizeof(char)];//28 characters would be 56 bytes!!!. We are allocating more space than we require.			
			//Header structure: 
			//1 byte for number of args
			//3 byte for format string type information,
			//3 bytes each for the type information for a maximum of 8 arguments
			byte *header = (byte *)(buffer+144);				
			uint offset = 0;
			char* ptr = buffer;
			string s1 , s2 , s3 , s4 , s5 , s6 , s7 , s8, s9;
			int stringMask = 0;
			uint argCount=0;			
			byte *ptrHeader = header;			
			s1 = s2 = s3 = s4 = s5 = s6 = s7 = s8 = s9 = defaultString;

			ev.Flags = 0x00120000; // define Constants
			ev.Guid = eventGuid;
			//IMP: evtype MUST  be the same as the one specified in the typeve field for CSharp in default.tmf
			ev.ProviderId = evtype;
			MofField *be = null;	
			if (header != null)
			{				
				be = &(&ev.UserData)[0];				
				header[0] = (byte)nargs; //WIN64 Changes (?)
				be->DataPointer = (void *)header;
				be->DataLength = (uint)(1+nargs*noOfBytesPerArg);
			}
			
			if (formatstring == null)
				formatstring = defaultFmtStr;				
			if (formatstring != null)
			{
				//data1 would, in most cases, be the format string
				argCount++;
				be = &(&ev.UserData)[1];
				ptr = buffer + offset;							
				if ((s1 = EncodeObject(formatstring, be, ptr, ref offset, ++header)) != null) 
				{
					stringMask |= 0x00000002;
				}				
			}
			
			if (argCount <= nargs)
			{
				argCount++;
				be = &(&ev.UserData)[2];
				ptr = buffer + offset;
				if ((s2 = EncodeObject(data2, be, ptr, ref offset, header+1*noOfBytesPerArg)) != null) 
				{
					stringMask |= 0x00000004;
				}
			}
			if (argCount <= nargs)
			{
				argCount++;
				be = &(&ev.UserData)[3];
				ptr = buffer + offset;
				if ((s3 = EncodeObject(data3, be, ptr, ref offset, header+2*noOfBytesPerArg)) != null) 
				{
					stringMask |= 0x00000008;
				}
			}
			if (argCount <= nargs)
			{
				argCount++;
				be = &(&ev.UserData)[4];
				ptr = buffer + offset;
				if ((s4 = EncodeObject(data4, be, ptr, ref offset, header+3*noOfBytesPerArg)) != null) 
				{
					stringMask |= 0x00000010;
				}
			}
			if (argCount <= nargs)
			{
				argCount++;
				be = &(&ev.UserData)[5];
				ptr = buffer + offset;
				if ((s5 = EncodeObject(data5, be, ptr, ref offset, header+4*noOfBytesPerArg)) != null) 
				{
					stringMask |= 0x00000020;
				}
			}
			if (argCount <= nargs)
			{
				argCount++;
				be = &(&ev.UserData)[6];
				ptr = buffer + offset;
				if ((s6 = EncodeObject(data6, be, ptr, ref offset,header+5*noOfBytesPerArg)) != null) 
				{
					stringMask |= 0x00000040;
				}
			}
			if (argCount <= nargs)
			{
				argCount++;
				be = &(&ev.UserData)[7];
				ptr = buffer + offset;
				if ((s7 = EncodeObject(data7, be, ptr, ref offset,header+6*noOfBytesPerArg)) != null) 
				{
					stringMask |= 0x00000080;
				}
			
			}
			if (argCount <= nargs)
			{
				argCount++;
				be = &(&ev.UserData)[8];
				ptr = buffer + offset;
				if ((s8 = EncodeObject(data8, be, ptr, ref offset,header+7*noOfBytesPerArg)) != null) 
				{
					stringMask |= 0x00000100;
				}
			}
			if (argCount <= nargs)
			{
				argCount++;
				be = &(&ev.UserData)[9];
				ptr = buffer + offset;
				if ((s9 = EncodeObject(data9, be, ptr, ref offset, header+8*noOfBytesPerArg)) != null) 
				{
					stringMask |= 0x00000200;
				}
			}
			
			//
			// Now pin all the strings and use the stringMask to pass them over through
			// mofField. 
			//

			fixed (char*  vptr1 = s1, vptr2 = s2, vptr3 = s3, vptr4 = s4, vptr5 = s5, vptr6 = s6, vptr7 = s7, vptr8 = s8, vptr9 = s9 )
			{
				
				if ((stringMask & 0x00000002)!= 0)
				{
					
					(&ev.UserData)[1].DataLength = (uint) (s1.Length<65535/2?s1.Length*2:65535);//s1.Length*2;										

					(&ev.UserData)[1].DataPointer = (void*)(vptr1);
				}
				if ((stringMask & 0x00000004)!= 0)
				{
					(&ev.UserData)[2].DataLength = (uint) (s2.Length<65535/2?s2.Length*2:65535);//s2.Length * 2;

					(&ev.UserData)[2].DataPointer = (void*)(vptr2);
				}
				if ((stringMask & 0x00000008)!= 0)
				{
					(&ev.UserData)[3].DataLength = (uint) (s3.Length<65535/2?s3.Length*2:65535);//s3.Length * 2;
					(&ev.UserData)[3].DataPointer = (void*)(vptr3);
				}
				if ((stringMask & 0x00000010)!= 0)
				{
					(&ev.UserData)[4].DataLength = (uint) (s4.Length<65535/2?s4.Length*2:65535);//s4.Length * 2;
					(&ev.UserData)[4].DataPointer = (void*)(vptr4);
				}
				if ((stringMask & 0x00000020)!= 0)
				{
					(&ev.UserData)[5].DataLength = (uint) (s5.Length<65535/2?s5.Length*2:65535);//s5.Length * 2;
					(&ev.UserData)[5].DataPointer = (void*)(vptr5);
				}
				if ((stringMask & 0x00000040)!= 0)
				{
					(&ev.UserData)[6].DataLength = (uint) (s6.Length<65535/2?s6.Length*2:65535);//s6.Length * 2;
					(&ev.UserData)[6].DataPointer = (void*)(vptr6);
				}
				if ((stringMask & 0x00000080)!= 0)
				{
					(&ev.UserData)[7].DataLength = (uint) (s7.Length<65535/2?s7.Length*2:65535);//s7.Length * 2;
					(&ev.UserData)[7].DataPointer = (void*)(vptr7);
				}
				if ((stringMask & 0x00000100)!= 0)
				{
					(&ev.UserData)[8].DataLength = (uint) (s8.Length<65535/2?s8.Length*2:65535);//s8.Length * 2;
					(&ev.UserData)[8].DataPointer = (void*)(vptr8);
				}
				if ((stringMask & 0x00000200)!= 0)
				{
					(&ev.UserData)[9].DataLength = (uint) (s9.Length<65535/2?s9.Length*2:65535);//s9.Length * 2;
					(&ev.UserData)[9].DataPointer = (void*)(vptr9);					
				}
				ev.BufferSize = 48 + (argCount+1) * 16;//the extra mof field is for the header
				status = EtwTrace.TraceEvent(traceHandle, (char*)&ev);
			}
			return status;
		}
		public unsafe int DecodeTraceMessage(byte* message, char* buffer, int bufferSize /* in chars */, ref int dataSize /*Note: This is # of *chars* and not bytes*/)
		{
			if (buffer == null || message == null || bufferSize <= 0)
				return 0; //TODO[1]: Do we need a more detailed error code ?
            try
            {
                int i=0;
                byte nargs = *message;
                ushort lenFmtStr = *(ushort *)(message+2);			
                char* pcFmtStr = (char *)(message+1+nargs*noOfBytesPerArg);//start of the format string
                byte* argData = message+1+nargs*noOfBytesPerArg+lenFmtStr*2; //start of the argument data					
                object[] argObject = new object[nargs];			
                byte argType;
                ushort argLen;
                String formatString = new String(pcFmtStr,0,lenFmtStr);	
                //Excluding the format string
                for(i = 0; i < nargs-1; i++)
                {				
                    argType = *(message+1+(i+1)*noOfBytesPerArg);
                    argLen = *(ushort *)(message+1+(i+1)*noOfBytesPerArg+1); //WIN64 Changes (?)				
                    switch(argType)
                    {
                        case TypeNumberMap.NULL_NO:
                            argObject[i] = null;
                            break;
                        case TypeNumberMap.STRING_NO:
                        {						
                            String s;
                            if (argLen == 0)
                                s = "";
                            else s = new String((char *)argData,0,argLen);
                            argObject[i] = s;								
                            argLen *= 2; //adjust the length
                            break;
                        }
                        case TypeNumberMap.SBYTE_NO:
                        {
                            sbyte sb = *(sbyte *)argData; //WIN64 Changes
                            argObject[i] = sb;						
                            break;
                        }
                        case TypeNumberMap.BYTE_NO:
                        {
                            byte b = *argData; //WIN64 Changes
                            argObject[i] = b;						
                            break;
                        }
                        case TypeNumberMap.INT16_NO:
                        {
                            short s = *(short *)argData; //WIN64 Changes
                            argObject[i] = s;						
                            break;
                        }
                        case TypeNumberMap.UINT16_NO:
                        {
                            ushort us = *(ushort *)argData; //WIN64 Changes
                            argObject[i] = us;						
                            break;
                        }
                        case TypeNumberMap.INT32_NO:
                        {
                            int id = *(int *)argData; //WIN64 Changes
                            argObject[i] = id;						
                            break;
                        }
                        case TypeNumberMap.UINT32_NO:
                        {
                            uint uid = *(uint *)argData; //WIN64 Changes
                            argObject[i] = uid;						
                            break;
                        }
                        case TypeNumberMap.INT64_NO:
                        {
                            long l = *(long *)argData; //WIN64 Changes
                            argObject[i] = l;						
                            break;
                        }
                        case TypeNumberMap.UINT64_NO:
                        {
                            ulong ul = *(ulong *)argData; //WIN64 Changes
                            argObject[i] = ul;						
                            break;
                        }
                        case TypeNumberMap.CHAR_NO:
                        {
                            char c = *(char *)argData; //WIN64 Changes
                            argObject[i] = c;					
                            break;
                        }
                        case TypeNumberMap.SINGLE_NO:
                        {
                            float f = *(float *)argData; //WIN64 Changes
                            argObject[i] = f;						
                            break;
                        }
                        case TypeNumberMap.DOUBLE_NO:
                        {
                            double d = *(double *)argData; //WIN64 Changes
                            argObject[i] = d;						
                            break;
                        }
                        case TypeNumberMap.BOOLEAN_NO:
                        {
                            bool b = *(bool *)argData; //WIN64 Changes
                            argObject[i] = b;						
                            break;
                        }
                        case TypeNumberMap.DECIMAL_NO:
                        {
                            decimal d = *(decimal *)argData; //WIN64 Changes
                            argObject[i] = d;						
                            break;
                        }
					
                    }	
                    argData += argLen;
				
                }			
                string fStr = String.Format(formatString,argObject);	
                if (fStr.Length==0)//empty string
                    fStr="Format string was empty!";										
                int arrLen = fStr.Length*2;
                dataSize = arrLen+1;
                fixed(char* carray = fStr.ToCharArray())
                {								
					
                    if (arrLen+1 <= bufferSize)
                    {
                        for(i = 0; i < arrLen; i++)
                            buffer[i] = carray[i]; //WIN64 Changes (?)
                        //add null terminator
                        buffer[i+1] = (char)0x00; //WIN64 Changes (?)
					
                        return 1;
                    }
                    else
                    {
                        //TODO[1]: Do we need to copy as many characters as we can ? 
                        //Not sure if it is useful to do so because the caller may have to come back
                        //with the right buffer size to get all the data. So why copy part of the data twice ?
                        return 0;
                    }
                }	
            }
            catch(Exception e)
            {
                Console.WriteLine("Exception caught: {0}", e.Message);
                return -1;
            }
		}

		
        // ========================================================================
        // The following are the Message String Wrappers for Software Tracing Messages
        // using Flags.
        // There are entried for Format string and zero through 8 arguments.
        // These are kept small so they will be inlined
        // ========================================================================
        // Just the format string
        public unsafe void TraceMessage(uint traceFlags, object format )
        {			
            if ((traceFlags&Flags) != 0) 
            {				
                EncodeTraceMessage(MessageGuid, (int)14,1, format, null, null, null, null, null, null, null, null);
            }           
        }
        // Just one argument
        public unsafe void TraceMessage(uint traceFlags, object format, object data1 )
        {
            if ((traceFlags&Flags) != 0) 
            {	
				
                EncodeTraceMessage(MessageGuid, (int)14, 2, format, data1, null, null, null, null, null, null,null);
            }
            
        }
        // Just two arguments
        public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2 )
        {
			
            if ((traceFlags&Flags) != 0) 
            {
				
                EncodeTraceMessage(MessageGuid, (int)14, 3, format, data1, data2, null, null, null, null, null, null);
            }            
        }
        // Just three arguments
        public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3 )
        {			
            if ((traceFlags&Flags) != 0) 
            {				
                EncodeTraceMessage(MessageGuid, (int)14, 4, format, data1, data2, data3, null, null, null, null, null);
            }            
        }
        // Just four arguments
        public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3, object data4 )
        {
            if ((traceFlags&Flags) != 0) 
            {				
                EncodeTraceMessage(MessageGuid, (int)14, 5, format, data1, data2, data3, data4, null, null, null, null);
            }            
        }
        // Just five arguments
        public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3, object data4, object data5 )
        {
			
            if ((traceFlags&Flags) != 0) 
            {										
                EncodeTraceMessage(MessageGuid, (int)14, 6, format, data1, data2, data3, data4, data5, null, null, null);
            }            
        }
        // Just six arguments
        public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3, object data4, object data5, object data6 )
        {
			
            if ((traceFlags&Flags) != 0) 
            {								
                EncodeTraceMessage(MessageGuid, (int)14, 7, format, data1, data2, data3, data4, data5, data6, null, null);
            }            
        }
        // Just seven arguments
        public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3, object data4, object data5, object data6, object data7 )
        {
			
            if ((traceFlags&Flags) != 0) 
            {
								
                EncodeTraceMessage(MessageGuid, (int)14, 8, format, data1, data2, data3, data4, data5, data6, data7, null);
            }
            
        }
        // Just eight arguments
        public unsafe void TraceMessage(uint traceFlags, object format, object data1, object data2, object data3, object data4, object data5, object data6, object data7, object data8 )
        {
			
            if ((traceFlags&Flags) != 0) 
            {						
                EncodeTraceMessage(MessageGuid, (int)14, 9, format, data1, data2, data3, data4, data5, data6, data7, data8);
            }            
        }
    }
}