RefAssemblyGenerator.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.IO.Compression;
  5. using System.Linq;
  6. using dnlib.DotNet;
  7. using dnlib.DotNet.Emit;
  8. using dnlib.DotNet.Writer;
  9. public class RefAssemblyGenerator
  10. {
  11. static void PatchRefAssembly(string file)
  12. {
  13. var reader = typeof(RefAssemblyGenerator).Assembly.GetManifestResourceStream("avalonia.snk");
  14. var snk = new byte[reader.Length];
  15. reader.Read(snk, 0, snk.Length);
  16. var def = AssemblyDef.Load(new MemoryStream(File.ReadAllBytes(file)));
  17. foreach(var t in def.ManifestModule.Types)
  18. ProcessType(t);
  19. def.Write(file, new ModuleWriterOptions(def.ManifestModule)
  20. {
  21. StrongNameKey = new StrongNameKey(snk),
  22. });
  23. }
  24. static void ProcessType(TypeDef type)
  25. {
  26. foreach (var nested in type.NestedTypes)
  27. ProcessType(nested);
  28. if (type.IsInterface)
  29. {
  30. var hideMethods = type.Name.EndsWith("Impl");
  31. var injectMethod = hideMethods
  32. || type.CustomAttributes.Any(a =>
  33. a.AttributeType.FullName.EndsWith("NotClientImplementableAttribute"));
  34. if (hideMethods)
  35. {
  36. foreach (var m in type.Methods)
  37. {
  38. m.Attributes |= MethodAttributes.Public | MethodAttributes.Assembly;
  39. m.Attributes ^= MethodAttributes.Public;
  40. }
  41. }
  42. if(injectMethod)
  43. {
  44. type.Methods.Add(new MethodDefUser("NotClientImplementable",
  45. new MethodSig(CallingConvention.Default, 0, type.Module.CorLibTypes.Void),
  46. MethodAttributes.Assembly
  47. | MethodAttributes.Abstract
  48. | MethodAttributes.NewSlot
  49. | MethodAttributes.HideBySig));
  50. }
  51. }
  52. }
  53. public static void GenerateRefAsmsInPackage(string packagePath)
  54. {
  55. using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite),
  56. ZipArchiveMode.Update))
  57. {
  58. foreach (var entry in archive.Entries.ToList())
  59. {
  60. if (entry.FullName.StartsWith("ref/"))
  61. entry.Delete();
  62. }
  63. foreach (var entry in archive.Entries.ToList())
  64. {
  65. if (entry.FullName.StartsWith("lib/"))
  66. {
  67. if (entry.Name.EndsWith(".dll"))
  68. {
  69. using (Helpers.UseTempDir(out var temp))
  70. {
  71. var file = Path.Combine(temp, entry.Name);
  72. entry.ExtractToFile(file);
  73. PatchRefAssembly(file);
  74. archive.CreateEntryFromFile(file, "ref/" + entry.FullName.Substring(4));
  75. }
  76. }
  77. else if (entry.Name.EndsWith(".xml"))
  78. {
  79. var newEntry = archive.CreateEntry("ref/" + entry.FullName.Substring(4),
  80. CompressionLevel.Optimal);
  81. using (var src = entry.Open())
  82. using (var dst = newEntry.Open())
  83. src.CopyTo(dst);
  84. }
  85. }
  86. }
  87. }
  88. }
  89. }