You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.7 KiB

3 years ago
  1. using System;
  2. using System.IO;
  3. using System.Management.Automation;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using ICSharpCode.Decompiler.CSharp;
  7. using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
  8. using ICSharpCode.Decompiler.Metadata;
  9. namespace ICSharpCode.Decompiler.PowerShell
  10. {
  11. [Cmdlet(VerbsCommon.Get, "DecompiledProject")]
  12. [OutputType(typeof(string))]
  13. public class GetDecompiledProjectCmdlet : PSCmdlet, IProgress<DecompilationProgress>
  14. {
  15. [Parameter(Position = 0, Mandatory = true)]
  16. public CSharpDecompiler Decompiler { get; set; }
  17. [Parameter(Position = 1, Mandatory = true)]
  18. [Alias("PSPath", "OutputPath")]
  19. [ValidateNotNullOrEmpty]
  20. public string LiteralPath { get; set; }
  21. readonly object syncObject = new object();
  22. int completed;
  23. string fileName;
  24. ProgressRecord progress;
  25. public void Report(DecompilationProgress value)
  26. {
  27. lock (syncObject)
  28. {
  29. completed++;
  30. progress = new ProgressRecord(1, "Decompiling " + fileName, $"Completed {completed} of {value.TotalUnits}: {value.Status}") {
  31. PercentComplete = (int)(completed * 100.0 / value.TotalUnits)
  32. };
  33. }
  34. }
  35. protected override void ProcessRecord()
  36. {
  37. string path = GetUnresolvedProviderPathFromPSPath(LiteralPath);
  38. if (!Directory.Exists(path))
  39. {
  40. WriteObject("Destination directory must exist prior to decompilation");
  41. return;
  42. }
  43. try
  44. {
  45. var task = Task.Run(() => DoDecompile(path));
  46. int timeout = 100;
  47. // Give the decompiler some time to spin up all threads
  48. Thread.Sleep(timeout);
  49. while (!task.IsCompleted)
  50. {
  51. ProgressRecord progress;
  52. lock (syncObject)
  53. {
  54. progress = this.progress;
  55. this.progress = null;
  56. }
  57. if (progress != null)
  58. {
  59. timeout = 100;
  60. WriteProgress(progress);
  61. }
  62. else
  63. {
  64. Thread.Sleep(timeout);
  65. timeout = Math.Min(1000, timeout * 2);
  66. }
  67. }
  68. task.Wait();
  69. WriteProgress(new ProgressRecord(1, "Decompiling " + fileName, "Decompilation finished") { RecordType = ProgressRecordType.Completed });
  70. }
  71. catch (Exception e)
  72. {
  73. WriteVerbose(e.ToString());
  74. WriteError(new ErrorRecord(e, ErrorIds.DecompilationFailed, ErrorCategory.OperationStopped, null));
  75. }
  76. }
  77. private void DoDecompile(string path)
  78. {
  79. MetadataFile module = Decompiler.TypeSystem.MainModule.MetadataFile;
  80. var assemblyResolver = new UniversalAssemblyResolver(module.FileName, false, module.Metadata.DetectTargetFrameworkId());
  81. WholeProjectDecompiler decompiler = new WholeProjectDecompiler(assemblyResolver);
  82. decompiler.ProgressIndicator = this;
  83. fileName = module.FileName;
  84. completed = 0;
  85. decompiler.DecompileProject(module, path);
  86. }
  87. }
  88. }