private string GenerateManifest(EventProvider input)
        {
            var events = new StringBuilder();
            var tasks = new StringBuilder();
            var templates = new StringBuilder();

            int eventId = 1;
            int taskId = 1;

            foreach (var item in input.Items)
            {
                var e = item as EventProviderEvent;
                var t = item as EventProviderTask;
                if (e != null)
                {
                    var templateId = HandleEventArgs(templates, eventId, e.Items);

                    events.AppendFormat(@"
              <event value=""{0}"" symbol=""{4}_{1}"" task=""{1}"" opcode=""win:Info"" level=""win:{2}"" {3}/>",
                        eventId,
                        e.Name,
                        e.Level,
                        templateId == null ? "" : @"template=""" + templateId + @""" ",
                        m_safeProviderName
                        );
                    eventId++;

                    tasks.AppendFormat(@"
              <task value=""{0}"" name=""{1}"" />",
                        taskId,
                        e.Name
                        );
                    taskId++;
                }
                else if (t != null)
                {
                    var templateId = HandleEventArgs(templates, eventId, t.Start);

                    events.AppendFormat(@"
              <event value=""{0}"" symbol=""{4}_{1}_Start"" task=""{1}"" opcode=""win:Start"" level=""win:{2}"" {3}/>",
                        eventId,
                        t.Name,
                        t.Level,
                        templateId == null ? "" : @"template=""" + templateId + @""" ",
                        m_safeProviderName
                        );
                    eventId++;

                    templateId = HandleEventArgs(templates, eventId, t.Stop);

                    events.AppendFormat(@"
              <event value=""{0}"" symbol=""{4}_{1}_Stop"" task=""{1}"" opcode=""win:Stop"" level=""win:{2}"" {3}/>",
                        eventId,
                        t.Name,
                        t.Level,
                        templateId == null ? "" : @"template=""" + templateId + @""" ",
                        m_safeProviderName
                        );
                    eventId++;

                    tasks.AppendFormat(@"
              <task value=""{0}"" name=""{1}"" />",
                        taskId,
                        t.Name
                        );
                    taskId++;
                }
                else
                {
                    throw new InvalidDataException(System.String.Format("Invalid event type: {0}", item.GetType()));
                }
            }

            var manifest = new StringBuilder();
            manifest.AppendFormat(
            @"<?xml version=""1.0"" encoding=""utf-8""?>
            <instrumentationManifest
              xmlns=""http://schemas.microsoft.com/win/2004/08/events""
              xmlns:win=""http://manifests.microsoft.com/win/2004/08/windows/events""
              xmlns:xs=""http://www.w3.org/2001/XMLSchema""
              >
              <instrumentation>
            <events>
              <provider
            name=""{0}""
            symbol=""{1}""
            guid=""{2}""
            resourceFileName=""placeholder.dll""
            messageFileName=""placeholder.dll""
            >
            <tasks>{3}
            </tasks>
            <templates>{4}
            </templates>
            <events>{5}
            </events>
              </provider>
            </events>
              </instrumentation>
            </instrumentationManifest>",
            input.Name,
            m_safeProviderName,
            input.Guid,
            tasks,
            templates,
            events
            );

            var xmlManifest = manifest.ToString();

            File.WriteAllText(OutputDir + m_filename + ".man", xmlManifest, Encoding.UTF8);

            return xmlManifest;
        }
        private void GenerateHeader(EventProvider input, string xmlManifest)
        {
            var eventMethods = new StringBuilder();

            foreach (var item in input.Items)
            {
                var e = item as EventProviderEvent;
                var t = item as EventProviderTask;
                if (e != null)
                {
                    HandleEventMethods(eventMethods, e.Name, m_safeProviderName + "_" + e.Name, e.Items);
                }
                else if (t != null)
                {
                    HandleEventMethods(eventMethods, t.Name + "Start", m_safeProviderName + "_" + t.Name + "_Start", t.Start);
                    HandleEventMethods(eventMethods, t.Name + "Stop", m_safeProviderName + "_" + t.Name + "_Stop", t.Stop);
                }
                else
                {
                    throw new InvalidDataException(System.String.Format("Invalid event type: {0}", item.GetType()));
                }
            }

            var manifest = new StringBuilder();
            manifest.AppendFormat(
            @"#pragma once

            struct _EVENT_FILTER_DESCRIPTOR;

            void EventCallback{1}(
            _In_ const GUID* SourceId,
            _In_ ULONG ControlCode,
            _In_ UCHAR Level,
            _In_ ULONGLONG MatchAnyKeyword,
            _In_ ULONGLONG MatchAllKeyword,
            _In_opt_ _EVENT_FILTER_DESCRIPTOR* FilterData,
            _Inout_opt_ PVOID CallbackContext
            );

            #define MCGEN_PRIVATE_ENABLE_CALLBACK_V2 EventCallback{1}

            #include ""{0}Base.h""

            class __declspec(uuid(""{3}"")) {0}Base
            {{
            public:

            {0}Base()
            : m_delayedEventWrite(false)
            {{
            EventRegister{1}();

            if (m_delayedEventWrite)
            {{
            EventWriteManifest();
            }}
            }}

            ~{0}Base()
            {{
            if ({1}Handle != 0)
            {{
            EventWriteManifest();
            }}
            EventUnregister{1}();
            }}

            bool IsEnabled()
            {{
            return {1}_Context.IsEnabled == EVENT_CONTROL_CODE_ENABLE_PROVIDER;
            }}
            {2}
            void EventDelayedWriteManifest()
            {{
            m_delayedEventWrite = true;
            }}

            void EventWriteManifest()
            {{
            static const char manifest[] =
            R""({4})"";

            // Currently a single chunk supported
            static_assert(sizeof(manifest) < ManifestEnvelope::MaxChunkSize, ""Only one manifest chunk currently supported"");

            EVENT_DESCRIPTOR eventDescr = {{ 0xFFFE, 1, 0, 0, 0xFE, 0xFFFE, -1 }};
            ManifestEnvelope envelope = {{ 1, 1, 0, 0x5B, 1, 0 }};

            EVENT_DATA_DESCRIPTOR dataDescr[2] = {{}};
            dataDescr[0].Ptr = reinterpret_cast<ULONGLONG>(&envelope);
            dataDescr[0].Size = sizeof(envelope);
            dataDescr[1].Ptr = reinterpret_cast<ULONGLONG>(manifest);
            dataDescr[1].Size = sizeof(manifest) - 1;

            ULONG ret = EventWrite({1}Handle, &eventDescr, ARRAYSIZE(dataDescr), dataDescr);
            #ifndef NDEBUG
            if (ret != ERROR_SUCCESS)
            {{
            __debugbreak();
            }}
            #endif
            }}

            private:

            #pragma pack(push, 1)
            struct ManifestEnvelope
            {{
            uint8_t Format;
            uint8_t MajorVersion;
            uint8_t MinorVersion;
            uint8_t Magic;
            uint16_t TotalChunks;
            uint16_t ChunkNumber;

            static const uint16_t MaxChunkSize = 0xFF00;
            }};
            #pragma pack(pop)

            bool m_delayedEventWrite;
            }};

            __declspec(selectany) {0}Base {0};

            inline void EventCallback{1}(
            _In_ const GUID* /*SourceId*/,
            _In_ ULONG ControlCode,
            _In_ UCHAR /*Level*/,
            _In_ ULONGLONG /*MatchAnyKeyword*/,
            _In_ ULONGLONG /*MatchAllKeyword*/,
            _In_opt_ _EVENT_FILTER_DESCRIPTOR* /*FilterData*/,
            _Inout_opt_ PVOID /*CallbackContext*/
            )
            {{
            if (ControlCode == EVENT_CONTROL_CODE_ENABLE_PROVIDER)
            {{
            // The callback may be called during the call to EventRegisterXxx(), in which
            // case the handle is not set yet. Manifest will be sent at the end of the
            // constructor after EventRegister{1}() completes
            if ({1}Handle != 0)
            {{
            {0}.EventWriteManifest();
            }}
            else
            {{
            {0}.EventDelayedWriteManifest();
            }}
            }}

            if (ControlCode == EVENT_CONTROL_CODE_DISABLE_PROVIDER)
            {{
            {0}.EventWriteManifest();
            }}
            }}",
            m_filename,         // {0} ex: 'EtwLogger'
            m_safeProviderName, // {1} ex: 'MMaitre_TraceEtw'
            eventMethods,       // {2}
            input.Guid,         // {3} ex: '{d7bcc40a-0866-52c3-aade-b3c8d32fd38e}'
            xmlManifest         // {4}
            );

            File.WriteAllText(OutputDir + m_filename + ".h", manifest.ToString(), Encoding.UTF8);
        }