using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using System.Text; if (args.Length < 2) { Console.Error.WriteLine("Usage: InteropInspect ... | --type "); return 1; } var path = args[0]; var detail = false; string detailType = null; var keywords = new List(); for (int i = 1; i < args.Length; i++) { if (args[i] == "--type" && i + 1 < args.Length) { detail = true; detailType = args[++i]; } else keywords.Add(args[i]); } using var fs = File.OpenRead(path); using var pe = new PEReader(fs); var md = pe.GetMetadataReader(); string GetString(StringHandle h) => md.GetString(h); string GetNs(TypeDefinition t) { var ns = GetString(t.Namespace); var decl = t.GetDeclaringType(); if (!decl.IsNil) { var outer = md.GetTypeDefinition(decl); return GetNs(outer) + "+" + GetString(outer.Name); } return ns; } foreach (var tdh in md.TypeDefinitions) { var td = md.GetTypeDefinition(tdh); var fullName = GetNs(td) + "." + GetString(td.Name); bool match; if (detail) match = fullName.Equals(detailType, StringComparison.OrdinalIgnoreCase); else match = keywords.Any(k => fullName.IndexOf(k, StringComparison.OrdinalIgnoreCase) >= 0 || (k.StartsWith("field:") && td.GetFields().Any(f => GetString(md.GetFieldDefinition(f).Name).Contains(k[6..], StringComparison.OrdinalIgnoreCase)))); if (!match) continue; if (!detail) { Console.WriteLine(fullName); continue; } var sb = new StringBuilder(); sb.AppendLine($"TYPE {fullName}"); if (!td.BaseType.IsNil) { try { sb.AppendLine($" base: {ResolveName(md, td.BaseType)}"); } catch { } } foreach (var iih in td.GetInterfaceImplementations()) { var ii = md.GetInterfaceImplementation(iih); try { sb.AppendLine($" impl: {ResolveName(md, ii.Interface)}"); } catch { } } sb.AppendLine(" fields:"); foreach (var fh in td.GetFields()) { var f = md.GetFieldDefinition(fh); var constantHandle = f.GetDefaultValue(); var constantValue = ""; if (!constantHandle.IsNil) { var constant = md.GetConstant(constantHandle); var reader = md.GetBlobReader(constant.Value); constantValue = " = " + reader.ReadConstant(constant.TypeCode); } sb.AppendLine($" {GetString(f.Name)}{constantValue}"); } sb.AppendLine(" methods:"); foreach (var mh in td.GetMethods()) { var m = md.GetMethodDefinition(mh); var attrs = m.Attributes; var prms = m.GetParameters().Select(ph => md.GetParameter(ph)) .Select(pp => $"{GetString(pp.Name)}"); sb.AppendLine($" {GetString(m.Name)}({string.Join(", ", prms)}) [{attrs}]"); } sb.AppendLine(" properties:"); foreach (var ph in td.GetProperties()) { var p = md.GetPropertyDefinition(ph); sb.AppendLine($" {GetString(p.Name)}"); } Console.Write(sb.ToString()); } return 0; static string ResolveName(MetadataReader md, EntityHandle h) { if (h.Kind == HandleKind.TypeReference) { var tr = md.GetTypeReference((TypeReferenceHandle)h); return $"{md.GetString(tr.Namespace)}.{md.GetString(tr.Name)}"; } if (h.Kind == HandleKind.TypeDefinition) { var td2 = md.GetTypeDefinition((TypeDefinitionHandle)h); return $"{md.GetString(td2.Namespace)}.{md.GetString(td2.Name)}"; } return h.Kind.ToString(); }