public static string GetManifestForRegisteredProvider()

in src/TraceEvent/RegisteredTraceEventParser.cs [88:514]


        public static string GetManifestForRegisteredProvider(Guid providerGuid)
        {
            int buffSize = 84000;       // Still in the small object heap.  
            byte* buffer = (byte*)System.Runtime.InteropServices.Marshal.AllocHGlobal(buffSize);
            byte* enumBuffer = null;

            TraceEventNativeMethods.EVENT_RECORD eventRecord = new TraceEventNativeMethods.EVENT_RECORD();
            eventRecord.EventHeader.ProviderId = providerGuid;

            // We keep events of a given event number together in the output
            string providerName = null;
            SortedDictionary<int, StringWriter> events = new SortedDictionary<int, StringWriter>();
            // We keep tasks separated by task ID
            SortedDictionary<int, TaskInfo> tasks = new SortedDictionary<int, TaskInfo>();
            // Templates where the KEY is the template string and the VALUE is the template name (backwards)  
            Dictionary<string, string> templateIntern = new Dictionary<string, string>(8);

            // Remember any enum types we have.   Value is XML for the enum (normal) 
            Dictionary<string, string> enumIntern = new Dictionary<string, string>();
            StringWriter enumLocalizations = new StringWriter();

            // Any task names used so far 
            Dictionary<string, int> taskNames = new Dictionary<string, int>();
            // Any  es used so far 
            Dictionary<string, int> opcodeNames = new Dictionary<string, int>();
            // This ensures that we have unique event names. 
            Dictionary<string, int> eventNames = new Dictionary<string, int>();

            SortedDictionary<ulong, string> keywords = new SortedDictionary<ulong, string>();
            List<ProviderDataItem> keywordsItems = TraceEventProviders.GetProviderKeywords(providerGuid);
            if (keywordsItems != null)
            {
                foreach (var keywordItem in keywordsItems)
                {
                    // Skip the reserved keywords.   
                    if (keywordItem.Value >= 1000000000000UL)
                    {
                        continue;
                    }

                    keywords[keywordItem.Value] = MakeLegalIdentifier(keywordItem.Name);
                }
            }

            for (int ver = 0; ver <= 255; ver++)
            {
                eventRecord.EventHeader.Version = (byte) ver;
                int count;
                int status;
                for (; ; )
                {
                    int dummy;
                    status = ETWParsing.TdhGetAllEventsInformation(&eventRecord, IntPtr.Zero, out dummy, out count, buffer, ref buffSize);
                    if (status != 122 || 20000000 < buffSize) // 122 == Insufficient buffer keep it under 2Meg
                    {
                        break;
                    }

                    Marshal.FreeHGlobal((IntPtr)buffer);
                    buffer = (byte*)Marshal.AllocHGlobal(buffSize);
                }

                // TODO FIX NOW deal with too small of a buffer.  
                if (status == 0)
                {
                    TRACE_EVENT_INFO** eventInfos = (TRACE_EVENT_INFO**)buffer;
                    for (int i = 0; i < count; i++)
                    {
                        TRACE_EVENT_INFO* eventInfo = eventInfos[i];
                        byte* eventInfoBuff = (byte*)eventInfo;
                        EVENT_PROPERTY_INFO* propertyInfos = &eventInfo->EventPropertyInfoArray;

                        if (providerName == null)
                        {
                            if (eventInfo->ProviderNameOffset != 0)
                            {
                                providerName = new string((char*)(&eventInfoBuff[eventInfo->ProviderNameOffset]));
                            }
                            else
                            {
                                providerName = "provider(" + eventInfo->ProviderGuid.ToString() + ")";
                            }
                        }

                        // Compute task name
                        string taskName = null;
                        if (eventInfo->TaskNameOffset != 0)
                        {
                            taskName = MakeLegalIdentifier((new string((char*)(&eventInfoBuff[eventInfo->TaskNameOffset]))));
                        }
                        if (taskName == null)
                        {
                            taskName = "task_" + eventInfo->EventDescriptor.Task.ToString();
                        }

                        // Ensure task name is unique.  
                        int taskNumForName;
                        if (taskNames.TryGetValue(taskName, out taskNumForName) && taskNumForName != eventInfo->EventDescriptor.Task)
                        {
                            taskName = taskName + "_" + eventInfo->EventDescriptor.Task.ToString();
                        }

                        taskNames[taskName] = eventInfo->EventDescriptor.Task;

                        // Compute opcode name
                        string opcodeName = "";
                        if (eventInfo->EventDescriptor.Opcode != 0)
                        {
                            if (eventInfo->OpcodeNameOffset != 0)
                            {
                                opcodeName = MakeLegalIdentifier((new string((char*)(&eventInfoBuff[eventInfo->OpcodeNameOffset]))));
                            }
                            else
                            {
                                opcodeName = "opcode_" + eventInfo->EventDescriptor.Opcode.ToString();
                            }
                        }

                        // Ensure opcode name is unique.  
                        int opcodeNumForName;
                        if (opcodeNames.TryGetValue(opcodeName, out opcodeNumForName) && opcodeNumForName != eventInfo->EventDescriptor.Opcode)
                        {
                            // If we did not find a name, use 'opcode and the disambiguator
                            if (eventInfo->OpcodeNameOffset == 0)
                            {
                                opcodeName = "opcode";
                            }

                            opcodeName = opcodeName + "_" + eventInfo->EventDescriptor.Task.ToString() + "_" + eventInfo->EventDescriptor.Opcode.ToString();
                        }
                        opcodeNames[opcodeName] = eventInfo->EventDescriptor.Opcode;

                        // And event name 
                        string eventName = taskName;
                        if (!taskName.EndsWith(opcodeName, StringComparison.OrdinalIgnoreCase))
                        {
                            eventName += Capitalize(opcodeName);
                        }

                        // Ensure uniqueness of the event name
                        int eventNumForName;
                        if (eventNames.TryGetValue(eventName, out eventNumForName) && eventNumForName != eventInfo->EventDescriptor.Id)
                        {
                            eventName = eventName + eventInfo->EventDescriptor.Id.ToString();
                        }

                        eventNames[eventName] = eventInfo->EventDescriptor.Id;

                        // Get task information
                        TaskInfo taskInfo;
                        if (!tasks.TryGetValue(eventInfo->EventDescriptor.Task, out taskInfo))
                        {
                            tasks[eventInfo->EventDescriptor.Task] = taskInfo = new TaskInfo() { Name = taskName };
                        }

                        var symbolName = eventName;
                        if (eventInfo->EventDescriptor.Version > 0)
                        {
                            symbolName += "_V" + eventInfo->EventDescriptor.Version;
                        }

                        StringWriter eventWriter;
                        if (!events.TryGetValue(eventInfo->EventDescriptor.Id, out eventWriter))
                        {
                            events[eventInfo->EventDescriptor.Id] = eventWriter = new StringWriter();
                        }

                        eventWriter.Write("     <event value=\"{0}\" symbol=\"{1}\" version=\"{2}\" task=\"{3}\"",
                            eventInfo->EventDescriptor.Id,
                            symbolName,
                            eventInfo->EventDescriptor.Version,
                            taskName);
                        if (eventInfo->EventDescriptor.Opcode != 0)
                        {
                            string opcodeId;
                            if (eventInfo->EventDescriptor.Opcode < 10)       // It is a reserved opcode.  
                            {
                                // For some reason opcodeName does not have the underscore, which we need. 
                                if (eventInfo->EventDescriptor.Opcode == (byte)TraceEventOpcode.DataCollectionStart)
                                {
                                    opcodeId = "win:DC_Start";
                                }
                                else if (eventInfo->EventDescriptor.Opcode == (byte)TraceEventOpcode.DataCollectionStop)
                                {
                                    opcodeId = "win:DC_Stop";
                                }
                                else
                                {
                                    opcodeId = "win:" + opcodeName;
                                }
                            }
                            else
                            {
                                opcodeId = opcodeName;
                                if (taskInfo.Opcodes == null)
                                {
                                    taskInfo.Opcodes = new SortedDictionary<int, string>();
                                }

                                if (!taskInfo.Opcodes.ContainsKey(eventInfo->EventDescriptor.Opcode))
                                {
                                    taskInfo.Opcodes[eventInfo->EventDescriptor.Opcode] = opcodeId;
                                }
                            }
                            eventWriter.Write(" opcode=\"{0}\"", opcodeId);
                        }
                        // TODO handle cases outside standard levels 
                        if ((int)TraceEventLevel.Always <= eventInfo->EventDescriptor.Level && eventInfo->EventDescriptor.Level <= (int)TraceEventLevel.Verbose)
                        {
                            var asLevel = (TraceEventLevel)eventInfo->EventDescriptor.Level;
                            var levelName = "win:" + asLevel;
                            eventWriter.Write(" level=\"{0}\"", levelName);
                        }

                        var keywordStr = GetKeywordStr(keywords, (ulong)eventInfo->EventDescriptor.Keyword);
                        if (keywordStr.Length > 0)
                        {
                            eventWriter.Write(" keywords=\"" + keywordStr + "\"", eventInfo->EventDescriptor.Keyword);
                        }

                        if (eventInfo->TopLevelPropertyCount != 0)
                        {
                            var templateWriter = new StringWriter();
                            string[] propertyNames = new string[eventInfo->TopLevelPropertyCount];
                            for (int j = 0; j < eventInfo->TopLevelPropertyCount; j++)
                            {
                                EVENT_PROPERTY_INFO* propertyInfo = &propertyInfos[j];
                                var propertyName = new string((char*)(&eventInfoBuff[propertyInfo->NameOffset]));
                                propertyNames[j] = propertyName;
                                var enumAttrib = "";

                                // Deal with any maps (bit fields or enumerations)
                                if (propertyInfo->MapNameOffset != 0)
                                {
                                    string mapName = new string((char*)(&eventInfoBuff[propertyInfo->MapNameOffset]));

                                    if (enumBuffer == null)
                                    {
                                        enumBuffer = (byte*)System.Runtime.InteropServices.Marshal.AllocHGlobal(buffSize);
                                    }

                                    if (!enumIntern.ContainsKey(mapName))
                                    {
                                        EVENT_MAP_INFO* enumInfo = (EVENT_MAP_INFO*)enumBuffer;
                                        var hr = TdhGetEventMapInformation(&eventRecord, mapName, enumInfo, ref buffSize);
                                        if (hr == 0)
                                        {
                                            // We only support manifest enums for now.  
                                            if (enumInfo->Flag == MAP_FLAGS.EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP ||
                                                enumInfo->Flag == MAP_FLAGS.EVENTMAP_INFO_FLAG_MANIFEST_BITMAP)
                                            {
                                                StringWriter enumWriter = new StringWriter();
                                                string enumName = new string((char*)(&enumBuffer[enumInfo->NameOffset]));
                                                enumAttrib = " map=\"" + enumName + "\"";
                                                if (enumInfo->Flag == MAP_FLAGS.EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP)
                                                {
                                                    enumWriter.WriteLine("     <valueMap name=\"{0}\">", enumName);
                                                }
                                                else
                                                {
                                                    enumWriter.WriteLine("     <bitMap name=\"{0}\">", enumName);
                                                }

                                                EVENT_MAP_ENTRY* mapEntries = &enumInfo->MapEntryArray;
                                                for (int k = 0; k < enumInfo->EntryCount; k++)
                                                {
                                                    int value = mapEntries[k].Value;
                                                    string valueName = new string((char*)(&enumBuffer[mapEntries[k].NameOffset])).Trim();
                                                    enumWriter.WriteLine("      <map value=\"0x{0:x}\" message=\"$(string.map_{1}{2})\"/>", value, enumName, valueName);
                                                    enumLocalizations.WriteLine("    <string id=\"map_{0}{1}\" value=\"{2}\"/>", enumName, valueName, valueName);
                                                }
                                                if (enumInfo->Flag == MAP_FLAGS.EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP)
                                                {
                                                    enumWriter.WriteLine("     </valueMap>", enumName);
                                                }
                                                else
                                                {
                                                    enumWriter.WriteLine("     </bitMap>", enumName);
                                                }

                                                enumIntern[mapName] = enumWriter.ToString();
                                            }
                                        }
                                    }
                                }

                                // Remove anything that does not look like an ID (.e.g space)
                                propertyName = Regex.Replace(propertyName, "[^A-Za-z0-9_]", "");
                                TdhInputType propertyType = propertyInfo->InType;
                                string countOrLengthAttrib = "";

                                if ((propertyInfo->Flags & PROPERTY_FLAGS.ParamCount) != 0)
                                {
                                    countOrLengthAttrib = " count=\"" + propertyNames[propertyInfo->CountOrCountIndex] + "\"";
                                }
                                else if ((propertyInfo->Flags & PROPERTY_FLAGS.ParamLength) != 0)
                                {
                                    countOrLengthAttrib = " length=\"" + propertyNames[propertyInfo->LengthOrLengthIndex] + "\"";
                                }

                                templateWriter.WriteLine("      <data name=\"{0}\" inType=\"win:{1}\"{2}{3}/>", propertyName, propertyType.ToString(), enumAttrib, countOrLengthAttrib);
                            }
                            var templateStr = templateWriter.ToString();

                            // See if this template already exists, and if not make it 
                            string templateName;
                            if (!templateIntern.TryGetValue(templateStr, out templateName))
                            {
                                templateName = eventName + "Args";
                                if (eventInfo->EventDescriptor.Version > 0)
                                {
                                    templateName += "_V" + eventInfo->EventDescriptor.Version;
                                }

                                templateIntern[templateStr] = templateName;
                            }
                            eventWriter.Write(" template=\"{0}\"", templateName);
                        }
                        eventWriter.WriteLine("/>");
                    }
                }
                else if (status == 1168 && ver != 0)        // Not Found give up
                {
                    break;
                }
            }
            if (enumBuffer != null)
            {
                System.Runtime.InteropServices.Marshal.FreeHGlobal((IntPtr)enumBuffer);
            }

            System.Runtime.InteropServices.Marshal.FreeHGlobal((IntPtr)buffer);
            if (providerName == null)
            {
                throw new ApplicationException("Could not find provider with at GUID of " + providerGuid.ToString());
            }

            StringWriter manifest = new StringWriter();
            manifest.WriteLine("<instrumentationManifest xmlns=\"http://schemas.microsoft.com/win/2004/08/events\">");
            manifest.WriteLine(" <instrumentation xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:win=\"http://manifests.microsoft.com/win/2004/08/windows/events\">");
            manifest.WriteLine("  <events>");
            manifest.WriteLine("   <provider name=\"{0}\" guid=\"{{{1}}}\" resourceFileName=\"{0}\" messageFileName=\"{0}\" symbol=\"{2}\" source=\"Xml\" >",
                    providerName, providerGuid, Regex.Replace(providerName, @"[^\w]", ""));

            StringWriter localizedStrings = new StringWriter();

            if (keywords != null)
            {
                manifest.WriteLine("    <keywords>");
                foreach (var keyValue in keywords)
                {
                    manifest.WriteLine("     <keyword name=\"{0}\" message=\"$(string.keyword_{1})\" mask=\"0x{2:x}\"/>",
                        keyValue.Value, keyValue.Value, keyValue.Key);
                    localizedStrings.WriteLine("    <string id=\"keyword_{0}\" value=\"{1}\"/>", keyValue.Value, keyValue.Value);
                }
                manifest.WriteLine("    </keywords>");
            }

            manifest.WriteLine("    <tasks>");
            foreach (var taskValue in tasks.Keys)
            {
                var task = tasks[taskValue];
                manifest.WriteLine("     <task name=\"{0}\" message=\"$(string.task_{1})\" value=\"{2}\"{3}>", task.Name, task.Name, taskValue,
                    task.Opcodes == null ? "/" : "");       // If no opcodes, terminate immediately.  
                localizedStrings.WriteLine("    <string id=\"task_{0}\" value=\"{1}\"/>", task.Name, task.Name);
                if (task.Opcodes != null)
                {
                    manifest.WriteLine(">");
                    manifest.WriteLine("      <opcodes>");
                    foreach (var keyValue in task.Opcodes)
                    {
                        manifest.WriteLine("       <opcode name=\"{0}\" message=\"$(string.opcode_{1}{2})\" value=\"{3}\"/>",
                            keyValue.Value, task.Name, keyValue.Value, keyValue.Key);
                        localizedStrings.WriteLine("    <string id=\"opcode_{0}{1}\" value=\"{2}\"/>", task.Name, keyValue.Value, keyValue.Value);
                    }
                    manifest.WriteLine("      </opcodes>");
                    manifest.WriteLine("     </task>");
                }
            }
            manifest.WriteLine("    </tasks>");

            if (enumIntern.Count > 0)
            {
                manifest.WriteLine("    <maps>");
                foreach (var map in enumIntern.Values)
                {
                    manifest.Write(map);
                }

                manifest.WriteLine("    </maps>");
                localizedStrings.Write(enumLocalizations.ToString());
            }

            manifest.WriteLine("    <events>");
            foreach (StringWriter eventStr in events.Values)
            {
                manifest.Write(eventStr.ToString());
            }

            manifest.WriteLine("    </events>");

            manifest.WriteLine("    <templates>");
            foreach (var keyValue in templateIntern)
            {
                manifest.WriteLine("     <template tid=\"{0}\">", keyValue.Value);
                manifest.Write(keyValue.Key);
                manifest.WriteLine("     </template>");
            }
            manifest.WriteLine("    </templates>");
            manifest.WriteLine("   </provider>");
            manifest.WriteLine("  </events>");
            manifest.WriteLine(" </instrumentation>");
            string strings = localizedStrings.ToString();
            if (strings.Length > 0)
            {
                manifest.WriteLine(" <localization>");
                manifest.WriteLine("  <resources culture=\"{0}\">", IetfLanguageTag(CultureInfo.CurrentCulture));
                manifest.WriteLine("   <stringTable>");
                manifest.Write(strings);
                manifest.WriteLine("   </stringTable>");
                manifest.WriteLine("  </resources>");
                manifest.WriteLine(" </localization>");
            }

            manifest.WriteLine("</instrumentationManifest>");
            return manifest.ToString(); ;
        }