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); }