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.

101 lines
2.7 KiB

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