/// <summary>
        /// Creates a new MetaData instance from the serialized data at the current position of 'reader'
        /// of length 'length'.   This typically points at the PAYLOAD AREA of a meta-data events)
        /// 'fileFormatVersionNumber' is the version number of the file as a whole
        /// (since that affects the parsing of this data) and 'processID' is the process ID for the
        /// whole stream (since it needs to be put into the EVENT_RECORD.
        ///
        /// When this constructor returns the reader has read all data given to it (thus it has
        /// move the read pointer by 'length')
        /// </summary>
        public EventPipeEventMetaData(PinnedStreamReader reader, int length, int fileFormatVersionNumber, int pointerSize, int processId)
        {
            StreamLabel eventDataEnd = reader.Current.Add(length);

            _eventRecord = (TraceEventNativeMethods.EVENT_RECORD *)Marshal.AllocHGlobal(sizeof(TraceEventNativeMethods.EVENT_RECORD));
            ClearMemory(_eventRecord, sizeof(TraceEventNativeMethods.EVENT_RECORD));

            if (pointerSize == 4)
            {
                _eventRecord->EventHeader.Flags = TraceEventNativeMethods.EVENT_HEADER_FLAG_32_BIT_HEADER;
            }
            else
            {
                _eventRecord->EventHeader.Flags = TraceEventNativeMethods.EVENT_HEADER_FLAG_64_BIT_HEADER;
            }

            _eventRecord->EventHeader.ProcessId = processId;

            StreamLabel metaDataStart = reader.Current;

            if (fileFormatVersionNumber == 1)
            {
                _eventRecord->EventHeader.ProviderId = reader.ReadGuid();
            }
            else
            {
                ProviderName = reader.ReadNullTerminatedUnicodeString();
                _eventRecord->EventHeader.ProviderId = GetProviderGuidFromProviderName(ProviderName);
            }

            var eventId = (ushort)reader.ReadInt32();

            _eventRecord->EventHeader.Id = eventId;
            Debug.Assert(_eventRecord->EventHeader.Id == eventId);  // No truncation

            var version = reader.ReadInt32();

            _eventRecord->EventHeader.Version = (byte)version;
            Debug.Assert(_eventRecord->EventHeader.Version == version);  // No truncation

            if (fileFormatVersionNumber >= 3)
            {
                long keywords = reader.ReadInt64();
                _eventRecord->EventHeader.Keyword = (ulong)keywords;
            }

            int metadataLength = reader.ReadInt32();

            Debug.Assert(0 <= metadataLength && metadataLength < length);
            if (0 < metadataLength)
            {
                // TODO why do we repeat the event number it is redundant.
                eventId = (ushort)reader.ReadInt32();
                Debug.Assert(_eventRecord->EventHeader.Id == eventId);  // No truncation
                EventName = reader.ReadNullTerminatedUnicodeString();
                Debug.Assert(EventName.Length < length / 2);

                // Deduce the opcode from the name.
                if (EventName.EndsWith("Start", StringComparison.OrdinalIgnoreCase))
                {
                    _eventRecord->EventHeader.Opcode = (byte)TraceEventOpcode.Start;
                }
                else if (EventName.EndsWith("Stop", StringComparison.OrdinalIgnoreCase))
                {
                    _eventRecord->EventHeader.Opcode = (byte)TraceEventOpcode.Stop;
                }

                _eventRecord->EventHeader.Keyword = (ulong)reader.ReadInt64();

                // TODO why do we repeat the event number it is redundant.
                version = reader.ReadInt32();
                Debug.Assert(_eventRecord->EventHeader.Version == version);     // No truncation

                _eventRecord->EventHeader.Level = (byte)reader.ReadInt32();
                Debug.Assert(_eventRecord->EventHeader.Level <= 5);

                // Fetch the parameter information
                int parameterCount = reader.ReadInt32();
                Debug.Assert(0 <= parameterCount && parameterCount < length / 8); // Each parameter takes at least 8 bytes.
                if (parameterCount > 0)
                {
                    ParameterDefinitions = new Tuple <TypeCode, string> [parameterCount];
                    for (int i = 0; i < parameterCount; i++)
                    {
                        var type = (TypeCode)reader.ReadInt32();
                        Debug.Assert((uint)type < 24);      // There only a handful of type codes.
                        var name = reader.ReadNullTerminatedUnicodeString();
                        ParameterDefinitions[i] = new Tuple <TypeCode, string>(type, name);
                        Debug.Assert(reader.Current <= eventDataEnd);
                    }
                }
            }
            Debug.Assert(reader.Current == eventDataEnd);
        }